From 3f7664f652552a1090f3a3869436d41530d79c0c Mon Sep 17 00:00:00 2001 From: MUQING <1966944300@qq.com> Date: Sat, 30 Dec 2023 10:01:18 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E5=86=99=E6=AD=8C=E8=AF=8D=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=EF=BC=8C=E6=B7=BB=E5=8A=A0=E6=82=AC=E6=B5=AE=E7=AA=97?= =?UTF-8?q?=E6=AD=8C=E8=AF=8D=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 3 +- app/src/main/AndroidManifest.xml | 1 + .../main/java/com/muqingbfq/MediaPlayer.java | 6 +- .../com/muqingbfq/MyButtonClickReceiver.java | 28 ++ app/src/main/java/com/muqingbfq/api/url.java | 6 +- app/src/main/java/com/muqingbfq/bfq.java | 17 +- app/src/main/java/com/muqingbfq/bfqkz.java | 3 +- .../java/com/muqingbfq/fragment/Media.java | 23 +- .../java/com/muqingbfq/fragment/search.java | 14 +- app/src/main/java/com/muqingbfq/home.java | 40 ++ app/src/main/java/com/muqingbfq/main.java | 2 + .../muqingbfq/mq/FloatingLyricsService.java | 221 +++++++++++ .../mq/NotificationManagerCompat.java | 16 +- app/src/main/java/com/muqingbfq/sz.java | 3 +- .../main/java/com/muqingbfq/view/LrcView.java | 352 ++++++++++++++++++ app/src/main/res/drawable/bf.xml | 4 +- app/src/main/res/drawable/like.xml | 4 +- app/src/main/res/drawable/syq.xml | 4 +- app/src/main/res/drawable/xyq.xml | 4 +- app/src/main/res/drawable/zt.xml | 4 +- app/src/main/res/layout-land/activity_bfq.xml | 3 +- app/src/main/res/layout/activity_bfq.xml | 192 +++++----- app/src/main/res/layout/float_lrcview.xml | 77 ++++ app/src/main/res/layout/view_lrc.xml | 12 + app/src/main/res/values/attrs.xml | 8 + 25 files changed, 902 insertions(+), 145 deletions(-) create mode 100644 app/src/main/java/com/muqingbfq/mq/FloatingLyricsService.java create mode 100644 app/src/main/java/com/muqingbfq/view/LrcView.java create mode 100644 app/src/main/res/layout/float_lrcview.xml create mode 100644 app/src/main/res/layout/view_lrc.xml create mode 100644 app/src/main/res/values/attrs.xml diff --git a/app/build.gradle b/app/build.gradle index bcad2c1..729b34c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -51,7 +51,8 @@ dependencies { implementation 'com.squareup.okhttp3:okhttp:4.11.0' implementation 'com.github.bumptech.glide:glide:4.16.0' - implementation 'com.github.wangchenyan:lrcview:2.2.1' +// 废弃的歌词组件 +// implementation 'com.github.wangchenyan:lrcview:2.2.1' implementation 'com.google.android.flexbox:flexbox:3.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a6e5cc9..5ccfa37 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -72,6 +72,7 @@ + { }); - } + }*/ } @SuppressLint("ClickableViewAccessibility") @Override @@ -211,7 +209,9 @@ public class bfq extends AppCompatActivity { public class Touch implements View.OnTouchListener { - private float downY, moveY; + private float downY; + + @SuppressLint("ClickableViewAccessibility") @Override public boolean onTouch(View view, MotionEvent motionEvent) {LinearLayout root = binding.getRoot(); switch (motionEvent.getAction()) { @@ -220,7 +220,7 @@ public class bfq extends AppCompatActivity { break; case MotionEvent.ACTION_MOVE: //长按事件,可以移动 - moveY = motionEvent.getRawY(); + float moveY = motionEvent.getRawY(); //移动的距离 float dy = moveY - downY; //重新设置控件的位置。移动 @@ -267,6 +267,7 @@ public class bfq extends AppCompatActivity { public void finish() { super.finish(); view = null; - lrcview = null; + lrcView = null; + main.handler.removeCallbacks(bfqkz.mt.updateSeekBar); // 在播放开始时启动更新进度 } } \ No newline at end of file diff --git a/app/src/main/java/com/muqingbfq/bfqkz.java b/app/src/main/java/com/muqingbfq/bfqkz.java index f343f6f..1fe2122 100644 --- a/app/src/main/java/com/muqingbfq/bfqkz.java +++ b/app/src/main/java/com/muqingbfq/bfqkz.java @@ -19,6 +19,7 @@ import androidx.media.MediaBrowserServiceCompat; import com.muqingbfq.api.url; import com.muqingbfq.mq.BluetoothMusicController; +import com.muqingbfq.mq.FloatingLyricsService; import com.muqingbfq.mq.gj; import com.muqingbfq.mq.wj; @@ -95,7 +96,6 @@ public class bfqkz extends MediaBrowserServiceCompat { playback = new PlaybackStateCompat.Builder() .setState(PlaybackStateCompat.STATE_NONE, 0, 1.0f) .build(); - Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_LAUNCHER); intent.setComponent(new ComponentName(this, home.class));//用ComponentName得到class对象 @@ -111,6 +111,7 @@ public class bfqkz extends MediaBrowserServiceCompat { setSessionToken(mSession.getSessionToken()); notify = new com.muqingbfq.mq.NotificationManagerCompat(this); + } class callback extends MediaSessionCompat.Callback { diff --git a/app/src/main/java/com/muqingbfq/fragment/Media.java b/app/src/main/java/com/muqingbfq/fragment/Media.java index 2ef6973..7e18a95 100644 --- a/app/src/main/java/com/muqingbfq/fragment/Media.java +++ b/app/src/main/java/com/muqingbfq/fragment/Media.java @@ -1,5 +1,7 @@ package com.muqingbfq.fragment; + import android.widget.SeekBar; + import com.muqingbfq.R; import com.muqingbfq.bfq; import com.muqingbfq.bfq_an; @@ -7,8 +9,11 @@ import com.muqingbfq.bfqkz; import com.muqingbfq.databinding.ActivityBfqBinding; import com.muqingbfq.main; import com.muqingbfq.mq.gj; +import com.muqingbfq.view.LrcView; + import org.json.JSONObject; -public class Media{ + +public class Media { public static void setTime_a(String str) { if (bfq.view == null) { return; @@ -35,7 +40,8 @@ public class Media{ return; } bfq.binding.tdt.setProgress(progress); - bfq.lrcview.updateTime(progress); +// bfq.lrcview.updateTime(progress); + bfq.lrcView.setTimeLrc(progress); } public static void setbf(boolean bool) { @@ -56,11 +62,13 @@ public class Media{ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { setTime_b(bfq_an.getTime(progress)); } + @Override public void onStartTrackingTouch(SeekBar seekBar) { // 拖动条移动中 main.handler.removeCallbacks(bfqkz.mt.updateSeekBar); } + @Override public void onStopTrackingTouch(SeekBar seekBar) { // 播放音乐到指定位置 @@ -70,12 +78,11 @@ public class Media{ }); //初始化播放器列表 if (bfqkz.xm != null) { -// main.handler.removeCallbacks(bfqkz.mt.updateSeekBar); // 在播放开始时启动更新进度 long duration = bfqkz.mt.getDuration(); - binding.tdt.setMax((int) bfqkz.mt.getDuration()); + binding.tdt.setMax(bfqkz.mt.getDuration()); setTime_a(bfq_an.getTime(duration)); long position = bfqkz.mt.getCurrentPosition(); -// main.handler.post(bfqkz.mt.updateSeekBar); // 在播放开始时启动更新进度 + main.handler.post(bfqkz.mt.updateSeekBar); // 在播放开始时启动更新进度 loadLyric(); setProgress((int) position); } @@ -83,7 +90,7 @@ public class Media{ public static void loadLyric() { - if (bfq.lrcview == null || com.muqingbfq.bfq.lrc == null) { + if (com.muqingbfq.bfq.lrc == null) { return; } JSONObject jsonObject; @@ -95,7 +102,9 @@ public class Media{ } catch (Exception e) { gj.sc(e); } - bfq.lrcview.loadLrc(a, b); + LrcView.setLrc(a, b); +// bfq.lrcView.getLrc(); +// bfq.lrcView.loadLrc(a, b); } diff --git a/app/src/main/java/com/muqingbfq/fragment/search.java b/app/src/main/java/com/muqingbfq/fragment/search.java index 65a1826..965770a 100644 --- a/app/src/main/java/com/muqingbfq/fragment/search.java +++ b/app/src/main/java/com/muqingbfq/fragment/search.java @@ -25,7 +25,6 @@ import com.muqingbfq.databinding.FragmentSearchBinding; import com.muqingbfq.list.MyViewHoder; import com.muqingbfq.main; import com.muqingbfq.mq.gj; -import com.muqingbfq.mq.wj; import com.muqingbfq.mq.wl; import com.muqingbfq.xm; @@ -39,7 +38,6 @@ public class search extends Fragment { public static RecyclerView.Adapter lbspq; List list = new ArrayList<>(); List xmList = new ArrayList<>(); - gd.baseadapter adapter_gd; public String name; public FragmentSearchBinding inflate; @@ -55,7 +53,6 @@ public class search extends Fragment { TypedValue typedValue = new TypedValue(); requireContext().getTheme().resolveAttribute(android.R.attr.windowBackground, typedValue, true); // 设置背景颜色 - adapter_gd = new gd.baseadapter(getContext(), xmList); view.setBackgroundColor(typedValue.data); inflate.tablayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override @@ -101,7 +98,7 @@ public class search extends Fragment { GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), k); inflate.recyclerview.setLayoutManager(gridLayoutManager); - inflate.recyclerview.setAdapter(adapter_gd); + inflate.recyclerview.setAdapter(new gd.baseadapter(getContext(), xmList)); } new start(name); } @@ -123,14 +120,7 @@ public class search extends Fragment { } else if (i == 1) { gd(); } - main.handler.post(() -> { - if (i == 0) { - lbspq.notifyDataSetChanged(); - } else if (i == 1) { - adapter_gd.notifyDataSetChanged(); - } -// lbspq.notifyDataSetChanged(); - }); + main.handler.post(() -> inflate.recyclerview.getAdapter().notifyDataSetChanged()); } } diff --git a/app/src/main/java/com/muqingbfq/home.java b/app/src/main/java/com/muqingbfq/home.java index a839c83..c310cef 100644 --- a/app/src/main/java/com/muqingbfq/home.java +++ b/app/src/main/java/com/muqingbfq/home.java @@ -5,12 +5,16 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.net.Uri; import android.os.Bundle; +import android.provider.Settings; import android.support.v4.media.MediaBrowserCompat; import android.util.DisplayMetrics; import android.view.Menu; import android.view.MenuItem; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.appcompat.app.ActionBarDrawerToggle; import androidx.appcompat.app.AppCompatActivity; @@ -21,9 +25,11 @@ import androidx.viewpager2.adapter.FragmentStateAdapter; import androidx.viewpager2.widget.ViewPager2; import com.muqingbfq.databinding.ActivityHomeBinding; +import com.muqingbfq.databinding.FloatLrcviewBinding; import com.muqingbfq.fragment.bfq_db; import com.muqingbfq.fragment.gd_adapter; import com.muqingbfq.fragment.wode; +import com.muqingbfq.mq.FloatingLyricsService; import com.muqingbfq.mq.gj; import java.util.ArrayList; @@ -77,6 +83,7 @@ public class home extends AppCompatActivity { binding.editView.setOnClickListener(view -> startActivity(new Intent(this, activity_search.class))); UI(); +// startService(new Intent(this, FloatingLyricsService.class)); } catch (Exception e) { yc.tc(this, e); } @@ -87,21 +94,25 @@ public class home extends AppCompatActivity { private class Adaper extends FragmentStateAdapter { List list = new ArrayList<>(); + public Adaper(@NonNull FragmentActivity fragmentActivity) { super(fragmentActivity); list.add(new gd_adapter()); list.add(new wode()); } + @NonNull @Override public Fragment createFragment(int position) { return list.get(position); } + @Override public int getItemCount() { return list.size(); } } + public void UI() { adapter = new Adaper(this); binding.viewPager.setAdapter(adapter); @@ -144,6 +155,35 @@ public class home extends AppCompatActivity { }); } + @Override + protected void onStart() { + super.onStart(); + stopService(new Intent(this, FloatingLyricsService.class)); + } + + ActivityResultLauncher LyricsService = + registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> { + if (Settings.canDrawOverlays(this)) { + startService(new Intent(this, FloatingLyricsService.class)); + } + }); + + @Override + protected void onStop() { + super.onStop(); + if (!FloatingLyricsService.get()) { + return; + } + if (!Settings.canDrawOverlays(this)) { + // 无权限,需要申请权限 + Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, + Uri.parse("package:" + getPackageName())); + LyricsService.launch(intent); + } else { + startService(new Intent(this, FloatingLyricsService.class)); + } + } + @Override protected void onPause() { super.onPause(); diff --git a/app/src/main/java/com/muqingbfq/main.java b/app/src/main/java/com/muqingbfq/main.java index 3b58d8e..6a56926 100644 --- a/app/src/main/java/com/muqingbfq/main.java +++ b/app/src/main/java/com/muqingbfq/main.java @@ -2,6 +2,7 @@ package com.muqingbfq; import android.annotation.SuppressLint; import android.app.Application; +import android.content.Intent; import android.content.SharedPreferences; import android.os.Handler; import android.os.Looper; @@ -9,6 +10,7 @@ import android.os.Looper; import androidx.appcompat.app.AppCompatDelegate; import com.muqingbfq.login.visitor; +import com.muqingbfq.mq.FloatingLyricsService; import com.muqingbfq.mq.wj; import com.muqingbfq.mq.wl; diff --git a/app/src/main/java/com/muqingbfq/mq/FloatingLyricsService.java b/app/src/main/java/com/muqingbfq/mq/FloatingLyricsService.java new file mode 100644 index 0000000..2c28e15 --- /dev/null +++ b/app/src/main/java/com/muqingbfq/mq/FloatingLyricsService.java @@ -0,0 +1,221 @@ +package com.muqingbfq.mq; + +import android.annotation.SuppressLint; +import android.app.Service; +import android.content.Intent; +import android.graphics.Color; +import android.graphics.PixelFormat; +import android.os.Build; +import android.os.Handler; +import android.os.IBinder; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; + +import androidx.annotation.Nullable; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.muqingbfq.bfq_an; +import com.muqingbfq.bfqkz; +import com.muqingbfq.databinding.FloatLrcviewBinding; +import com.muqingbfq.main; +import com.muqingbfq.view.LrcView; + +import java.io.File; +import java.lang.reflect.Type; + +public class FloatingLyricsService extends Service implements View.OnClickListener, View.OnTouchListener { + private WindowManager windowManager; + private View layout; + public Runnable updateSeekBar = new Runnable() { + @Override + public void run() { + if (bfqkz.mt.isPlaying() && lrcView != null) { + long position = bfqkz.mt.getCurrentPosition(); + lrcView.setTimeLrc(position); + } + handler.postDelayed(this, 1000); // 每秒更新一次进度 + } + }; + @SuppressLint("StaticFieldLeak") + public static FloatingLyricsService lei; + + public static boolean get() { + File file = new File(wj.filesdri + "FloatingLyricsService.json"); + if (file.exists() && file.isFile()) { + String dqwb = wj.dqwb(file.toString()); + Gson gson = new Gson(); + Type type = new TypeToken() { + }.getType(); + SETUP setup = gson.fromJson(dqwb, type); + return setup.i != 0; + } else { + return true; + } + } + Handler handler = new Handler(); + LrcView lrcView; + WindowManager.LayoutParams params; + + public static class SETUP { + //0是关闭 1是打开 2是锁定 + public int i; + public float TOP; + public int Y; + } + + public SETUP setup = new SETUP(); + File file; + + public int lock() { + if (setup != null && setup.i == 2) { + return WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + } + return WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + } + + @Override + public void onCreate() { + super.onCreate(); + lei = this; + try { + file = new File(wj.filesdri + "FloatingLyricsService.json"); + if (file.exists() && file.isFile()) { + String dqwb = wj.dqwb(file.toString()); + Gson gson = new Gson(); + Type type = new TypeToken() { + }.getType(); + setup = gson.fromJson(dqwb, type); + } else { + setup.i = 1; + setup.TOP = 0; + setup.Y = -main.g; + } + + + } catch (Exception e) { + wj.sc(file.toString()); + gj.sc(e); + } + // 创建悬浮窗歌词的 View +// FloatLrcviewBinding + FloatLrcviewBinding binding = FloatLrcviewBinding.inflate(LayoutInflater.from(this)); + layout = binding.getRoot(); + layout.setOnTouchListener(this); +// ViewGroup.LayoutParams layoutParams = layout.getLayoutParams(); +// layout.setLayoutParams(layoutParams); + +// int i = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;FLAG_NOT_TOUCH_MODAL + params = new WindowManager.LayoutParams( + WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.WRAP_CONTENT, + Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? + WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY : + WindowManager.LayoutParams.TYPE_PHONE, + lock(), + PixelFormat.TRANSLUCENT + ); + + params.y = setup.Y; + + lrcView = binding.lrcView; + bfq_an.kz bfqAn = new bfq_an.kz(); + binding.kg.setOnClickListener(bfqAn); + binding.syq.setOnClickListener(bfqAn); + binding.xyq.setOnClickListener(bfqAn); + binding.lock.setOnClickListener(this); +// params.gravity = Gravity.CENTER; + + + // 获取 WindowManager 并将悬浮窗歌词添加到窗口中 + windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); + if (setup.i == 2) { + params.flags = lock(); + layout.setBackground(null); + lrcView.setAlpha(0.5f); + layout.findViewById(com.muqingbfq.R.id.controlLayout).setVisibility(View.GONE); + } + windowManager.addView(layout, params); + gj.sc("添加成功"); + handler.post(updateSeekBar); // 在播放开始时启动更新进度 + } + + @Override + public void onDestroy() { + super.onDestroy(); + // 在 Service 销毁时移除悬浮窗歌词 + if (windowManager != null && layout != null) { + windowManager.removeView(layout); + handler.removeCallbacks(bfqkz.mt.updateSeekBar); // 在播放开始时启动更新进度 + } + lei = null; + } + + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } + + public void baocun() { + String s = new Gson().toJson(setup); + wj.xrwb(new File(wj.filesdri + "FloatingLyricsService.json").toString(), s); + } + + private int initialY; + private float initialTouchY; + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + switch (motionEvent.getAction()) { + case MotionEvent.ACTION_DOWN: + // 记录触摸事件的初始位置和坐标 + initialY = params.y; + initialTouchY = motionEvent.getRawY(); + return true; + case MotionEvent.ACTION_MOVE: + // 计算触摸事件的偏移量,将悬浮窗口的位置设置为初始位置加上偏移量 + int offsetY = (int) (motionEvent.getRawY() - initialTouchY); + setup.Y = initialY + offsetY; + params.y = setup.Y; + windowManager.updateViewLayout(layout, params); + return true; + case MotionEvent.ACTION_UP: + baocun(); + break; + + } + return false; + } + + @Override + public void onClick(View view) { + setyc(); + } + + public void setyc() { + setup.i = 2; + params.flags = lock(); + layout.setBackground(null); + lrcView.setAlpha(0.5f); + layout.findViewById(com.muqingbfq.R.id.controlLayout).setVisibility(View.GONE); + windowManager.updateViewLayout(layout, params); + baocun(); + } + + public void show() { + setup.i = 1; + params.flags = lock(); + layout.setBackgroundColor(Color.parseColor("#50000000")); + lrcView.setAlpha(1.0f); + layout.findViewById(com.muqingbfq.R.id.controlLayout).setVisibility(View.VISIBLE); + windowManager.updateViewLayout(layout, params); + baocun(); + } +} diff --git a/app/src/main/java/com/muqingbfq/mq/NotificationManagerCompat.java b/app/src/main/java/com/muqingbfq/mq/NotificationManagerCompat.java index 3efd72d..d0e3246 100644 --- a/app/src/main/java/com/muqingbfq/mq/NotificationManagerCompat.java +++ b/app/src/main/java/com/muqingbfq/mq/NotificationManagerCompat.java @@ -54,8 +54,10 @@ public class NotificationManagerCompat { setAction("syq")); pendingIntent_xyq = getBroadcast(context, my. setAction("xyq")); + pendingIntent_lrc = getBroadcast(context, my. + setAction("lrc")); style = new androidx.media.app.NotificationCompat.MediaStyle() - .setShowActionsInCompactView(0, 1, 2) + .setShowActionsInCompactView(1, 2, 3) .setMediaSession(bfqkz.mSession.getSessionToken()); notificationManager = androidx.core.app.NotificationManagerCompat.from(context); notificationBuilder = getNotificationBuilder(context) @@ -79,10 +81,13 @@ public class NotificationManagerCompat { zz = bfqkz.xm.zz; } notificationBuilder.mActions.clear(); - notificationBuilder.addAction(android.R.drawable.ic_media_previous, "syq", pendingIntent_syq) // #0 - .addAction(bfqkz.mt.isPlaying() ? android.R.drawable.ic_media_pause : android.R.drawable.ic_media_play + notificationBuilder + .addAction(R.drawable.like, "like", pendingIntent_kg) // #0 + .addAction(R.drawable.syq, "syq", pendingIntent_syq) // #0 + .addAction(bfqkz.mt.isPlaying() ? R.drawable.bf : R.drawable.zt , "kg", pendingIntent_kg) // #1 - .addAction(android.R.drawable.ic_media_next, "xyq", pendingIntent_xyq) + .addAction(R.drawable.xyq, "xyq", pendingIntent_xyq) + .addAction(R.drawable.lock, "lrc", pendingIntent_lrc) .setContentTitle(name) .setContentText(zz) .setOngoing(bfqkz.mt.isPlaying()); @@ -91,7 +96,8 @@ public class NotificationManagerCompat { private PendingIntent pendingIntent_kg, pendingIntent_syq, - pendingIntent_xyq; + pendingIntent_xyq, + pendingIntent_lrc; private final String CHANNEL_ID = "muqing_yy_id"; public void notificationManager_notify() { diff --git a/app/src/main/java/com/muqingbfq/sz.java b/app/src/main/java/com/muqingbfq/sz.java index bec6aad..a0ba1c8 100644 --- a/app/src/main/java/com/muqingbfq/sz.java +++ b/app/src/main/java/com/muqingbfq/sz.java @@ -79,7 +79,8 @@ public class sz extends AppCompatActivity { return super.onOptionsItemSelected(item); } - ActivityResultLauncher intent = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), + ActivityResultLauncher intent = registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), result -> { if (Settings.canDrawOverlays(this)) { com.muqingbfq.mq.floating.start(sz.this); diff --git a/app/src/main/java/com/muqingbfq/view/LrcView.java b/app/src/main/java/com/muqingbfq/view/LrcView.java new file mode 100644 index 0000000..4543759 --- /dev/null +++ b/app/src/main/java/com/muqingbfq/view/LrcView.java @@ -0,0 +1,352 @@ +package com.muqingbfq.view; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.LinearSmoothScroller; +import androidx.recyclerview.widget.RecyclerView; + +import com.muqingbfq.R; +import com.muqingbfq.main; +import com.muqingbfq.mq.gj; +import com.muqingbfq.yc; + +import java.util.ArrayList; +import java.util.List; + +public class LrcView extends RecyclerView { + private void sc(Object obj) { + gj.sc("LRC " + obj); + } + + static List lrclist = new ArrayList<>(); + + static class lrc { + String lrc, tlyric; + long time; + + public lrc(String lrc, long time) { + this.lrc = lrc; + this.time = time; + } + + public lrc(String lrc, String tlyric, long time) { + this.lrc = lrc; + this.tlyric = tlyric; + this.time = time; + } + + public lrc setTlyric(String str) { + this.tlyric = str; + return this; + } + + } + + public LrcView(Context context) { + super(context); + init(); + } + + AttributeSet attrs; + boolean Lrcline; + LinearLayoutManager linearLayoutManager; + + public LrcView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + this.attrs = attrs; + init(); + } + + public LrcView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + this.attrs = attrs; + init(); + } + + private void init() { + if (attrs != null) { + TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.LrcView); + TextColor = ta.getColor(R.styleable.LrcView_TextColor, + ContextCompat.getColor(getContext(), R.color.text)); + Lrcline = ta.getBoolean(R.styleable.LrcView_Lrcline, true); + ta.recycle(); + } + linearLayoutManager = new LinearLayoutManager(getContext()) { + + @Override + public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { + RecyclerView.SmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext()); + smoothScroller.setTargetPosition(position); + startSmoothScroll(smoothScroller); + } + + }; + setLayoutManager(linearLayoutManager); + setAdapter(new adaper()); + setForeground(null); + setOverScrollMode(RecyclerView.OVER_SCROLL_NEVER); + if (!Lrcline) { + addItemDecoration( new RecyclerView.ItemDecoration() { + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + + int parentHeight = parent.getHeight(); + int childHeight = view.getHeight(); + + int topMargin = (parentHeight - childHeight) / 2; + + // 设置第一项的顶部间距 + if (parent.getChildAdapterPosition(view) == 0) { + outRect.top = topMargin; + } + } + }); + } + } + + private static class CenterSmoothScroller extends LinearSmoothScroller { + + CenterSmoothScroller(Context context) { + super(context); + } + + @Override + public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) { + return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2); + } + + @Override + protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { + return 100f / displayMetrics.densityDpi; + } + } + + public static void setLrc(String a, String b) { + setLrc(a); + if (TextUtils.isEmpty(b)) { + return; + } + b.trim(); + String[] lines = b.split("\n"); + for (String line : lines) { + String[] parts = line.split("]"); + if (parts.length >= 2) { + String timeString = parts[0].substring(1); + String lyric = parts[1].trim(); + String[] timeParts = timeString.split(":"); + if (timeParts.length >= 2) { + int minute = Integer.parseInt(timeParts[0]); + String[] secondParts = timeParts[1].split("\\."); + if (secondParts.length >= 2) { + int second = Integer.parseInt(secondParts[0]); + int millisecond = Integer.parseInt(secondParts[1]); + long time = (long) minute * 60 * 1000 + second * 1000L + millisecond; + int currentLineIndex = getCurrentLineIndex(time); + lrclist.set(currentLineIndex, lrclist.get(currentLineIndex).setTlyric(lyric)); +// gj.sc(lyric); + } + } + } + } + } + + public static void setLrc(String a) { + lrclist.clear(); + // 去除空格 + a.trim(); + if (TextUtils.isEmpty(a)) { + return; + } + String[] lines = a.split("\n"); + for (String line : lines) { + String[] parts = line.split("]"); + if (parts.length >= 2) { + String timeString = parts[0].substring(1); + String lyric = parts[1].trim(); + String[] timeParts = timeString.split(":"); + if (timeParts.length >= 2) { + int minute = Integer.parseInt(timeParts[0]); + String[] secondParts = timeParts[1].split("\\."); + if (secondParts.length >= 2) { + int second = Integer.parseInt(secondParts[0]); + int millisecond = Integer.parseInt(secondParts[1]); + long time = (long) minute * 60 * 1000 + second * 1000L + millisecond; + lrclist.add(new lrc(lyric, time)); +// gj.sc(lyric); + } + } + } + } + } + + class adaper extends RecyclerView.Adapter { + + @NonNull + @Override + public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View inflate = LayoutInflater.from(getContext()).inflate(R.layout.view_lrc, parent, false); + TextView textView = inflate.findViewById(R.id.text); + textView.setTextColor(TextColor); + textView.setTextSize( + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 20, + getResources().getDisplayMetrics())); + return new VH(inflate); + } + + @Override + public void onBindViewHolder(@NonNull VH holder, int position) { + if (lrclist.isEmpty()) { + holder.textView.setText("纯音乐,请欣赏"); + return; + } + if (Lrcline) { + int currentLineIndex = getCurrentLineIndex(); + if (currentLineIndex >= 0 && currentLineIndex < lrclist.size()) { + + String text; + if (lrclist.size() <= 3) { + for (lrc a : lrclist) { + if (a.time == 5940000 && a.lrc.equals("纯音乐,请欣赏")) { + text = "纯音乐,请欣赏"; + holder.textView.setText(text); + return; + } + } + } + lrc currentLrc = lrclist.get(currentLineIndex); + text = currentLrc.lrc; + if (currentLrc.tlyric != null) { + text += "\n" + currentLrc.tlyric; + } + holder.textView.setText(text); + } + } else { + try { + lrc lrc = lrclist.get(position); + StringBuilder stringBuffer = new StringBuilder(); + stringBuffer.append(lrc.lrc); + if (lrc.tlyric != null) { + stringBuffer.append("\n").append(lrc.tlyric); + } + stringBuffer.append("\n"); + holder.textView.setAlpha(0.1f); + if (getCurrentLineIndex(time) == position) { + holder.textView.setAlpha(1.0f); + } + holder.textView.setText(stringBuffer.toString()); + } catch (Exception e) { + gj.sc("LrcView.ADAPER.onBindViewHolder" + e); + } + } + } + + @Override + public int getItemCount() { + gj.sc(lrclist.size()); + if (lrclist.size() < 3) { + for (lrc a : lrclist) { + if (a.time == 5940000 && a.lrc.equals("纯音乐,请欣赏")) { + return 1; + } + } + } + if (Lrcline) { + return 1; + } + if (lrclist.isEmpty()) { + return 1; + } + return lrclist.size(); + } + } + + class VH extends RecyclerView.ViewHolder { + TextView textView; + + public VH(@NonNull View itemView) { + super(itemView); + textView = itemView.findViewById(R.id.text); + } + } +/* @Override + public void onDraw(@NonNull Canvas canvas) { + super.onDraw(canvas); + setTimeLrc(canvas); + }*/ + + private int getCurrentLineIndex() { + int index = -1; + for (int i = 0; i < lrclist.size(); i++) { + lrc lineLrc = lrclist.get(i); + if (lineLrc.time <= time) { + index = i; + } else { + break; + } + } + return index; + } + + private static int getCurrentLineIndex(long time) { + int index = -1; + for (int i = 0; i < lrclist.size(); i++) { + lrc lineLrc = lrclist.get(i); + if (lineLrc.time <= time) { + index = i; + } else { + break; + } + } + return index; + } + + int TextColor; + long time; + + @SuppressLint("NotifyDataSetChanged") + public void setTimeLrc(long a) { + this.time = a; + if (!Lrcline) { + int currentLineIndex = getCurrentLineIndex(a); + if (currentLineIndex == -1) { + return; + } + linearLayoutManager.smoothScrollToPosition(this, + new RecyclerView.State(), currentLineIndex); +// smoothScrollToPosition(getCurrentLineIndex(a)); + getAdapter().notifyItemChanged(--currentLineIndex); + getAdapter().notifyItemChanged(getCurrentLineIndex(a)); + return; + } + getAdapter().notifyDataSetChanged(); + } + + public void getLrc() { + for (lrc a : lrclist) { + sc(a.time + ":" + a.lrc + ":" + a.tlyric); + } + } +} diff --git a/app/src/main/res/drawable/bf.xml b/app/src/main/res/drawable/bf.xml index 53eafb3..39a973e 100644 --- a/app/src/main/res/drawable/bf.xml +++ b/app/src/main/res/drawable/bf.xml @@ -1,6 +1,6 @@ - - - - + - + android:layout_height="260dp" + android:layout_weight="2"/> + + + + + + + + + + + + + + + + + + + app:layout_constraintBottom_toTopOf="@+id/kg" + tools:layout_editor_absoluteX="20dp"> - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/float_lrcview.xml b/app/src/main/res/layout/float_lrcview.xml new file mode 100644 index 0000000..78b7cff --- /dev/null +++ b/app/src/main/res/layout/float_lrcview.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + +