从GitHub移植过来

This commit is contained in:
muqing 2025-01-15 18:55:44 +08:00
commit 756cd6e75c
215 changed files with 15785 additions and 0 deletions

17
.gitignore vendored Normal file
View File

@ -0,0 +1,17 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.idea
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
*.apk

20
README.md Normal file
View File

@ -0,0 +1,20 @@
## 简介
一个对接网易云的音乐播放器
## 截图
暂无
## 联系作者
* QQ:1966944300
* 邮箱:1966944300@qq.com
## 后台
* Github: [网易云音乐 API](https://github.com/Binaryify/NeteaseCloudMusicApi)
## 关于
在兴趣的驱动下,写一个`免费`的东西,有欣喜,也还有汗水,希望你喜欢我的作品,同时也能支持一下。
## 修改JAR的包
(主要修改内容MD3化)
com.github.QuadFlask:colorpicker:0.0.15
# (歌词做全局变量给悬浮窗歌词)
'com.github.wangchenyan:lrcview:2.2.1'

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

94
app/build.gradle Normal file
View File

@ -0,0 +1,94 @@
plugins {
id 'com.android.application'
id 'kotlin-android'
}
android {
signingConfigs {
debug {
storeFile file('../muqing.jks')
storePassword 'muqing153'
keyAlias 'muqing'
keyPassword 'muqing153'
}
}
namespace 'com.muqingbfq'
compileSdk 34
defaultConfig {
applicationId "com.muqingbfq"
minSdk 24
//noinspection ExpiredTargetSdkVersion,OldTargetApi
targetSdk 34
versionCode 1
versionName "2.6.0"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildTypes {
release {
// shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
android.applicationVariants.configureEach {
variant ->
variant.outputs.configureEach {
//apk文件名
outputFileName = "Cloud_music-${variant.name}-v${variant.versionName}.apk"
}
}
kotlinOptions {
jvmTarget = '1.8'
}
viewBinding {
enabled = true
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.7.0'
implementation 'com.google.android.material:material:1.10.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'com.google.code.gson:gson:2.9.1'
implementation 'com.squareup.okhttp3:okhttp:4.11.0'
//
implementation 'com.github.bumptech.glide:glide:4.16.0'
implementation 'jp.wasabeef:glide-transformations:4.3.0'
implementation "androidx.palette:palette-ktx:1.0.0"
//
// 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'
//
implementation 'com.mpatric:mp3agic:0.9.1'
//
// release
// $lastVersion
implementation 'com.gitee.zackratos:UltimateBarX:v0.8.1'
// api project(path: ':lrcview')
//
api "com.github.cy745:EaseView:e11c3208a9"
api "androidx.dynamicanimation:dynamicanimation-ktx:1.0.0-alpha03"
implementation "androidx.media3:media3-exoplayer:1.4.0"
implementation "androidx.media3:media3-ui:1.4.0"
implementation "androidx.media3:media3-common:1.4.0"
implementation "androidx.media3:media3-session:1.4.0"
implementation 'androidx.activity:activity:1.9.1'
implementation "androidx.lifecycle:lifecycle-process:2.6.1"
}

21
app/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -0,0 +1,20 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.muqingbfq",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "2.6.0",
"outputFile": "Cloud_music-release-v2.6.0.apk"
}
],
"elementType": "File"
}

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- 存储权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 外部存储的写权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 外部存储的读权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<uses-permission android:name="android.permission.INTERNET" /> <!-- 网络权限 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- 申请通知栏权限 -->
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<uses-permission android:name="android.permission.RECEIVE_NOTIFICATIONS" /> <!-- 蓝牙连接 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <!-- 悬浮窗权限 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" /> <!-- 主题壁纸 -->
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/><!--你正在使用前台服务,并且目标 SDK 为 34因此需要在 Android 13 (API 34) 上请求-->
<application
android:name=".main"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:preserveLegacyExternalStorage="true"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:enableOnBackInvokedCallback="true"
android:theme="@style/Theme.muqing"
android:usesCleartextTraffic="true"
tools:targetApi="tiramisu">
<activity
android:name=".home"
android:exported="true"
android:theme="@style/Theme.start">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".login.user_logs" />
<activity android:name=".clean.fragment_clean" />
<activity android:name=".activity_search" />
<!-- <activity-->
<!-- android:name=".bfq"-->
<!-- android:configChanges="keyboardHidden|screenSize"-->
<!-- android:theme="@style/fragment_dialog" />-->
<activity android:name=".fragment.mp3" />
<activity android:name=".fragment.gd" />
<activity android:name=".activity_about_software" />
<activity android:name=".sz" />
<activity android:name=".mq.llq" />
<activity android:name=".yc" />
<activity
android:name=".activity.Music"
android:configChanges="keyboardHidden|screenSize"
android:theme="@style/fragment_dialog" />
<service
android:name=".bfqkz"
android:exported="true"
tools:ignore="ExportedService">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</service>
<service android:name=".mq.FloatingLyricsService" android:exported="true"
tools:ignore="ExportedService" />
<service
android:name=".PlaybackService"
android:exported="true"
android:foregroundServiceType="mediaPlayback"
tools:ignore="ExportedService">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService" />
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
</application>
</manifest>

View File

@ -0,0 +1,56 @@
<h2>开源在线音乐播放器项目</h2>
<p>该项目由作者MUQING编写,采用了 JAVA 设计语言,该应用对接了网易云音乐API,为用户提供了一系列功能丰富的服务:</p>
<ol>
<li><strong>音乐搜索与发现</strong>
<ul>
<li>用户可以通过搜索框快速查找网易云音乐曲库中的歌曲、歌单。</li>
</ul>
</li>
<li><strong>在线播放与下载</strong>
<ul>
<li>支持在线流媒体播放,用户可以流畅地收听高品质音乐,并可根据网络状况切换不同音质。</li>
<li>提供音乐下载功能,用户可将喜欢的歌曲保存到本地进行离线播放。</li>
</ul>
</li>
<li><strong>个性化歌单与收藏</strong>
<ul>
<li>用户能收藏自己的歌单,以及收藏其他用户的优秀歌单。</li>
</ul>
</li>
<li><strong>歌词显示与同步</strong>
<ul>
<li>在播放音乐时,同步展示歌词,并支持歌词滚动与定位。</li>
</ul>
</li>
<li><strong>账号绑定与同步</strong>
<ul>
<li>用户可以使用网易云音乐账号登录,实现离线歌单和播放历史。</li>
</ul>
</li>
<!-- <li><strong>界面定制与主题更换</strong>
<ul>
<li>应用遵循Material 3设计规范提供美观且符合最新设计趋势的UI体验。</li>
<li>用户可以根据个人喜好调整界面颜色、字体大小等,以达到最佳视觉效果。</li>
</ul>
</li>-->
<!--
<li><strong>社交互动</strong>
<ul>
<li>允许用户查看并参与歌曲评论区讨论,与其他音乐爱好者交流心得。</li>
</ul>
</li>
-->
<li><strong>智能推荐系统</strong>
<ul>
<li>根据用户的听歌习惯和偏好,推送个性化的音乐推荐。</li>
</ul>
</li>
<li><strong>后台播放与控制</strong>
<ul>
<li>支持通知栏控制和小部件操作,即使在其他应用或屏幕关闭状态下也能方便控制音乐播放。</li>
</ul>
</li>
</ol>
<p>通过这个开源项目开发者学习如何对接第三方API实现音乐播放功能还能了解各种小功能和细节的实现。</p>

View File

@ -0,0 +1,54 @@
package com.colorpicker;
import android.graphics.Color;
public class ColorCircle {
private float x, y;
private float[] hsv = new float[3];
private float[] hsvClone;
private int color;
public ColorCircle(float x, float y, float[] hsv) {
set(x, y, hsv);
}
public double sqDist(float x, float y) {
double dx = this.x - x;
double dy = this.y - y;
return dx * dx + dy * dy;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public float[] getHsv() {
return hsv;
}
public float[] getHsvWithLightness(float lightness) {
if (hsvClone == null)
hsvClone = hsv.clone();
hsvClone[0] = hsv[0];
hsvClone[1] = hsv[1];
hsvClone[2] = lightness;
return hsvClone;
}
public void set(float x, float y, float[] hsv) {
this.x = x;
this.y = y;
this.hsv[0] = hsv[0];
this.hsv[1] = hsv[1];
this.hsv[2] = hsv[2];
this.color = Color.HSVToColor(this.hsv);
}
public int getColor() {
return color;
}
}

View File

@ -0,0 +1,39 @@
package com.colorpicker;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.ColorDrawable;
import com.colorpicker.builder.PaintBuilder;
public class ColorCircleDrawable extends ColorDrawable {
private float strokeWidth;
private Paint strokePaint = PaintBuilder.newPaint().style(Paint.Style.STROKE).stroke(strokeWidth).color(0xff9e9e9e).build();
private Paint fillPaint = PaintBuilder.newPaint().style(Paint.Style.FILL).color(0).build();
private Paint fillBackPaint = PaintBuilder.newPaint().shader(PaintBuilder.createAlphaPatternShader(26)).build();
public ColorCircleDrawable(int color) {
super(color);
}
@Override
public void draw(Canvas canvas) {
canvas.drawColor(0);
int width = canvas.getWidth();
float radius = width / 2f;
strokeWidth = radius / 8f;
this.strokePaint.setStrokeWidth(strokeWidth);
this.fillPaint.setColor(getColor());
canvas.drawCircle(radius, radius, radius - strokeWidth, fillBackPaint);
canvas.drawCircle(radius, radius, radius - strokeWidth, fillPaint);
canvas.drawCircle(radius, radius, radius - strokeWidth, strokePaint);
}
@Override
public void setColor(int color) {
super.setColor(color);
invalidateSelf();
}
}

View File

@ -0,0 +1,156 @@
package com.colorpicker;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.preference.Preference;
import androidx.annotation.NonNull;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import com.colorpicker.builder.ColorPickerClickListener;
import com.colorpicker.builder.ColorPickerDialogBuilder;
import com.muqingbfq.R;
public class ColorPickerPreference extends Preference {
protected boolean alphaSlider;
protected boolean lightSlider;
protected boolean border;
protected int selectedColor = 0;
protected ColorPickerView.WHEEL_TYPE wheelType;
protected int density;
private boolean pickerColorEdit;
private String pickerTitle;
private String pickerButtonCancel;
private String pickerButtonOk;
protected ImageView colorIndicator;
public ColorPickerPreference(Context context) {
super(context);
}
public ColorPickerPreference(Context context, AttributeSet attrs) {
super(context, attrs);
initWith(context, attrs);
}
public ColorPickerPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initWith(context, attrs);
}
private void initWith(Context context, AttributeSet attrs) {
final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ColorPickerPreference);
try {
alphaSlider = typedArray.getBoolean(R.styleable.ColorPickerPreference_alphaSlider, false);
lightSlider = typedArray.getBoolean(R.styleable.ColorPickerPreference_lightnessSlider, false);
border = typedArray.getBoolean(R.styleable.ColorPickerPreference_border, true);
density = typedArray.getInt(R.styleable.ColorPickerPreference_density, 8);
wheelType = ColorPickerView.WHEEL_TYPE.indexOf(typedArray.getInt(R.styleable.ColorPickerPreference_wheelType, 0));
selectedColor = typedArray.getInt(R.styleable.ColorPickerPreference_initialColor, 0xffffffff);
pickerColorEdit = typedArray.getBoolean(R.styleable.ColorPickerPreference_pickerColorEdit, true);
pickerTitle = typedArray.getString(R.styleable.ColorPickerPreference_pickerTitle);
if (pickerTitle==null)
pickerTitle = "Choose color";
pickerButtonCancel = typedArray.getString(R.styleable.ColorPickerPreference_pickerButtonCancel);
if (pickerButtonCancel==null)
pickerButtonCancel = "cancel";
pickerButtonOk = typedArray.getString(R.styleable.ColorPickerPreference_pickerButtonOk);
if (pickerButtonOk==null)
pickerButtonOk = "ok";
} finally {
typedArray.recycle();
}
setWidgetLayoutResource(R.layout.color_widget);
}
@Override
protected void onBindView(@NonNull View view) {
super.onBindView(view);
int tmpColor = isEnabled()
? selectedColor
: darken(selectedColor, .5f);
colorIndicator = (ImageView) view.findViewById(R.id.color_indicator);
ColorCircleDrawable colorChoiceDrawable = null;
Drawable currentDrawable = colorIndicator.getDrawable();
if (currentDrawable != null && currentDrawable instanceof ColorCircleDrawable)
colorChoiceDrawable = (ColorCircleDrawable) currentDrawable;
if (colorChoiceDrawable == null)
colorChoiceDrawable = new ColorCircleDrawable(tmpColor);
colorIndicator.setImageDrawable(colorChoiceDrawable);
}
public void setValue(int value) {
if (callChangeListener(value)) {
selectedColor = value;
persistInt(value);
notifyChanged();
}
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
setValue(restoreValue ? getPersistedInt(0) : (Integer) defaultValue);
}
@Override
protected void onClick() {
ColorPickerDialogBuilder builder = ColorPickerDialogBuilder
.with(getContext())
.setTitle(pickerTitle)
.initialColor(selectedColor)
.showBorder(border)
.wheelType(wheelType)
.density(density)
.showColorEdit(pickerColorEdit)
.setPositiveButton(pickerButtonOk, new ColorPickerClickListener() {
@Override
public void onClick(DialogInterface dialog, int selectedColorFromPicker, Integer[] allColors) {
setValue(selectedColorFromPicker);
}
})
.setNegativeButton(pickerButtonCancel, null);
if (!alphaSlider && !lightSlider) builder.noSliders();
else if (!alphaSlider) builder.lightnessSliderOnly();
else if (!lightSlider) builder.alphaSliderOnly();
builder
.build()
.show();
}
public static int darken(int color, float factor) {
int a = Color.alpha(color);
int r = Color.red(color);
int g = Color.green(color);
int b = Color.blue(color);
return Color.argb(a,
Math.max((int)(r * factor), 0),
Math.max((int)(g * factor), 0),
Math.max((int)(b * factor), 0));
}
}

View File

@ -0,0 +1,572 @@
package com.colorpicker;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.colorpicker.builder.ColorWheelRendererBuilder;
import com.colorpicker.builder.PaintBuilder;
import com.colorpicker.renderer.ColorWheelRenderOption;
import com.colorpicker.renderer.ColorWheelRenderer;
import com.colorpicker.slider.AlphaSlider;
import com.colorpicker.slider.LightnessSlider;
import com.muqingbfq.R;
import java.util.ArrayList;
public class ColorPickerView extends View {
private static final float STROKE_RATIO = 1.5f;
private Bitmap colorWheel;
private Canvas colorWheelCanvas;
private Bitmap currentColor;
private Canvas currentColorCanvas;
private boolean showBorder;
private int density = 8;
private float lightness = 1;
private float alpha = 1;
private int backgroundColor = 0x00000000;
private Integer initialColors[] = new Integer[]{null, null, null, null, null};
private int colorSelection = 0;
private Integer initialColor;
private Integer pickerColorEditTextColor;
private Paint colorWheelFill = PaintBuilder.newPaint().color(0).build();
private Paint selectorStroke = PaintBuilder.newPaint().color(0).build();
private Paint alphaPatternPaint = PaintBuilder.newPaint().build();
private ColorCircle currentColorCircle;
private ArrayList<OnColorChangedListener> colorChangedListeners = new ArrayList<OnColorChangedListener>();
private ArrayList<OnColorSelectedListener> listeners = new ArrayList<OnColorSelectedListener>();
private LightnessSlider lightnessSlider;
private AlphaSlider alphaSlider;
private EditText colorEdit;
private TextWatcher colorTextChange = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
try {
int color = Color.parseColor(s.toString());
// set the color without changing the edit text preventing stack overflow
setColor(color, false);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void afterTextChanged(Editable s) {
}
};
private LinearLayout colorPreview;
private ColorWheelRenderer renderer;
private int alphaSliderViewId, lightnessSliderViewId;
public ColorPickerView(Context context) {
super(context);
initWith(context, null);
}
public ColorPickerView(Context context, AttributeSet attrs) {
super(context, attrs);
initWith(context, attrs);
}
public ColorPickerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initWith(context, attrs);
}
@TargetApi(21)
public ColorPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initWith(context, attrs);
}
private void initWith(Context context, AttributeSet attrs) {
final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ColorPickerPreference);
density = typedArray.getInt(R.styleable.ColorPickerPreference_density, 10);
initialColor = typedArray.getInt(R.styleable.ColorPickerPreference_initialColor, 0xffffffff);
pickerColorEditTextColor = typedArray.getInt(R.styleable.ColorPickerPreference_pickerColorEditTextColor, 0xffffffff);
WHEEL_TYPE wheelType = WHEEL_TYPE.indexOf(typedArray.getInt(R.styleable.ColorPickerPreference_wheelType, 0));
ColorWheelRenderer renderer = ColorWheelRendererBuilder.getRenderer(wheelType);
alphaSliderViewId = typedArray.getResourceId(R.styleable.ColorPickerPreference_alphaSliderView, 0);
lightnessSliderViewId = typedArray.getResourceId(R.styleable.ColorPickerPreference_lightnessSliderView, 0);
setRenderer(renderer);
setDensity(density);
setInitialColor(initialColor, true);
typedArray.recycle();
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
updateColorWheel();
currentColorCircle = findNearestByColor(initialColor);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (alphaSliderViewId != 0)
setAlphaSlider((AlphaSlider) getRootView().findViewById(alphaSliderViewId));
if (lightnessSliderViewId != 0)
setLightnessSlider((LightnessSlider) getRootView().findViewById(lightnessSliderViewId));
updateColorWheel();
currentColorCircle = findNearestByColor(initialColor);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
updateColorWheel();
}
private void updateColorWheel() {
int width = getMeasuredWidth();
int height = getMeasuredHeight();
if (height < width)
width = height;
if (width <= 0)
return;
if (colorWheel == null || colorWheel.getWidth() != width) {
colorWheel = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);
colorWheelCanvas = new Canvas(colorWheel);
alphaPatternPaint.setShader(PaintBuilder.createAlphaPatternShader(26));
}
if (currentColor == null || currentColor.getWidth() != width) {
currentColor = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);
currentColorCanvas = new Canvas(currentColor);
}
drawColorWheel();
invalidate();
}
private void drawColorWheel() {
colorWheelCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
currentColorCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
if (renderer == null) return;
float half = colorWheelCanvas.getWidth() / 2f;
float strokeWidth = STROKE_RATIO * (1f + ColorWheelRenderer.GAP_PERCENTAGE);
float maxRadius = half - strokeWidth - half / density;
float cSize = maxRadius / (density - 1) / 2;
ColorWheelRenderOption colorWheelRenderOption = renderer.getRenderOption();
colorWheelRenderOption.density = this.density;
colorWheelRenderOption.maxRadius = maxRadius;
colorWheelRenderOption.cSize = cSize;
colorWheelRenderOption.strokeWidth = strokeWidth;
colorWheelRenderOption.alpha = alpha;
colorWheelRenderOption.lightness = lightness;
colorWheelRenderOption.targetCanvas = colorWheelCanvas;
renderer.initWith(colorWheelRenderOption);
renderer.draw();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int width = 0;
if (widthMode == MeasureSpec.UNSPECIFIED)
width = widthMeasureSpec;
else if (widthMode == MeasureSpec.AT_MOST)
width = MeasureSpec.getSize(widthMeasureSpec);
else if (widthMode == MeasureSpec.EXACTLY)
width = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int height = 0;
if (heightMode == MeasureSpec.UNSPECIFIED)
height = heightMeasureSpec;
else if (heightMode == MeasureSpec.AT_MOST)
height = MeasureSpec.getSize(heightMeasureSpec);
else if (heightMode == MeasureSpec.EXACTLY)
height = MeasureSpec.getSize(heightMeasureSpec);
int squareDimen = width;
if (height < width)
squareDimen = height;
setMeasuredDimension(squareDimen, squareDimen);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE: {
int lastSelectedColor = getSelectedColor();
currentColorCircle = findNearestByPosition(event.getX(), event.getY());
int selectedColor = getSelectedColor();
callOnColorChangedListeners(lastSelectedColor, selectedColor);
initialColor = selectedColor;
setColorToSliders(selectedColor);
updateColorWheel();
invalidate();
break;
}
case MotionEvent.ACTION_UP: {
int selectedColor = getSelectedColor();
if (listeners != null) {
for (OnColorSelectedListener listener : listeners) {
try {
listener.onColorSelected(selectedColor);
} catch (Exception e) {
e.printStackTrace();
}
}
}
setColorToSliders(selectedColor);
setColorText(selectedColor);
setColorPreviewColor(selectedColor);
invalidate();
break;
}
}
return true;
}
protected void callOnColorChangedListeners(int oldColor, int newColor) {
if (colorChangedListeners != null && oldColor != newColor) {
for (OnColorChangedListener listener : colorChangedListeners) {
try {
listener.onColorChanged(newColor);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(backgroundColor);
float maxRadius = canvas.getWidth() / (1f + ColorWheelRenderer.GAP_PERCENTAGE);
float size = maxRadius / density / 2;
if (colorWheel != null && currentColorCircle != null) {
colorWheelFill.setColor(Color.HSVToColor(currentColorCircle.getHsvWithLightness(this.lightness)));
colorWheelFill.setAlpha((int) (alpha * 0xff));
// a separate canvas is used to erase an issue with the alpha pattern around the edges
// draw circle slightly larger than it needs to be, then erase edges to proper dimensions
currentColorCanvas.drawCircle(currentColorCircle.getX(), currentColorCircle.getY(), size + 4, alphaPatternPaint);
currentColorCanvas.drawCircle(currentColorCircle.getX(), currentColorCircle.getY(), size + 4, colorWheelFill);
selectorStroke = PaintBuilder.newPaint().color(0xffffffff).style(Paint.Style.STROKE).stroke(size * (STROKE_RATIO - 1)).xPerMode(PorterDuff.Mode.CLEAR).build();
if (showBorder) colorWheelCanvas.drawCircle(currentColorCircle.getX(), currentColorCircle.getY(), size + (selectorStroke.getStrokeWidth() / 2f), selectorStroke);
canvas.drawBitmap(colorWheel, 0, 0, null);
currentColorCanvas.drawCircle(currentColorCircle.getX(), currentColorCircle.getY(), size + (selectorStroke.getStrokeWidth() / 2f), selectorStroke);
canvas.drawBitmap(currentColor, 0, 0, null);
}
}
private ColorCircle findNearestByPosition(float x, float y) {
ColorCircle near = null;
double minDist = Double.MAX_VALUE;
for (ColorCircle colorCircle : renderer.getColorCircleList()) {
double dist = colorCircle.sqDist(x, y);
if (minDist > dist) {
minDist = dist;
near = colorCircle;
}
}
return near;
}
private ColorCircle findNearestByColor(int color) {
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
ColorCircle near = null;
double minDiff = Double.MAX_VALUE;
double x = hsv[1] * Math.cos(hsv[0] * Math.PI / 180);
double y = hsv[1] * Math.sin(hsv[0] * Math.PI / 180);
for (ColorCircle colorCircle : renderer.getColorCircleList()) {
float[] hsv1 = colorCircle.getHsv();
double x1 = hsv1[1] * Math.cos(hsv1[0] * Math.PI / 180);
double y1 = hsv1[1] * Math.sin(hsv1[0] * Math.PI / 180);
double dx = x - x1;
double dy = y - y1;
double dist = dx * dx + dy * dy;
if (dist < minDiff) {
minDiff = dist;
near = colorCircle;
}
}
return near;
}
public int getSelectedColor() {
int color = 0;
if (currentColorCircle != null)
color = Utils.colorAtLightness(currentColorCircle.getColor(), this.lightness);
return Utils.adjustAlpha(this.alpha, color);
}
public Integer[] getAllColors() {
return initialColors;
}
public void setInitialColors(Integer[] colors, int selectedColor) {
this.initialColors = colors;
this.colorSelection = selectedColor;
Integer initialColor = this.initialColors[this.colorSelection];
if (initialColor == null) initialColor = 0xffffffff;
setInitialColor(initialColor, true);
}
public void setInitialColor(int color, boolean updateText) {
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
this.alpha = Utils.getAlphaPercent(color);
this.lightness = hsv[2];
this.initialColors[this.colorSelection] = color;
this.initialColor = color;
setColorPreviewColor(color);
setColorToSliders(color);
if (this.colorEdit != null && updateText)
setColorText(color);
currentColorCircle = findNearestByColor(color);
}
public void setLightness(float lightness) {
int lastSelectedColor = getSelectedColor();
this.lightness = lightness;
if (currentColorCircle != null) {
this.initialColor = Color.HSVToColor(Utils.alphaValueAsInt(this.alpha), currentColorCircle.getHsvWithLightness(lightness));
if (this.colorEdit != null)
this.colorEdit.setText(Utils.getHexString(this.initialColor, this.alphaSlider != null));
if (this.alphaSlider != null && this.initialColor != null)
this.alphaSlider.setColor(this.initialColor);
callOnColorChangedListeners(lastSelectedColor, this.initialColor);
updateColorWheel();
invalidate();
}
}
public void setColor(int color, boolean updateText) {
setInitialColor(color, updateText);
updateColorWheel();
invalidate();
}
public void setAlphaValue(float alpha) {
int lastSelectedColor = getSelectedColor();
this.alpha = alpha;
this.initialColor = Color.HSVToColor(Utils.alphaValueAsInt(this.alpha), currentColorCircle.getHsvWithLightness(this.lightness));
if (this.colorEdit != null)
this.colorEdit.setText(Utils.getHexString(this.initialColor, this.alphaSlider != null));
if (this.lightnessSlider != null && this.initialColor != null)
this.lightnessSlider.setColor(this.initialColor);
callOnColorChangedListeners(lastSelectedColor, this.initialColor);
updateColorWheel();
invalidate();
}
public void addOnColorChangedListener(OnColorChangedListener listener) {
this.colorChangedListeners.add(listener);
}
public void addOnColorSelectedListener(OnColorSelectedListener listener) {
this.listeners.add(listener);
}
public void setLightnessSlider(LightnessSlider lightnessSlider) {
this.lightnessSlider = lightnessSlider;
if (lightnessSlider != null) {
this.lightnessSlider.setColorPicker(this);
this.lightnessSlider.setColor(getSelectedColor());
}
}
public void setAlphaSlider(AlphaSlider alphaSlider) {
this.alphaSlider = alphaSlider;
if (alphaSlider != null) {
this.alphaSlider.setColorPicker(this);
this.alphaSlider.setColor(getSelectedColor());
}
}
public void setColorEdit(EditText colorEdit) {
this.colorEdit = colorEdit;
if (this.colorEdit != null) {
this.colorEdit.setVisibility(View.VISIBLE);
this.colorEdit.addTextChangedListener(colorTextChange);
setColorEditTextColor(pickerColorEditTextColor);
}
}
public void setColorEditTextColor(int argb) {
this.pickerColorEditTextColor = argb;
if (colorEdit != null)
colorEdit.setTextColor(argb);
}
public void setDensity(int density) {
this.density = Math.max(2, density);
invalidate();
}
public void setRenderer(ColorWheelRenderer renderer) {
this.renderer = renderer;
invalidate();
}
public void setColorPreview(LinearLayout colorPreview, Integer selectedColor) {
if (colorPreview == null)
return;
this.colorPreview = colorPreview;
if (selectedColor == null)
selectedColor = 0;
int children = colorPreview.getChildCount();
if (children == 0 || colorPreview.getVisibility() != View.VISIBLE)
return;
for (int i = 0; i < children; i++) {
View childView = colorPreview.getChildAt(i);
if (!(childView instanceof LinearLayout))
continue;
LinearLayout childLayout = (LinearLayout) childView;
if (i == selectedColor) {
childLayout.setBackgroundColor(Color.WHITE);
}
ImageView childImage = (ImageView) childLayout.findViewById(R.id.image_preview);
childImage.setClickable(true);
childImage.setTag(i);
childImage.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (v == null)
return;
Object tag = v.getTag();
if (tag == null || !(tag instanceof Integer))
return;
setSelectedColor((int) tag);
}
});
}
}
public void setSelectedColor(int previewNumber) {
if (initialColors == null || initialColors.length < previewNumber)
return;
this.colorSelection = previewNumber;
setHighlightedColor(previewNumber);
Integer color = initialColors[previewNumber];
if (color == null)
return;
setColor(color, true);
}
public void setShowBorder(boolean showBorder) {
this.showBorder = showBorder;
}
private void setHighlightedColor(int previewNumber) {
int children = colorPreview.getChildCount();
if (children == 0 || colorPreview.getVisibility() != View.VISIBLE)
return;
for (int i = 0; i < children; i++) {
View childView = colorPreview.getChildAt(i);
if (!(childView instanceof LinearLayout))
continue;
LinearLayout childLayout = (LinearLayout) childView;
if (i == previewNumber) {
childLayout.setBackgroundColor(Color.WHITE);
} else {
childLayout.setBackgroundColor(Color.TRANSPARENT);
}
}
}
private void setColorPreviewColor(int newColor) {
if (colorPreview == null || initialColors == null || colorSelection > initialColors.length || initialColors[colorSelection] == null)
return;
int children = colorPreview.getChildCount();
if (children == 0 || colorPreview.getVisibility() != View.VISIBLE)
return;
View childView = colorPreview.getChildAt(colorSelection);
if (!(childView instanceof LinearLayout))
return;
LinearLayout childLayout = (LinearLayout) childView;
ImageView childImage = (ImageView) childLayout.findViewById(R.id.image_preview);
childImage.setImageDrawable(new ColorCircleDrawable(newColor));
}
private void setColorText(int argb) {
if (colorEdit == null)
return;
colorEdit.setText(Utils.getHexString(argb, this.alphaSlider != null));
}
private void setColorToSliders(int selectedColor) {
if (lightnessSlider != null)
lightnessSlider.setColor(selectedColor);
if (alphaSlider != null)
alphaSlider.setColor(selectedColor);
}
public enum WHEEL_TYPE {
FLOWER, CIRCLE;
public static WHEEL_TYPE indexOf(int index) {
switch (index) {
case 0:
return FLOWER;
case 1:
return CIRCLE;
}
return FLOWER;
}
}
}

View File

@ -0,0 +1,5 @@
package com.colorpicker;
public interface OnColorChangedListener {
void onColorChanged(int selectedColor);
}

View File

@ -0,0 +1,5 @@
package com.colorpicker;
public interface OnColorSelectedListener {
void onColorSelected(int selectedColor);
}

View File

@ -0,0 +1,40 @@
package com.colorpicker;
import android.graphics.Color;
/**
* Created by Charles Andersons on 4/17/15.
*/
public class Utils {
public static float getAlphaPercent(int argb) {
return Color.alpha(argb) / 255f;
}
public static int alphaValueAsInt(float alpha) {
return Math.round(alpha * 255);
}
public static int adjustAlpha(float alpha, int color) {
return alphaValueAsInt(alpha) << 24 | (0x00ffffff & color);
}
public static int colorAtLightness(int color, float lightness) {
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
hsv[2] = lightness;
return Color.HSVToColor(hsv);
}
public static float lightnessOfColor(int color) {
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
return hsv[2];
}
public static String getHexString(int color, boolean showAlpha) {
int base = showAlpha ? 0xFFFFFFFF : 0xFFFFFF;
String format = showAlpha ? "#%08X" : "#%06X";
return String.format(format, (base & color)).toUpperCase();
}
}

View File

@ -0,0 +1,10 @@
package com.colorpicker.builder;
import android.content.DialogInterface;
/**
* Created by Charles Anderson on 4/17/15.
*/
public interface ColorPickerClickListener {
void onClick(DialogInterface d, int lastSelectedColor, Integer[] allColors);
}

View File

@ -0,0 +1,297 @@
package com.colorpicker.builder;
import androidx.appcompat.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.text.InputFilter;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.colorpicker.ColorPickerView;
import com.colorpicker.OnColorChangedListener;
import com.colorpicker.OnColorSelectedListener;
import com.colorpicker.Utils;
import com.colorpicker.renderer.ColorWheelRenderer;
import com.colorpicker.slider.AlphaSlider;
import com.colorpicker.slider.LightnessSlider;
import com.muqingbfq.R;
public class ColorPickerDialogBuilder {
private MaterialAlertDialogBuilder builder;
private LinearLayout pickerContainer;
private ColorPickerView colorPickerView;
private LightnessSlider lightnessSlider;
private AlphaSlider alphaSlider;
private EditText colorEdit;
private LinearLayout colorPreview;
private boolean isLightnessSliderEnabled = true;
private boolean isAlphaSliderEnabled = true;
private boolean isBorderEnabled = true;
private boolean isColorEditEnabled = false;
private boolean isPreviewEnabled = false;
private int pickerCount = 1;
private int defaultMargin = 0;
private int defaultMarginTop = 0;
private Integer[] initialColor = new Integer[]{null, null, null, null, null};
private ColorPickerDialogBuilder(Context context) {
this(context, 0);
}
private ColorPickerDialogBuilder(Context context, int theme) {
defaultMargin = getDimensionAsPx(context, R.dimen.default_slider_margin);
defaultMarginTop = getDimensionAsPx(context, R.dimen.default_margin_top);
builder = new MaterialAlertDialogBuilder(context, theme);
pickerContainer = new LinearLayout(context);
pickerContainer.setOrientation(LinearLayout.VERTICAL);
pickerContainer.setGravity(Gravity.CENTER_HORIZONTAL);
pickerContainer.setPadding(defaultMargin, defaultMarginTop, defaultMargin, 0);
LinearLayout.LayoutParams layoutParamsForColorPickerView = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0);
layoutParamsForColorPickerView.weight = 1;
colorPickerView = new ColorPickerView(context);
pickerContainer.addView(colorPickerView, layoutParamsForColorPickerView);
builder.setView(pickerContainer);
}
public static ColorPickerDialogBuilder with(Context context) {
return new ColorPickerDialogBuilder(context);
}
public static ColorPickerDialogBuilder with(Context context, int theme) {
return new ColorPickerDialogBuilder(context, theme);
}
public ColorPickerDialogBuilder setTitle(String title) {
builder.setTitle(title);
return this;
}
public ColorPickerDialogBuilder setTitle(int titleId) {
builder.setTitle(titleId);
return this;
}
public ColorPickerDialogBuilder initialColor(int initialColor) {
this.initialColor[0] = initialColor;
return this;
}
public ColorPickerDialogBuilder initialColors(int[] initialColor) {
for (int i = 0; i < initialColor.length && i < this.initialColor.length; i++) {
this.initialColor[i] = initialColor[i];
}
return this;
}
public ColorPickerDialogBuilder wheelType(ColorPickerView.WHEEL_TYPE wheelType) {
ColorWheelRenderer renderer = ColorWheelRendererBuilder.getRenderer(wheelType);
colorPickerView.setRenderer(renderer);
return this;
}
public ColorPickerDialogBuilder density(int density) {
colorPickerView.setDensity(density);
return this;
}
public ColorPickerDialogBuilder setOnColorChangedListener(OnColorChangedListener onColorChangedListener) {
colorPickerView.addOnColorChangedListener(onColorChangedListener);
return this;
}
public ColorPickerDialogBuilder setOnColorSelectedListener(OnColorSelectedListener onColorSelectedListener) {
colorPickerView.addOnColorSelectedListener(onColorSelectedListener);
return this;
}
public ColorPickerDialogBuilder setPositiveButton(CharSequence text, final ColorPickerClickListener onClickListener) {
builder.setPositiveButton(text, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
positiveButtonOnClick(dialog, onClickListener);
}
});
return this;
}
public ColorPickerDialogBuilder setPositiveButton(int textId, final ColorPickerClickListener onClickListener) {
builder.setPositiveButton(textId, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
positiveButtonOnClick(dialog, onClickListener);
}
});
return this;
}
public ColorPickerDialogBuilder setNegativeButton(CharSequence text, DialogInterface.OnClickListener onClickListener) {
builder.setNegativeButton(text, onClickListener);
return this;
}
public ColorPickerDialogBuilder setNegativeButton(int textId, DialogInterface.OnClickListener onClickListener) {
builder.setNegativeButton(textId, onClickListener);
return this;
}
public ColorPickerDialogBuilder noSliders() {
isLightnessSliderEnabled = false;
isAlphaSliderEnabled = false;
return this;
}
public ColorPickerDialogBuilder alphaSliderOnly() {
isLightnessSliderEnabled = false;
isAlphaSliderEnabled = true;
return this;
}
public ColorPickerDialogBuilder lightnessSliderOnly() {
isLightnessSliderEnabled = true;
isAlphaSliderEnabled = false;
return this;
}
public ColorPickerDialogBuilder showAlphaSlider(boolean showAlpha) {
isAlphaSliderEnabled = showAlpha;
return this;
}
public ColorPickerDialogBuilder showLightnessSlider(boolean showLightness) {
isLightnessSliderEnabled = showLightness;
return this;
}
public ColorPickerDialogBuilder showBorder(boolean showBorder) {
isBorderEnabled = showBorder;
return this;
}
public ColorPickerDialogBuilder showColorEdit(boolean showEdit) {
isColorEditEnabled = showEdit;
return this;
}
public ColorPickerDialogBuilder setColorEditTextColor(int argb) {
colorPickerView.setColorEditTextColor(argb);
return this;
}
public ColorPickerDialogBuilder showColorPreview(boolean showPreview) {
isPreviewEnabled = showPreview;
if (!showPreview)
pickerCount = 1;
return this;
}
public ColorPickerDialogBuilder setPickerCount(int pickerCount) throws IndexOutOfBoundsException {
if (pickerCount < 1 || pickerCount > 5)
throw new IndexOutOfBoundsException("Picker Can Only Support 1-5 Colors");
this.pickerCount = pickerCount;
if (this.pickerCount > 1)
this.isPreviewEnabled = true;
return this;
}
public AlertDialog build() {
Context context = builder.getContext();
colorPickerView.setInitialColors(initialColor, getStartOffset(initialColor));
colorPickerView.setShowBorder(isBorderEnabled);
if (isLightnessSliderEnabled) {
LinearLayout.LayoutParams layoutParamsForLightnessBar = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getDimensionAsPx(context, R.dimen.default_slider_height));
lightnessSlider = new LightnessSlider(context);
lightnessSlider.setLayoutParams(layoutParamsForLightnessBar);
pickerContainer.addView(lightnessSlider);
colorPickerView.setLightnessSlider(lightnessSlider);
lightnessSlider.setColor(getStartColor(initialColor));
lightnessSlider.setShowBorder(isBorderEnabled);
}
if (isAlphaSliderEnabled) {
LinearLayout.LayoutParams layoutParamsForAlphaBar = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getDimensionAsPx(context, R.dimen.default_slider_height));
alphaSlider = new AlphaSlider(context);
alphaSlider.setLayoutParams(layoutParamsForAlphaBar);
pickerContainer.addView(alphaSlider);
colorPickerView.setAlphaSlider(alphaSlider);
alphaSlider.setColor(getStartColor(initialColor));
alphaSlider.setShowBorder(isBorderEnabled);
}
if (isColorEditEnabled) {
LinearLayout.LayoutParams layoutParamsForColorEdit = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
colorEdit = (EditText) View.inflate(context, R.layout.color_edit, null);
colorEdit.setFilters(new InputFilter[]{new InputFilter.AllCaps()});
colorEdit.setSingleLine();
colorEdit.setVisibility(View.GONE);
// limit number of characters to hexColors
int maxLength = isAlphaSliderEnabled ? 9 : 7;
colorEdit.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)});
pickerContainer.addView(colorEdit, layoutParamsForColorEdit);
colorEdit.setText(Utils.getHexString(getStartColor(initialColor), isAlphaSliderEnabled));
colorPickerView.setColorEdit(colorEdit);
}
if (isPreviewEnabled) {
colorPreview = (LinearLayout) View.inflate(context, R.layout.color_preview, null);
colorPreview.setVisibility(View.GONE);
pickerContainer.addView(colorPreview);
if (initialColor.length == 0) {
ImageView colorImage = (ImageView) View.inflate(context, R.layout.color_selector, null);
colorImage.setImageDrawable(new ColorDrawable(Color.WHITE));
} else {
for (int i = 0; i < initialColor.length && i < this.pickerCount; i++) {
if (initialColor[i] == null)
break;
LinearLayout colorLayout = (LinearLayout) View.inflate(context, R.layout.color_selector, null);
ImageView colorImage = (ImageView) colorLayout.findViewById(R.id.image_preview);
colorImage.setImageDrawable(new ColorDrawable(initialColor[i]));
colorPreview.addView(colorLayout);
}
}
colorPreview.setVisibility(View.VISIBLE);
colorPickerView.setColorPreview(colorPreview, getStartOffset(initialColor));
}
return builder.create();
}
private Integer getStartOffset(Integer[] colors) {
Integer start = 0;
for (int i = 0; i < colors.length; i++) {
if (colors[i] == null) {
return start;
}
start = (i + 1) / 2;
}
return start;
}
private int getStartColor(Integer[] colors) {
Integer startColor = getStartOffset(colors);
return startColor == null ? Color.WHITE : colors[startColor];
}
private static int getDimensionAsPx(Context context, int rid) {
return (int) (context.getResources().getDimension(rid) + .5f);
}
private void positiveButtonOnClick(DialogInterface dialog, ColorPickerClickListener onClickListener) {
int selectedColor = colorPickerView.getSelectedColor();
Integer[] allColors = colorPickerView.getAllColors();
onClickListener.onClick(dialog, selectedColor, allColors);
}
}

View File

@ -0,0 +1,18 @@
package com.colorpicker.builder;
import com.colorpicker.ColorPickerView;
import com.colorpicker.renderer.ColorWheelRenderer;
import com.colorpicker.renderer.FlowerColorWheelRenderer;
import com.colorpicker.renderer.SimpleColorWheelRenderer;
public class ColorWheelRendererBuilder {
public static ColorWheelRenderer getRenderer(ColorPickerView.WHEEL_TYPE wheelType) {
switch (wheelType) {
case CIRCLE:
return new SimpleColorWheelRenderer();
case FLOWER:
return new FlowerColorWheelRenderer();
}
throw new IllegalArgumentException("wrong WHEEL_TYPE");
}
}

View File

@ -0,0 +1,82 @@
package com.colorpicker.builder;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader;
public class PaintBuilder {
public static PaintHolder newPaint() {
return new PaintHolder();
}
public static class PaintHolder {
private Paint paint;
private PaintHolder() {
this.paint = new Paint(Paint.ANTI_ALIAS_FLAG);
}
public PaintHolder color(int color) {
this.paint.setColor(color);
return this;
}
public PaintHolder antiAlias(boolean flag) {
this.paint.setAntiAlias(flag);
return this;
}
public PaintHolder style(Paint.Style style) {
this.paint.setStyle(style);
return this;
}
public PaintHolder mode(PorterDuff.Mode mode) {
this.paint.setXfermode(new PorterDuffXfermode(mode));
return this;
}
public PaintHolder stroke(float width) {
this.paint.setStrokeWidth(width);
return this;
}
public PaintHolder xPerMode(PorterDuff.Mode mode) {
this.paint.setXfermode(new PorterDuffXfermode(mode));
return this;
}
public PaintHolder shader(Shader shader) {
this.paint.setShader(shader);
return this;
}
public Paint build() {
return this.paint;
}
}
public static Shader createAlphaPatternShader(int size) {
size /= 2;
size = Math.max(8, size * 2);
return new BitmapShader(createAlphaBackgroundPattern(size), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
}
private static Bitmap createAlphaBackgroundPattern(int size) {
Paint alphaPatternPaint = PaintBuilder.newPaint().build();
Bitmap bm = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bm);
int s = Math.round(size / 2f);
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++) {
if ((i + j) % 2 == 0) alphaPatternPaint.setColor(0xffffffff);
else alphaPatternPaint.setColor(0xffd0d0d0);
c.drawRect(i * s, j * s, (i + 1) * s, (j + 1) * s, alphaPatternPaint);
}
return bm;
}
}

View File

@ -0,0 +1,34 @@
package com.colorpicker.renderer;
import com.colorpicker.ColorCircle;
import java.util.ArrayList;
import java.util.List;
public abstract class AbsColorWheelRenderer implements ColorWheelRenderer {
protected ColorWheelRenderOption colorWheelRenderOption;
protected List<ColorCircle> colorCircleList = new ArrayList<>();
public void initWith(ColorWheelRenderOption colorWheelRenderOption) {
this.colorWheelRenderOption = colorWheelRenderOption;
this.colorCircleList.clear();
}
@Override
public ColorWheelRenderOption getRenderOption() {
if (colorWheelRenderOption == null) colorWheelRenderOption = new ColorWheelRenderOption();
return colorWheelRenderOption;
}
public List<ColorCircle> getColorCircleList() {
return colorCircleList;
}
protected int getAlphaValueAsInt() {
return Math.round(colorWheelRenderOption.alpha * 255);
}
protected int calcTotalCount(float radius, float size) {
return Math.max(1, (int) ((1f - GAP_PERCENTAGE) * Math.PI / (Math.asin(size / radius)) + 0.5f));
}
}

View File

@ -0,0 +1,10 @@
package com.colorpicker.renderer;
import android.graphics.Canvas;
public class ColorWheelRenderOption {
public int density;
public float maxRadius;
public float cSize, strokeWidth, alpha, lightness;
public Canvas targetCanvas;
}

View File

@ -0,0 +1,16 @@
package com.colorpicker.renderer;
import com.colorpicker.ColorCircle;
import java.util.List;
public interface ColorWheelRenderer {
float GAP_PERCENTAGE = 0.025f;
void draw();
ColorWheelRenderOption getRenderOption();
void initWith(ColorWheelRenderOption colorWheelRenderOption);
List<ColorCircle> getColorCircleList();
}

View File

@ -0,0 +1,50 @@
package com.colorpicker.renderer;
import android.graphics.Color;
import android.graphics.Paint;
import com.colorpicker.ColorCircle;
import com.colorpicker.builder.PaintBuilder;
public class FlowerColorWheelRenderer extends AbsColorWheelRenderer {
private Paint selectorFill = PaintBuilder.newPaint().build();
private float[] hsv = new float[3];
private float sizeJitter = 1.2f;
@Override
public void draw() {
final int setSize = colorCircleList.size();
int currentCount = 0;
float half = colorWheelRenderOption.targetCanvas.getWidth() / 2f;
int density = colorWheelRenderOption.density;
float strokeWidth = colorWheelRenderOption.strokeWidth;
float maxRadius = colorWheelRenderOption.maxRadius;
float cSize = colorWheelRenderOption.cSize;
for (int i = 0; i < density; i++) {
float p = (float) i / (density - 1); // 0~1
float jitter = (i - density / 2f) / density; // -0.5 ~ 0.5
float radius = maxRadius * p;
float size = Math.max(1.5f + strokeWidth, cSize + (i == 0 ? 0 : cSize * sizeJitter * jitter));
int total = Math.min(calcTotalCount(radius, size), density * 2);
for (int j = 0; j < total; j++) {
double angle = Math.PI * 2 * j / total + (Math.PI / total) * ((i + 1) % 2);
float x = half + (float) (radius * Math.cos(angle));
float y = half + (float) (radius * Math.sin(angle));
hsv[0] = (float) (angle * 180 / Math.PI);
hsv[1] = radius / maxRadius;
hsv[2] = colorWheelRenderOption.lightness;
selectorFill.setColor(Color.HSVToColor(hsv));
selectorFill.setAlpha(getAlphaValueAsInt());
colorWheelRenderOption.targetCanvas.drawCircle(x, y, size - strokeWidth, selectorFill);
if (currentCount >= setSize) {
colorCircleList.add(new ColorCircle(x, y, hsv));
} else colorCircleList.get(currentCount).set(x, y, hsv);
currentCount++;
}
}
}
}

View File

@ -0,0 +1,45 @@
package com.colorpicker.renderer;
import android.graphics.Color;
import android.graphics.Paint;
import com.colorpicker.ColorCircle;
import com.colorpicker.builder.PaintBuilder;
public class SimpleColorWheelRenderer extends AbsColorWheelRenderer {
private Paint selectorFill = PaintBuilder.newPaint().build();
private float[] hsv = new float[3];
@Override
public void draw() {
final int setSize = colorCircleList.size();
int currentCount = 0;
float half = colorWheelRenderOption.targetCanvas.getWidth() / 2f;
int density = colorWheelRenderOption.density;
float maxRadius = colorWheelRenderOption.maxRadius;
for (int i = 0; i < density; i++) {
float p = (float) i / (density - 1); // 0~1
float radius = maxRadius * p;
float size = colorWheelRenderOption.cSize;
int total = calcTotalCount(radius, size);
for (int j = 0; j < total; j++) {
double angle = Math.PI * 2 * j / total + (Math.PI / total) * ((i + 1) % 2);
float x = half + (float) (radius * Math.cos(angle));
float y = half + (float) (radius * Math.sin(angle));
hsv[0] = (float) (angle * 180 / Math.PI);
hsv[1] = radius / maxRadius;
hsv[2] = colorWheelRenderOption.lightness;
selectorFill.setColor(Color.HSVToColor(hsv));
selectorFill.setAlpha(getAlphaValueAsInt());
colorWheelRenderOption.targetCanvas.drawCircle(x, y, size - colorWheelRenderOption.strokeWidth, selectorFill);
if (currentCount >= setSize)
colorCircleList.add(new ColorCircle(x, y, hsv));
else colorCircleList.get(currentCount).set(x, y, hsv);
currentCount++;
}
}
}
}

View File

@ -0,0 +1,189 @@
package com.colorpicker.slider;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.PorterDuff;
import androidx.annotation.DimenRes;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import com.muqingbfq.R;
public abstract class AbsCustomSlider extends View {
protected Bitmap bitmap;
protected Canvas bitmapCanvas;
protected Bitmap bar;
protected Canvas barCanvas;
protected OnValueChangedListener onValueChangedListener;
protected int barOffsetX;
protected int handleRadius = 20;
protected int barHeight = 5;
protected float value = 1;
protected boolean showBorder = false;
private boolean inVerticalOrientation = false;
public AbsCustomSlider(Context context) {
super(context);
init(context, null);
}
public AbsCustomSlider(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public AbsCustomSlider(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
TypedArray styledAttrs = context.getTheme().obtainStyledAttributes(
attrs, R.styleable.AbsCustomSlider, 0, 0);
try {
inVerticalOrientation = styledAttrs.getBoolean(
R.styleable.AbsCustomSlider_inVerticalOrientation, inVerticalOrientation);
} finally {
styledAttrs.recycle();
}
}
protected void updateBar() {
handleRadius = getDimension(R.dimen.default_slider_handler_radius);
barHeight = getDimension(R.dimen.default_slider_bar_height);
barOffsetX = handleRadius;
if (bar == null)
createBitmaps();
drawBar(barCanvas);
invalidate();
}
protected void createBitmaps() {
int width;
int height;
if (inVerticalOrientation) {
width = getHeight();
height = getWidth();
} else {
width = getWidth();
height = getHeight();
}
bar = Bitmap.createBitmap(Math.max(width - barOffsetX * 2, 1), barHeight, Bitmap.Config.ARGB_8888);
barCanvas = new Canvas(bar);
if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) {
if (bitmap != null) bitmap.recycle();
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmapCanvas = new Canvas(bitmap);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width;
int height;
if (inVerticalOrientation) {
width = getHeight();
height = getWidth();
canvas.rotate(-90);
canvas.translate(-width, 0);
} else {
width = getWidth();
height = getHeight();
}
if (bar != null && bitmapCanvas != null) {
bitmapCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
bitmapCanvas.drawBitmap(bar, barOffsetX, (height - bar.getHeight()) / 2, null);
float x = handleRadius + value * (width - handleRadius * 2);
float y = height / 2f;
drawHandle(bitmapCanvas, x, y);
canvas.drawBitmap(bitmap, 0, 0, null);
}
}
protected abstract void drawBar(Canvas barCanvas);
protected abstract void onValueChanged(float value);
protected abstract void drawHandle(Canvas canvas, float x, float y);
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
updateBar();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int width = 0;
if (widthMode == MeasureSpec.UNSPECIFIED)
width = widthMeasureSpec;
else if (widthMode == MeasureSpec.AT_MOST)
width = MeasureSpec.getSize(widthMeasureSpec);
else if (widthMode == MeasureSpec.EXACTLY)
width = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int height = 0;
if (heightMode == MeasureSpec.UNSPECIFIED)
height = heightMeasureSpec;
else if (heightMode == MeasureSpec.AT_MOST)
height = MeasureSpec.getSize(heightMeasureSpec);
else if (heightMode == MeasureSpec.EXACTLY)
height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE: {
if (bar != null) {
if (inVerticalOrientation) {
value = 1 - (event.getY() - barOffsetX) / bar.getWidth();
} else {
value = (event.getX() - barOffsetX) / bar.getWidth();
}
value = Math.max(0, Math.min(value, 1));
onValueChanged(value);
invalidate();
}
break;
}
case MotionEvent.ACTION_UP: {
onValueChanged(value);
if (onValueChangedListener != null)
onValueChangedListener.onValueChanged(value);
invalidate();
}
}
return true;
}
protected int getDimension(@DimenRes int id) {
return getResources().getDimensionPixelSize(id);
}
public void setShowBorder(boolean showBorder) {
this.showBorder = showBorder;
}
public void setOnValueChangedListener(OnValueChangedListener onValueChangedListener) {
this.onValueChangedListener = onValueChangedListener;
}
}

View File

@ -0,0 +1,99 @@
package com.colorpicker.slider;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import com.colorpicker.ColorPickerView;
import com.colorpicker.Utils;
import com.colorpicker.builder.PaintBuilder;
public class AlphaSlider extends AbsCustomSlider {
public int color;
private Paint alphaPatternPaint = PaintBuilder.newPaint().build();
private Paint barPaint = PaintBuilder.newPaint().build();
private Paint solid = PaintBuilder.newPaint().build();
private Paint clearingStroke = PaintBuilder.newPaint().color(0xffffffff).xPerMode(PorterDuff.Mode.CLEAR).build();
private Paint clearStroke = PaintBuilder.newPaint().build();
private Bitmap clearBitmap;
private Canvas clearBitmapCanvas;
private ColorPickerView colorPicker;
public AlphaSlider(Context context) {
super(context);
}
public AlphaSlider(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AlphaSlider(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void createBitmaps() {
super.createBitmaps();
alphaPatternPaint.setShader(PaintBuilder.createAlphaPatternShader(barHeight * 2));
clearBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
clearBitmapCanvas = new Canvas(clearBitmap);
}
@Override
protected void drawBar(Canvas barCanvas) {
int width = barCanvas.getWidth();
int height = barCanvas.getHeight();
barCanvas.drawRect(0, 0, width, height, alphaPatternPaint);
int l = Math.max(2, width / 256);
for (int x = 0; x <= width; x += l) {
float alpha = (float) x / (width - 1);
barPaint.setColor(color);
barPaint.setAlpha(Math.round(alpha * 255));
barCanvas.drawRect(x, 0, x + l, height, barPaint);
}
}
@Override
protected void onValueChanged(float value) {
if (colorPicker != null)
colorPicker.setAlphaValue(value);
}
@Override
protected void drawHandle(Canvas canvas, float x, float y) {
solid.setColor(color);
solid.setAlpha(Math.round(value * 255));
if (showBorder) canvas.drawCircle(x, y, handleRadius, clearingStroke);
if (value < 1) {
// this fixes the same artifact issue from ColorPickerView
// happens when alpha pattern is drawn underneath a circle with the same size
clearBitmapCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
clearBitmapCanvas.drawCircle(x, y, handleRadius * 0.75f + 4, alphaPatternPaint);
clearBitmapCanvas.drawCircle(x, y, handleRadius * 0.75f + 4, solid);
clearStroke = PaintBuilder.newPaint().color(0xffffffff).style(Paint.Style.STROKE).stroke(6).xPerMode(PorterDuff.Mode.CLEAR).build();
clearBitmapCanvas.drawCircle(x, y, handleRadius * 0.75f + (clearStroke.getStrokeWidth() / 2), clearStroke);
canvas.drawBitmap(clearBitmap, 0, 0, null);
} else {
canvas.drawCircle(x, y, handleRadius * 0.75f, solid);
}
}
public void setColorPicker(ColorPickerView colorPicker) {
this.colorPicker = colorPicker;
}
public void setColor(int color) {
this.color = color;
this.value = Utils.getAlphaPercent(color);
if (bar != null) {
updateBar();
invalidate();
}
}
}

View File

@ -0,0 +1,73 @@
package com.colorpicker.slider;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import com.colorpicker.ColorPickerView;
import com.colorpicker.Utils;
import com.colorpicker.builder.PaintBuilder;
public class LightnessSlider extends AbsCustomSlider {
private int color;
private Paint barPaint = PaintBuilder.newPaint().build();
private Paint solid = PaintBuilder.newPaint().build();
private Paint clearingStroke = PaintBuilder.newPaint().color(0xffffffff).xPerMode(PorterDuff.Mode.CLEAR).build();
private ColorPickerView colorPicker;
public LightnessSlider(Context context) {
super(context);
}
public LightnessSlider(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LightnessSlider(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void drawBar(Canvas barCanvas) {
int width = barCanvas.getWidth();
int height = barCanvas.getHeight();
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
int l = Math.max(2, width / 256);
for (int x = 0; x <= width; x += l) {
hsv[2] = (float) x / (width - 1);
barPaint.setColor(Color.HSVToColor(hsv));
barCanvas.drawRect(x, 0, x + l, height, barPaint);
}
}
@Override
protected void onValueChanged(float value) {
if (colorPicker != null)
colorPicker.setLightness(value);
}
@Override
protected void drawHandle(Canvas canvas, float x, float y) {
solid.setColor(Utils.colorAtLightness(color, value));
if (showBorder) canvas.drawCircle(x, y, handleRadius, clearingStroke);
canvas.drawCircle(x, y, handleRadius * 0.75f, solid);
}
public void setColorPicker(ColorPickerView colorPicker) {
this.colorPicker = colorPicker;
}
public void setColor(int color) {
this.color = color;
this.value = Utils.lightnessOfColor(color);
if (bar != null) {
updateBar();
invalidate();
}
}
}

View File

@ -0,0 +1,5 @@
package com.colorpicker.slider;
public interface OnValueChangedListener {
void onValueChanged(float value);
}

View File

@ -0,0 +1,257 @@
package com.dirror.lyricviewx
import android.graphics.Typeface
import android.graphics.drawable.Drawable
import android.text.Layout
import androidx.annotation.ColorInt
import androidx.annotation.FloatRange
import androidx.annotation.Px
import java.io.File
const val GRAVITY_CENTER = 0 // 居中
const val GRAVITY_LEFT = 1 // 左
const val GRAVITY_RIGHT = 2 // 右
fun Int.toLayoutAlign(): Layout.Alignment {
return when (this) {
GRAVITY_LEFT -> Layout.Alignment.ALIGN_NORMAL
GRAVITY_CENTER -> Layout.Alignment.ALIGN_CENTER
GRAVITY_RIGHT -> Layout.Alignment.ALIGN_OPPOSITE
else -> Layout.Alignment.ALIGN_CENTER
}
}
/**
* LyricViewX 接口
* LyricViewX 提取方便管理
*
* @author Moriafly
* @since 2021年1月28日16:29:16
*/
interface LyricViewXInterface {
/**
* 设置整句之间的间隔高度
* @param height px
*/
fun setSentenceDividerHeight(@Px height: Float)
/**
* 设置原句与翻译之间的间隔高度
* @param height px
*/
fun setTranslateDividerHeight(@Px height: Float)
/**
* 设置歌词整体的垂直偏移值配合[setHorizontalOffsetPercent]使用
* @param offset px
*
* @see [setHorizontalOffsetPercent]
*/
fun setHorizontalOffset(@Px offset: Float)
/**
* 设置歌词整体的垂直偏移相对于控件高度的百分比,0.5f即表示居中配合[setHorizontalOffset]使用
*
* @param percent 0.0f ~ 1.0f
*
* @see [setHorizontalOffset]
*/
fun setHorizontalOffsetPercent(@FloatRange(from = 0.0, to = 1.0) percent: Float)
/**
* 设置翻译相对与原词之间的缩放比例值
* @param scaleValue 一般来说 0.8f 是个不错的值
*/
fun setTranslateTextScaleValue(@FloatRange(from = 0.1, to = 2.0) scaleValue: Float)
/**
* 设置文字的对齐方向
*/
fun setTextGravity(gravity: Int)
/**
* 设置非当前行歌词字体颜色 [normalColor]
*/
fun setNormalColor(@ColorInt normalColor: Int)
/**
* 普通歌词文本字体大小 [size]单位 px
*/
fun setNormalTextSize(@Px size: Float)
/**
* 当前歌词文本字体大小
*/
fun setCurrentTextSize(size: Float)
/**
* 设置当前行歌词的字体颜色
*/
fun setCurrentColor(currentColor: Int)
/**
* 设置拖动歌词时选中歌词的字体颜色
*/
fun setTimelineTextColor(timelineTextColor: Int)
/**
* 设置拖动歌词时时间线的颜色
*/
fun setTimelineColor(timelineColor: Int)
/**
* 设置拖动歌词时右侧时间字体颜色
*/
fun setTimeTextColor(timeTextColor: Int)
/**
* 设置歌词为空时屏幕中央显示的文字 [label]暂无歌词
*/
fun setLabel(label: String)
/**
* 加载歌词文本
* 两种语言的歌词时间戳需要一致
*
* @param mainLyricText 第一种语言歌词文本
* @param secondLyricText 可选第二种语言歌词文本
*/
fun loadLyric(mainLyricText: String?, secondLyricText: String? = null)
/**
* 加载歌词 [LyricEntry] 集合
* 如果你在 Service 等地方自行解析歌词包装成 [LyricEntry] 集合那么可以使用此方法载入歌词
*
* @param lyricEntries 歌词集合
* @since 1.3.1
*/
fun loadLyric(lyricEntries: List<LyricEntry>)
/**
* 刷新歌词
*
* @param time 当前播放时间
*/
fun updateTime(time: Long, force: Boolean = false)
/**
* 设置歌词是否允许拖动
*
* @param draggable 是否允许拖动
* @param onPlayClickListener 设置歌词拖动后播放按钮点击监听器如果允许拖动则不能为 null
*/
fun setDraggable(draggable: Boolean, onPlayClickListener: OnPlayClickListener?)
/**
* 设置单击
*/
fun setOnSingerClickListener(onSingerClickListener: OnSingleClickListener?)
/**
* 获取当前歌词每句实体可用于歌词分享
*
* @return LyricEntry 集合
*/
fun getLyricEntryList(): List<LyricEntry>
/**
* 设置当前歌词每句实体
*/
fun setLyricEntryList(newList: List<LyricEntry>)
/**
* 获取当前行歌词
*/
fun getCurrentLineLyricEntry(): LyricEntry?
/**
* 为歌词设置自定义的字体
*
* @param file 字体文件
*/
fun setLyricTypeface(file: File)
/**
* 为歌词设置自定义的字体
*
* @param path 字体文件路径
*/
fun setLyricTypeface(path: String)
/**
* 为歌词设置自定义的字体可为空若为空则应清除字体
*
* @param typeface 字体对象
*/
fun setLyricTypeface(typeface: Typeface?)
/**
* 为歌词的过渡动画设置阻尼比数值越大回弹次数越多
*
* @param dampingRatio 阻尼比 详见[androidx.dynamicanimation.animation.SpringForce]
*/
fun setDampingRatioForLyric(dampingRatio: Float)
/**
* 为歌词视图的滚动动画设置阻尼比数值越大回弹次数越多
*
* @param dampingRatio 阻尼比 详见[androidx.dynamicanimation.animation.SpringForce]
*/
fun setDampingRatioForViewPort(dampingRatio: Float)
/**
* 为歌词的过渡动画设置刚度数值越大动画越短
*
* @param stiffness 刚度 详见[androidx.dynamicanimation.animation.SpringForce]
*/
fun setStiffnessForLyric(stiffness: Float)
/**
* 为歌词视图的滚动动画设置刚度数值越大动画越短
*
* @param stiffness 刚度 详见[androidx.dynamicanimation.animation.SpringForce]
*/
fun setStiffnessForViewPort(stiffness: Float)
/**
* 设置跳转播放按钮
*/
fun setPlayDrawable(drawable: Drawable)
/**
* 设置是否绘制歌词翻译
*/
fun setIsDrawTranslation(isDrawTranslation: Boolean)
/**
* 是否开启特定的模糊效果
*/
fun setIsEnableBlurEffect(isEnableBlurEffect: Boolean)
/**
* 设置元素的偏移百分比0.5f即表示居中
*
* @param itemOffsetPercent 0f ~ 1f 偏移百分比
*/
fun setItemOffsetPercent(@FloatRange(from = 0.0, to = 1.0) itemOffsetPercent: Float)
}
/**
* 播放按钮点击监听器点击后应该跳转到指定播放位置
*/
interface OnPlayClickListener {
/**
* 播放按钮被点击应该跳转到指定播放位置
*
* @return 是否成功消费该事件如果成功消费则会更新UI
*/
fun onPlayClick(time: Long): Boolean
}
/**
* 点击歌词布局
*/
interface OnSingleClickListener {
fun onClick()
}

View File

@ -0,0 +1,82 @@
package com.dirror.lyricviewx
import android.os.Build
import android.text.Layout
import android.text.StaticLayout
import android.text.TextPaint
/**
* 一行歌词实体
* @since 2021年1月19日09:51:40 Moriafly 基于 LrcEntry 改造转换为 kt 移除部分过时方法
* @param time 歌词时间
* @param text 歌词文本
*/
class LyricEntry(@JvmField val time: Long, @JvmField val text: String) : Comparable<LyricEntry> {
/**
* 第二文本
*/
@JvmField
var secondText: String? = null
/**
* staticLayout
*/
var staticLayout: StaticLayout? = null
private set
var secondStaticLayout: StaticLayout? = null
private set
@Deprecated("存在不显示翻译的情况会导致offset发生改变故不再固定存储offset")
/**
* 歌词距离视图顶部的距离
*/
var offset = Float.MIN_VALUE
/**
* 初始化
* @param textPaint 文本画笔
* @param width 宽度
* @param align 位置
*/
fun init(
textPaint: TextPaint,
secondTextPaint: TextPaint,
width: Int, align: Layout.Alignment
) {
staticLayout = createStaticLayout(text, textPaint, width, align)
secondStaticLayout = createStaticLayout(secondText, secondTextPaint, width, align)
offset = Float.MIN_VALUE
}
/**
* 继承 Comparable 比较
* @param other LyricEntry
* @return 时间差
*/
override fun compareTo(other: LyricEntry): Int {
return (time - other.time).toInt()
}
companion object {
fun createStaticLayout(
text: String?,
paint: TextPaint,
width: Number,
align: Layout.Alignment
): StaticLayout? {
if (text.isNullOrEmpty()) return null
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
StaticLayout.Builder
.obtain(text, 0, text.length, paint, width.toInt())
.setAlignment(align)
.setLineSpacing(0f, 1f)
.setIncludePad(false)
.build()
} else {
StaticLayout(text, paint, width.toInt(), align, 1f, 0f, false)
}
}
}
}

View File

@ -0,0 +1,289 @@
package com.dirror.lyricviewx
import android.animation.ArgbEvaluator
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.graphics.Rect
import android.text.TextUtils
import android.text.format.DateUtils
import android.view.MotionEvent
import java.io.*
import java.net.HttpURLConnection
import java.net.URL
import java.nio.charset.StandardCharsets
import java.util.*
import java.util.regex.Pattern
/**
* 工具类
* LrcUtils Kotlin
*/
object LyricUtil {
private val PATTERN_LINE = Pattern.compile("((\\[\\d\\d:\\d\\d\\.\\d{2,3}])+)(.+)")
private val PATTERN_TIME = Pattern.compile("\\[(\\d\\d):(\\d\\d)\\.(\\d{2,3})]")
private val argbEvaluator = ArgbEvaluator()
/**
* 从文件解析双语歌词
*/
fun parseLrc(lrcFiles: Array<out File?>?): List<LyricEntry>? {
if (lrcFiles == null || lrcFiles.size != 2 || lrcFiles[0] == null) {
return null
}
val mainLrcFile = lrcFiles[0]
val secondLrcFile = lrcFiles[1]
val mainEntryList = parseLrc(mainLrcFile)
val secondEntryList = parseLrc(secondLrcFile)
if (mainEntryList != null && secondEntryList != null) {
for (mainEntry in mainEntryList) {
for (secondEntry in secondEntryList) {
if (mainEntry.time == secondEntry.time) {
mainEntry.secondText = secondEntry.text
}
}
}
}
return mainEntryList
}
/**
* 从文件解析歌词
*/
private fun parseLrc(lrcFile: File?): List<LyricEntry>? {
if (lrcFile == null || !lrcFile.exists()) {
return null
}
val entryList: MutableList<LyricEntry> = ArrayList()
try {
val br =
BufferedReader(InputStreamReader(FileInputStream(lrcFile), StandardCharsets.UTF_8))
var line: String
while (br.readLine().also { line = it } != null) {
val list = parseLine(line)
if (list != null && list.isNotEmpty()) {
entryList.addAll(list)
}
}
br.close()
} catch (e: IOException) {
e.printStackTrace()
}
entryList.sort()
return entryList
}
/**
* 从文本解析双语歌词
*/
fun parseLrc(lrcTexts: Array<out String?>?): List<LyricEntry>? {
if (lrcTexts == null || lrcTexts.size != 2 || TextUtils.isEmpty(lrcTexts[0])) {
return null
}
val mainLrcText = lrcTexts[0]
val secondLrcText = lrcTexts[1]
val mainEntryList = mainLrcText?.let { parseLrc(it) }
/**
* 当输入的secondLrcText为空时,按如下格式解析歌词
* 音乐标签下载的第二种歌词格式
*
* [00:21.11]いつも待ち合わせより15分前集合
* [00:21.11]总会比相约时间早15分钟集合
* [00:28.32]駅の改札ぬける
* [00:28.32]穿过车站的检票口
* [00:31.39]ざわめきにわくわくだね
* [00:31.39]嘈杂声令内心兴奋不已
* [00:35.23]どこへ向かうかなんて
* [00:35.23]不在意接下来要去哪里
*/
if (TextUtils.isEmpty(secondLrcText)) {
var lastEntry: LyricEntry? = null
return mainEntryList?.filter { now ->
if (lastEntry == null) {
lastEntry = now
return@filter true
}
if (lastEntry!!.time == now.time) {
lastEntry!!.secondText = now.text
lastEntry = null
return@filter false
}
lastEntry = now
true
}
}
val secondEntryList = secondLrcText?.let { parseLrc(it) }
if (mainEntryList != null && secondEntryList != null) {
for (mainEntry in mainEntryList) {
for (secondEntry in secondEntryList) {
if (mainEntry.time == secondEntry.time) {
mainEntry.secondText = secondEntry.text
}
}
}
}
return mainEntryList
}
/**
* 从文本解析歌词
*/
private fun parseLrc(lrcText: String): List<LyricEntry>? {
var lyricText = lrcText.trim()
if (TextUtils.isEmpty(lyricText)) return null
if (lyricText.startsWith("\uFEFF")) {
lyricText = lyricText.replace("\uFEFF", "")
}
// 针对传入 Language="Media Monkey Format"; Lyrics="......"; 的情况
lyricText = lyricText.substringAfter("Lyrics=\"")
.substringBeforeLast("\";")
val entryList: MutableList<LyricEntry> = ArrayList()
val array = lyricText.split("\\n".toRegex()).toTypedArray()
for (line in array) {
val list = parseLine(line)
if (!list.isNullOrEmpty()) {
entryList.addAll(list)
}
}
entryList.sort()
return entryList
}
/**
* 获取网络文本需要在工作线程中执行
*/
fun getContentFromNetwork(url: String?, charset: String?): String? {
var lrcText: String? = null
try {
val url = URL(url)
val conn = url.openConnection() as HttpURLConnection
conn.requestMethod = "GET"
conn.connectTimeout = 10000
conn.readTimeout = 10000
if (conn.responseCode == 200) {
val `is` = conn.inputStream
val bos = ByteArrayOutputStream()
val buffer = ByteArray(1024)
var len: Int
while (`is`.read(buffer).also { len = it } != -1) {
bos.write(buffer, 0, len)
}
`is`.close()
bos.close()
lrcText = bos.toString(charset)
}
} catch (e: Exception) {
e.printStackTrace()
}
return lrcText
}
/**
* 解析一行歌词
*/
private fun parseLine(line: String): List<LyricEntry>? {
var lyricLine = line
if (TextUtils.isEmpty(lyricLine)) {
return null
}
lyricLine = lyricLine.trim { it <= ' ' }
// [00:17.65]让我掉下眼泪的
val lineMatcher = PATTERN_LINE.matcher(lyricLine)
if (!lineMatcher.matches()) {
return null
}
val times = lineMatcher.group(1)!!
val text = lineMatcher.group(3)!!
val entryList: MutableList<LyricEntry> = ArrayList()
// [00:17.65]
val timeMatcher = PATTERN_TIME.matcher(times)
while (timeMatcher.find()) {
val min = timeMatcher.group(1)!!.toLong()
val sec = timeMatcher.group(2)!!.toLong()
val milString = timeMatcher.group(3)!!
var mil = milString.toLong()
// 如果毫秒是两位数,需要乘以 10when 新增支持 1 - 6 位毫秒,很多获取的歌词存在不同的毫秒位数
when (milString.length) {
1 -> mil *= 100
2 -> mil *= 10
4 -> mil /= 10
5 -> mil /= 100
6 -> mil /= 1000
}
val time = min * DateUtils.MINUTE_IN_MILLIS + sec * DateUtils.SECOND_IN_MILLIS + mil
entryList.add(LyricEntry(time, text))
}
return entryList
}
/**
* 转为[:]
*/
fun formatTime(milli: Long): String {
val m = (milli / DateUtils.MINUTE_IN_MILLIS).toInt()
val s = (milli / DateUtils.SECOND_IN_MILLIS % 60).toInt()
val mm = String.format(Locale.getDefault(), "%02d", m)
val ss = String.format(Locale.getDefault(), "%02d", s)
return "$mm:$ss"
}
/**
* BUG java.lang.NoSuchFieldException: No field sDurationScale in class Landroid/animation/ValueAnimator; #3
*/
@SuppressLint("SoonBlockedPrivateApi")
@Deprecated("")
fun resetDurationScale() {
try {
val mField = ValueAnimator::class.java.getDeclaredField("sDurationScale")
mField.isAccessible = true
mField.setFloat(null, 1f)
} catch (e: Exception) {
e.printStackTrace()
}
}
/**
* 结合fraction计算两个值之间的比例
*/
fun calcScaleValue(a: Float, b: Float, f: Float, reverse: Boolean = false): Float {
if (b == 0f) return 1f
return 1f + ((a - b) / b) * (if (reverse) 1f - f else f)
}
/**
* 颜色值插值函数
*/
fun lerpColor(a: Int, b: Int, f: Float): Int {
return argbEvaluator.evaluate(f, a, b) as Int
}
/**
* 简单的插值函数
*/
fun lerp(from: Float, to: Float, fraction: Float): Float {
return from + (to - from) * fraction
}
/**
* 判断MotionEvent是否发生在Rect中
*/
fun MotionEvent.insideOf(rect: Rect?): Boolean {
rect ?: return false
return rect.contains(x.toInt(), y.toInt())
}
fun normalize(min: Float, max: Float, value: Float, limit: Boolean = false): Float {
if (min == max) return 1f
return ((value - min) / (max - min)).let {
if (limit) it.coerceIn(0f, 1f) else it
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,51 @@
package com.dirror.lyricviewx
import androidx.annotation.IntDef
const val STATE_CREATED = 1
const val STATE_INITIALIZING = 2
const val STATE_INITIALIZED = 3
const val STATE_ERROR = 4
@IntDef(
STATE_CREATED,
STATE_INITIALIZING,
STATE_INITIALIZED,
STATE_ERROR
)
@Retention(AnnotationRetention.SOURCE)
annotation class ReadyState
/**
* 简单的状态机根据 [readyState] 的状态决定当前任务的执行或延后与否
*/
open class ReadyHelper {
private var readyCallback: (Boolean) -> Unit = {}
@ReadyState
var readyState: Int = STATE_CREATED
set(value) {
if (field == value) return
when (value) {
STATE_INITIALIZED,
STATE_ERROR -> synchronized(readyCallback) {
field = value
readyCallback.invoke(value != STATE_ERROR)
}
else -> field = value
}
}
fun whenReady(performAction: (Boolean) -> Unit): Boolean {
return when (readyState) {
STATE_CREATED, STATE_INITIALIZING -> {
readyCallback = performAction
false
}
else -> {
performAction(readyState != STATE_ERROR)
true
}
}
}
}

View File

@ -0,0 +1,15 @@
package com.dirror.lyricviewx.extension
import android.graphics.BlurMaskFilter
import android.util.SparseArray
class BlurMaskFilterExt {
private val maskFilterCache = SparseArray<BlurMaskFilter>()
fun get(radius: Int): BlurMaskFilter? {
if (radius == 0 || radius > 25) return null
return maskFilterCache[radius] ?: BlurMaskFilter(radius.toFloat(), BlurMaskFilter.Blur.NORMAL)
.also { maskFilterCache.put(radius, it) }
}
}

View File

@ -0,0 +1,123 @@
package com.muqingbfq;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.text.Editable;
import android.view.View;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.muqingbfq.fragment.wode;
import com.muqingbfq.login.user_logs;
import com.muqingbfq.mq.EditViewDialog;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wl;
import com.muqingbfq.view.Edit;
import org.json.JSONObject;
public class HomeSteer {
home home;
ActivityResultLauncher<Intent> dlintent;
public HomeSteer(home home) {
this.home = home;
dlintent = home.registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
// 处理返回结果
Intent data = result.getData();
boolean bool = data.getBooleanExtra("bool", false);
if (bool) {
Yes();
return;
}
}
One();
});
SetIP();
// One();
}
public void One() {
MaterialAlertDialogBuilder materialAlertDialogBuilder = new MaterialAlertDialogBuilder(home);
materialAlertDialogBuilder.setTitle("引导登陆");
materialAlertDialogBuilder.setItems(new String[]{"游客", "登陆"}, (dialog, which) -> {
if (which == 0) {
new Thread() {
@Override
public void run() {
super.run();
//获取游客Cookie
String hq = wl.hq("/register/anonimous");
try {
JSONObject jsonObject = new JSONObject(hq);
wl.setcookie(jsonObject.getString("cookie"));
home.runOnUiThread(() -> Yes());
} catch (Exception e) {
home.runOnUiThread(() -> Toast.makeText(home, "游客登陆失败:" + e.getMessage(), Toast.LENGTH_SHORT).show());
gj.sc(e);
}
}
}.start();
} else if (which == 1) {
dlintent.launch(new Intent(home, user_logs.class));
}
});
materialAlertDialogBuilder.show();
}
public void Yes() {
}
/**
* 设置IP地址
*/
public void SetIP() {
SharedPreferences nickname = home.getSharedPreferences("Set_up", Context.MODE_PRIVATE);
if (nickname.getString("IP", "").isEmpty()) {
EditViewDialog editViewDialog = new EditViewDialog(home, "IP");
editViewDialog.setMessage("请输入部署了NeteaseCloudMusicApi的服务器地址\n例如" +
"https://api.csm.sayqz.com");
// editViewDialog.setPositive()
editViewDialog.buttonb.setEnabled(false);
editViewDialog.editText.setMaxLines(1);
editViewDialog.editText.addTextChangedListener(new Edit.TextWatcher() {
@Override
public void beforeTextChanged(CharSequence var1, int var2, int var3, int var4) {
}
@Override
public void onTextChanged(CharSequence var1, int var2, int var3, int var4) {
//正则表达式检查是否为 https://api.csm.sayqz.com这样的
editViewDialog.buttonb.setEnabled(var1.toString().matches("^(https?://).+[^/]"));
}
@Override
public void afterTextChanged(Editable var1) {
}
});
editViewDialog.setPositive(v -> {
main.api = editViewDialog.getEditText();
nickname.edit().putString("IP", editViewDialog.getEditText()).apply();
One();
editViewDialog.dismiss();
});
editViewDialog.show();
} else {
main.api = nickname.getString("IP", "");
One();
}
}
}

View File

@ -0,0 +1,56 @@
package com.muqingbfq;
import androidx.annotation.NonNull;
import java.io.Serializable;
import java.util.Objects;
public class MP3 implements Serializable {
public String id, name, zz, url;
// 音乐的贴图
public String picurl;
public MP3(){}
public MP3(String id) {
this.id = id;
}
public MP3(String id, String name, String zz, String picurl) {
this.id = id;
this.name = name;
this.zz = zz;
this.picurl = picurl;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof MP3)) return false;
MP3 mp3 = (MP3) o;
if (id.equals(mp3.id)) {
return true;
}
return Objects.equals(id, mp3.id) &&
Objects.equals(name, mp3.name) &&
Objects.equals(zz, mp3.zz) &&
Objects.equals(picurl, mp3.picurl);
}
@Override
public int hashCode() {
return Objects.hash(id, name, zz, picurl);
}
@NonNull
@Override
public String toString() {
return "MP3{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", zz='" + zz + '\'' +
", picurl=" + picurl +
",url=" + url +
'}';
}
}

View File

@ -0,0 +1,217 @@
package com.muqingbfq;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Intent;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.media3.common.C;
import androidx.media3.common.MediaItem;
import androidx.media3.common.MediaMetadata;
import androidx.media3.common.PlaybackException;
import androidx.media3.common.Player;
import androidx.media3.common.Tracks;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.session.MediaSession;
import androidx.media3.session.MediaSessionService;
import com.google.common.base.Strings;
import com.google.gson.Gson;
import com.muqingbfq.api.url;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wj;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class PlaybackService extends MediaSessionService {
public static MediaSession mediaSession = null;
public static List<MP3> list = new ArrayList<>();
//历史记录
// public static final List<MediaItem> listHistory = new ArrayList<>();
public static void ListSave() {
new Thread(() -> wj.xrwb(wj.filesdri + "list.json", new Gson().toJson(list))).start();
}
public Player.Listener PlayerListener = new Player.Listener() {
@Override
public void onPlayWhenReadyChanged(boolean playWhenReady, int reason) {
// 处理 playWhenReady 的变化
}
@Override
public void onPlaybackStateChanged(int playbackState) {
// 处理播放状态的变化
if (playbackState == Player.STATE_ENDED) {
// 检查当前播放的媒体项是否是最后一项
Player player = mediaSession.getPlayer();
if (player.getCurrentMediaItemIndex() == player.getMediaItemCount() - 1) {
// 如果是最后一项回到第一项并播放
player.seekTo(0,0);
player.play();
}
}
}
@Override
public void onPositionDiscontinuity(@NonNull Player.PositionInfo oldPosition, @NonNull Player.PositionInfo newPosition, int reason) {
// 处理位置不连续变化
}
@Override
public void onMediaItemTransition(@Nullable MediaItem mediaItem, @Player.MediaItemTransitionReason int reason) {
if (mediaItem != null) {
// 输出当前的 MediaItem 信息
String title = mediaItem.mediaMetadata.title != null ? mediaItem.mediaMetadata.title.toString() : "未知标题";
String artist = mediaItem.mediaMetadata.artist != null ? mediaItem.mediaMetadata.artist.toString() : "未知艺术家";
// bfqkz.lishi_list.removeIf(mp3 -> mp3.id.equals(mediaItem.mediaId));
// bfqkz.lishi_list.add(0, new MP3(mediaItem.mediaId, title, artist, mediaItem.mediaMetadata.artworkUri.toString()));
// new Thread(() -> wj.xrwb(wj.gd + "mp3_hc.json", new Gson().toJson(bfqkz.lishi_list))).start();
}
}
@Override
public void onTracksChanged(@Nullable Tracks tracks) {
gj.sc(tracks);
// Update UI using current tracks.
}
int error_count = 0;//设置错误次数
MediaItem currentMediaItem = null;
int currentIndex = 0;
@Override
public void onPlayerError(@NonNull PlaybackException error) {
// 当播放发生错误时调用
// 如果错误是由于资源找不到
Player player = mediaSession.getPlayer();
if (++error_count > 3) {
currentIndex = player.getNextMediaItemIndex();
if (currentIndex != C.INDEX_UNSET) {
gj.sc("播放失败,已跳过");
return;
} else {
currentMediaItem = player.getMediaItemAt(currentIndex); // 获取下一首的 MediaItem
}
} else {
currentMediaItem = player.getCurrentMediaItem();
currentIndex = player.getCurrentMediaItemIndex(); // 获取当前播放项的索引
}
new Thread(() -> {
MP3 hq = url.hq(new MP3(currentMediaItem.mediaId));
hq.picurl = url.picurl(hq.id);
// 设置新的 MediaItem
MediaItem newMediaItem = currentMediaItem.buildUpon()
.setUri(hq.url) // 更新 URI
.build(); // 构建新的 MediaItem
main.handler.post(() -> {
player.replaceMediaItem(currentIndex, newMediaItem);
player.prepare();
player.play();
error_count = 0;
});
}).start();
}
};
@UnstableApi
public void onCreate() {
super.onCreate();
ExoPlayer player = new ExoPlayer.Builder(this)
.build();
mediaSession = new MediaSession.Builder(this, player).build();
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setComponent(new ComponentName(this, home.class));//用ComponentName得到class对象
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);// 关键的一步设置启动模式两种情况
PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
mediaSession.setSessionActivity(pendingIntent);
// 添加 ExoPlayer 监听器
player.addListener(PlayerListener);
String nickname = wj.dqwb(wj.filesdri + "list.json");
if (!Strings.isNullOrEmpty(nickname)) {
try {
list = new Gson().fromJson(nickname, new com.google.gson.reflect.TypeToken<List<MP3>>() {
}.getType());
for (MP3 mediaItem : list) {
player.addMediaItem(PlaybackService.GetMp3(mediaItem));
}
} catch (Exception e) {
gj.sc(e);
list = new ArrayList<>();
wj.sc(wj.filesdri + "list.json");
}
}
}
@Nullable
@Override
public MediaSession onGetSession(@NonNull MediaSession.ControllerInfo controllerInfo) {
return mediaSession;
}
@Override
public void onDestroy() {
mediaSession.getPlayer().release();
mediaSession.release();
mediaSession = null;
super.onDestroy();
}
public static MediaItem GetMp3(MP3 mp3) {
// 创建媒体的元数据如标题描述图片等
MediaMetadata mediaMetadata = new MediaMetadata.Builder()
.setTitle(mp3.name)
.setArtist(mp3.zz)
.setAlbumTitle(mp3.zz)
.setArtworkUri(Uri.parse(mp3.picurl)) // 图片URL
.build();
// 创建带有元数据的 MediaItem
return new MediaItem.Builder()
.setMediaId(mp3.id) // 设置媒体的唯一ID
.setUri(Strings.isNullOrEmpty(mp3.url) ? "" : mp3.url)
.setMediaMetadata(mediaMetadata) // 将元数据添加到 MediaItem
.build();
}
public static void AddMediaItem(MP3 mp3) {
if (mediaSession != null) {
new Thread(() -> {
MediaItem mediaItem = GetMp3(mp3);
main.handler.post(() -> {
Player player = mediaSession.getPlayer();
for (int i = 0; i < player.getMediaItemCount(); i++) {
MediaItem existingItem = player.getMediaItemAt(i);
if (Objects.equals(existingItem.mediaId, mp3.id)) {
player.seekTo(i, 0);
return;
}
}
player.addMediaItem(0, mediaItem);
player.seekTo(0, 0);
player.prepare();
player.play();
});
}).start();
}
}
}

View File

@ -0,0 +1,22 @@
package com.muqingbfq;
public class XM {
public String id, name, message;
public Object picurl;
public XM(String id, String name, String picurl) {
this.id = id;
this.name = name;
this.picurl = picurl;
}
public XM(String id, String name,String message, String picurl) {
this.id = id;
this.name = name;
this.picurl = picurl;
this.message = message;
}
public XM(String id, String name, int picurl) {
this.id = id;
this.name = name;
this.picurl = picurl;
}
}

View File

@ -0,0 +1,544 @@
package com.muqingbfq.activity;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.LayerDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.DecelerateInterpolator;
import android.widget.SeekBar;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.lifecycle.ViewModelProvider;
import androidx.media3.common.MediaItem;
import androidx.media3.common.MediaMetadata;
import androidx.media3.common.Player;
import androidx.media3.common.util.Util;
import androidx.palette.graphics.Palette;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
import com.muqingbfq.MP3;
import com.muqingbfq.PlaybackService;
import com.muqingbfq.R;
import com.muqingbfq.bfq_an;
import com.muqingbfq.bfqkz;
import com.muqingbfq.databinding.ActivityMusicBinding;
import com.muqingbfq.fragment.Media;
import com.muqingbfq.main;
import com.muqingbfq.mq.AppCompatActivity;
import com.muqingbfq.mq.MusicViewModel;
import com.muqingbfq.mq.gj;
public class Music extends AppCompatActivity<ActivityMusicBinding> implements GestureDetector.OnGestureListener {
private Player player = PlaybackService.mediaSession.getPlayer();
private int TdtHeight = 15;
public static Bitmap backgroundbitmap=null;
public static void startActivity(Context context, MP3 mp3) {
Intent intent = new Intent(context, Music.class);
intent.putExtra("MP3", mp3);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(intent);
}
public static void startActivity(Context context) {
Intent intent = new Intent(context, Music.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(intent);
}
DisplayMetrics displayMetrics = new DisplayMetrics();
GestureDetector gestureDetector;
float Minfloat = 1000f;
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gestureDetector = new GestureDetector(this, this);
setContentView();
color(backgroundbitmap);
// 获取屏幕的高度
WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
ViewCompat.setOnApplyWindowInsetsListener(binding.getRoot(), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
// 创建新的MarginLayoutParams
ViewGroup.LayoutParams layoutParams = binding.toolbar.getLayoutParams();
// 设置margin
((ViewGroup.MarginLayoutParams) layoutParams).setMargins(0, systemBars.top, 0, 0);
binding.toolbar.setLayoutParams(layoutParams);
if (gj.isTablet(this)) {
// binding.image2.setLayoutParams(layoutParams);
ViewGroup.LayoutParams layoutParams1 = binding.cardview.getLayoutParams();
layoutParams1.width = displayMetrics.heightPixels / 2;
layoutParams1.height = displayMetrics.heightPixels / 2;
}
return insets;
});
Minfloat = displayMetrics.heightPixels - displayMetrics.heightPixels / 3f;
binding.kg.setOnClickListener(view -> Util.handlePlayPauseButtonAction(player));
binding.xyq.setOnClickListener(v -> {
boolean b = player.hasNextMediaItem();
if (b) {
player.seekToNextMediaItem();
} else {
gj.ts(v.getContext(), "已经是最后一首了");
}
});
binding.syq.setOnClickListener(v -> {
boolean b = player.hasPreviousMediaItem();
if (b) {
player.seekToPreviousMediaItem();
} else {
gj.ts(v.getContext(), "已经是第一首了");
}
});
player.addListener(Listener);
if (PlaybackService.mediaSession != null) {
updateUI(player);
}
binding.tdt.post(() -> TdtHeight = binding.tdt.getHeight());
binding.tdt.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
long actualPosition = (progress * player.getDuration()) / 100;
String time = bfq_an.getTime(actualPosition);
binding.timeB.setText(time);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
// 获取 View 当前的高度;
// 创建一个 ValueAnimator从当前高度逐渐增加到目标高度
ValueAnimator animator = ValueAnimator.ofInt(TdtHeight, TdtHeight + 10);
animator.setDuration(300); // 设置动画持续时间为 300 毫秒
animator.setInterpolator(new DecelerateInterpolator()); // 设置动画插值器
// 在动画过程中更新 View 的高度
animator.addUpdateListener(animation -> {
// 获取当前动画的值高度
int animatedValue = (int) animation.getAnimatedValue();
// 更新 View 的高度
ViewGroup.LayoutParams layoutParams = seekBar.getLayoutParams();
layoutParams.height = animatedValue;
seekBar.setLayoutParams(layoutParams);
});
// 开始动画
animator.start();
isDrag = true;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
isDrag = false;
int progress = seekBar.getProgress();
if (progress >= 100) {
player.seekToNextMediaItem();
} else {
long actualPosition = (progress * player.getDuration()) / 100;
player.seekTo(actualPosition);
}
ValueAnimator animator = ValueAnimator.ofInt(TdtHeight, TdtHeight - 10);
animator.setDuration(300); // 设置动画持续时间为 300 毫秒
animator.setInterpolator(new DecelerateInterpolator()); // 设置动画插值器
// 在动画过程中更新 View 的高度
animator.addUpdateListener(animation -> {
// 获取当前动画的值高度
int animatedValue = (int) animation.getAnimatedValue();
// 更新 View 的高度
ViewGroup.LayoutParams layoutParams = seekBar.getLayoutParams();
layoutParams.height = animatedValue;
seekBar.setLayoutParams(layoutParams);
});
// 开始动画
animator.start();
}
});
binding.back.setOnClickListener(v -> finish());
binding.fragmentBfq.setOnClickListener(v -> {
if (binding.cardview.getVisibility() == View.VISIBLE) {
binding.cardview.setVisibility(View.GONE);
binding.lrcView.setVisibility(View.VISIBLE);
} else {
binding.cardview.setVisibility(View.VISIBLE);
binding.lrcView.setVisibility(View.GONE);
}
});
binding.lrcView.setNormalTextSize(80f);
binding.lrcView.setCurrentTextSize(100f);
binding.lrcView.setTranslateTextScaleValue(0.8f);
binding.lrcView.setHorizontalOffset(-50f);
binding.lrcView.setHorizontalOffsetPercent(0.5f);
binding.lrcView.setItemOffsetPercent(0.5f);
binding.lrcView.setIsDrawTranslation(true);
binding.lrcView.setIsEnableBlurEffect(true);
// binding.cardview.setLayoutParams(layoutParams);
binding.lrcView.setDraggable(true, time -> {
player.seekTo(time);
return false;
});
binding.lrcView.setOnSingerClickListener(() -> switchViews(binding.lrcView, binding.cardview));
binding.fragmentBfq.setOnTouchListener((v, event) -> {
gestureDetector.onTouchEvent(event);
if (event.getAction() == MotionEvent.ACTION_UP) {
if (binding.getRoot().getRootView().getTranslationY() > (getResources().getDisplayMetrics().heightPixels / 2.0f)) {
finish();
return true;
}
ObjectAnimator animator = ObjectAnimator.ofFloat(binding.getRoot().getRootView()
, "y", binding.getRoot().getRootView().getTranslationY(), 0);
animator.setDuration(500);
animator.start();
}
return true;
});
//播放列表
binding.bfqListMp3.setOnClickListener(v -> com.muqingbfq.fragment.bflb_db.start(v.getContext()));
}
//是否拖动
private boolean isDrag = false;
Runnable runnable = new Runnable() {
@Override
public void run() {
if (player != null && !isDrag) {
// 获取当前进度和持续时间
long currentPosition = player.getCurrentPosition();
long duration = player.getDuration();
// 更新进度条假设有一个 SeekBar 名为 seekBar
if (duration > 0) {
int progress = (int) ((currentPosition * 100) / duration);
// gj.sc(progress);
if (progress < 1) {
progress = 1;
}
binding.tdt.setProgress(progress);
// binding.tdt.setMax(100);
binding.lrcView.updateTime(currentPosition, true);
binding.timeA.setText(bfq_an.getTime(duration));
binding.timeB.setText(bfq_an.getTime(currentPosition));
}
}
// 计划下一次更新
main.handler.postDelayed(this, 1000); // 每秒更新一次
}
};
@Override
public void finish() {
super.finish();
player.removeListener(Listener);
}
private Player.Listener Listener = new Player.Listener() {
@Override
public void onEvents(@NonNull Player player, @NonNull Player.Events events) {
// 监听播放状态变化
if (events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED)) {
boolean isPlaying = player.getPlayWhenReady();
if (isPlaying) {
gj.sc("正在播放");
} else {
gj.sc("播放暂停");
}
}
// 监听下一曲事件
if (events.contains(Player.EVENT_MEDIA_ITEM_TRANSITION)) {
MediaItem currentMediaItem = player.getCurrentMediaItem();
if (currentMediaItem != null) {
gj.sc("播放下一曲: ");
}
}
// 监听上一曲事件通常通过手动调用控制播放器的skipToPrevious方法实现
if (events.contains(Player.EVENT_MEDIA_ITEM_TRANSITION)) {
// 你的逻辑代码处理上一曲
gj.sc("播放上一曲");
}
if (events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED)) {
int playbackState = player.getPlaybackState();
switch (playbackState) {
case Player.STATE_READY:
if (player.getPlayWhenReady()) {
if (bfqkz.lrc != null) {
String[] strings = Media.loadLyric();
binding.lrcView.loadLyric(strings[0], strings[1]);
}
gj.sc("播放开始");
}
break;
case Player.STATE_ENDED:
gj.sc("播放结束");
break;
default:
// 处理其他状态
break;
}
}
updateUI(player);
}
};
@Override
protected ActivityMusicBinding getViewBindingObject(LayoutInflater layoutInflater) {
return ActivityMusicBinding.inflate(layoutInflater);
}
@Override
protected void onResume() {
super.onResume();
main.handler.post(runnable);
}
@Override
protected void onPause() {
super.onPause();
// 取消所有未完成的任务
main.handler.removeCallbacks(runnable);
}
private void updateUI(Player player) {
boolean shouldShowPlayButton = Util.shouldShowPlayButton(player);
binding.kg.setImageResource(shouldShowPlayButton ? R.drawable.zt : R.drawable.bf);
// 获取当前播放的 MediaItem
MediaItem currentMediaItem = player.getCurrentMediaItem();
if (currentMediaItem != null && !isFinishing() && !isDestroyed()) {
MediaMetadata metadata = currentMediaItem.mediaMetadata;
String title = metadata.title != null ? metadata.title.toString() : "没有名字的音乐?";
String artist = metadata.artist != null ? metadata.artist.toString() : "未知艺术家";
binding.name.setText(title);
binding.zz.setText(artist);
SetBackGround(metadata.artworkUri);
}
}
private void SetBackGround(Uri artworkUri){
Glide.with(this)
.asBitmap()
.load(artworkUri)
.apply(new RequestOptions()
.placeholder(R.drawable.ic_launcher_foreground)
.error(R.drawable.ic_launcher_foreground))
.addListener(new RequestListener<Bitmap>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<Bitmap> target, boolean isFirstResource) {
return true;
}
@Override
public boolean onResourceReady(@NonNull Bitmap resource,
@NonNull Object model, Target<Bitmap> target,
@NonNull DataSource dataSource,
boolean isFirstResource) {
color(resource);
backgroundbitmap = resource;
binding.cardview.imageView.setImageBitmap(resource);
return true;
}
}).into(binding.cardview.imageView);
}
private void color(Bitmap bitmap) {
if (bitmap == null) {
return;
}
Palette.Builder builder = new Palette.Builder(bitmap);
builder.generate(palette -> {
// 获取图片中柔和的亮色
int lightMutedColor = palette.getLightMutedColor(Color.GRAY);
Palette.Swatch vibrantSwatch = palette.getLightVibrantSwatch();
if (vibrantSwatch != null) {
int bodyTextColor = vibrantSwatch.getBodyTextColor();
binding.lrcView.setCurrentColor(bodyTextColor);
binding.lrcView.setTimelineTextColor(bodyTextColor);
// 计算半亮度的颜色直接将RGB分量除以2并向下取整
int halfBrightnessColor = (bodyTextColor & 0x00FFFFFF) / 2;
binding.lrcView.setNormalColor(halfBrightnessColor);
GradientDrawable gradientDrawable = new GradientDrawable(
GradientDrawable.Orientation.BOTTOM_TOP, // 渐变方向从上到下
new int[]{vibrantSwatch.getRgb(), lightMutedColor} // 渐变颜色数组
);
setTint(vibrantSwatch.getTitleTextColor());
gradientDrawable.setShape(GradientDrawable.RECTANGLE);
binding.getRoot().setBackground(gradientDrawable);
} else {
int color = palette.getLightVibrantColor(Color.WHITE);
int titleTextColor = palette.getVibrantColor(Color.GRAY);
binding.lrcView.setCurrentColor(titleTextColor);
binding.lrcView.setTimelineTextColor(titleTextColor);
// 计算半亮度的颜色直接将RGB分量除以2并向下取整
int halfBrightnessColor = (titleTextColor & 0x00FFFFFF) / 2;
binding.lrcView.setNormalColor(halfBrightnessColor);
GradientDrawable gradientDrawable = new GradientDrawable(
GradientDrawable.Orientation.BOTTOM_TOP, // 渐变方向从上到下
new int[]{color, lightMutedColor} // 渐变颜色数组
);
setTint(titleTextColor);
gradientDrawable.setShape(GradientDrawable.RECTANGLE);
binding.getRoot().setBackground(gradientDrawable);
}
});
}
private void setTint(int color) {
// this.ColorTint = color;
ColorStateList colorStateList = ColorStateList.valueOf(color);
binding.kg.setImageTintList(colorStateList);
binding.syq.setImageTintList(colorStateList);
binding.xyq.setImageTintList(colorStateList);
binding.bfqListMp3.setImageTintList(colorStateList);
binding.control.setImageTintList(colorStateList);
binding.like.setImageTintList(colorStateList);
binding.download.setImageTintList(colorStateList);
binding.image2.setImageTintList(colorStateList);
binding.name.setTextColor(color);
binding.zz.setTextColor(color);
binding.timeA.setTextColor(color);
binding.timeB.setTextColor(color);
Drawable progressDrawable = binding.tdt.getProgressDrawable();
LayerDrawable layerDrawable = (LayerDrawable) progressDrawable;
Drawable progress = layerDrawable.findDrawableByLayerId(android.R.id.progress);
progress.setColorFilter(color, PorterDuff.Mode.SRC_IN);
// 设置进度条背景的颜色
Drawable background = layerDrawable.findDrawableByLayerId(android.R.id.background);
background.setColorFilter(Color.GRAY, PorterDuff.Mode.SRC_IN);
}
//触摸
// public boolean onTouchEvent(MotionEvent event)
@Override
public boolean onDown(@NonNull MotionEvent e) {
return false;
}
@Override
public void onShowPress(@NonNull MotionEvent e) {
}
@Override
public boolean onSingleTapUp(@NonNull MotionEvent e) {
// 判断是哪个视图被点击了
if (!gj.isTablet(this)) {
switchViews(binding.cardview, binding.lrcView);
}
return true;
}
boolean isswitchViews = false;//是否在执行中
private void switchViews(final View view1, final View view2) {
// 隐藏view1并显示view2的动画效果
if (isswitchViews || gj.isTablet(this)) {
return;
}
isswitchViews = true;
if (view2.getId() == binding.lrcView.getId()) {
binding.lrcView.updateTime(player.getCurrentPosition(), true);
}
view1.animate()
.alpha(0.0f)
.setDuration(500)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
view1.setVisibility(View.GONE);
view2.setVisibility(View.VISIBLE);
view2.setAlpha(0.0f);
view2.animate().alpha(1.0f).setDuration(500).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
isswitchViews = false;
}
});
}
});
}
// 判断触摸点是否在视图范围内的辅助方法
@Override
public boolean onScroll(MotionEvent e1, @NonNull MotionEvent e2,
float distanceX, float distanceY) {
float y = binding.getRoot().getRootView().getTranslationY() - distanceY;
y = Math.max(0, y);
//移动的距离
int heightPixels = getResources().getDisplayMetrics().heightPixels;
if (y > heightPixels - heightPixels / 5.0) {
finish();
return true;
}
binding.getRoot().getRootView().setTranslationY(y);
return true;
}
@Override
public void onLongPress(@NonNull MotionEvent e) {
}
@Override
public boolean onFling(MotionEvent e1, @NonNull MotionEvent e2,
float velocityX, float velocityY) {
return false;
}
}

View File

@ -0,0 +1,169 @@
package com.muqingbfq;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.os.Build;
import android.os.Bundle;
import android.text.Html;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.google.android.material.bottomsheet.BottomSheetDragHandleView;
import com.muqingbfq.databinding.ActivityAboutSoftwareBinding;
import com.muqingbfq.databinding.ListKaifazheBinding;
import com.muqingbfq.mq.AppCompatActivity;
import com.muqingbfq.mq.FragmentActivity;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wj;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class activity_about_software extends FragmentActivity<ActivityAboutSoftwareBinding> {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView();
try {
String versionName = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
binding.text2.setText(String.format("%s Bate", versionName));
} catch (PackageManager.NameNotFoundException e) {
yc.start(this, e);
}
setSupportActionBar(findViewById(R.id.toolbar));
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
findViewById(R.id.button1).setOnClickListener(view -> {
});
TextView viewById = findViewById(R.id.text1);
AssetManager assets = getAssets();
try {
InputStream open = assets.open("about.html");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(open));
StringBuilder stringBuilder = new StringBuilder();
String ling;
while ((ling = bufferedReader.readLine()) != null) {
stringBuilder.append(ling);
}
viewById.setText(Html.fromHtml(stringBuilder.toString(), Html.FROM_HTML_MODE_LEGACY));
open.close();
bufferedReader.close();
} catch (IOException e) {
viewById.setText(String.format("错误:%s", e));
}
}
MenuItem itemA;
@Override
public boolean onCreateOptionsMenu(Menu menu) {
itemA= menu.add("特别鸣谢");
itemA.setTitle("特别鸣谢");
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
int itemId = item.getItemId();
if (itemId == android.R.id.home) {
finish();
} else if (item == itemA) {
new botton(this);
}
return super.onOptionsItemSelected(item);
}
@Override
protected ActivityAboutSoftwareBinding getViewBindingObject(LayoutInflater layoutInflater) {
return ActivityAboutSoftwareBinding.inflate(layoutInflater);
}
class botton extends BottomSheetDialog {
List<Object[]> list = new ArrayList<>();
public botton(@NonNull Context context) {
super(context);
setTitle("特别鸣谢");
list.add(new Object[]{"2923268971","薄荷今天吃什么?", "维护开发者", "QQ"});
list.add(new Object[]{"3301074923","威廉", "主要测试BUG", "QQ"});
show();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout linearLayout = new LinearLayout(getContext());
RecyclerView recyclerView = new RecyclerView(getContext());
recyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
recyclerView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
linearLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
linearLayout.setOrientation(LinearLayout.VERTICAL);
linearLayout.setPadding(50,0,50,500);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(new RecyclerView.Adapter<VH>() {
@NonNull
@Override
public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ListKaifazheBinding binding = ListKaifazheBinding.inflate(getLayoutInflater());
return new VH(binding.getRoot());
}
@Override
public void onBindViewHolder(@NonNull VH holder, int position) {
Object[] objects = list.get(position);
holder.name.setText(objects[1].toString());
holder.zz.setText(objects[2].toString());
// https://q1.qlogo.cn/g?b=qq&nk=1966944300&s=100
Glide.with(getContext())
.load("https://q1.qlogo.cn/g?b=qq&nk=" + objects[0] + "&s=100")
.error(R.drawable.ic_launcher_foreground)
.into(holder.imageView);
}
@Override
public int getItemCount() {
return list.size();
}
});
linearLayout.setGravity(Gravity.CENTER_HORIZONTAL);
linearLayout.addView(new BottomSheetDragHandleView(getContext()));
linearLayout.addView(recyclerView);
setContentView(linearLayout);
}
}
class VH extends RecyclerView.ViewHolder {
public TextView name, zz;
public ImageView imageView;
public VH(@NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.text1);
zz = itemView.findViewById(R.id.text2);
imageView = itemView.findViewById(R.id.imageView);
}
}
}

View File

@ -0,0 +1,345 @@
package com.muqingbfq;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.flexbox.AlignItems;
import com.google.android.flexbox.FlexDirection;
import com.google.android.flexbox.FlexWrap;
import com.google.android.flexbox.FlexboxLayoutManager;
import com.google.android.material.search.SearchView;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.muqingbfq.databinding.ActivitySearchBinding;
import com.muqingbfq.databinding.ListTextBinding;
import com.muqingbfq.databinding.ViewSearchItemBinding;
import com.muqingbfq.fragment.search;
import com.muqingbfq.mq.FragmentActivity;
import com.muqingbfq.mq.VH;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wj;
import com.muqingbfq.view.Edit;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class activity_search extends FragmentActivity<ActivitySearchBinding> {
// private List<String> json_list = new ArrayList<>();
private final List<String> list = new ArrayList<>();
public static void start(Activity context, View view) {
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(context,
view, "edit");
context.startActivity(new Intent(context, activity_search.class), options.toBundle());
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getViewBinding().getRoot());
setToolbar();
FlexboxLayoutManager manager = new FlexboxLayoutManager(this) {
@Override
public boolean canScrollVertically() {
return false;
}
};
//设置主轴排列方式
manager.setFlexDirection(FlexDirection.ROW);
//设置是否换行
manager.setFlexWrap(FlexWrap.WRAP);
manager.setAlignItems(AlignItems.STRETCH);//历史记录的LayoutManager
binding.listRecycler.setLayoutManager(manager);
// binding.listRecycler.setAdapter(new SearchRecordAdapter());
/* binding.deleat.setOnClickListener(v -> new MaterialAlertDialogBuilder(
activity_search.this)
.setTitle("删除")
.setMessage("清空历史记录?")
.setNegativeButton("取消", null)
.setPositiveButton("确定", (dialogInterface, ii) -> {
int i = 0;
Iterator<String> iterator = json_list.iterator();
while (iterator.hasNext()) {
iterator.next();
iterator.remove();
binding.listRecycler.getAdapter().notifyItemRemoved(i++);
}
binding.xxbj1.setVisibility(View.GONE);
wj.sc(wj.filesdri + wj.lishi_json);
})
.show());*/
binding.searchRecycler.setLayoutManager(new LinearLayoutManager(this));
binding.searchRecycler.setAdapter(new search_adapter(list, this::start));
//设置项点击监听
final Object o = new Object();
binding.searchview.getEditText().addTextChangedListener(new Edit.TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
new Thread() {
@SuppressLint("NotifyDataSetChanged")
@Override
public void run() {
synchronized (o) {
list.clear();
String hq = com.muqingbfq.mq.wl.
hq("/search/suggest?keywords=" + s + "&type=mobile");
try {
JSONArray jsonArray = new JSONObject(hq).getJSONObject("result")
.getJSONArray("allMatch");
int length = jsonArray.length();
for (int i = 0; i < length; i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
String keyword = jsonObject.getString("keyword");
list.add(keyword);
}
activity_search.this.runOnUiThread(() ->
binding.searchRecycler.getAdapter().notifyDataSetChanged());
} catch (Exception e) {
gj.sc(e);
}
}
}
}.start();
}
@Override
public void afterTextChanged(Editable s) {
}
});
/* if (binding.toolbar.collapse(contextualToolbar, binding.barlayout)) {
// Clear selection.
return;
}*/
binding.searchview.inflateMenu(R.menu.search);
binding.searchview.setOnMenuItemClickListener(
menuItem -> {
binding.searchview.hide();
start(binding.searchview.getText().toString());
return true;
});
binding.searchview.addTransitionListener(
(searchView, previousState, newState) -> {
if (newState == SearchView.TransitionState.SHOWING ||
newState == SearchView.TransitionState.SHOWN) {
searchView.setText(binding.toolbar.getText());
} else if (newState == SearchView.TransitionState.HIDING ||
newState == SearchView.TransitionState.HIDDEN) {
binding.toolbar.setText(searchView.getText());
}
});
binding.searchview
.getEditText()
.setOnEditorActionListener(
(v, actionId, event) -> {
binding.toolbar.setText(binding.searchview.getText());
binding.searchview.hide();
start(binding.searchview.getText().toString());
return false;
});
binding.toolbar.setOnMenuItemClickListener(item -> {
//搜索
start(binding.toolbar.getText().toString());
return true;
});
}
@FunctionalInterface
public interface TaskAction<T> {
void execute(T t);
}
public static class search_adapter extends RecyclerView.Adapter<VH<ViewSearchItemBinding>> {
public List<String> list;
TaskAction<String> taskAction;
public search_adapter(List<String> list, TaskAction<String> taskAction) {
this.taskAction = taskAction;
this.list = list;
}
@NonNull
@Override
public VH<ViewSearchItemBinding> onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new VH<>(ViewSearchItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
}
@Override
public void onBindViewHolder(@NonNull VH holder, int position) {
String s = list.get(position);
((TextView) holder.itemView).setText(s);
holder.itemView.setOnClickListener(v -> taskAction.execute(s));
}
@Override
public int getItemCount() {
return list.size();
}
}
public void dismiss() {
binding.searchview.hide();
}
public static void addSearchRecord(String name,List<String> json_list,SearchRecordAdapter adapter) {
try {
int existingIndex = json_list.indexOf(name);
if (existingIndex != -1) {
// 交换两个元素的位置
json_list.remove(name);
json_list.add(0, name);
adapter.notifyItemMoved(existingIndex, 0);
} else {
// json_list.remove(name);
json_list.add(0, name);
adapter.notifyItemInserted(0);
}
wj.xrwb(wj.filesdri + wj.lishi_json, new Gson().toJson(json_list));
} catch (Exception e) {
gj.sc(e);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuItem sousuo = menu.add("搜索");
sousuo.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
return super.onCreateOptionsMenu(menu);
}
@Override
protected ActivitySearchBinding getViewBindingObject(LayoutInflater layoutInflater) {
return ActivitySearchBinding.inflate(layoutInflater);
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
int itemId = item.getItemId();
if (itemId == android.R.id.home) {
end();
}
return true;
}
public void start(String name) {
dismiss();
if (!TextUtils.isEmpty(name)) {
search sea = (search) getSupportFragmentManager().findFragmentById(R.id.search_fragment);
binding.searchFragment.setVisibility(View.VISIBLE);
sea.sx(name);
// addSearchRecordd(name);
}
}
public static class SearchRecordAdapter extends RecyclerView.Adapter<VH<ListTextBinding>> {
SearchView searchView;
public List<String> json_list = new ArrayList<>();
public SearchRecordAdapter(SearchView searchView) {
this.searchView = searchView;
String dqwb = wj.dqwb(wj.filesdri + wj.lishi_json);
if (dqwb != null) {
try {
json_list = new Gson().fromJson(dqwb, new TypeToken<List<String>>() {
}.getType());
} catch (Exception e) {
wj.sc(wj.filesdri + wj.lishi_json);
// yc.start(activity_search.this, e);
}
}
gj.sc(json_list.size());
// RecyclerView.ItemAnimator animator = new DefaultItemAnimator() {
// @Override
// public boolean animateRemove(RecyclerView.ViewHolder holder) {
// ObjectAnimator fadeAnimator = ObjectAnimator.ofFloat(holder.itemView, "alpha", 1f, 0f);
// fadeAnimator.setDuration(getRemoveDuration());
// fadeAnimator.addListener(new AnimatorListenerAdapter() {
// @Override
// public void onAnimationEnd(Animator animation) {
// dispatchRemoveFinished(holder);
// holder.itemView.setAlpha(1f);
// }
// });
// fadeAnimator.start();
// return false;
// }
// };
// binding.listRecycler.setItemAnimator(animator);
}
@NonNull
@Override
public VH<ListTextBinding> onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new VH<>(ListTextBinding.inflate(LayoutInflater.from(parent.getContext()),
parent, false));
}
@Override
public void onBindViewHolder(@NonNull VH<ListTextBinding> holder, int position) {
String keyword = json_list.get(position);
holder.binding.getRoot().setText(keyword);
holder.binding.getRoot().setOnClickListener(v -> {
searchView.setText(keyword);
// start(keyword);
});
holder.binding.getRoot().setOnCloseIconClickListener(view -> {
json_list.remove(keyword);
notifyItemRemoved(holder.getBindingAdapterPosition());
wj.xrwb(wj.filesdri + wj.lishi_json, new Gson().toJson(json_list));
});
}
@Override
public int getItemCount() {
return json_list.size();
}
}
// @Override
// public void onBackPressed() {
// end();
// }
private void end() {
if (binding.searchview.isShowing()) {
binding.searchview.hide();
return;
}
if (binding.searchFragment.getVisibility() == View.VISIBLE) {
binding.searchFragment.setVisibility(View.GONE);
} else {
finish();
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
// ActivityCompat.finishAffinity(this);
}
}
@Override
public void finish() {
super.finish();
}
}

View File

@ -0,0 +1,133 @@
package com.muqingbfq.adapter;
import android.annotation.SuppressLint;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.media3.common.MediaItem;
import androidx.media3.common.Player;
import androidx.palette.graphics.Palette;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
import com.muqingbfq.MP3;
import com.muqingbfq.PlaybackService;
import com.muqingbfq.R;
import com.muqingbfq.XM;
import com.muqingbfq.api.playlist;
import com.muqingbfq.bfqkz;
import com.muqingbfq.databinding.ListGdBinding;
import com.muqingbfq.fragment.gd;
import com.muqingbfq.fragment.mp3;
import com.muqingbfq.main;
import com.muqingbfq.mq.VH;
import com.muqingbfq.mq.gj;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class AdapterGd extends RecyclerView.Adapter<VH<ListGdBinding>> {
public List<XM> list = new ArrayList<>();
@NonNull
@Override
public VH<ListGdBinding> onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new VH<>(ListGdBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
}
@Override
public void onBindViewHolder(@NonNull VH<ListGdBinding> holder, int position) {
XM xm = list.get(position);
holder.itemView.setOnClickListener(v -> {
mp3.drawable = holder.binding.image.getDrawable();
mp3.start(v.getContext(), new String[]{xm.id, xm.name});
});
Glide.with(holder.itemView.getContext())
.asBitmap()
.load(xm.picurl)
.addListener(new RequestListener<Bitmap>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<Bitmap> target, boolean isFirstResource) {
return true;
}
@Override
public boolean onResourceReady(@NonNull Bitmap resource,
@NonNull Object model, Target<Bitmap> target,
@NonNull DataSource dataSource, boolean isFirstResource) {
Palette.from(resource).generate(palette -> {
int color = palette.getLightMutedColor(Color.WHITE);
GradientDrawable gradientDrawable = new GradientDrawable(
GradientDrawable.Orientation.BOTTOM_TOP,
new int[]{color, color});
gradientDrawable.setAlpha(128);
holder.binding.text1.setBackground(gradientDrawable);
holder.binding.getRoot().setRippleColor(ColorStateList.valueOf(color));
});
holder.binding.image.setImageBitmap(resource);
return true;
}
})
.into(holder.binding.image);
holder.binding.text1.setText(xm.name);
holder.binding.kg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread() {
@SuppressLint("NotifyDataSetChanged")
@Override
public void run() {
super.run();
List<MP3> an = playlist.hq(xm.id);
if (bfqkz.ms == 2) {
Collections.shuffle(bfqkz.list);
}
main.handler.post(() -> {
if (PlaybackService.mediaSession == null) {
return;
}
Player player = PlaybackService.mediaSession.getPlayer();
player.clearMediaItems();
for (MP3 mp3 : an) {
// gj.sc(mp3.url);
MediaItem mediaItem = PlaybackService.GetMp3(mp3);
player.addMediaItem(mediaItem);
}
player.prepare();
player.seekTo(0,0);
player.play();
//保存播放列表
PlaybackService.list.clear();
PlaybackService.list.addAll(an);
PlaybackService.ListSave();
});
}
}.start();
}
});
}
@Override
public int getItemCount() {
return list.size();
}
}

View File

@ -0,0 +1,96 @@
package com.muqingbfq.adapter;
import android.annotation.SuppressLint;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.media3.common.MediaItem;
import androidx.media3.common.Player;
import androidx.palette.graphics.Palette;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.muqingbfq.MP3;
import com.muqingbfq.PlaybackService;
import com.muqingbfq.XM;
import com.muqingbfq.api.playlist;
import com.muqingbfq.bfqkz;
import com.muqingbfq.databinding.ListGdBBinding;
import com.muqingbfq.databinding.ListGdBinding;
import com.muqingbfq.fragment.mp3;
import com.muqingbfq.main;
import com.muqingbfq.mq.VH;
import com.muqingbfq.mq.gj;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class AdapterGdH extends RecyclerView.Adapter<VH<ListGdBBinding>> {
public List<XM> list = new ArrayList<>();
public AdapterGdH() {}
public AdapterGdH(List<XM> list) {
this.list = list;
}
@NonNull
@Override
public VH<ListGdBBinding> onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new VH<>(ListGdBBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
}
@Override
public void onBindViewHolder(@NonNull VH<ListGdBBinding> holder, int position) {
XM xm = list.get(position);
holder.binding.text1.setText(xm.name);
holder.binding.text2.setText(xm.message);
gj.sc(xm.picurl);
Glide.with(holder.itemView.getContext())
.asBitmap()
.load(xm.picurl)
.addListener(new RequestListener<Bitmap>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<Bitmap> target, boolean isFirstResource) {
return true;
}
@Override
public boolean onResourceReady(@NonNull Bitmap resource,
@NonNull Object model, Target<Bitmap> target,
@NonNull DataSource dataSource, boolean isFirstResource) {
Palette.from(resource).generate(palette -> {
Palette.Swatch lightVibrantSwatch = palette.getVibrantSwatch();
if (lightVibrantSwatch != null) {
int color = lightVibrantSwatch.getRgb();
holder.binding.text1.setTextColor(color);
holder.binding.getRoot().setRippleColor(ColorStateList.valueOf(color));
}
});
holder.binding.image.setImageBitmap(resource);
return true;
}
})
.into(holder.binding.image);
holder.binding.getRoot().setOnClickListener(v -> mp3.start(v.getContext(), new String[]{xm.id, xm.name}));
}
@Override
public int getItemCount() {
return list.size();
}
}

View File

@ -0,0 +1,123 @@
package com.muqingbfq.adapter;
import android.annotation.SuppressLint;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.media3.common.MediaItem;
import androidx.media3.common.Player;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.google.common.base.Strings;
import com.muqingbfq.MP3;
import com.muqingbfq.PlaybackService;
import com.muqingbfq.R;
import com.muqingbfq.api.url;
import com.muqingbfq.databinding.ListMp3ImageBinding;
import com.muqingbfq.main;
import com.muqingbfq.mq.VH;
import com.muqingbfq.mq.gj;
import java.util.ArrayList;
import java.util.List;
public class AdapterMp3 extends RecyclerView.Adapter<VH<ListMp3ImageBinding>> {
public List<MP3> list = new ArrayList<>();
public AdapterMp3() {
}
public AdapterMp3(List<MP3> list) {
this.list = list;
}
@NonNull
@Override
public VH<ListMp3ImageBinding> onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new VH<>(ListMp3ImageBinding.inflate(
LayoutInflater.from(parent.getContext()), parent, false));
}
@SuppressLint("NotifyDataSetChanged")
@Override
public void onBindViewHolder(@NonNull VH<ListMp3ImageBinding> holder, int position) {
MP3 x = list.get(position);
holder.binding.wb1.setText(x.name);
holder.binding.zz.setText(x.zz);
int themeColor = gj.getThemeColor(holder.itemView.getContext(), com.google.android.material.R.attr.colorSurface);
holder.binding.getRoot().setCardBackgroundColor(themeColor);
if (PlaybackService.mediaSession != null) {
Player player = PlaybackService.mediaSession.getPlayer();
MediaItem currentMediaItem = player.getCurrentMediaItem();
if (currentMediaItem != null) {
String mediaId = currentMediaItem.mediaId;
if (mediaId.equals(x.id)) {
// holder.binding.getRoot()
holder.binding.getRoot().setCardBackgroundColor(
gj.getThemeColor(holder.itemView.getContext(), com.google.android.material.R.attr.colorSurfaceVariant));
}
}
}
if (Strings.isNullOrEmpty(x.picurl)) {
holder.binding.text1.setText(String.valueOf(position + 1));
holder.binding.imageView.setVisibility(ViewGroup.GONE);
holder.binding.linsum.setVisibility(View.VISIBLE);
}else{
Glide.with(holder.itemView.getContext()).load(list.get(position).picurl)
.apply(new RequestOptions().placeholder(R.drawable.ic_launcher_foreground))
.error(R.drawable.ic_launcher_foreground)
.into(holder.binding.imageView);
}
holder.itemView.setOnClickListener(view -> {
if (PlaybackService.mediaSession == null) {
return;
}
Player player = PlaybackService.mediaSession.getPlayer();
new Thread() {
@Override
public void run() {
super.run();
MP3 hq = url.hq(x);
// gj.sc(String.format("链接:%s图片%s", hq.url,hq.picurl));
main.handler.post(() -> {
for (int i = 0; i < player.getMediaItemCount(); i++) {
MediaItem currentItem = player.getMediaItemAt(i);
if (currentItem.mediaId.equals(hq.id)) {
gj.sc("存在播放:" + currentItem.mediaId + "==" + hq.id + " i=" + i);
player.seekTo(i,0);
player.prepare();
player.play();
notifyDataSetChanged();
return;
}
}
gj.sc("不存在添加播放");
PlaybackService.list.add(hq);
PlaybackService.ListSave();
MediaItem mediaItem = PlaybackService.GetMp3(hq);
player.addMediaItem(0,mediaItem);
player.seekTo(0,0);
player.prepare();
player.play();
notifyDataSetChanged();
});
}
}.start();
});
}
@Override
public int getItemCount() {
return list.size();
}
}

View File

@ -0,0 +1,181 @@
package com.muqingbfq.api;
import android.annotation.SuppressLint;
import android.content.Context;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.mpatric.mp3agic.ID3v2;
import com.mpatric.mp3agic.Mp3File;
import com.muqingbfq.MP3;
import com.muqingbfq.main;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wj;
import com.muqingbfq.mq.wl;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class FileDownloader {
OkHttpClient client = new OkHttpClient();
AlertDialog dialog;
TextView textView;
Context context;
public FileDownloader(Context context) {
this.context = context;
main.handler.post(() -> {
textView = new TextView(context);
dialog = new MaterialAlertDialogBuilder(context)
.setTitle("下载中...")
.setView(textView)
.show();
});
}
public void downloadFile(MP3 x) {
Request request = new Request.Builder()
.url(main.api + url.api + "?id=" + x.id + "&level=" +
"standard" + "&cookie=" + wl.Cookie)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
e.printStackTrace();
// 下载失败处理
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
if (!response.isSuccessful()) {
// 下载失败处理
return;
}
try {
JSONObject json = new JSONObject(response.body().string());
JSONArray data = json.getJSONArray("data");
JSONObject jsonObject = data.getJSONObject(0);
String url = jsonObject.getString("url");
downloadFile(url, x);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
long fileSizeDownloaded = 0;
public void downloadFile(String url, MP3 x) {
Request request = new Request.Builder()
.url(url)
.build();
// 创建通知渠道仅适用于Android 8.0及以上版本
// 发起请求
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
e.printStackTrace();
// 下载失败处理
}
@SuppressLint("SetTextI18n")
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if (!response.isSuccessful()) {
// 下载失败处理
return;
}
File outputFile = new File(wj.mp3, x.id + ".mp3");
File parentFile = outputFile.getParentFile();
if (!parentFile.isDirectory()) {
parentFile.mkdirs();
}
InputStream inputStream = null;
FileOutputStream outputStream = null;
try {
byte[] buffer = new byte[4096];
long fileSize = response.body().contentLength();
inputStream = response.body().byteStream();
outputStream = new FileOutputStream(outputFile);
int read;
fileSizeDownloaded = 0;
while ((read = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, read);
fileSizeDownloaded += read;
// 更新通知栏进度
// updateNotificationProgress(context, fileSize, fileSizeDownloaded);
if (textView != null) {
main.handler.post(() ->
textView.setText(x.name + ":" +
(int) ((fileSizeDownloaded * 100) / fileSize)));
}
}
try {
Mp3File mp3file = new Mp3File(outputFile);
if (mp3file.hasId3v2Tag()) {
ID3v2 id3v2Tag = mp3file.getId3v2Tag();
// 设置新的ID值
gj.sc(x.name);
id3v2Tag.setTitle(x.name);
id3v2Tag.setArtist(x.zz);
id3v2Tag.setAlbum(x.zz);
id3v2Tag.setLyrics(com.muqingbfq.api.url.Lrc(x.id));
ByteArrayOutputStream o = new ByteArrayOutputStream();
if (x.picurl instanceof String) {
Request build = new Request.Builder().url(x.picurl)
.build();
Response execute = client.newCall(build).execute();
if (execute.isSuccessful()) {
id3v2Tag.setAlbumImage(execute.body().bytes()
, "image/jpeg");
}
}
o.close();
mp3file.save(wj.mp3 + x.id);
outputFile.delete();
}
// 保存修改后的音乐文件删除原来的文件
} catch (Exception e) {
gj.sc(e);
outputFile.delete();
}
dismiss();
// 下载完成处理
} catch (IOException e) {
e.printStackTrace();
// 下载失败处理
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
dismiss();
}
}
});
}
public void dismiss() {
if (dialog == null) {
return;
}
main.handler.post(() -> dialog.dismiss());
}
}

View File

@ -0,0 +1,224 @@
package com.muqingbfq.api;
import android.app.Activity;
import android.os.Environment;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.mpatric.mp3agic.ID3v2;
import com.mpatric.mp3agic.Mp3File;
import com.muqingbfq.MP3;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wj;
import com.muqingbfq.mq.wl;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.File;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
public class playlist extends Thread {
public static final String api = "/playlist/track/all?id=";
public static String gethq(String uid) {
if (wj.cz(wj.filesdri + "user.mq")) {
return wl.hq(api + uid + "&limit=100" + "&cookie=" + wl.Cookie);
// gj.sc(hq);
} else {
return wl.hq(api + uid + "&limit=100");
}
}
public static boolean hq(List<MP3> list, String uid) {
switch (uid) {
case "mp3_xz.json":
return playlist.hq_xz(list);
case "mp3_like.json":
return playlist.hq_like(list);
case "mp3_hc.json":
return hq_hc(list);
}
list.clear();
try {
String hq = wj.dqwb(wj.gd + uid);
if (hq == null || hq.isEmpty()) {
hq = gethq(uid);
}
list.clear();
JSONObject json = new JSONObject(hq);
JSONArray songs = json.getJSONArray("songs");
int length = songs.length();
for (int i = 0; i < length; i++) {
JSONObject jsonObject = songs.getJSONObject(i);
String id = jsonObject.getString("id");
String name = jsonObject.getString("name");
try {
String tns = jsonObject.getString("tns");
tns = tns.replace("[\"", "(");
tns = tns.replace("\"]", ")");
name += tns;
} catch (Exception e) {
e.printStackTrace();
}
JSONObject al = jsonObject.getJSONObject("al");
JSONArray ar = jsonObject.getJSONArray("ar");
StringBuilder zz = new StringBuilder();
int length_a = ar.length();
for (int j = 0; j < length_a; j++) {
zz.append(ar.getJSONObject(j).getString("name"))
.append("/");
}
zz.append("-").append(al.getString("name"));
String picUrl = al.getString("picUrl");
list.add(new MP3(id, name, zz.toString(), picUrl));
}
return true;
} catch (Exception e) {
gj.sc("失败的错误 " + e);
}
return false;
}
public static List<MP3> hq(String uid) {
List<MP3> list = new ArrayList<>();
try {
String hq = wj.dqwb(wj.gd + uid);
if (hq == null || hq.isEmpty()) {
hq = gethq(uid);
}
JSONObject json = new JSONObject(hq);
JSONArray songs = json.getJSONArray("songs");
int length = songs.length();
for (int i = 0; i < length; i++) {
JSONObject jsonObject = songs.getJSONObject(i);
String id = jsonObject.getString("id");
String name = jsonObject.getString("name");
try {
String tns = jsonObject.getString("tns");
tns = tns.replace("[\"", "(");
tns = tns.replace("\"]", ")");
name += tns;
} catch (Exception e) {
e.printStackTrace();
}
JSONObject al = jsonObject.getJSONObject("al");
JSONArray ar = jsonObject.getJSONArray("ar");
StringBuilder zz = new StringBuilder();
int length_a = ar.length();
for (int j = 0; j < length_a; j++) {
zz.append(ar.getJSONObject(j).getString("name"))
.append("/");
}
zz.append("-").append(al.getString("name"));
String picUrl = al.getString("picUrl");
list.add(new MP3(id, name, zz.toString(), picUrl));
}
return list;
} catch (Exception e) {
gj.sc("失败的错误 " + e);
}
return list;
}
public static boolean hq_like(List<MP3> list) {
try {
String dqwb = wj.dqwb(wj.gd + "mp3_like.json");
if (dqwb == null) {
return false;
}
Type type = new TypeToken<List<MP3>>() {
}.getType();
Gson gson = new Gson();
list.clear();
list.addAll(gson.fromJson(dqwb, type));
return true;
} catch (Exception e) {
gj.sc("失败的错误 " + e);
}
return false;
}
public static boolean hq_xz(List<MP3> list) {
try {
File file = new File(wj.filesdri + "mp3");
File[] files = file.listFiles();
list.clear();
for (File value : files) {
ID3v2 mp3File = new Mp3File(value).getId3v2Tag();
String id = value.getName();
String name = mp3File.getTitle();
String zz = mp3File.getArtist();
list.add(new MP3(id, name, zz, value.toString()));
}
return true;
} catch (Exception e) {
gj.sc("失败的错误 " + e);
}
return false;
}
public static boolean hq_hc(List<MP3> list) {
try {
String dqwb = wj.dqwb(wj.gd + "mp3_hc.json");
if (dqwb == null) {
return false;
}
Type type = new TypeToken<List<MP3>>() {
}.getType();
Gson gson = new Gson();
list.clear();
list.addAll(gson.fromJson(dqwb, type));
return true;
} catch (Exception e) {
gj.sc("失败的错误 " + e);
wj.sc(wj.gd + "mp3_hc.json");
}
return false;
}
public static void hq_cd(Activity context, List<MP3> list) {
boolean cd = wj.isCD(context);
if (!cd) {
return;
}
list.clear();
try {
String absolutePath = Environment.getExternalStorageDirectory().getAbsolutePath();
CD(new File(absolutePath), list);
} catch (Exception e) {
gj.sc("失败的错误 " + e);
}
}
private static void CD(File file, List<MP3> list) {
for (File a : file.listFiles()) {
if (a.isFile()) {
try {
// 创建一个 Mp3File 对象用于读取 MP3 文件
Mp3File mp3file = new Mp3File(a);
// 检查是否存在 ID3v2 标签
if (mp3file.hasId3v2Tag()) {
// 获取 ID3v2 标签实例
ID3v2 id3v2tag = mp3file.getId3v2Tag();
MP3 mp3 = new MP3(a.toString(), id3v2tag.getTitle(),
id3v2tag.getArtist()
, a.toString());
list.add(mp3);
}
} catch (Exception e) {
e.printStackTrace();
}
} else if (a.isDirectory()) {
String string = a.getName();
if (string.startsWith(".") || string.equals("Android") || string.equals("data")) {
continue;
}
CD(a, list);
}
}
}
}

View File

@ -0,0 +1,117 @@
package com.muqingbfq.api;
import android.text.TextUtils;
import com.muqingbfq.main;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wj;
import com.muqingbfq.mq.wl;
import com.muqingbfq.XM;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.text.DecimalFormat;
import java.util.List;
public class resource {
public static void recommend(List<XM> list) {
try {
list.clear();
JSONObject json;
String hq = wl.hq("/recommend/resource?cookie=" + wl.Cookie);
if (hq == null) {
hq = wj.dqwb(wj.gd_json);
if (hq != null) {
json = new JSONObject(hq);
if (json.getInt("code") == 200) {
wj.xrwb(wj.gd_json, hq);
JSONArray recommend = json.getJSONArray("recommend");
int length = recommend.length();
for (int i = 0; i < length; i++) {
JSONObject jsonObject = recommend.getJSONObject(i);
add(jsonObject, list);
}
}
}
return;
}
json = new JSONObject(hq);
if (json.getInt("code") == 200) {
wj.xrwb(wj.gd_json, hq);
JSONArray recommend = json.getJSONArray("recommend");
int length = recommend.length();
for (int i = 0; i < length; i++) {
JSONObject jsonObject = recommend.getJSONObject(i);
add(jsonObject, list);
}
}
} catch (Exception e) {
gj.sc("resource tuijian" + e);
}
}
public static XM Playlist_content(String UID) throws JSONException {
String hq = wl.get(main.api + "/playlist/detail?id=" + UID);
JSONObject js = new JSONObject(hq).getJSONObject("playlist");
String id = js.getString("id");
String name = js.getString("name");
String coverImgUrl = js.getString("coverImgUrl");
long playCount = js.getLong("playCount");
String formattedNumber = String.valueOf(playCount);
if (playCount > 9999) {
DecimalFormat df = new DecimalFormat("#,###.0万");
formattedNumber = df.format(playCount / 10000);
}
String s = js.getInt("trackCount") + "首,"
+ "by " + js.getJSONObject("creator").getString("nickname")
+ ",播放"
+ formattedNumber + "";
return new XM(id, name, s, coverImgUrl);
}
// 排行榜
public static void leaderboard(List<XM> list) {
String hq;
try {
if (wj.cz(wj.gd_phb)) {
hq = wj.dqwb(wj.gd_phb);
} else {
hq = wl.hq("/toplist");
if (hq == null) {
return;
}
wj.xrwb(wj.gd_phb, hq);
}
JSONObject jsonObject = new JSONObject(hq);
if (jsonObject.getInt("code") == 200) {
JSONArray list_array = jsonObject.getJSONArray("list");
int length = list_array.length();
for (int i = 0; i < length; i++) {
JSONObject get = list_array.getJSONObject(i);
String id = get.getString("id");
String name = get.getString("name") + "\n";
String description = get.getString("description");
if (!TextUtils.isEmpty(description) && !description.equals("null")) {
name += description;
}
String coverImgUrl = get.getString("coverImgUrl");
list.add(new XM(id, name, coverImgUrl));
}
}
} catch (Exception e) {
gj.sc(e);
}
}
private static void add(JSONObject jsonObject, List<XM> list) throws Exception {
String id = jsonObject.getString("id");
String name = jsonObject.getString("name");
String picUrl = jsonObject.getString("picUrl");
list.add(new XM(id, name, picUrl));
}
}

View File

@ -0,0 +1,114 @@
package com.muqingbfq.api;
import com.mpatric.mp3agic.ID3v2;
import com.mpatric.mp3agic.Mp3File;
import com.muqingbfq.MP3;
import com.muqingbfq.fragment.Media;
import com.muqingbfq.home;
import com.muqingbfq.main;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wj;
import com.muqingbfq.mq.wl;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class url extends Thread {
public static String api = "/song/url/v1";
MP3 x;
public url(MP3 x) {
this.x = x;
start();
}
public static MP3 hq(MP3 x) {
// gj.sc(x.id);
MP3 mp3 = new MP3();
mp3.name = x.name;
mp3.id = x.id;
mp3.picurl = x.picurl;
mp3.zz = x.zz;
mp3.url = x.url;
getLrc(x.id);
Media.loadLyric();
try {
if (wj.cz(mp3.id)) {
mp3.url = mp3.id;
return mp3;
} else if (wj.cz(wj.mp3 + mp3.id)) {
mp3.url = wj.mp3 + mp3.id;
return mp3;
} else if (wj.cz(wj.filesdri + "hc/" + mp3.id)) {
mp3.url = wj.filesdri + "hc/" + mp3.id;
return mp3;
}
String level = "standard";
boolean wiFiConnected = gj.isWiFiConnected();
if (wiFiConnected) {
level = "exhigh";
}
String hq = wl.hq(api + "?id=" + mp3.id + "&level=" +
level + "&cookie=" + wl.Cookie);
if (hq == null) {
return null;
}
JSONObject json = new JSONObject(hq);
// gj.sc(json);
if (json.getInt("code") == -460) {
String message = json.getString("message");
gj.sc(message);
return null;
}
JSONArray data = json.getJSONArray("data");
JSONObject jsonObject = data.getJSONObject(0);
// gj.sc(jsonObject.getString("url"));
mp3.url = jsonObject.getString("url");
mp3.picurl = picurl(mp3.id);
return mp3;
} catch (JSONException e) {
gj.sc("url hq :" + e);
}
return null;
}
public static void getLrc(String id) {
String file = wj.mp3 + id;
boolean cz = wj.cz(id);
if (cz) {
file = id;
}
if (cz || wj.cz(file)) {
try {
Mp3File mp3file = new Mp3File(file);
if (mp3file.hasId3v2Tag()) {
ID3v2 id3v2Tag = mp3file.getId3v2Tag();
com.muqingbfq.bfqkz.lrc = id3v2Tag.getLyrics();
}
if (com.muqingbfq.bfqkz.lrc == null) {
com.muqingbfq.bfqkz.lrc = wl.hq("/lyric?id=" + id);
}
} catch (Exception e) {
gj.sc("url getlrc:" + e);
}
} else {
com.muqingbfq.bfqkz.lrc = wl.hq("/lyric?id=" + id);
}
}
public static String Lrc(String id) {
return wl.hq("/lyric?id=" + id);
}
public static String picurl(String id) {
String hq = wl.hq("/song/detail?ids=" + id);
try {
return new JSONObject(hq).getJSONArray("songs").getJSONObject(0)
.getJSONObject("al").getString("picUrl");
} catch (Exception e) {
gj.sc("url picurl:" + e);
}
return null;
}
}

View File

@ -0,0 +1,60 @@
package com.muqingbfq;
import android.view.View;
import android.widget.ImageView;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.muqingbfq.api.url;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wj;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
public class bfq_an {
static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("mm:ss", Locale.CHINA);
public static String getTime(long time) {
return simpleDateFormat.format(new Date(time));
}
public static boolean islike() {
boolean contains = false;
String dqwb = wj.dqwb(wj.gd + "mp3_like.json");
if (dqwb != null) {
try {
Type type = new TypeToken<List<MP3>>() {
}.getType();
List<MP3> o = new Gson().fromJson(dqwb, type);
if (o != null) {
contains = o.contains(bfqkz.xm);
}
} catch (Exception e) {
wj.sc(wj.gd + "mp3_like.json");
}
}
return bfqkz.like_bool = contains;
}
public static boolean getlike(MP3 xm) {
boolean contains = false;
String dqwb = wj.dqwb(wj.gd + "mp3_like.json");
if (dqwb != null) {
try {
Type type = new TypeToken<List<MP3>>() {
}.getType();
List<MP3> o = new Gson().fromJson(dqwb, type);
if (o != null) {
contains = o.contains(xm);
}
} catch (Exception e) {
wj.sc(wj.gd + "mp3_like.json");
}
}
return contains;
}
}

View File

@ -0,0 +1,93 @@
package com.muqingbfq;
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.media.MediaBrowserCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.media.MediaBrowserServiceCompat;
import com.muqingbfq.api.url;
import com.muqingbfq.mq.gj;
import java.util.ArrayList;
import java.util.List;
public class bfqkz extends MediaBrowserServiceCompat {
public static List<MP3> list = new ArrayList<>();
//保存原始list顺序
public static List<MP3> list_baocun = new ArrayList<>();
public static List<MP3> lishi_list = new ArrayList<>();
public static int ms;
// 0 循环 1 顺序 2 随机
public static MP3 xm;
public static boolean like_bool;
public static String lrc;
@SuppressLint("StaticFieldLeak")
public static int getmti() {
if (xm == null) {
return 0;
}
int i = bfqkz.list.indexOf(xm) + 1;
if (i >= bfqkz.list.size()) {
i = 0;
}
return i;
}
public PendingIntent pendingIntent;
public MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
@Override
public void onCreate() {
// super.onCreate();
// Intent intent = new Intent(Intent.ACTION_MAIN);
// intent.addCategory(Intent.CATEGORY_LAUNCHER);
// intent.setComponent(new ComponentName(this, home.class));//用ComponentName得到class对象
// intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
// | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);// 关键的一步设置启动模式两种情况
// pendingIntent = com.muqingbfq.mq.NotificationManagerCompat.getActivity(this, intent);
// com.muqingbfq.api.playlist.hq_hc(bfqkz.lishi_list);
// new BluetoothMusicController(this);
// playback = new PlaybackStateCompat.Builder();
// playback.setState(PlaybackStateCompat.STATE_NONE, 0, 1.0f)
// .build();
// mSession.setCallback(new callback());
// mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
//
// playback.setActions(PlaybackStateCompat.ACTION_PLAY);
// playback.setActions(PlaybackStateCompat.ACTION_STOP);
//
// mSession.setPlaybackState(playback.build());
// setSessionToken(mSession.getSessionToken());
// mSession.setActive(true);
// notify = new com.muqingbfq.mq.NotificationManagerCompat(this);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Nullable
@Override
public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, @Nullable Bundle rootHints) {
return null;
}
@Override
public void onLoadChildren(@NonNull String parentId, @NonNull Result<List<MediaBrowserCompat.MediaItem>> result) {
}
}

View File

@ -0,0 +1,133 @@
package com.muqingbfq.clean;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.text.format.Formatter;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.muqingbfq.R;
import com.muqingbfq.databinding.ActivityCleanBinding;
import com.muqingbfq.mq.FragmentActivity;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wj;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class fragment_clean extends FragmentActivity<ActivityCleanBinding> {
List<String[]> list = new ArrayList<>();
List<String> list_box = new ArrayList<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView();
// setToolbar();
UI();
}
private void UI() {
list.clear();
list.add(new String[]{"下载的音乐", wj.mp3});
list.add(new String[]{"下载的歌单",wj.gd});
list.add(new String[]{"缓存的音乐",wj.filesdri+"hc"});
list.add(new String[]{"内部缓存", getCacheDir().toString()});
String s = Glide.getPhotoCacheDir(this).toString();
list.add(new String[]{"Glide缓存", s});
binding.toolbar.setTitle("储存清理");
binding.recyclerview.setAdapter(adapter);
}
private final RecyclerView.Adapter<VH> adapter = new RecyclerView.Adapter<VH>() {
@NonNull
@Override
public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View inflate = LayoutInflater.from(fragment_clean.this).
inflate(R.layout.list_clean, parent, false);
return new VH(inflate);
}
@SuppressLint({"ClickableViewAccessibility", "SetTextI18n"})
@Override
public void onBindViewHolder(@NonNull VH holder, int position) {
String[] s = list.get(position);
File file = new File(s[1]);
long leng = 0;
int size = 0;
if (file.isDirectory()) {
gj.sc(file.toString());
for (File a : file.listFiles()) {
leng += a.length();
size++;
}
} else {
holder.checkBox.setEnabled(false);
}
String s1 = Formatter.formatFileSize(fragment_clean.this, leng);
holder.checkBox.setText(s[0] + ":" + s1 + " 共计:" + size+" 个文件");
holder.checkBox.setOnCheckedChangeListener((compoundButton, b) -> {
if (b) {
list_box.add(file.toString());
}else {
list_box.remove(file.toString());
}
menu_deleat.setVisible(list_box.size() > 0);
});
}
@Override
public int getItemCount() {
return list.size();
}
};
class VH extends RecyclerView.ViewHolder {
public CheckBox checkBox;
public VH(@NonNull View itemView) {
super(itemView);
checkBox = itemView.findViewById(R.id.box);
}
}
MenuItem menu_deleat;
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu_deleat = menu.add("删除");
menu_deleat.setIcon(R.drawable.delete);
menu_deleat.setTitle("删除");
menu_deleat.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu_deleat.setVisible(false);
return super.onCreateOptionsMenu(menu);
}
@Override
protected ActivityCleanBinding getViewBindingObject(LayoutInflater layoutInflater) {
return ActivityCleanBinding.inflate(layoutInflater);
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
} else if (item == menu_deleat) {
for (int i = 0; i < list_box.size(); i++) {
File s= new File(list_box.get(i));
wj.sc(s);
}
list_box.clear();
menu_deleat.setVisible(false);
UI();
}
return super.onOptionsItemSelected(item);
}
}

View File

@ -0,0 +1,29 @@
package com.muqingbfq.fragment;
import com.dirror.lyricviewx.LyricViewX;
import com.muqingbfq.mq.gj;
import org.json.JSONObject;
public class Media {
public static String[] loadLyric() {
if (com.muqingbfq.bfqkz.lrc == null) {
return null;
}
JSONObject jsonObject;
String a = null, b = null;
try {
jsonObject = new JSONObject(com.muqingbfq.bfqkz.lrc);
a = jsonObject.getJSONObject("lrc").getString("lyric");
b = jsonObject.getJSONObject("tlyric").getString("lyric");
} catch (Exception e) {
gj.sc("Media loadLyric " + e);
}
LyricViewX.lrc(a, b);
// gj.sc(LyricViewX.lyricEntryList.get(0).text);
return new String[]{a, b};
}
}

View File

@ -0,0 +1,230 @@
package com.muqingbfq.fragment;
import static android.content.Context.WINDOW_SERVICE;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.media3.common.MediaItem;
import androidx.media3.common.Player;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.muqingbfq.PlaybackService;
import com.muqingbfq.R;
import com.muqingbfq.bfqkz;
import com.muqingbfq.databinding.FragmentBflbDbBinding;
import com.muqingbfq.databinding.ListMp3ABinding;
import com.muqingbfq.list.MyViewHoder;
import com.muqingbfq.main;
import com.muqingbfq.yc;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class bflb_db extends BottomSheetDialog {
public static RecyclerView.Adapter<MyViewHoder> adapter;
FragmentBflbDbBinding binding;
private void ingList() {
if (PlaybackService.mediaSession == null) {
return;
}
Player player = PlaybackService.mediaSession.getPlayer();
List<MediaItem> list = new ArrayList<>();
int mediaItemCount = player.getMediaItemCount();
for (int i = 0; i < mediaItemCount; i++) {
list.add(player.getMediaItemAt(i));
}
binding.lb.setAdapter(new spq(list));
}
@Override
public void onStart() {
super.onStart();
// 获取底部弹窗的根视图
View view = findViewById(com.google.android.material.R.id.design_bottom_sheet);
if (view != null) {
// 设置宽度
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.width = (int) (getContext().getResources().getDisplayMetrics().widthPixels * 0.6); // 占屏幕宽度的 60%
view.setLayoutParams(layoutParams);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = FragmentBflbDbBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
// 设置高度
// DisplayMetrics displayMetrics = new DisplayMetrics();
// WindowManager windowManager = (WindowManager) getContext().getSystemService(WINDOW_SERVICE);
// windowManager.getDefaultDisplay().getMetrics(displayMetrics);
// binding.getRoot().getLayoutParams().height = displayMetrics.heightPixels - displayMetrics.heightPixels / 3;
// binding.getRoot().requestLayout();
// 设置固定的高度例如 500dp
try {
ingList();
if (bfqkz.xm != null) {
binding.lb.smoothScrollToPosition(getI());
}
binding.textView.setOnClickListener(v -> {
if (bfqkz.xm != null) {
binding.lb.smoothScrollToPosition(getI());
}
});
binding.sc.setOnClickListener(view -> new MaterialAlertDialogBuilder(getContext())
.setTitle("清空播放列表")
.setPositiveButton("确定", (dialogInterface, i) -> {
bfqkz.list.clear();
dismiss();
})
.setNegativeButton("取消", null)
.show());
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0) {
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
int fromPosition = viewHolder.getAbsoluteAdapterPosition();
int toPosition = target.getAbsoluteAdapterPosition();
// 在这里处理数据集的移动
// Collections.swap(bfqkz.list, fromPosition, toPosition);
Player player = PlaybackService.mediaSession.getPlayer();
player.moveMediaItem(fromPosition, toPosition);
adapter.notifyItemMoved(fromPosition, toPosition);
return true; // 返回true表示已经处理了拖动
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
// 不处理滑动操作
}
});
itemTouchHelper.attachToRecyclerView(binding.lb);
} catch (Exception e) {
yc.start(getContext(), e);
}
}
private int getI() {
if (PlaybackService.mediaSession == null) {
return 0;
}
Player player = PlaybackService.mediaSession.getPlayer();
int i = player.getCurrentMediaItemIndex();
if (i == -1) {
i = 0;
}
return i;
}
public bflb_db(Context context) {
super(context);
}
public static void start(Context context) {
bflb_db dialog = new bflb_db(context);
dialog.setOnShowListener(dialogInterface -> {
BottomSheetDialog d = (BottomSheetDialog) dialogInterface;
FrameLayout bottomSheet = d.findViewById(com.google.android.material.R.id.design_bottom_sheet);
if (bottomSheet != null) {
BottomSheetBehavior<View> behavior = BottomSheetBehavior.from(bottomSheet);
behavior.setState(BottomSheetBehavior.STATE_EXPANDED); // 默认展开
behavior.setSkipCollapsed(true); // 禁止折叠
}
});
dialog.show();
}
private class spq extends RecyclerView.Adapter<MyViewHoder> {
List<MediaItem> list;
public spq(List<MediaItem> list) {
this.list = list;
adapter = this;
}
@NonNull
@Override
public MyViewHoder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new MyViewHoder(ListMp3ABinding.
inflate(getLayoutInflater(), parent, false));
}
@SuppressLint("NotifyDataSetChanged")
@Override
public void onBindViewHolder(@NonNull MyViewHoder holder, int position) {
MediaItem mediaItem = list.get(position);
holder.bindingA.name.setText(mediaItem.mediaMetadata.title);
holder.bindingA.zz.setText(String.format(" · %s", mediaItem.mediaMetadata.artist));
int color = ContextCompat.getColor(holder.getContext(), R.color.text);
//获取当前播放的项目
if (PlaybackService.mediaSession != null) {
if (mediaItem.mediaId.equals(PlaybackService.mediaSession.getPlayer().getCurrentMediaItem().mediaId)) {
color = ContextCompat.getColor(holder.getContext(), R.color.text_cz);
}
}
holder.bindingA.name.setTextColor(color);
holder.bindingA.zz.setTextColor(color);
holder.itemView.setOnClickListener(view -> {
if (PlaybackService.mediaSession != null) {
new Thread() {
@Override
public void run() {
super.run();
// gj.sc(String.format("id=%s",mediaItem.mediaId));
// MP3 hq = url.hq(new MP3(mediaItem.mediaId));
// gj.sc(hq);
main.handler.post(() -> {
Player player = PlaybackService.mediaSession.getPlayer();
int absoluteAdapterPosition = holder.getAbsoluteAdapterPosition();
player.seekTo(absoluteAdapterPosition, 0);
// player.replaceMediaItem(absoluteAdapterPosition, PlaybackService.GetMp3(hq));
player.prepare();
player.play();
notifyDataSetChanged();
});
}
}.start();
}
});
holder.bindingA.delete.setOnClickListener(v -> {
list.remove(holder.getAbsoluteAdapterPosition());
PlaybackService.ListSave();
PlaybackService.list.removeIf(mp3 -> mp3.id.equals(mediaItem.mediaId));
notifyItemRemoved(holder.getAbsoluteAdapterPosition());
});
}
@Override
public int getItemCount() {
// binding.textView.setText(String.valueOf(bfqkz.list.size()));
return list.size();
}
}
@Override
public void dismiss() {
super.dismiss();
adapter = null;
}
}

View File

@ -0,0 +1,190 @@
package com.muqingbfq.fragment;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.media3.common.MediaItem;
import androidx.media3.common.MediaMetadata;
import androidx.media3.common.Player;
import androidx.media3.common.util.Util;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.muqingbfq.PlaybackService;
import com.muqingbfq.R;
import com.muqingbfq.activity.Music;
import com.muqingbfq.bfq_an;
import com.muqingbfq.databinding.FragmentBfqDbBinding;
import com.muqingbfq.main;
import com.muqingbfq.mq.Fragment;
import com.muqingbfq.mq.gj;
public class bfq_db extends Fragment<FragmentBfqDbBinding> implements GestureDetector.OnGestureListener {
private GestureDetector gestureDetector;
@Override
protected FragmentBfqDbBinding inflateViewBinding(LayoutInflater inflater, ViewGroup container) {
return FragmentBfqDbBinding.inflate(inflater, container, false);
}
@SuppressLint("ClickableViewAccessibility")
@Override
public void setUI(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
// 获取当前活动的主题
binding.txb.setOnClickListener(view -> bflb_db.start(getContext()));
gestureDetector = new GestureDetector(getContext(), this);
binding.kg.setOnClickListener(view -> {
if (PlaybackService.mediaSession != null) {
Util.handlePlayPauseButtonAction(PlaybackService.mediaSession.getPlayer());
}
});
binding.getRoot().setOnTouchListener((view, motionEvent) -> {
gestureDetector.onTouchEvent(motionEvent);
if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
binding.linearLayout.setTranslationX(0);
// binding.getRoot().setAlpha(1.0f);
}
return false;
});
}
@Override
public void onResume() {
super.onResume();
main.handler.post(runnable); // 恢复监听或更新UI
}
@Override
public void onPause() {
super.onPause();
main.handler.removeCallbacks(runnable);
if (PlaybackService.mediaSession != null) {
PlaybackService.mediaSession.getPlayer().removeListener(playerListener); // 移除监听器
}
}
private void setUI(Player player) {
binding.kg.setImageResource(player.isPlaying() ? R.drawable.bf : R.drawable.zt);
MediaItem currentMediaItem = player.getCurrentMediaItem();
if (currentMediaItem != null) {
MediaMetadata metadata = currentMediaItem.mediaMetadata;
String title = metadata.title != null ? metadata.title.toString() : "没有名字的音乐?";
String artist = metadata.artist != null ? metadata.artist.toString() : "未知艺术家";
binding.textview1.setText(title);
binding.textview2.setText(artist);
if (player.getMediaItemCount() > 0) {
binding.getRoot().setVisibility(View.VISIBLE);
} else {
binding.getRoot().setVisibility(View.GONE);
}
} else {
binding.getRoot().setVisibility(View.GONE);
}
}
private final Player.Listener playerListener = new Player.Listener() {
@Override
public void onEvents(@NonNull Player player, @NonNull Player.Events events) {
// boolean shouldShowPlayButton = Util.shouldShowPlayButton(player);
// gj.sc("播放状态" + shouldShowPlayButton);
setUI(player);
}
};
private void setPlay() {
if (PlaybackService.mediaSession != null) {
PlaybackService.mediaSession.getPlayer().addListener(playerListener);
}
}
Runnable runnable = new Runnable() {
@Override
public void run() {
if (PlaybackService.mediaSession != null) {
setPlay();
setUI(PlaybackService.mediaSession.getPlayer());
main.handler.removeCallbacks(this);
} else {
main.handler.postDelayed(this, 1000);
}
}
};
@Override
public boolean onDown(@NonNull MotionEvent motionEvent) {
return true;
}
@Override
public void onShowPress(@NonNull MotionEvent motionEvent) {
}
@Override
public boolean onSingleTapUp(@NonNull MotionEvent motionEvent) {
// bfq.startactivity(getContext(), bfqkz.xm);
Music.startActivity(getContext());
return true;
}
@Override
public boolean onScroll(@Nullable MotionEvent motionEvent, @NonNull MotionEvent motionEvent1,
float v, float v1) {
if (PlaybackService.mediaSession == null) {
return false;
}
Player player = PlaybackService.mediaSession.getPlayer();
if (player.getMediaItemCount() == 0) {
//如果只有一首曲子
return false;
}
if (player.getCurrentMediaItemIndex() == 0) {
//如果没有上一曲
if (v < 0) {
v = 0;
}
}else if (player.getCurrentMediaItemIndex() == player.getMediaItemCount() - 1) {
//如果没有下一曲
if (v > 0) {
v = 0;
}
}
binding.linearLayout.setTranslationX(binding.linearLayout.getTranslationX() - v);
return false;
}
@Override
public void onLongPress(@NonNull MotionEvent motionEvent) {
}
@Override
public boolean onFling(@Nullable MotionEvent e1,
@NonNull MotionEvent e2, float v, float v1) {
float distance = e1.getX() - e2.getX();
float threshold = getResources().getDisplayMetrics().widthPixels / 2.0f;
if (PlaybackService.mediaSession == null) {
return false;
}
Player player = PlaybackService.mediaSession.getPlayer();
// 判断手势方向并限制滑动距离
if (distance > threshold) {
// 向左滑动 下一曲
player.seekToNextMediaItem();
} else if (distance < -threshold) {
// 向右滑动 上一曲
player.seekToPreviousMediaItem();
}
return true;
}
}

View File

@ -0,0 +1,282 @@
package com.muqingbfq.fragment;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Filter;
import android.widget.Filterable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.muqingbfq.R;
import com.muqingbfq.XM;
import com.muqingbfq.adapter.AdapterGdH;
import com.muqingbfq.api.resource;
import com.muqingbfq.databinding.ActivityGdBinding;
import com.muqingbfq.databinding.ListGdBBinding;
import com.muqingbfq.mq.FragmentActivity;
import com.muqingbfq.mq.VH;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wl;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class gd extends FragmentActivity<ActivityGdBinding> {
public Adapter adapter = new Adapter();
int k;
public static void start(Activity context, String[] str, View view) {
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(context,
view, "text");
Intent intent = new Intent(context, gd.class);
intent.putExtra("id", str[0]);
intent.putExtra("name", str[1]);
context.startActivity(intent, options.toBundle());
}
public static void start(Context context, String[] str) {
Intent intent = new Intent(context, gd.class);
intent.putExtra("id", str[0]);
intent.putExtra("name", str[1]);
context.startActivity(intent);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView();
Intent intent = getIntent();
binding.title.setText(intent.getStringExtra("name"));
// k = (int) (getResources().getDisplayMetrics().widthPixels / getResources().getDisplayMetrics().density + 0.5f);
// GridLayoutManager gridLayoutManager = new GridLayoutManager(this, k / 120);
binding.lb.setLayoutManager(new LinearLayoutManager(this));
binding.lb.setAdapter(adapter);
binding.edittext.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (binding.edittext.getVisibility() == View.VISIBLE) {
adapter.getFilter().filter(charSequence);
}
}
@Override
public void afterTextChanged(Editable editable) {
}
});
String id = intent.getStringExtra("id");
binding.fragmentDb.post(new Runnable() {
@Override
public void run() {
int height = binding.fragmentDb.getHeight();
binding.lb.setPadding(0,0,0,height);
}
});
new start(id);
}
@Override
protected ActivityGdBinding getViewBindingObject(LayoutInflater layoutInflater) {
return ActivityGdBinding.inflate(layoutInflater);
}
class start extends Thread {
String id;
public start(String id) {
binding.recyclerview1Bar.setVisibility(View.VISIBLE);
this.id = id;
adapter.list.clear();
start();
}
@Override
public void run() {
super.run();
if (id.equals("排行榜")) {
resource.leaderboard(adapter.list);
} else {
String hq = wl.hq("/search?keywords=" + id + "&limit=" + (k * 3) + "&type=1000");
try {
JSONArray jsonArray = new JSONObject(hq).getJSONObject("result")
.getJSONArray("playlists");
int length = jsonArray.length();
for (int i = 0; i < length; i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
String id = jsonObject.getString("id");
String name = jsonObject.getString("name");
String coverImgUrl = jsonObject.getString("coverImgUrl");
adapter.list.add(new XM(id, name, coverImgUrl));
}
} catch (Exception e) {
gj.sc(e);
}
}
runOnUiThread(() -> {
binding.lb.setAdapter(adapter);
binding.recyclerview1Bar.setVisibility(View.GONE);
if (adapter.list.isEmpty()) {
binding.recyclerview1Text.setVisibility(View.VISIBLE);
binding.recyclerview1Text.setOnClickListener(v -> new start(id));
} else {
binding.recyclerview1Text.setVisibility(View.GONE);
}
});
}
}
/*
public void setonlong(int position) {
XM xm = list.get(position);
gj.sc(xm.name);
String[] stringArray = getResources()
.getStringArray(R.array.gd_list);
if (!wj.cz(wj.gd + xm.id)) {
stringArray = new String[]{"下载歌单"};
}
String[] finalStringArray = stringArray;
new MaterialAlertDialogBuilder(this).
setItems(stringArray, (dialog, id) -> {
switch (finalStringArray[id]) {
case "下载歌单":
new Thread() {
@SuppressLint("NotifyDataSetChanged")
@Override
public void run() {
String hq = playlist.gethq(xm.id);
if (hq != null) {
try {
XM fh = resource.Playlist_content(xm.id);
JSONObject json = new JSONObject(hq);
json.put("name", fh.name);
json.put("picUrl", fh.picurl);
json.put("message", fh.message);
// json.put(fh.id, json);
wj.xrwb(wj.gd + xm.id, json.toString());
// wode.addlist(fh);
// main.handler.post(() -> notifyItemChanged(position));
} catch (JSONException e) {
gj.sc("list gd onclick thear " + e);
}
}
}
}.start();
break;
case "删除歌单":
// 删除项目
try {
wj.sc(wj.gd + xm.id);
// wode.removelist(xm);
} catch (Exception e) {
gj.sc(e);
}
break;
}
// 在这里处理菜单项的点击事件
}).show();
}
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuItem itemA = menu.add("搜索");
itemA.setTitle("搜索");
itemA.setIcon(R.drawable.sousuo);
itemA.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
int itemId = item.getItemId();
if (itemId == android.R.id.home) {
if (binding.edittext.getVisibility() == View.VISIBLE) {
binding.title.setVisibility(View.VISIBLE);
binding.edittext.setVisibility(View.GONE);
gj.ycjp(binding.edittext);
adapter.getFilter().filter("");
} else {
ActivityCompat.finishAfterTransition(this);
}
} else if (itemId == 0) {
binding.title.setVisibility(View.GONE);
binding.edittext.setVisibility(View.VISIBLE);
// gj.tcjp(binding.edittext);
}
return true;
}
public class Adapter extends AdapterGdH implements Filterable {
private List<XM> list_ys;
public Adapter() {
list_ys = list;
}
@Override
public void onBindViewHolder(@NonNull VH<ListGdBBinding> holder, int position) {
super.onBindViewHolder(holder, position);
}
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence charSequence) {
String charString = charSequence.toString();
if (charString.isEmpty()) {
//没有过滤的内容则使用源数据
list = list_ys;
} else {
List<XM> filteredList = new ArrayList<>();
for (int i = 0; i < list_ys.size(); i++) {
XM xm = list_ys.get(i);
if (xm.name.contains(charString)) {
filteredList.add(list_ys.get(i));
}
}
list = filteredList;
}
FilterResults filterResults = new FilterResults();
filterResults.values = list;
return filterResults;
}
@SuppressLint("NotifyDataSetChanged")
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
list = (List<XM>) filterResults.values;
binding.lb.setAdapter(adapter);
}
};
}
}
}

View File

@ -0,0 +1,130 @@
package com.muqingbfq.fragment;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.muqingbfq.MP3;
import com.muqingbfq.R;
import com.muqingbfq.XM;
import com.muqingbfq.activity_search;
import com.muqingbfq.adapter.AdapterGd;
import com.muqingbfq.adapter.AdapterMp3;
import com.muqingbfq.api.resource;
import com.muqingbfq.databinding.FragmentGdBinding;
import com.muqingbfq.databinding.ListMp3ImageBinding;
import com.muqingbfq.main;
import com.muqingbfq.mq.Fragment;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wj;
import com.muqingbfq.mq.wl;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class gd_adapter extends Fragment<FragmentGdBinding> {
List<XM> list = new ArrayList<>();
AdapterMp3 adapterMp3 = new AdapterMp3();
@Override
protected FragmentGdBinding inflateViewBinding(LayoutInflater inflater, ViewGroup container) {
return FragmentGdBinding.inflate(inflater, container, false);
}
AdapterGd adapterGd = new AdapterGd();
@Override
public void setUI(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext(),LinearLayoutManager.HORIZONTAL,false);
binding.recyclerview1.setHasFixedSize(true);
binding.recyclerview1.setNestedScrollingEnabled(false);
binding.recyclerview1.setLayoutManager(linearLayoutManager);
adapterGd.list = list;
binding.recyclerview1.setAdapter(adapterGd);
new Thread() {
@Override
public void run() {
super.run();
resource.recommend(list);
main.handler.post(new sx());
}
}.start();
mp3list();
binding.recyclerview2.setLayoutManager(new LinearLayoutManager(getContext()));
binding.recyclerview2.setNestedScrollingEnabled(false);
binding.recyclerview2.setAdapter(adapterMp3);
// requireActivity().findViewById(R.id.linearLayout4).post(new Runnable() {
// @Override
// public void run() {
// binding.recyclerview2.setPadding(0, 0, 0,
// requireActivity().findViewById(R.id.linearLayout4).getHeight());
// }
// });
}
private class sx implements Runnable {
@SuppressLint("NotifyDataSetChanged")
@Override
public void run() {
binding.recyclerview1.getAdapter().notifyDataSetChanged();
binding.recyclerview1Bar.setVisibility(View.GONE);
}
}
public void mp3list() {
new Thread() {
@SuppressLint("NotifyDataSetChanged")
@Override
public void run() {
super.run();
String hq = wl.hq("/recommend/songs" + "?cookie=" + wl.Cookie);
if (hq == null) {
hq = wj.dqwb(wj.filesdri + "songs.json");
}
try {
JSONObject jsonObject = new JSONObject(hq);
JSONObject data = jsonObject.getJSONObject("data");
JSONArray dailySongs = data.getJSONArray("dailySongs");
for (int i = 0; i < dailySongs.length(); i++) {
JSONObject jsonObject1 = dailySongs.getJSONObject(i);
String id = jsonObject1.getString("id");
String name = jsonObject1.getString("name");
JSONArray ar = jsonObject1.getJSONArray("ar");
StringBuilder zz = new StringBuilder();
for (int j = 0; j < ar.length(); j++) {
zz.append(ar.getJSONObject(j).getString("name")).append(' ');
}
JSONObject al = jsonObject1.getJSONObject("al");
String picUrl = al.getString("picUrl");
adapterMp3.list.add(new MP3(id, name, zz.toString(), picUrl));
}
wj.xrwb(wj.filesdri + "songs.json", hq);
requireActivity().runOnUiThread(() -> {
adapterMp3.notifyDataSetChanged();
binding.recyclerview2Bar.setVisibility(View.GONE);
});
} catch (Exception e) {
gj.sc(e);
}
}
}.start();
}
public void Gdlist() {
}
}

View File

@ -0,0 +1,364 @@
package com.muqingbfq.fragment;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.media3.common.MediaItem;
import androidx.media3.common.Player;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
import com.muqingbfq.MP3;
import com.muqingbfq.PlaybackService;
import com.muqingbfq.R;
import com.muqingbfq.adapter.AdapterMp3;
import com.muqingbfq.api.playlist;
import com.muqingbfq.api.url;
import com.muqingbfq.bfqkz;
import com.muqingbfq.databinding.ActivityMp3Binding;
import com.muqingbfq.databinding.ListMp3ImageBinding;
import com.muqingbfq.main;
import com.muqingbfq.mq.FragmentActivity;
import com.muqingbfq.mq.VH;
import com.muqingbfq.mq.gj;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import jp.wasabeef.glide.transformations.BlurTransformation;
public class mp3 extends FragmentActivity<ActivityMp3Binding> {
private List<MP3> list = new ArrayList<>();
private List<MP3> list_ys = new ArrayList<>();
public Adapter adapter;
public static void start(Activity context, String[] str, View view) {
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(context,
view, "text");
Intent intent = new Intent(context, mp3.class);
intent.putExtra("id", str[0]);
intent.putExtra("name", str[1]);
context.startActivity(intent, options.toBundle());
}
public static void start(Context context, String[] strings) {
Intent intent = new Intent(context, mp3.class);
intent.putExtra("id", strings[0]);
intent.putExtra("name", strings[1]);
context.startActivity(intent);
}
public static Drawable drawable = null;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView();
// drawable=null;
TypedValue typedValue = new TypedValue();
getTheme().resolveAttribute(android.R.attr.windowBackground, typedValue, true);
; // 获取当前主题的背景颜色
if (drawable != null) {
// 4. 设置到 ImageView
ImageView imageView = findViewById(R.id.toolbarimage);
Glide.with(this)
.load(drawable)
.apply(RequestOptions.bitmapTransform(new BlurTransformation(26,3)))
.addListener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<Drawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target<Drawable> target, @NonNull DataSource dataSource, boolean isFirstResource) {
// 使用 Glide 加载图片并应用高斯模糊效果
// 1. 创建渐变遮罩层从底部白色渐变到顶部透明
GradientDrawable gradient = new GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP,
new int[] {typedValue.data, Color.TRANSPARENT});
gradient.setShape(GradientDrawable.RECTANGLE);
// 3. 使用 LayerDrawable 来组合模糊图像和渐变效果
LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{resource, gradient});
imageView.setImageDrawable(layerDrawable);
return true;
}
})
.into(imageView);
}
ViewCompat.setOnApplyWindowInsetsListener(binding.getRoot(), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, 0, systemBars.right, systemBars.bottom);
// binding.toolbar.setPadding(0, systemBars.top, 0, 0);
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) binding.toolbar.getLayoutParams();
params.setMargins(0, systemBars.top, 0, 0); // 参数分别是 left, top, right, bottom
binding.toolbar.setLayoutParams(params);
return insets;
});
Intent intent = getIntent();
binding.title.setText(intent.getStringExtra("name"));
String id = intent.getStringExtra("id");
adapter = new Adapter(list);
binding.lb.setLayoutManager(new LinearLayoutManager(this));
binding.lb.setAdapter(adapter);
new start(id);
binding.edittext.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (binding.edittext.getVisibility() == View.VISIBLE) {
adapter.getFilter().filter(charSequence);
}
}
@Override
public void afterTextChanged(Editable editable) {
}
});
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
if (binding.edittext.getVisibility() == View.VISIBLE) {
binding.title.setVisibility(View.VISIBLE);
binding.edittext.setVisibility(View.GONE);
gj.ycjp(binding.edittext);
adapter.getFilter().filter("");
} else {
finish();
// ActivityCompat.finishAfterTransition(mp3.this);
}
}
});
binding.fragmentDb.post(() -> {
int height = binding.fragmentDb.getHeight();
binding.lb.setPadding(0, 0, 0, height);
});
binding.playButton.setOnClickListener(v -> {
v.setEnabled(false);
if (PlaybackService.mediaSession == null) {
return;
}
Player player = PlaybackService.mediaSession.getPlayer();
player.clearMediaItems();
List<MP3> aalist = new ArrayList<>(list);
if (bfqkz.ms == 2) {
Collections.shuffle(aalist);
}
for (int i = 0; i < aalist.size(); i++) {
MP3 mp3 = aalist.get(i);
// mp3 = url.hq(mp3);
MediaItem mediaItem = PlaybackService.GetMp3(mp3);
player.addMediaItem(mediaItem);
}
player.prepare();
player.seekTo(0, 0);
player.play();
//保存播放列表
PlaybackService.list.clear();
PlaybackService.list.addAll(aalist);
PlaybackService.ListSave();
new Thread(new Runnable() {
@Override
public void run() {
while (true){
try {
Thread.sleep(500);
//检测音乐是否播放
runOnUiThread(() -> {
if (!player.isPlaying()) {
return;
}
v.setEnabled(true);
});
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}).start();
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuItem itemA = menu.add("搜索");
itemA.setTitle("搜索");
itemA.setIcon(R.drawable.sousuo);
itemA.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
return super.onCreateOptionsMenu(menu);
}
@Override
protected ActivityMp3Binding getViewBindingObject(LayoutInflater layoutInflater) {
return ActivityMp3Binding.inflate(layoutInflater);
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
int itemId = item.getItemId();
if (itemId == android.R.id.home) {
if (binding.edittext.getVisibility() == View.VISIBLE) {
binding.title.setVisibility(View.VISIBLE);
binding.edittext.setVisibility(View.GONE);
gj.ycjp(binding.edittext);
adapter.getFilter().filter("");
} else {
ActivityCompat.finishAfterTransition(this);
}
} else if (itemId == 0) {
binding.title.setVisibility(View.GONE);
binding.edittext.setVisibility(View.VISIBLE);
gj.tcjp(binding.edittext);
}
return true;
}
@SuppressLint("NotifyDataSetChanged")
class start extends Thread {
String id;
public start(String id) {
binding.recyclerview1Bar.setVisibility(View.VISIBLE);
this.id = id;
list.clear();
list_ys.clear();
start();
}
@Override
public void run() {
super.run();
switch (id) {
case "mp3_xz.json":
playlist.hq_xz(list);
break;
case "mp3_like.json":
playlist.hq_like(list);
break;
case "cd.json":
playlist.hq_cd(mp3.this, list);
break;
default:
playlist.hq(list, id);
break;
}
list_ys = list;
main.handler.post(() -> {
binding.lb.getAdapter().notifyDataSetChanged();
binding.recyclerview1Bar.setVisibility(View.GONE);
if (list.isEmpty()) {
binding.recyclerview1Text.setVisibility(View.VISIBLE);
binding.recyclerview1Text.setOnClickListener(v -> new start(id));
} else {
binding.recyclerview1Text.setVisibility(View.GONE);
}
});
}
}
public class Adapter extends AdapterMp3 implements Filterable {
private List<MP3> list_ys;
public Adapter(List<MP3> list) {
this.list = list;
list_ys = list;
}
@Override
public void onBindViewHolder(@NonNull VH<ListMp3ImageBinding> holder, int position) {
super.onBindViewHolder(holder, position);
}
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence charSequence) {
String charString = charSequence.toString();
if (charString.isEmpty()) {
//没有过滤的内容则使用源数据
list = list_ys;
} else {
List<MP3> filteredList = new ArrayList<>();
for (int i = 0; i < list_ys.size(); i++) {
MP3 mp3 = list_ys.get(i);
if (mp3.name.contains(charString)
|| mp3.zz.contains(charString)) {
filteredList.add(list_ys.get(i));
}
}
list = filteredList;
}
FilterResults filterResults = new FilterResults();
filterResults.values = list;
return filterResults;
}
@SuppressLint("NotifyDataSetChanged")
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
list = (List<MP3>) filterResults.values;
notifyDataSetChanged();
}
};
}
}
public static void startactivity(Context context, String id) {
context.startActivity(new Intent(context, mp3.class).putExtra("id", id));
}
@Override
public void finish() {
super.finish();
adapter = null;
}
}

View File

@ -0,0 +1,231 @@
package com.muqingbfq.fragment;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import com.google.android.material.tabs.TabLayoutMediator;
import com.muqingbfq.MP3;
import com.muqingbfq.XM;
import com.muqingbfq.adapter.AdapterGdH;
import com.muqingbfq.adapter.AdapterMp3;
import com.muqingbfq.databinding.FragmentSearchBinding;
import com.muqingbfq.databinding.RecyclerVBinding;
import com.muqingbfq.main;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wl;
import org.json.JSONArray;
import org.json.JSONObject;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
public class search extends Fragment {
public FragmentSearchBinding binding;
public String string;
List<Fragment> fragments=new ArrayList<>();
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
binding = FragmentSearchBinding.inflate(inflater, container, false);
binding.viewPager.setSaveEnabled(false);
adapter = new FragmentStateAdapter(this) {
@NonNull
@Override
public Fragment createFragment(int position) {
return fragments.get(position);
}
@Override
public int getItemCount() {
return fragments.size();
}
};
return binding.getRoot();
}
public static class mp3 extends Fragment {
public static mp3 newInstance(String string) {
mp3 fragment = new mp3();
Bundle args = new Bundle();
args.putString("string", string);
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
List<MP3> list = new ArrayList<>();
String string = getArguments().getString("string");
RecyclerVBinding binding = RecyclerVBinding.inflate(inflater, container, false);
binding.recycleview.setLayoutManager(new LinearLayoutManager(getContext()));
binding.recycleview.setAdapter(new AdapterMp3(list));
list.clear();
binding.recyclerviewBar.setVisibility(View.VISIBLE);
binding.recyclerviewText.setVisibility(View.GONE);
new Thread() {
@SuppressLint("NotifyDataSetChanged")
@Override
public void run() {
super.run();
mp3(list, string);
main.handler.post(() -> {
binding.recyclerviewBar.setVisibility(View.GONE);
if (list.isEmpty()) {
binding.recyclerviewText.setVisibility(View.VISIBLE);
} else {
binding.recyclerviewText.setVisibility(View.GONE);
}
binding.recycleview.getAdapter().notifyDataSetChanged();
});
}
}.start();
return binding.getRoot();
}
}
public static class gd extends Fragment {
public static gd newInstance(String string) {
gd fragment = new gd();
Bundle args = new Bundle();
args.putString("string", string);
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
List<XM> list = new ArrayList<>();
String string = getArguments().getString("string");
RecyclerVBinding binding = RecyclerVBinding.inflate(inflater, container, false);
binding.recycleview.setLayoutManager(new LinearLayoutManager(getContext()));
binding.recycleview.setAdapter(new AdapterGdH(list));
list.clear();
binding.recyclerviewBar.setVisibility(View.VISIBLE);
binding.recyclerviewText.setVisibility(View.GONE);
new Thread() {
@SuppressLint("NotifyDataSetChanged")
@Override
public void run() {
super.run();
gd(list, string);
main.handler.post(() -> {
binding.recyclerviewBar.setVisibility(View.GONE);
if (list.isEmpty()) {
binding.recyclerviewText.setVisibility(View.VISIBLE);
} else {
binding.recyclerviewText.setVisibility(View.GONE);
}
binding.recycleview.getAdapter().notifyDataSetChanged();
});
}
}.start();
return binding.getRoot();
}
}
private FragmentStateAdapter adapter;
@SuppressLint("NotifyDataSetChanged")
public void sx(String string) {
this.string = string;
fragments.clear();
fragments.add(mp3.newInstance(string));
fragments.add(gd.newInstance(string));
binding.viewPager.setAdapter(adapter);
adapter.notifyDataSetChanged();
String[] strtab = new String[]{"歌曲", "歌单"};
//将tabbView绑定到tab
new TabLayoutMediator(binding.tablayout, binding.viewPager, (tab, position) ->
tab.setText(strtab[position])).attach();
}
private static void mp3(List<MP3> list, String str) {
try {
Long.parseLong(str);
com.muqingbfq.api.playlist.hq(list, str);
return;
} catch (NumberFormatException e) {
gj.sc(e);
}
String hq = wl.hq("/search?keywords=" + str + "&type=1");
try {
JSONArray jsonArray = new JSONObject(hq).getJSONObject("result")
.getJSONArray("songs");
int length = jsonArray.length();
for (int i = 0; i < length; i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
String id = jsonObject.getString("id");
String name = jsonObject.getString("name");
JSONArray artists = jsonObject.getJSONArray("artists");
int length1 = artists.length();
StringBuilder zz = null;
for (int j = 0; j < length1; j++) {
JSONObject josn = artists.getJSONObject(j);
String name_zz = josn.getString("name");
if (zz == null) {
zz = new StringBuilder(name_zz);
} else {
zz.append("/").append(name_zz);
}
}
list.add(new MP3(id, name, zz.toString(), ""));
}
} catch (Exception e) {
gj.sc(e);
}
}
private static void gd(List<XM> list, String str) {
try {
Long.parseLong(str);
String hq = wl.hq("/playlist/detail?id=" + str);
JSONObject js = new JSONObject(hq).getJSONObject("playlist");
String id = js.getString("id");
String name = js.getString("name");
String coverImgUrl = js.getString("coverImgUrl");
// gj.sc(name);
list.add(new XM(id, name, coverImgUrl));
return;
} catch (Exception e) {
gj.sc(e);
}
try {
String hq = wl.hq("/search?keywords=" + str + "&type=1000");
JSONArray jsonArray = new JSONObject(hq).getJSONObject("result")
.getJSONArray("playlists");
int length = jsonArray.length();
for (int i = 0; i < length; i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
String id = jsonObject.getString("id");
String name = jsonObject.getString("name");
String coverImgUrl = jsonObject.getString("coverImgUrl");
long playCount = jsonObject.getLong("playCount");
String formattedNumber = String.valueOf(playCount);
if (playCount > 9999) {
DecimalFormat df = new DecimalFormat("#,###.0万");
formattedNumber = df.format(playCount / 10000);
}
String s = jsonObject.getInt("trackCount") + "首,"
+ "by " + jsonObject.getJSONObject("creator").getString("nickname")
+ ",播放"
+ formattedNumber + "";
list.add(new XM(id, name, s, coverImgUrl));
}
} catch (Exception e) {
gj.sc(e);
}
}
}

View File

@ -0,0 +1,69 @@
package com.muqingbfq.fragment;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.widget.Toast;
import com.muqingbfq.R;
import com.muqingbfq.activity_about_software;
import com.muqingbfq.clean.fragment_clean;
import com.muqingbfq.main;
import com.muqingbfq.mq.gj;
import java.util.List;
public class sz {
@SuppressLint("NonConstantResourceId")
public static void switch_sz(Context context, int id) {
if (id == R.id.a) {
gj.llq(context, "https://github.com/muqing153/CloudMusic");
} else if (id == R.id.b) {
context.startActivity(new Intent(context, com.muqingbfq.sz.class));
// 设置中心
} else if (id == R.id.c) {
context.startActivity(new Intent(context, fragment_clean.class));
// 储存清理
} else if (id == R.id.d) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse("mqqapi://card/show_pslcard?card_type=group&uin="
+ 674891685));
context.startActivity(intent);
} catch (Exception e) {
Toast.makeText(context, "无法打开 QQ", Toast.LENGTH_SHORT).show();
}
// 如果没有安装 QQ 客户端或无法打开 QQ您可以在此处理异常
// 官方聊群
} else if (id == R.id.e) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(
"mqqwpa://im/chat?chat_type=wpa&uin=" + "1966944300"));
context.startActivity(intent);
} catch (Exception e) {
// 如果没有安装 QQ 或无法跳转则会抛出异常
Toast.makeText(context, "无法打开 QQ", Toast.LENGTH_SHORT).show();
}
// 联系作者
} else if (id == R.id.f) {
context.startActivity(new Intent(context, activity_about_software.class));
// 关于软件
} else if (id == R.id.g) {
// 关闭软件
ActivityManager mActivityManager = (ActivityManager)
main.application.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> mList = mActivityManager.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo runningAppProcessInfo : mList)
{
if (runningAppProcessInfo.pid != android.os.Process.myPid())
{
android.os.Process.killProcess(runningAppProcessInfo.pid);
}
}
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
}
}
}

View File

@ -0,0 +1,273 @@
package com.muqingbfq.fragment;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.gson.Gson;
import com.muqingbfq.R;
import com.muqingbfq.XM;
import com.muqingbfq.api.playlist;
import com.muqingbfq.api.resource;
import com.muqingbfq.databinding.FragmentWdBinding;
import com.muqingbfq.login.user_logs;
import com.muqingbfq.login.visitor;
import com.muqingbfq.main;
import com.muqingbfq.mq.EditViewDialog;
import com.muqingbfq.mq.Fragment;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wj;
import com.muqingbfq.mq.wl;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class wode extends Fragment<FragmentWdBinding> {
public TextView name, jieshao;
public ImageView imageView;
private final Object[][] lista = {
{R.drawable.mdimusicbox, "最近播放", "mp3_hc.json"},
{R.drawable.download, "下载音乐", "mp3_xz.json"},
{R.drawable.mdialbum, "喜欢音乐", "mp3_like.json"},
{R.drawable.filesearc, "本地搜索", "cd.json"},
{R.drawable.api, "更换接口", "API"},
{R.drawable.gd, "导入歌单", "gd"},
{R.drawable.paihangbang, "排行榜", "排行榜"},
{R.drawable.ic_launcher_foreground, "开发中", ""}
};
@Override
protected FragmentWdBinding inflateViewBinding(LayoutInflater inflater, ViewGroup container) {
return FragmentWdBinding.inflate(inflater, container, false);
}
@Override
public void setUI(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
name = binding.text1;
jieshao = binding.text2;
imageView = binding.imageView;
binding.cardview.setOnClickListener(new dl());
binding.recyclerview1.setNestedScrollingEnabled(false);
binding.recyclerview1.setLayoutManager(new GridLayoutManager(getContext(), 4));
binding.recyclerview1.setFocusable(false);
binding.recyclerview1.setAdapter(new RecyclerView.Adapter<VH>() {
@NonNull
@Override
public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View inflate = View.inflate(getContext(), R.layout.view_button, null);
return new VH(inflate);
}
@Override
public void onBindViewHolder(@NonNull VH holder, int position) {
String s = lista[position][1].toString();
holder.textView.setText(s);
holder.imageView.setImageResource((Integer) lista[position][0]);
String data = lista[position][2].toString();
holder.itemView.setOnClickListener(view -> {
switch (data) {
case "cd.json":
case "mp3_hc.json":
case "mp3_xz.json":
case "mp3_like.json":
Intent a = new Intent(getContext(), com.muqingbfq.fragment.mp3.class);
a.putExtra("id", data);
a.putExtra("name", s);
getContext().startActivity(a);
break;
case "排行榜":
gd.start(getActivity(), new String[]{data, s});
break;
case "API":
EditViewDialog editViewDialog = new EditViewDialog(getContext(), "更换接口API")
.setMessage("当前接口:\n" + main.api);
editViewDialog.setPositive(view1 -> {
String str = editViewDialog.getEditText();
boolean http = str.startsWith("http");
if (str.isEmpty() || !http) {
gj.ts(getContext(), "请输入正确的api");
} else {
gj.ts(getContext(), "更换成功");
main.api = str;
wj.xrwb(wj.filesdri + "API.mq", main.api);
editViewDialog.dismiss();
}
}).show();
break;
case "gd":
EditViewDialog editViewDialog1 = new EditViewDialog(getContext(),
"导入歌单")
.setMessage("请用网易云https链接来进行导入或者歌单id");
editViewDialog1.setPositive(view1 -> {
String str = editViewDialog1.getEditText();
// 使用正则表达式提取链接
Pattern pattern = Pattern.compile("https?://[\\w./?=&]+");
Matcher matcher = pattern.matcher(str);
if (matcher.find())
str = matcher.group();
if (!str.isEmpty()) {
// 使用截取方法获取歌单 ID
str = str.substring(str.indexOf("id=") + 3, str.indexOf("&"));
}
String finalStr = str;
gj.ts(getContext(), "导入中");
new Thread() {
@Override
public void run() {
super.run();
String hq = playlist.gethq(finalStr);
if (hq != null) {
try {
XM fh = resource.Playlist_content(finalStr);
JSONObject json = new JSONObject(hq);
json.put("name", fh.name);
json.put("picUrl", fh.picurl);
json.put("message", fh.message);
// json.put(fh.id, json);
wj.xrwb(wj.gd + finalStr, json.toString());
// addlist(fh);
} catch (JSONException e) {
gj.sc("list gd onclick thear " + e);
}
}
}
}.start();
editViewDialog1.dismiss();
}).show();
break;
}
});
}
@Override
public int getItemCount() {
return lista.length;
}
});
binding.recyclerview2.setNestedScrollingEnabled(false);
binding.recyclerview2.setLayoutManager(new LinearLayoutManager(getContext()));
// adaper = new baseadapter();
// binding.recyclerview2.setAdapter(adaper);
// sx();
new threadLogin().start();
}
ActivityResultLauncher<Intent> dlintent = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
// 处理返回结果
Intent data = result.getData();
boolean bool = data.getBooleanExtra("bool", false);
if (bool) {
// gj.sc("dl");
new threadLogin().start();
}
// ...
}
});
class dl implements View.OnClickListener {
@Override
public void onClick(View v) {
File file = new File(wj.filesdri, "user.mq");
if (file.exists()) {
String[] a = new String[]{"退出登录"};
new MaterialAlertDialogBuilder(getContext())
.setItems(a, (dialogInterface, i) -> {
boolean delete = file.delete();
if (delete) {
wj.sc(wj.filesdri + "user.mq");
binding.text1.setText(getString(R.string.app_name));
binding.text2.setText(getString(R.string.app_name));
imageView.setImageResource(R.drawable.ic_launcher_foreground);
new visitor();//游客模式
wj.sc(wj.filesdri + "user.mq");
// new com.muqingbfq.login.user_message();
}
}).show();
} else {
dlintent.launch(new Intent(getContext(), user_logs.class));
}
}
}
class VH extends RecyclerView.ViewHolder {
public ImageView imageView;
public TextView textView;
public VH(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.image);
textView = itemView.findViewById(R.id.text1);
}
}
//登陆 获取用户信息 头像 昵称 签名
class threadLogin extends Thread {
public void run() {
String hq = wl.hq("/user/account?cookie=" + wl.Cookie);
if (hq != null) {
try {
JSONObject jsonObject = new JSONObject(hq);
int code = jsonObject.getInt("code");
if (code == 200) {
JSONObject profile = jsonObject.getJSONObject("profile");
String nickname = profile.getString("nickname");
String avatarUrl = profile.getString("avatarUrl");
String signature = profile.getString("signature");
requireActivity().runOnUiThread(() -> {
binding.text1.setText(nickname);
binding.text2.setText(signature);
Glide.with(getContext())
.load(avatarUrl)
.error(R.drawable.ic_launcher_foreground)
.into(binding.imageView);
});
wj.xrwb(wj.filesdri + "user.mq", new Gson().toJson(new user_logs.USER(nickname, signature, avatarUrl)));
}
} catch (Exception e) {
gj.sc(e);
}
} else {
if (!wj.cz(wj.filesdri + "user.mq")) {
return;
}
String dqwb = wj.dqwb(wj.filesdri + "user.mq");
user_logs.USER user = new Gson().fromJson(dqwb, user_logs.USER.class);
requireActivity().runOnUiThread(() -> {
binding.text1.setText(user.name);
binding.text2.setText(user.qianming);
Glide.with(getContext())
.load(user.picUrl)
.error(R.drawable.ic_launcher_foreground)
.into(binding.imageView);
});
}
}
}
}

View File

@ -0,0 +1,348 @@
package com.muqingbfq;
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.FrameLayout;
import androidx.activity.EdgeToEdge;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import androidx.core.graphics.Insets;
import androidx.core.view.GravityCompat;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.Fragment;
import androidx.media3.session.MediaController;
import androidx.media3.session.SessionToken;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.flexbox.AlignItems;
import com.google.android.flexbox.FlexDirection;
import com.google.android.flexbox.FlexWrap;
import com.google.android.flexbox.FlexboxLayoutManager;
import com.google.android.material.card.MaterialCardView;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.search.SearchView;
import com.google.common.base.Strings;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.muqingbfq.databinding.ActivityHomeBinding;
import com.muqingbfq.fragment.gd_adapter;
import com.muqingbfq.fragment.search;
import com.muqingbfq.fragment.sz;
import com.muqingbfq.fragment.wode;
import com.muqingbfq.mq.AppCompatActivity;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wl;
import com.muqingbfq.view.Edit;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class home extends AppCompatActivity<ActivityHomeBinding> {
@Override
protected ActivityHomeBinding getViewBindingObject(LayoutInflater layoutInflater) {
return ActivityHomeBinding.inflate(layoutInflater);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.Theme_muqing);
EdgeToEdge.enable(this);
super.onCreate(savedInstanceState);
SessionToken sessionToken =
new SessionToken(this, new ComponentName(this, PlaybackService.class));
ListenableFuture<MediaController> controllerFuture =
new MediaController.Builder(this, sessionToken).buildAsync();
controllerFuture.addListener(() -> {
}, MoreExecutors.directExecutor());
if (Strings.isNullOrEmpty(wl.Cookie)) {
new HomeSteer(this) {
@Override
public void Yes() {
UI();
}
};
} else UI();
}
@Override
protected void onResume() {
super.onResume();
}
public void toolbar() {
setSupportActionBar(binding.toolbar);
}
public void UI() {
setContentView();
// 禁止ViewPager2滑动
binding.viewPager.setUserInputEnabled(false);
ViewCompat.setOnApplyWindowInsetsListener(binding.getRoot(), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
// v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
v.setPadding(systemBars.left, 0, systemBars.right, 0);
binding.chb.setPadding(0, systemBars.top, 0, 0);
return insets;
});
// viewTop=binding.
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
if (binding.searchview.isShowing()) {
binding.searchview.hide();
return;
}
moveTaskToBack(true);
}
});
//初始化侧滑
binding.chb.setNavigationItemSelectedListener(item -> {
sz.switch_sz(home.this, item.getItemId());
return false;
});
List<Fragment> list = new ArrayList<>();
list.add(new gd_adapter());
list.add(new wode());
binding.viewPager.setAdapter(new FragmentStateAdapter(this) {
@NonNull
@Override
public Fragment createFragment(int position) {
return list.get(position);
}
@Override
public int getItemCount() {
return list.size();
}
});
binding.viewPager.setCurrentItem(0,false);
if (!gj.isTablet(this)) {
binding.linearLayout4.post(() -> {
int height = binding.linearLayout4.getHeight();
binding.viewPager.setPadding(0, 0, 0, height);
});
}
binding.fragmentDb.post(() -> {
int height = binding.fragmentDb.getHeight();
binding.searchview.setPadding(0, 0, 0, height);
});
binding.tablayout.addView("推荐", R.drawable.zhuye).setOnClickListener(v -> {
for (int i = 0; i < binding.tablayout.sizeView; i++) {
MaterialCardView childAt = (MaterialCardView) binding.tablayout.linearLayout.getChildAt(i);
if (i == 0) {
//背景高亮
childAt.setCardBackgroundColor(gj.getThemeColor(v.getContext(), com.google.android.material.R.attr.colorPrimaryContainer));
} else {
//背景恢复
childAt.setCardBackgroundColor(gj.getThemeColor(v.getContext(), com.google.android.material.R.attr.colorSurface));
}
}
binding.viewPager.setCurrentItem(0,false);
});
binding.tablayout.addView("我的", R.drawable.user).setOnClickListener(v -> {
for (int i = 0; i < binding.tablayout.sizeView; i++) {
MaterialCardView childAt = (MaterialCardView) binding.tablayout.linearLayout.getChildAt(i);
if (i == 1) {
//背景高亮
childAt.setCardBackgroundColor(gj.getThemeColor(v.getContext(), com.google.android.material.R.attr.colorPrimaryContainer));
} else {
//背景恢复
childAt.setCardBackgroundColor(gj.getThemeColor(v.getContext(), com.google.android.material.R.attr.colorSurface));
}
}
binding.viewPager.setCurrentItem(1,false);
});
toolbar();
SearchUI();
}
@Override
protected void onPause() {
super.onPause();
//在销毁 Activity 之前系统会先调用 onDestroy()系统调用此回调的原因如下
// 保存列表数据
}
public boolean issearchclicklist = false;//是否点击了列表项目
//搜索建议列表
private List<String> searchList = new ArrayList<>();
private activity_search.SearchRecordAdapter searchRecordAdapter;
public void SearchUI() {
binding.searchview
.getEditText()
.setOnEditorActionListener(
(v, actionId, event) -> {
// binding.searchview.hide();
searchStart(binding.toolbar.getText().toString());
return false;
});
binding.searchview.setOnMenuItemClickListener(
menuItem -> {
// Handle menuItem click.
return true;
});
FlexboxLayoutManager manager = new FlexboxLayoutManager(this);
//设置主轴排列方式
manager.setFlexDirection(FlexDirection.ROW);
//设置是否换行
manager.setFlexWrap(FlexWrap.WRAP);
manager.setAlignItems(AlignItems.STRETCH);//历史记录的LayoutManager
binding.listRecycler.setNestedScrollingEnabled(false);
binding.listRecycler.setLayoutManager(manager);
binding.searchview.addTransitionListener(
(searchView, previousState, newState) -> {
if (newState == SearchView.TransitionState.SHOWING) {
// Handle search view opened.
gj.sc("SHOWING");
binding.tablayout.setVisibility(View.GONE);
// 添加 Fragment
getSupportFragmentManager()
.beginTransaction()
.replace(binding.searchFragment.getId(), new search())
.commit();
searchRecordAdapter = new activity_search.SearchRecordAdapter(binding.searchview);
binding.listRecycler.setAdapter(searchRecordAdapter);
} else if (newState == SearchView.TransitionState.SHOWN) {
gj.sc("SHOWN");
} else if (newState == SearchView.TransitionState.HIDING) {
if (!gj.isTablet(this)) {
binding.tablayout.setVisibility(View.VISIBLE);
}
searchRecordAdapter = null;
binding.listRecycler.setAdapter(null);
binding.searchFragment.setVisibility(View.GONE);
binding.searchRecycler.setVisibility(View.GONE);
binding.xxbj1.setVisibility(View.VISIBLE);
// 移除当前显示的 Fragment
getSupportFragmentManager().beginTransaction()
.remove(getSupportFragmentManager()
.findFragmentById(binding.searchFragment.getId()))
.commit();
}
});
final Object o = new Object();
binding.searchview.getEditText().addTextChangedListener(new Edit.TextWatcher() {
@Override
public void beforeTextChanged(CharSequence var1, int var2, int var3, int var4) {
}
@Override
public void onTextChanged(CharSequence var1, int var2, int var3, int var4) {
new Thread() {
@SuppressLint("NotifyDataSetChanged")
@Override
public void run() {
synchronized (o) {
searchList.clear();
String hq = com.muqingbfq.mq.wl.
hq("/search/suggest?keywords=" + var1.toString() + "&type=mobile");
try {
JSONArray jsonArray = new JSONObject(hq).getJSONObject("result")
.getJSONArray("allMatch");
int length = jsonArray.length();
for (int i = 0; i < length; i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
String keyword = jsonObject.getString("keyword");
searchList.add(keyword);
}
runOnUiThread(() -> binding.searchRecycler.setAdapter(new activity_search.search_adapter(searchList, string -> {
gj.sc(string);
issearchclicklist = true;
binding.searchRecycler.setAdapter(null);
binding.searchRecycler.setVisibility(View.GONE);
binding.xxbj1.setVisibility(View.GONE);
binding.searchFragment.setVisibility(View.VISIBLE);
binding.searchview.setText(string);
searchStart(string);
// binding.searchRecycler.set
})));
} catch (Exception e) {
gj.sc(e);
}
}
}
}.start();
}
@Override
public void afterTextChanged(Editable var1) {
if (Strings.isNullOrEmpty(var1.toString())) {
binding.searchRecycler.setAdapter(null);
binding.searchRecycler.setVisibility(View.GONE);
binding.xxbj1.setVisibility(View.VISIBLE);
binding.searchFragment.setVisibility(View.GONE);
} else if (!issearchclicklist) {
binding.searchRecycler.setVisibility(View.VISIBLE);
binding.xxbj1.setVisibility(View.GONE);
binding.searchFragment.setVisibility(View.GONE);
} else issearchclicklist = false;
}
});
binding.toolbar.setNavigationIcon(R.drawable.menu);
binding.deleat.setOnClickListener(v -> new MaterialAlertDialogBuilder(
v.getContext())
.setTitle("删除")
.setMessage("清空历史记录?")
.setNegativeButton("取消", null)
.setPositiveButton("确定", (dialogInterface, ii) -> {
searchRecordAdapter.json_list.clear();
binding.listRecycler.setAdapter(searchRecordAdapter);
com.muqingbfq.mq.wj.sc(com.muqingbfq.mq.wj.filesdri +
com.muqingbfq.mq.wj.lishi_json);
})
.show());
}
public void searchStart(String name) {
issearchclicklist = true;
binding.toolbar.setText(binding.searchview.getText());
if (!TextUtils.isEmpty(name)) {
search sea = (search) getSupportFragmentManager().findFragmentById(binding.searchFragment.getId());
binding.searchFragment.setVisibility(View.VISIBLE);
binding.searchRecycler.setVisibility(View.GONE);
sea.sx(name);
activity_search.addSearchRecord(name, searchRecordAdapter.json_list, searchRecordAdapter);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.home, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.menu_search) {
binding.searchview.show();
// startActivity(new Intent(this, activity_search.class));
} else if (item.getItemId() == android.R.id.home) {
//展开侧滑
binding.chct.openDrawer(GravityCompat.START);
}
return super.onOptionsItemSelected(item);
}
}

View File

@ -0,0 +1,28 @@
package com.muqingbfq.list;
import android.content.Context;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.muqingbfq.R;
import com.muqingbfq.databinding.ListMp3ABinding;
import com.muqingbfq.databinding.ListMp3Binding;
public class MyViewHoder extends RecyclerView.ViewHolder {
public ListMp3Binding binding;
public ListMp3ABinding bindingA;
public MyViewHoder(@NonNull ListMp3Binding itemView) {
super(itemView.getRoot());
binding = itemView;
}
public MyViewHoder(@NonNull ListMp3ABinding itemView) {
super(itemView.getRoot());
bindingA = itemView;
}
public Context getContext() {
return itemView.getContext();
}
}

View File

@ -0,0 +1,5 @@
package com.muqingbfq.list;
public class file_list {
}

View File

@ -0,0 +1,4 @@
package com.muqingbfq.list;
public class yylb {
}

View File

@ -0,0 +1,250 @@
package com.muqingbfq.login;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Base64;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import androidx.core.view.WindowCompat;
import com.google.gson.Gson;
import com.muqingbfq.databinding.ActivityUserLogsBinding;
import com.muqingbfq.main;
import com.muqingbfq.mq.AppCompatActivity;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wj;
import com.muqingbfq.mq.wl;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Objects;
public class user_logs extends AppCompatActivity<ActivityUserLogsBinding> {
@Override
protected ActivityUserLogsBinding getViewBindingObject(LayoutInflater layoutInflater) {
return ActivityUserLogsBinding.inflate(layoutInflater);
}
public static class USER {
public String name, qianming;
public Object picUrl;
public USER(String user, String qianming, Object picUrl) {
this.name = user;
this.qianming = qianming;
this.picUrl = picUrl;
}
}
erweima thread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView();
setSupportActionBar(binding.toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
binding.login.setOnClickListener(view1 -> {
if (!TextUtils.isEmpty(binding.editUser.getText())) {
wl.setcookie(binding.editUser.getText().toString());
}
new Thread(() -> {
gj.sc(wl.Cookie);
String hq = wl.hq("/login/status?cookie=" + wl.Cookie);
try {
JSONObject jsonObject = new JSONObject(hq);
JSONObject data = jsonObject.getJSONObject("data");
JSONObject account1 = data.getJSONObject("account");
finish(true);
} catch (JSONException e) {
gj.sc(e);
runOnUiThread(() -> {
gj.ycjp(binding.editUser);
Toast.makeText(user_logs.this, "不成功的Cookie登陆", Toast.LENGTH_SHORT).show();
});
}
}).start();
});
binding.button1.setOnClickListener(view -> {
if (binding.layout1.getVisibility() == View.VISIBLE) {
binding.layout1.setVisibility(View.GONE);
binding.layout2.setVisibility(View.VISIBLE);
binding.button1.setText("账号");
thread = new erweima();
thread.start();
} else {
thread.interrupt();
binding.button1.setText("二维码");
binding.layout1.setVisibility(View.VISIBLE);
binding.layout2.setVisibility(View.GONE);
}
});
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
finish(false);
}
});
}
//some statement
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish(false);
}
return super.onOptionsItemSelected(item);
}
public void finish(boolean aBoolean) {
Intent resultIntent = new Intent();
resultIntent.putExtra("bool", aBoolean);
setResult(RESULT_OK, resultIntent);
super.finish();
}
public static Bitmap stringToBitmap(String string) {
Bitmap bitmap = null;
try {
byte[] bitmapArray = Base64.decode(string.split(",")[1], Base64.DEFAULT);
bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0, bitmapArray.length);
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
public String account, password;
class CloudUser extends Thread {
public CloudUser() {
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
View v = getWindow().peekDecorView();
if (null != v) {
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
user_logs.this.account = binding.editUser.getText().toString();
gj.xcts(user_logs.this, "设置成功");
wl.setcookie(account);
finish();
// start();
}
@Override
public void run() {
super.run();
try {
String hq = wl.hq("/login/cellphone?phone=" + account + "&password=" + password);
if (TextUtils.isEmpty(hq)) {
return;
}
JSONObject jsonObject = new JSONObject(hq);
int code = jsonObject.getInt("code");
if (code == 200) {
JSONObject data = jsonObject.getJSONObject("profile");
String nickname = data.getString("nickname");//用户名
String avatarUrl = data.getString("avatarUrl");//用户头像
String signature = data.getString("signature");//用户签名
String cookie = jsonObject.getString("cookie");
String s = new Gson().toJson(new user_logs.USER(nickname, signature, avatarUrl));
wj.xrwb(wj.filesdri + "user.mq", s);
user_logs.this.finish(true);
} else if (code == 502) {
gj.xcts(user_logs.this, jsonObject.getString("message"));
} else {
gj.xcts(user_logs.this, "找不到此账号");
}
} catch (Exception e) {
gj.sc(e);
}
}
}
class erweima extends Thread {
int code = 800;
String unikey, qrimg, hq;
private long time = 0;
public erweima() {
binding.text1.setText("请使用网易云音乐扫码");
}
@Override
public void run() {
super.run();
while (code != 0 && !Thread.currentThread().isInterrupted()) {
gj.sc(code);
try {
hq = wl.hq("/login/qr/check?key=" + unikey + Time());
if (hq != null) {
JSONObject json = new JSONObject(hq);
code = json.getInt("code");
switch (code) {
case 800:
case 400:
setwb("二维码过期");
hqkey();
break;
case 801:
setwb("等待扫码");
break;
case 802:
setwb("等待确认");
break;
case 803:
setwb("登录成功");
wl.setcookie(json.getString("cookie"));
code = 0;
user_logs.this.finish(true);
break;
default:
code = 0;
// 默认情况下的操作
break;
}
}
sleep(1000);
} catch (Exception e) {
Thread.currentThread().interrupt();
gj.sc(e);
}
}
}
private void hqkey() throws Exception {
unikey = new JSONObject(Objects.requireNonNull(wl.hq("/login/qr/key"))).
getJSONObject("data").getString("unikey");
JSONObject jsonObject = new JSONObject(Objects.requireNonNull(wl.hq("/login/qr/create?key=" +
unikey +
"&qrimg=base64")));
qrimg = jsonObject.getJSONObject("data").getString("qrimg");
main.handler.post(() -> binding.image.setImageBitmap(user_logs.stringToBitmap(qrimg)));
}
private String Time() {
if (time < System.currentTimeMillis() - 1000) {
time = System.currentTimeMillis();
}
return "&timestamp" + time;
}
private void setwb(String wb) {
main.handler.post(() -> binding.text1.setText(wb));
}
}
}

View File

@ -0,0 +1,29 @@
package com.muqingbfq.login;
import android.content.Intent;
import androidx.appcompat.app.AppCompatActivity;
import com.muqingbfq.mq.wj;
import com.muqingbfq.mq.wl;
import com.muqingbfq.yc;
import org.json.JSONException;
import org.json.JSONObject;
public class visitor extends Thread {
public visitor() {
start();
}
@Override
public void run() {
super.run();
String hq = wl.hq("/register/anonimous");
try {
JSONObject jsonObject = new JSONObject(hq);
wl.setcookie(jsonObject.getString("cookie"));
} catch (Exception e) {
com.muqingbfq.mq.gj.sc(e);
}
}
}

View File

@ -0,0 +1,117 @@
package com.muqingbfq;
import android.annotation.SuppressLint;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ProcessLifecycleOwner;
import com.google.gson.reflect.TypeToken;
import com.muqingbfq.login.visitor;
import com.muqingbfq.mq.FloatingLyricsService;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wj;
import com.muqingbfq.mq.wl;
import java.io.File;
import java.lang.reflect.Type;
import java.util.List;
public class main extends Application {
public static Application application;
public static Handler handler = new Handler(Looper.getMainLooper());
public static String api = "https://api.csm.sayqz.com";
// public static String http = "https://www.muqingkaifazhe.top/muqingbfq.php"; 过时的更新检测
public static SharedPreferences sp;
public static SharedPreferences.Editor edit;
@Override
public void onCreate() {
super.onCreate();
if (wj.filesdri == null) {
new wj(this);
}
File file = new File(wj.filesdri + "API.mq");
if (file.exists() && file.isFile()) {
String dqwb = wj.dqwb(file.toString());
if (!TextUtils.isEmpty(dqwb) && dqwb.startsWith("http")) {
api = dqwb;
} else {
file.delete();
}
} else {
wj.xrwb(file.toString(), main.api);
}
application = this;
sp = getSharedPreferences("Set_up", MODE_PRIVATE);
edit = sp.edit();
boolean bj = false;
try {
com.muqingbfq.bfqkz.ms = sp.getInt("ms", 1);
} catch (Exception e) {
edit.putInt("ms", 1);
bj = true;
com.muqingbfq.bfqkz.ms = 1;
}
try {
wl.Cookie = sp.getString("Cookie", "");
} catch (Exception e) {
edit.putString("Cookie", "");
wl.Cookie = "";
bj = true;
}
if (bj) {
edit.commit();
}
wl.Cookie = main.sp.getString("Cookie", "");
if (wl.Cookie.isEmpty()) {
new visitor();
}
SharedPreferences theme = getSharedPreferences("theme", MODE_PRIVATE);
@SuppressLint("CommitPrefEdits") SharedPreferences.Editor edit = theme.edit();
int i = theme.getInt("theme", AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
if (i == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) {
edit.putInt("theme", AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
edit.apply();
}
AppCompatDelegate.setDefaultNightMode(i);
String jsonList = this.getSharedPreferences("list", Context.MODE_PRIVATE)
.getString("listData", null); // 获取保存的 JSON 字符串
if (jsonList != null) {
Type type = new TypeToken<List<MP3>>() {
}.getType();
bfqkz.list = new com.google.gson.Gson().fromJson(jsonList, type);
// JSON 字符串转换回列表数据
}
// bfqkz.xm = wj.getMP3FromFile();
// 注册 ProcessLifecycleOwner 以监听应用生命周期事件
ProcessLifecycleOwner.get().getLifecycle().addObserver(new DefaultLifecycleObserver() {
@Override
public void onStart(@Nullable LifecycleOwner owner) {
// 应用进入前台
gj.sc("onStart");
if (FloatingLyricsService.lei != null) {
stopService(new Intent(main.this, FloatingLyricsService.class));
}
}
@Override
public void onStop(@Nullable LifecycleOwner owner) {
// 应用进入后台
gj.sc("onStop");
if (Settings.canDrawOverlays(main.this) && FloatingLyricsService.lei == null ) {
startService(new Intent(main.this, FloatingLyricsService.class));
}
}
});
}
}

View File

@ -0,0 +1,65 @@
package com.muqingbfq.mq;
import android.content.res.Configuration;
import android.graphics.Color;
import android.os.Build;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import androidx.activity.EdgeToEdge;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.viewbinding.ViewBinding;
import com.muqingbfq.R;
public abstract class AppCompatActivity<ViewBindingType extends ViewBinding> extends androidx.appcompat.app.AppCompatActivity {
protected abstract ViewBindingType getViewBindingObject(LayoutInflater layoutInflater);
protected ViewBindingType getViewBinding() {
binding = getViewBindingObject(getLayoutInflater());
return binding;
}
public ViewBindingType binding;
public void setContentView() {
EdgeToEdge.enable(this);
super.setContentView(getViewBinding().getRoot());
// Window window = getWindow();
//// 请求进行全屏布局+更改状态栏字体颜色
// // 获取程序是不是夜间模式
// int uiMode = getApplicationContext().getResources().getConfiguration().uiMode;
// if ((uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES) {
//// SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION and SYSTEM_UI_FLAG_LAYOUT_STABLE请求进行全屏布局
//// SYSTEM_UI_FLAG_VISIBLE进行更改状态栏字体颜色
// window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_VISIBLE);//白色
// } else {
// window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);//黑色
//
// }
//// 让内容显示在系统栏的后面,也就是显示在状态栏和导航栏的后面
// WindowCompat.setDecorFitsSystemWindows(window, true);
//// 沉浸状态栏(给任务栏上透明的色)(Android 10 只需要将系统栏颜色设为完全透明即可:)
// window.setStatusBarColor(Color.TRANSPARENT);
// // 沉浸导航栏设置透明色
// window.setNavigationBarColor(Color.TRANSPARENT);
//
//// 在安卓10以上禁用系统栏视觉保护
//// 当设置了 导航栏 栏背景为透明时NavigationBarContrastEnforced 如果为true则系统会自动绘制一个半透明背景
//// 状态栏的StatusBarContrast 效果同理但是值默认为false因此不用设置
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// window.setNavigationBarContrastEnforced(false);
// }
ViewCompat.setOnApplyWindowInsetsListener(binding.getRoot(), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
// v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
v.setPadding(systemBars.left, systemBars.top, systemBars.right,0);
return insets;
});
}
}

View File

@ -0,0 +1,176 @@
package com.muqingbfq.mq;
import android.annotation.SuppressLint;
import android.content.Context;
import android.text.InputType;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.muqingbfq.R;
import com.muqingbfq.main;
public class EditViewDialog {
public EditText editText;
public Button buttona, buttonb;
public MaterialAlertDialogBuilder AlertDialogBuilder;
private AlertDialog alertDialog;
public EditViewDialog(@NonNull Context context, String str) {
AlertDialogBuilder = new MaterialAlertDialogBuilder(context);
setTitle(str);
@SuppressLint("InflateParams") View inflate = LayoutInflater.from(context).inflate(R.layout.view_edit, null);
editText = inflate.findViewById(R.id.editview);
buttona = inflate.findViewById(R.id.button1);
buttonb = inflate.findViewById(R.id.button2);
AlertDialogBuilder.setView(inflate);
buttona.setOnClickListener(view -> dismiss());
buttonb.setOnClickListener(view -> dismiss());
}
public EditViewDialog setTitle(String str) {
AlertDialogBuilder.setTitle(str);
return this;
}
public EditViewDialog setMessage(String str) {
AlertDialogBuilder.setMessage(str);
return this;
}
public AlertDialog show() {
alertDialog = AlertDialogBuilder.show();
alertDialog.setCancelable(true);
alertDialog.setCanceledOnTouchOutside(false);
return alertDialog;
}
public String getEditText() {
return editText.getText().toString();
}
public EditViewDialog setEditinputType(String str) {
int inputType;
switch (str) {
case "textCapCharacters":
inputType = InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS;
break;
case "textCapWords":
inputType = InputType.TYPE_TEXT_FLAG_CAP_WORDS;
break;
case "textCapSentences":
inputType = InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
break;
case "textAutoCorrect":
inputType = InputType.TYPE_TEXT_FLAG_AUTO_CORRECT;
break;
case "textAutoComplete":
inputType = InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE;
break;
case "textMultiLine":
inputType = InputType.TYPE_TEXT_FLAG_MULTI_LINE;
break;
case "textImeMultiLine":
inputType = InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE;
break;
case "textNoSuggestions":
inputType = InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
break;
case "textUri":
inputType = InputType.TYPE_TEXT_VARIATION_URI;
break;
case "textEmailAddress":
inputType = InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
break;
case "textEmailSubject":
inputType = InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT;
break;
case "textShortMessage":
inputType = InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE;
break;
case "textLongMessage":
inputType = InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE;
break;
case "textPersonName":
inputType = InputType.TYPE_TEXT_VARIATION_PERSON_NAME;
break;
case "textPostalAddress":
inputType = InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS;
break;
case "textPassword":
inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD;
break;
case "textVisiblePassword":
inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
break;
case "textWebEditText":
inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT;
break;
case "textFilter":
inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_FILTER;
break;
case "textPhonetic":
inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PHONETIC;
break;
case "number":
inputType = InputType.TYPE_CLASS_NUMBER;
break;
case "numberSigned":
inputType = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED;
break;
case "numberDecimal":
inputType = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL;
break;
case "phone":
inputType = InputType.TYPE_CLASS_PHONE;
break;
case "datetime":
inputType = InputType.TYPE_CLASS_DATETIME;
break;
case "date":
inputType = InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_DATE;
break;
case "time":
inputType = InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_TIME;
break;
case "none":
case "text":
default:
inputType = InputType.TYPE_CLASS_TEXT;
break;
}
editText.setInputType(inputType);
return this;
}
public void dismiss() {
main.handler.post(() -> alertDialog.dismiss());
}
/**
* 取消按钮
* @param a
*/
public void setNegative(View.OnClickListener a) {
buttona.setOnClickListener(a);
}
/**
* 确定按钮
* @param a
* @return
*/
public EditViewDialog setPositive(View.OnClickListener a) {
buttonb.setOnClickListener(a);
return this;
}
public interface OnClickListener extends View.OnClickListener {
@Override
void onClick(View view);
}
}

View File

@ -0,0 +1,242 @@
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.util.TypedValue;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import androidx.annotation.Nullable;
import com.dirror.lyricviewx.LyricEntry;
import com.dirror.lyricviewx.LyricViewX;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.muqingbfq.PlaybackService;
import com.muqingbfq.bfqkz;
import com.muqingbfq.databinding.FloatLrcviewBinding;
import java.io.File;
import java.lang.reflect.Type;
public class FloatingLyricsService extends Service {
private WindowManager windowManager;
FloatLrcviewBinding binding;
public Runnable updateSeekBar = new Runnable() {
@Override
public void run() {
if (PlaybackService.mediaSession == null || LyricViewX.lyricEntryList.isEmpty()) {
handler.postDelayed(this, 1000);
return;
}
int index = 0;
for (int i = 0; i < LyricViewX.lyricEntryList.size(); i++) {
LyricEntry lineLrc = LyricViewX.lyricEntryList.get(i);
if (lineLrc.time <= PlaybackService.mediaSession.getPlayer().getCurrentPosition()) {
index = i;
} else {
break;
}
}
if (index < LyricViewX.lyricEntryList.size()) {
LyricEntry currentLrc = LyricViewX.lyricEntryList.get(index);
binding.lrcView.setText(currentLrc.text);
if (currentLrc.secondText != null) {
binding.lrcViewMessage.setText(currentLrc.secondText);
} else {
binding.lrcViewMessage.setText("");
}
}
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<SETUP>() {
}.getType();
SETUP setup = gson.fromJson(dqwb, type);
return setup.i != 0;
} else {
return false;
}
}
Handler handler = new Handler();
WindowManager.LayoutParams params;
public static class SETUP {
//0是关闭 1是打开 2是锁定
public int i = 1, size = 20;
public float Alpha = 0.9f;
public String Color = "#0088FF";
public int Y = 0;
}
public SETUP setup = new SETUP();
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;
}
private int initialY;
private float initialTouchY;
@Override
public void onCreate() {
super.onCreate();
lei = this;
try {
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<SETUP>() {
}.getType();
setup = gson.fromJson(dqwb, type);
} else {
setup = new SETUP();
}
if (setup.i == 0) {
//在Service中关闭自己
stopSelf();
return;
}
// 创建悬浮窗歌词的 View
// FloatLrcviewBinding
binding = FloatLrcviewBinding.inflate(LayoutInflater.from(this));
// binding.getRoot().setOnTouchListener(this);
// 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;
binding.getRoot().setAlpha(setup.Alpha);
float v = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
setup.size,
getResources().getDisplayMetrics());
binding.lrcView.setTextSize(v);
binding.lrcView.setTextColor(Color.parseColor(setup.Color));
binding.lrcViewMessage.setTextSize(v - 1.0f);
binding.lrcViewMessage.setTextColor(Color.parseColor(setup.Color));
binding.lock.setColorFilter(Color.BLACK);
binding.lock.setOnClickListener(v1 -> setyc());
// params.gravity = Gravity.CENTER;
// 获取 WindowManager 并将悬浮窗歌词添加到窗口中
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
windowManager.addView(binding.getRoot(), params);
if (setup.i == 2) {
setyc();
} else {
show();
}
handler.post(updateSeekBar); // 在播放开始时启动更新进度
} catch (Exception e) {
wj.sc(wj.filesdri + "FloatingLyricsService.json");
gj.sc(getClass() + ":" + e);
}
}
@Override
public void onDestroy() {
super.onDestroy();
// Service.stopSelf();
// Service 销毁时移除悬浮窗歌词
if (windowManager != null && binding != null) {
windowManager.removeView(binding.getRoot());
handler.removeCallbacks(updateSeekBar); // 在播放开始时启动更新进度
}
lei = null;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
public void baocun() {
wj.xrwb(new File(wj.filesdri + "FloatingLyricsService.json").toString(),
new Gson().toJson(setup));
}
public static void baocun(SETUP setup) {
if (setup == null) {
return;
}
wj.xrwb(new File(wj.filesdri + "FloatingLyricsService.json").toString(),
new Gson().toJson(setup));
}
@SuppressLint("ClickableViewAccessibility")
public void setyc() {
setup.i = 2;
params.flags = lock();
binding.lock.setVisibility(View.GONE);
binding.getRoot().setCardBackgroundColor(Color.parseColor("#00FFFFFF"));
binding.getRoot().setOnTouchListener(null);
params.type = Build.VERSION.SDK_INT < Build.VERSION_CODES.O ?
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT : WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
//将alpha设置为最大遮挡不透明度
params.alpha = 0.8f;
windowManager.updateViewLayout(binding.getRoot(), params);
baocun();
}
@SuppressLint({"CheckResult", "ClickableViewAccessibility"})
public void show() {
setup.i = 1;
params.flags = lock();
binding.lock.setVisibility(View.VISIBLE);
binding.getRoot().setCardBackgroundColor(Color.parseColor("#FFFFFF"));
binding.getRoot().setOnTouchListener((v12, event) -> {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 获取初始Y位置和初始触摸Y坐标
initialY = params.y;
initialTouchY = event.getRawY();
return true;
case MotionEvent.ACTION_MOVE:
// 手指在Y轴移动时计算新的Y位置
params.y = initialY + (int) (event.getRawY() - initialTouchY);
// 更新悬浮窗的Y轴位置
setup.Y = params.y;
windowManager.updateViewLayout(binding.getRoot(), params);
return true;
}
return true;
});
windowManager.updateViewLayout(binding.getRoot(), params);
baocun();
}
}

View File

@ -0,0 +1,27 @@
package com.muqingbfq.mq;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.viewbinding.ViewBinding;
public abstract class Fragment<Binding extends ViewBinding> extends androidx.fragment.app.Fragment {
protected abstract Binding inflateViewBinding(LayoutInflater inflater,ViewGroup container);
public Binding binding;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding=inflateViewBinding(inflater,container);
setUI(inflater, container, savedInstanceState);
return binding.getRoot();
}
public abstract void setUI(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState);
}

View File

@ -0,0 +1,60 @@
package com.muqingbfq.mq;
import android.view.MenuItem;
import android.view.View;
import androidx.activity.EdgeToEdge;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.viewbinding.ViewBinding;
import com.muqingbfq.R;
public abstract class FragmentActivity<ViewBindingType extends ViewBinding>
extends AppCompatActivity<ViewBindingType> {
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
}
return super.onOptionsItemSelected(item);
}
public void setToolbar() {
View viewById = findViewById(R.id.toolbar);
if (viewById != null) {
setSupportActionBar((Toolbar) viewById);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
}
@Override
public void setContentView() {
EdgeToEdge.enable(this);
super.setContentView(getViewBinding().getRoot());
ViewCompat.setOnApplyWindowInsetsListener(binding.getRoot(), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, 0, systemBars.right, systemBars.bottom);
return insets;
});
setToolbar();
}
public void onBack() {
// getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
// @Override
// public void handleOnBackPressed() {
// if (binding.searchview.isShowing()) {
// binding.searchview.hide();
// return;
// }
// moveTaskToBack(true);
// }
// });
}
}

View File

@ -0,0 +1,13 @@
package com.muqingbfq.mq;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class MusicViewModel extends ViewModel {
private MutableLiveData<String> imageUrl = new MutableLiveData<>();
public MutableLiveData<String> getImageUrl() {
return imageUrl;
}
}

View File

@ -0,0 +1,13 @@
package com.muqingbfq.mq;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewbinding.ViewBinding;
public class RecyclerAdapter {
}

View File

@ -0,0 +1,16 @@
package com.muqingbfq.mq;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewbinding.ViewBinding;
public class VH<bind extends ViewBinding> extends RecyclerView.ViewHolder {
public bind binding;
public VH(bind itemView) {
super(itemView.getRoot());
binding = itemView;
}
}

View File

@ -0,0 +1,170 @@
package com.muqingbfq.mq;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.Service;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.net.Uri;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.muqingbfq.main;
import com.muqingbfq.yc;
import org.json.JSONObject;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Collections;
import java.util.List;
public class gj {
public static void ts(Context a, Object b) {
Toast.makeText(a, b.toString(), Toast.LENGTH_SHORT).show();
}
public static void xcts(Context context, Object b) {
main.handler.post(() -> Toast.makeText(context, b.toString(), Toast.LENGTH_SHORT).show());
}
public static boolean isAppInForeground(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Service.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> runningAppProcessInfoList = activityManager.getRunningAppProcesses();
if (runningAppProcessInfoList == null) {
Log.d("runningAppProcess:", "runningAppProcessInfoList is null!");
return false;
}
for (ActivityManager.RunningAppProcessInfo processInfo : runningAppProcessInfoList) {
if (processInfo.processName.equals(context.getPackageName()) && (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND)) {
return true;
}
}
return false;
}
/**
* 判断是否是平板
* @param context
* @return
*/
public static boolean isTablet(Context context) {
DisplayMetrics dm = context.getResources().getDisplayMetrics();
return dm.widthPixels > dm.heightPixels;
}
public static int getThemeColor(Context context, int id) {
TypedValue typedValue = new TypedValue();
if (context.getTheme().resolveAttribute(id, typedValue, true)) {
return typedValue.data;
} else {
return -1;
}
}
public static void sc(Object a) {
if (a == null) {
a = "null";
}
Log.d("打印", a.toString());
}
public static void llq(Context context, String str) {
context.startActivity(new Intent(context, llq.class).putExtra("url", str));
}
public static void fx(Context context, String str) {
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, str);
context.startActivity(shareIntent);
}
/**
* 复制文字到剪切板
*/
public static void fz(Context context, String text) {
ClipboardManager systemService =
(ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
// 创建能够存入剪贴板的ClipData对象
//Label这是任意文字标签
ClipData mClipData = ClipData.newPlainText("Label", text);
//将ClipData数据复制到剪贴板
systemService.setPrimaryClip(mClipData);
gj.ts(context, "复制成功");
}
public static boolean isWiFiConnected() {
try {
for (NetworkInterface networkInterface : Collections.list(NetworkInterface.getNetworkInterfaces())) {
if (networkInterface.isUp() && !networkInterface.isLoopback()) {
if (networkInterface.getDisplayName().contains("wlan")) {
return true; // Wi-Fi网络
} else if (networkInterface.getDisplayName().contains("rmnet")) {
return false; // 流量网络
}
}
}
} catch (SocketException e) {
gj.sc(e);
}
return false; // 默认为流量网络
}
public static void tcjp(EditText editText) {
editText.requestFocus();//获取焦点
InputMethodManager imm = (InputMethodManager)
editText.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
// gj.sc(imm.isActive());
//没有显示键盘弹出
imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
}
public static void ycjp(EditText editText) {
InputMethodManager imm = (InputMethodManager)
editText.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isActive()) //有显示键盘隐藏
imm.hideSoftInputFromWindow(editText.getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
}
public static int getztl(Context context) {
// 获得状态栏高度
@SuppressLint({"InternalInsetResource", "DiscouragedApi"}) int resourceId =
context.getResources().
getIdentifier("status_bar_height", "dimen", "android");
return context.getResources().getDimensionPixelSize(resourceId);
}
public static int getbackgroundColor(AppCompatActivity appCompatActivity) {
TypedArray array = appCompatActivity.getTheme().obtainStyledAttributes(new int[]{
android.R.attr.colorBackground
// android.R.attr.textColorPrimary,
});
int backgroundColor = array.getColor(0, 0xFF00FF);
// int textColor = array.getColor(1, 0xFF00FF);
array.recycle();
return backgroundColor;
}
/**
* dp转px
* @param context
* @param dpValue
*/
public static int dp2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}

View File

@ -0,0 +1,217 @@
package com.muqingbfq.mq;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.muqingbfq.R;
import com.muqingbfq.databinding.ActivityLlqBinding;
import com.muqingbfq.databinding.ViewDownloadBinding;
import com.muqingbfq.main;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Locale;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class llq extends AppCompatActivity<ActivityLlqBinding> {
WebView web;
@Override
protected ActivityLlqBinding getViewBindingObject(LayoutInflater layoutInflater) {
return ActivityLlqBinding.inflate(layoutInflater);
}
@SuppressLint("SetJavaScriptEnabled")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView();
Intent intent = getIntent();
setSupportActionBar(binding.toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
web = binding.webview;
web.getSettings().setJavaScriptEnabled(true);
web.getSettings().setDomStorageEnabled(true);
// 禁用缓存
web.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
web.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
setTitle(web.getTitle());
// 在这里获取到了网页的标题
}
});
web.setDownloadListener((url1, userAgent, contentDisposition, mimetype, contentLength) -> {
String size = "0B";
if (contentLength > 0) {
final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"};
int digitGroups = (int) (Math.log10(contentLength) / Math.log10(1024));
size = String.format(Locale.getDefault(), "%.1f %s", contentLength
/ Math.pow(1024, digitGroups), units[digitGroups]);
}
final String filename = url1.substring(url1.lastIndexOf('/') + 1);
new MaterialAlertDialogBuilder(llq.this)
.setTitle(filename)
.setMessage("文件链接:" + url1 +
"\n文件大小" + size)
.setNegativeButton("取消", null)
.setNegativeButton("下载", (dialogInterface, i) -> {
// 检查权限
if (ContextCompat.checkSelfPermission(llq.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
// 如果没有写入存储的权限则请求权限
ActivityCompat.requestPermissions(llq.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
1);
} else {
ViewDownloadBinding inflate = ViewDownloadBinding.inflate(getLayoutInflater());
AlertDialog show = new MaterialAlertDialogBuilder(llq.this)
.setTitle(String.format(Locale.getDefault()
, "文件名称:%s", filename))
.setMessage(String.format(Locale.getDefault()
, "下载路径:%s", Environment.
getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()))
.setView(inflate.getRoot())
.show();
OkHttpClient okHttpClient = new OkHttpClient();
Request build = new Request.Builder()
.url(url1)
.build();
okHttpClient.newCall(build).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
InputStream inputStream = response.body().byteStream();
long l = response.body().contentLength();
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(),
filename);
FileOutputStream fileOutputStream = null;
try {
int read;
fileOutputStream = new FileOutputStream(file);
byte[] bytes = new byte[2048];
long downloadedSize = 0;
while ((read = inputStream.read(bytes)) != -1) {
fileOutputStream.write(bytes, 0, read);
downloadedSize += read;
int progress = (int) ((100 * downloadedSize) / l);
main.handler.post(() -> inflate.textview.setText(
String.format(Locale.getDefault(),
"%d%%", progress)));
}
fileOutputStream.close();
} catch (Exception e) {
gj.sc(e);
} finally {
if (fileOutputStream != null) {
fileOutputStream.close();
}
}
main.handler.post(() -> {
gj.ts(llq.this, "下载完成");
show.dismiss();
});
}
});
}
}).show();
});
web.setWebChromeClient(new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
if (newProgress == 100) {
binding.webViewProgressBar.setVisibility(View.GONE);
} else {
binding.webViewProgressBar.setProgress(newProgress);
if (!binding.webViewProgressBar.isShown()) {
binding.webViewProgressBar.setVisibility(View.VISIBLE);
}
}
}
});
loadUrl(intent.getStringExtra("url"));
}
private void loadUrl(String url) {
web.loadUrl(url);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1 && grantResults.length > 0 &&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 权限已授予执行文件下载操作
gj.ts(this, "权限已授予,请重新执行文件下载操作");
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.llq, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public void onBackPressed() {
if (web.canGoBack()) {
web.goBack();
} else {
finish();
}
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
int itemId = item.getItemId();
if (itemId == android.R.id.home) {
finish();
} else if (itemId == R.id.fx) {
gj.fx(this, web.getUrl());
// 服务中心
} else if (itemId == R.id.sx) {
web.reload();
} else if (itemId == R.id.menu_web) {
startActivity(new Intent(Intent.ACTION_VIEW,
Uri.parse(web.getUrl())));
}
return super.onOptionsItemSelected(item);
}
}

View File

@ -0,0 +1,237 @@
package com.muqingbfq.mq;
import static androidx.core.content.ContextCompat.startActivity;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.provider.Settings;
import android.util.Log;
import androidx.core.app.ActivityCompat;
import com.google.gson.Gson;
import com.muqingbfq.MP3;
import com.muqingbfq.home;
import com.muqingbfq.yc;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class wj {
public static String filesdri;
public static String mp3 = "mp3/";
public static String lishi_json = "lishi.json";
public static String gd = "gd/";
public static String tx = "image/";
public static String gd_json = "gd.json", gd_xz = "gd_xz.json",
gd_phb = "gd_phb.json", mp3_like = "mp3_like.json";
public wj(Context context) {
try {
wj.filesdri = context.getExternalFilesDir("").getAbsolutePath() + "/";
// context.getFilesDir().toString() + "/";
gd_json = filesdri + gd_json;
mp3 = filesdri + mp3;
gd = filesdri + gd;
gd_xz = filesdri + gd_xz;
gd_phb = filesdri + gd_phb;
mp3_like = gd + mp3_like;
tx = filesdri + tx;
} catch (Exception e) {
yc.start(context, e);
}
}
/*
* 这里定义的是一个文件保存的方法写入到文件中所以是输出流
* */
public static boolean xrwb(String url, String text) {
if (text == null) {
text = "";
}
File file = new File(url);
//如果文件不存在创建文件
try {
File parentFile = file.getParentFile();
if (!parentFile.isDirectory()) {
parentFile.mkdirs();
}
if (!file.exists())
file.createNewFile();
//创建FileOutputStream对象写入内容
FileOutputStream fos = new FileOutputStream(file);
//向文件中写入内容
fos.write(text.getBytes());
fos.close();
} catch (Exception e) {
gj.sc(e);
}
return false;
}
public static String dqwb(String url) {
try {
File file = new File(url);
if (!file.exists()) {
return null;
}
FileInputStream fis = new FileInputStream(file);
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
StringBuilder str = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
str.append(line);
}
br.close();
fis.close();
return str.toString();
} catch (Exception e) {
gj.sc(e);
}
return null;
}
public static boolean cz(String url) {
return new File(url).exists();
}
public static boolean sc(String url) {
File file = new File(url);
return file.delete();
}
public static void sc(File url) {
if (url.exists()) {
File[] files = url.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
// 递归调用删除子文件夹及其内容
sc(file);
} else {
file.delete(); // 删除文件
}
}
}
url.delete(); // 删除当前文件夹
}
}
public String convertToMd5(String url) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] messageDigest = md.digest(url.getBytes());
StringBuilder hexString = new StringBuilder();
for (byte value : messageDigest) {
String hex = Integer.toHexString(0xFF & value);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
public static void fz(String sourceFilePath, String targetFilePath) {
File sourceFile = new File(sourceFilePath);
File targetFile = new File(targetFilePath);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
try (InputStream in = Files.newInputStream(sourceFile.toPath());
OutputStream out = Files.newOutputStream(targetFile.toPath())) {
byte[] buf = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(buf)) > 0) {
out.write(buf, 0, bytesRead);
}
// 文件复制完成
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 保存MP3对象到文件
public static void setMP3ToFile(MP3 mp3) {
if (mp3 == null) {
return;
}
Gson gson = new Gson();
String json = gson.toJson(mp3);
xrwb(filesdri + "mp3.dat", json);
}
// 从文件中加载MP3对象
public static MP3 getMP3FromFile() {
Gson gson = new Gson();
MP3 mp3 = null;
try {
File file = new File(filesdri + "mp3.dat");
if (file.exists() && file.length() > 0) {
FileReader reader = new FileReader(file);
mp3 = gson.fromJson(reader, MP3.class);
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
return mp3;
}
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
public static boolean isCD(Activity context) {
//检查权限NEED_PERMISSION是否被授权 PackageManager.PERMISSION_GRANTED表示同意授权
if (Build.VERSION.SDK_INT >= 30) {
if (!Environment.isExternalStorageManager()) {
Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
context.startActivity(intent);
} else {
Log.i("swyLog", "Android 11以上当前已有权限");
return true;
}
} else {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
PackageManager.PERMISSION_GRANTED) {
//申请权限
ActivityCompat.requestPermissions(context
, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
} else {
Log.i("swyLog", "Android 6.0以上11以下当前已有权限");
return true;
}
} else {
Log.i("swyLog", "Android 6.0以下,已获取权限");
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,118 @@
package com.muqingbfq.mq;
import android.content.Context;
import androidx.annotation.OptIn;
import androidx.media3.common.MediaItem;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.database.DatabaseProvider;
import androidx.media3.database.StandaloneDatabaseProvider;
import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.cache.Cache;
import androidx.media3.datasource.cache.CacheDataSource;
import androidx.media3.datasource.cache.LeastRecentlyUsedCacheEvictor;
import androidx.media3.datasource.cache.SimpleCache;
import com.muqingbfq.main;
import java.io.File;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class wl {
public static String Cookie;
public static void setcookie(String cookie) {
wl.Cookie = cookie;
main.edit.putString("Cookie", cookie);
main.edit.commit();
}
public static String hq(String url) {
try {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(main.api + url)
.build();
Response response = client.newCall(request).execute();
if (response.body() != null) {
return response.body().string();
}
} catch (Exception e) {
gj.sc("wl hq(Strnig) " + e);
}
return null;
}
public static String post(String str, String[][] a) {
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
// MediaType mediaType = MediaType.parse("text/plain");
MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
for (String[] b : a) {
builder.addFormDataPart(b[0], b[1]);
}
builder.addFormDataPart("cookie", Cookie);
Request request = new Request.Builder()
.url(main.api + str)
.method("POST", builder.build())
.addHeader("User-Agent", "Apifox/1.0.0 (https://apifox.com)")
.addHeader("Accept", "*/*")
.addHeader("Host", "139.196.224.229:3000")
.addHeader("Connection", "keep-alive")
.build();
try {
Response response = client.newCall(request).execute();
if (response.body() != null) {
return response.body().string();
}
} catch (Exception e) {
gj.sc(e);
}
return null;
}
public static String get(String url) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.build();
try {
Response response = client.newCall(request).execute();
if (response.body() != null) {
return response.body().string();
}
} catch (Exception e) {
gj.sc("wl get(Strnig) " + e);
}
return null;
}
@OptIn(markerClass = UnstableApi.class)
public static DataSource.Factory DownMp3() {
Context context = main.application;
DatabaseProvider databaseProvider = new StandaloneDatabaseProvider(context);
// 创建一个 File 对象来指定缓存目录
File downloadDirectory = new File(wj.mp3);
// 如果缓存目录不存在则创建它
if (!downloadDirectory.exists()) {
downloadDirectory.mkdirs();
}
Cache cache =
new SimpleCache(
downloadDirectory, new LeastRecentlyUsedCacheEvictor(100 * 1024 * 1024), databaseProvider);
CacheDataSource.Factory httpDataSourceFactory = new CacheDataSource.Factory();
return new CacheDataSource.Factory()
.setCache(cache)
.setUpstreamDataSourceFactory(httpDataSourceFactory);
}
}

View File

@ -0,0 +1,274 @@
package com.muqingbfq;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.Fragment;
import androidx.media3.common.Player;
import com.colorpicker.ColorPickerView;
import com.colorpicker.builder.ColorPickerDialogBuilder;
import com.dirror.lyricviewx.LyricEntry;
import com.dirror.lyricviewx.LyricViewX;
import com.google.android.material.slider.Slider;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.muqingbfq.databinding.ActivitySzBinding;
import com.muqingbfq.databinding.ActivitySzSetlrcBinding;
import com.muqingbfq.mq.AppCompatActivity;
import com.muqingbfq.mq.FloatingLyricsService;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wj;
import java.io.File;
import java.lang.reflect.Type;
public class sz extends AppCompatActivity<ActivitySzBinding> {
@Override
protected ActivitySzBinding getViewBindingObject(LayoutInflater layoutInflater) {
return ActivitySzBinding.inflate(layoutInflater);
}
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView();
ViewCompat.setOnApplyWindowInsetsListener(binding.getRoot(), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
// v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
setSupportActionBar(binding.toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setTitle(getString(R.string.sz));
SharedPreferences theme = getSharedPreferences("theme", MODE_PRIVATE);
@SuppressLint("CommitPrefEdits") SharedPreferences.Editor edit = theme.edit();
int i = theme.getInt("theme", AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
if (i == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) {
binding.switchA1.setChecked(true);
binding.switchA2.setEnabled(false);
} else {
binding.switchA1.setChecked(false);
binding.switchA2.setEnabled(true);
binding.switchA2.setChecked(i == AppCompatDelegate.MODE_NIGHT_YES);
}
binding.switchA1.setOnCheckedChangeListener((compoundButton, b) -> {
if (b) {
// 跟随系统设置切换颜色模式
int ms = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM;
AppCompatDelegate.setDefaultNightMode(ms);
edit.putInt("theme", ms);
edit.apply();
}
binding.switchA2.setEnabled(!b);
});
binding.switchA2.setOnCheckedChangeListener((compoundButton, b) -> {
if (compoundButton.isEnabled()) {
int ms;
if (b) {
ms = AppCompatDelegate.MODE_NIGHT_YES;
} else {
ms = AppCompatDelegate.MODE_NIGHT_NO;
}
AppCompatDelegate.setDefaultNightMode(ms);
edit.putInt("theme", ms);
edit.commit();
}
});
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
}
return super.onOptionsItemSelected(item);
}
public static class setlrc extends Fragment implements Slider.OnSliderTouchListener, Slider.OnChangeListener {
ActivitySzSetlrcBinding binding;
ActivityResultLauncher<Intent> LyricsService = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
if (Settings.canDrawOverlays(getContext())) {
// getContext().startService(new Intent(getContext(), FloatingLyricsService.class));
binding.switchA3.setChecked(true);
binding.slide1.setEnabled(true);
} else {
binding.switchA3.setChecked(false);
binding.slide1.setEnabled(false);
}
UI();
});
FloatingLyricsService.SETUP setup;
Handler handler = new Handler();
private Runnable ThreadLrc = new Runnable() {
@Override
public void run() {
if (PlaybackService.mediaSession == null) {
handler.postDelayed(this, 1000);
return;
}
Player player = PlaybackService.mediaSession.getPlayer();
int index = 0;
for (int i = 0; i < LyricViewX.lyricEntryList.size(); i++) {
LyricEntry lineLrc = LyricViewX.lyricEntryList.get(i);
gj.sc(player.getCurrentPosition());
if (lineLrc.time <= player.getCurrentPosition()) {
index = i;
} else {
break;
}
}
if (index < LyricViewX.lyricEntryList.size()) {
LyricEntry currentLrc = LyricViewX.lyricEntryList.get(index);
if (currentLrc.secondText != null) {
binding.lrcViewMessage.setText(currentLrc.secondText);
} else {
binding.lrcViewMessage.setText("");
}
binding.lrcView.setText(currentLrc.text);
}
handler.postDelayed(this, 1000);
}
};
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding = ActivitySzSetlrcBinding.inflate(inflater, container, false);
UI();
return binding.getRoot();
}
private void UI() {
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<FloatingLyricsService.SETUP>() {
}.getType();
binding.slide1.setEnabled(true);
setup = gson.fromJson(dqwb, type);
binding.slide1.setValue(setup.size);
binding.lrcView.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, setup.size, getResources().getDisplayMetrics()));
binding.lrcView.setTextColor(Color.parseColor(setup.Color));
binding.lrcViewMessage.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, setup.size, getResources().getDisplayMetrics()) - 1.0f);
binding.lrcViewMessage.setTextColor(Color.parseColor(setup.Color));
binding.lrclin.setOnClickListener(view -> ColorPickerDialogBuilder.with(view.getContext()).setTitle("调色盘").initialColor(Color.parseColor(setup.Color)).wheelType(ColorPickerView.WHEEL_TYPE.FLOWER).density(6).setOnColorSelectedListener(selectedColor -> {
}).setPositiveButton("确定", (dialog, selectedColor, allColors) -> {
setup.Color = String.format("#%08X", selectedColor);
binding.lrcView.setTextColor(selectedColor);
binding.lrcViewMessage.setTextColor(selectedColor);
FloatingLyricsService.baocun(setup);
}).setNegativeButton("取消", null).build().show());
binding.textSlide1.setText(String.valueOf(setup.size));
if (setup.i != 0) {
binding.switchA3.setChecked(true);
}
binding.lock.setVisibility(View.VISIBLE);
binding.lock.setImageResource(setup.i == 2 ? R.drawable.lock : R.drawable.lock_open);
handler.post(ThreadLrc);
} else {
binding.lock.setVisibility(View.GONE);
}
binding.switchA3.setOnCheckedChangeListener((compoundButton, b) -> {
if (b) {
if (setup != null) {
setup.i = 1;
}
if (!Settings.canDrawOverlays(getContext())) {
// 无权限需要申请权限
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getContext().getPackageName()));
LyricsService.launch(intent);
} else {
getContext().startService(new Intent(getContext(), FloatingLyricsService.class));
}
} else {
if (setup != null) {
setup.i = 0;
}
main.application.stopService(new Intent(main.application, FloatingLyricsService.class));
}
FloatingLyricsService.baocun(setup);
});
//强制跳转到权限界面
binding.switchA3.setOnLongClickListener(v -> {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getContext().getPackageName()));
LyricsService.launch(intent);
return false;
});
binding.slide1.setLabelFormatter(value -> String.valueOf((int) value));
binding.slide1.addOnChangeListener(this);
binding.slide1.addOnChangeListener(this);
binding.slide1.addOnSliderTouchListener(this);
binding.lock.setOnClickListener(view -> {
if (setup.i == 1) {
setup.i = 2;
binding.lock.setImageResource(R.drawable.lock);
} else if (setup.i == 2) {
setup.i = 1;
binding.lock.setImageResource(R.drawable.lock_open);
}
FloatingLyricsService.baocun(setup);
});
}
@Override
public void onDestroy() {
super.onDestroy();
handler.removeCallbacks(ThreadLrc);
}
@Override
public void onStartTrackingTouch(@NonNull Slider slider) {
}
@Override
public void onStopTrackingTouch(@NonNull Slider slider) {
if (setup == null) {
return;
}
FloatingLyricsService.baocun(setup);
}
@Override
public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) {
if (setup == null) {
return;
}
if (slider == binding.slide1) {
setup.size = (int) value;
float v = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, setup.size, getResources().getDisplayMetrics());
binding.lrcView.setTextSize(v);
binding.lrcViewMessage.setTextSize(v - 1.0f);
binding.textSlide1.setText(String.valueOf(setup.size));
}
}
}
}

View File

@ -0,0 +1,55 @@
package com.muqingbfq.view;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.google.android.material.card.MaterialCardView;
import com.muqingbfq.R;
public class CardImage extends MaterialCardView {
public ImageView imageView;
public CardImage(Context context) {
super(context);
start();
}
public CardImage(Context context, AttributeSet attrs) {
super(context, attrs);
start();
}
public CardImage(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
start();
}
public void start() {
imageView = new ImageView(getContext());
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
addView(imageView);
imageView.setImageResource(R.drawable.ic_launcher_foreground);
}
public void setImage(Object bitmap) {
try {
Glide.with(this)
.load(bitmap)
.error(R.drawable.ic_launcher_foreground)
.into(imageView);
} catch (Exception e) {
e.printStackTrace();
}
}
public void setImageapply(Object bitmap) {
Glide.with(getContext())
.load(bitmap)
.apply(new RequestOptions().placeholder(R.drawable.ic_launcher_foreground))
// .error(R.drawable.app_warning)
.into(imageView);
}
}

View File

@ -0,0 +1,168 @@
package com.muqingbfq.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
import android.text.Editable;
import android.text.NoCopySpan;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import com.google.android.material.textfield.TextInputLayout;
import com.muqingbfq.R;
public class Edit extends LinearLayout {
public Edit(@NonNull Context context) {
super(context);
initView();
}
AttributeSet attrs;
public Edit(Context context, AttributeSet attrs) {
super(context, attrs);
this.attrs=attrs;
initView();
}
public Edit(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.attrs=attrs;
initView();
}
ImageView chahao;
public EditText editText;
private void initView() {
TextInputLayout layout = new TextInputLayout(getContext());
// layout.clearIconDrawable
setGravity(Gravity.CENTER_VERTICAL);
setBackgroundResource(R.drawable.ui_editview);
setPadding(30, 0, 30, 0);
//构建编辑框
editText = new EditText(getContext());
editText.setHint("搜索");
editText.setSingleLine(true);
editText.setBackground(null);
editText.setTransitionName("edit");
Drawable startIcon = ContextCompat.getDrawable(getContext(), R.drawable.sousuo);
startIcon.setTint(ContextCompat.getColor(getContext(),
R.color.text_tm));
Drawable endIcon = ContextCompat.getDrawable(getContext(), R.drawable.chahao);
editText.setCompoundDrawablesRelativeWithIntrinsicBounds(startIcon, null, endIcon, null);
editText.setImeOptions(EditorInfo.IME_ACTION_SEARCH);
// editText.passwordToggleEnabled
addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence var1, int var2, int var3, int var4) {
}
@Override
public void onTextChanged(CharSequence var1, int var2, int var3, int var4) {
iskong();
}
@Override
public void afterTextChanged(Editable var1) {
}
});
ImageView imageView = new ImageView(getContext());
imageView.setImageResource(R.drawable.sousuo);
addView(imageView, (int) TypedValue.applyDimension(TypedValue.
COMPLEX_UNIT_DIP, 26, getResources().getDisplayMetrics())
, (int) TypedValue.applyDimension(TypedValue.
COMPLEX_UNIT_DIP, 26, getResources().getDisplayMetrics()));
LayoutParams layoutParams = new LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.weight = 1;
layoutParams.gravity = Gravity.CENTER;
addView(editText, layoutParams);
chahao = new ImageView(getContext());
chahao.setImageResource(R.drawable.chahao);
Drawable rippleDrawable = new RippleDrawable(
ContextCompat.getColorStateList(getContext(),R.color.bj),
chahao.getBackground(),
null
);
chahao.setBackground(rippleDrawable);
chahao.setOnClickListener(view -> {
editText.setText("");
view.setVisibility(GONE);
});
addView(chahao, (int) TypedValue.applyDimension(TypedValue.
COMPLEX_UNIT_DIP, 26, getResources().getDisplayMetrics())
, (int) TypedValue.applyDimension(TypedValue.
COMPLEX_UNIT_DIP, 26, getResources().getDisplayMetrics()));
iskong();
if (attrs != null) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.Edit);
boolean isEnabled = a.getBoolean(R.styleable.Edit_Enabled, true);
if (!isEnabled) {
removeView(imageView);
removeView(chahao);
// editText.setGravity(Gravity.CENTER);
editText.setFocusable(false);
editText.setFocusableInTouchMode(false);
// editText.setEnabled(false);
editText.setClickable(false);
}
a.recycle();
}
}
public void addTextChangedListener(TextWatcher textWatcher) {
editText.addTextChangedListener(textWatcher);
}
public void iskong() {
if (editText.getText().toString().isEmpty()) {
chahao.setVisibility(GONE);
} else {
chahao.setVisibility(VISIBLE);
}
}
@Override
public void setLayoutParams(ViewGroup.LayoutParams params) {
// params.width = ViewGroup.LayoutParams.MATCH_PARENT;
params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
super.setLayoutParams(params);
// setGravity(Gravity.CENTER_VERTICAL);
}
public void setOnEditorActionListener(TextView.OnEditorActionListener a) {
editText.setOnEditorActionListener(a);
}
public void setText(String s) {
editText.setText(s);
}
public Editable getText() {
return editText.getText();
}
public interface TextWatcher extends NoCopySpan, android.text.TextWatcher {
void beforeTextChanged(CharSequence var1, int var2, int var3, int var4);
void onTextChanged(CharSequence var1, int var2, int var3, int var4);
void afterTextChanged(Editable var1);
}
}

View File

@ -0,0 +1,73 @@
package com.muqingbfq.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
public class RecyclerViewH extends RecyclerView {
public RecyclerViewH(@NonNull Context context) {
super(context);
}
public RecyclerViewH(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public RecyclerViewH(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
// private boolean disallowIntercept = false;
private int startX = 0;
private int startY = 0;
boolean isDispatch = true;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (isDispatch) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = (int) ev.getX();
startY = (int) ev.getY();
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
int endX = (int) ev.getX();
int endY = (int) ev.getY();
int disX = Math.abs(endX - startX);
int disY = Math.abs(endY - startY);
if (Math.abs(disY) > ViewConfiguration.get(getContext()).getScaledTouchSlop()) {
// 当前手指移动距离大于系统认定的最小滚动距离时不允许父容器拦截触摸事件
getParent().requestDisallowInterceptTouchEvent(true);
} else {
break;
}
/*
if (disX > disY) {
//为了解决RecyclerView嵌套RecyclerView时横向滑动的问题
if (disallowIntercept) {
getParent().requestDisallowInterceptTouchEvent(disallowIntercept);
} else {
getParent().requestDisallowInterceptTouchEvent(canScrollHorizontally(startX - endX));
}
} else {
getParent().requestDisallowInterceptTouchEvent(true);
}*/
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
getParent().requestDisallowInterceptTouchEvent(false);
break;
}
}
return super.dispatchTouchEvent(ev);
}
@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
super.requestDisallowInterceptTouchEvent(disallowIntercept);
}
}

View File

@ -0,0 +1,47 @@
package com.muqingbfq.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.TextPaint;
import android.util.AttributeSet;
import androidx.appcompat.widget.AppCompatTextView;
public class StrokeTextView extends AppCompatTextView {
public StrokeTextView(Context context) {
super(context);
}
public StrokeTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public StrokeTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
// 获取当前TextView的Paint对象
TextPaint textPaint = getPaint();
// 保存原来的文本颜色
int currentTextColor = getCurrentTextColor();
// 设置描边效果
textPaint.setStyle(Paint.Style.STROKE); // 设置为描边
textPaint.setStrokeWidth(1); // 设置描边的宽度
setTextColor(Color.BLACK); // 描边的颜色
// 绘制描边
super.onDraw(canvas);
// 恢复原来的文本颜色并绘制文本内容
textPaint.setStyle(Paint.Style.FILL); // 恢复为填充
setTextColor(currentTextColor); // 恢复原来的颜色
super.onDraw(canvas);
}
}

View File

@ -0,0 +1,115 @@
package com.muqingbfq.view;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.media.Image;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.LinearLayoutCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import com.google.android.material.card.MaterialCardView;
import com.muqingbfq.R;
import com.muqingbfq.mq.gj;
public class TabLayout extends MaterialCardView {
public TabLayout(Context context) {
this(context, null);
}
public TabLayout(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public TabLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs,defStyleAttr);
Init(context, attrs, defStyleAttr);
}
public LinearLayout linearLayout;
private void Init(Context context, AttributeSet attrs, int defStyleAttr) {
linearLayout = new LinearLayout(context, attrs, defStyleAttr);
int a = gj.dp2px(context, 9);
LinearLayout.LayoutParams layoutParams ;
if (gj.isTablet(context)) {
// 这是平板模式
layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.MATCH_PARENT);
linearLayout.setOrientation(LinearLayout.VERTICAL);
linearLayout.setGravity(Gravity.CENTER);
setContentPadding(a, 0, a, 0);
} else {
// 这是手机模式
layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
linearLayout.setGravity(Gravity.CENTER);
setContentPadding(0, a, 0, a);
}
// linearLayout.setBackgroundColor(Color.BLACK);
addView(linearLayout,layoutParams);
// addView(new Button(context));
}
public int sizeView = 0;
@SuppressLint("ResourceType")
public View addView(String title, int icon) {
Context context = getContext();
Item itemB = new Item(context);
itemB.imageView.setImageResource(icon);
itemB.textView.setText(title);
LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
int a = gj.dp2px(context, 26);
if (!gj.isTablet(context)) {
layoutParams.setMargins(a, 0, a, 0);
} else {
layoutParams.setMargins(0, a, 0, a);
}
linearLayout.addView(itemB, layoutParams);
if (sizeView == 0) {
itemB.setCardBackgroundColor(gj.getThemeColor(context, com.google.android.material.R.attr.colorPrimaryContainer));
}
sizeView++;
return itemB;
}
public static class Item extends MaterialCardView {
ImageView imageView;
TextView textView;
public Item(Context context) {
this(context, null);
}
public Item(Context context, @Nullable AttributeSet attrs) {
super(new ContextThemeWrapper(context, com.google.android.material.R.style.Widget_Material3_CardView_Elevated), attrs);
setUseCompatPadding(true);
setFocusable(true);
setClickable(true);
// 没有边缘线
setStrokeWidth(0);
int padding = gj.dp2px(context, 6);
setContentPadding(padding,padding,padding,padding);
inflate(context, R.layout.view_tab, this);
imageView = findViewById(R.id.image);
textView = findViewById(R.id.text);
}
}
}

View File

@ -0,0 +1,36 @@
package com.muqingbfq.view;
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import androidx.annotation.NonNull;
public class Text extends androidx.appcompat.widget.AppCompatTextView {
public Text(@NonNull Context context) {
super(context);
initView();
}
public Text(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public Text(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
this.setEllipsize(TextUtils.TruncateAt.MARQUEE);
this.setSingleLine(true);
this.setMarqueeRepeatLimit(-1);
}
@Override
public boolean isFocused() {
return true;
}
}

View File

@ -0,0 +1,29 @@
package com.muqingbfq.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.appbar.MaterialToolbar;
public class Toolbar extends MaterialToolbar {
public Toolbar(@NonNull Context context) {
super(context);
}
public Toolbar(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public Toolbar(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// 处理触摸事件逻辑
return false;
}
}

View File

@ -0,0 +1,72 @@
package com.muqingbfq;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import androidx.annotation.Nullable;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.muqingbfq.databinding.ActivityYcBinding;
import com.muqingbfq.mq.AppCompatActivity;
import com.muqingbfq.mq.gj;
public class yc extends AppCompatActivity<ActivityYcBinding> {
public Object exception;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView();
Intent intent = getIntent();
exception = intent.getStringExtra("e");
String deviceModel = Build.MODEL;
String deviceManufacturer = Build.MANUFACTURER;
String osVersion = Build.VERSION.RELEASE;
int sdkVersion = Build.VERSION.SDK_INT;
@SuppressLint("HardwareIds") String deviceId = Settings.Secure.getString(getContentResolver(),
Settings.Secure.ANDROID_ID);
DisplayMetrics metrics = getResources().getDisplayMetrics();
int widthPixels = metrics.widthPixels;
int heightPixels = metrics.heightPixels;
float density = metrics.density;
int densityDpi = metrics.densityDpi;
// 假设你已经获取到了手机信息保存在相应的变量中
String wb = "设备型号:" + deviceModel + "\n"
+ "制造商:" + deviceManufacturer + "\n"
+ "设备ID" + deviceId + "\n"
+ "操作系统版本:" + osVersion + "\n"
+ "SDK版本" + sdkVersion + "\n"
+ "屏幕尺寸:" + widthPixels + "x" + heightPixels + "\n"
+ "屏幕密度:" + density + "\n"
+ "密度DPI" + densityDpi + "\n" +
"异常信息: " + exception.toString();
binding.text.setText(wb);
binding.button2.setOnClickListener(view -> finish());
}
public static void start(Context context, Object e) {
gj.sc(e);
Intent intent = new Intent(context, yc.class);
intent.putExtra("e",e.toString());
context.startActivity(intent);
}
public static void tc(Context context, Object exception) {
new MaterialAlertDialogBuilder(context)
.setTitle("不是特别重要的警告")
.setMessage(exception.toString())
.setNegativeButton("无视", null)
.setPositiveButton("分享", null)
.show();
}
@Override
protected ActivityYcBinding getViewBindingObject(LayoutInflater layoutInflater) {
return ActivityYcBinding.inflate(layoutInflater);
}
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="24"
android:viewportHeight="24"
android:width="128dp"
android:height="128dp">
<path
android:pathData="M18 16.08c-0.76 0 -1.44 0.3 -1.96 0.77L8.91 12.7c0.05 -0.23 0.09 -0.46 0.09 -0.7s-0.04 -0.47 -0.09 -0.7l7.05 -4.11c0.54 0.5 1.25 0.81 2.04 0.81c1.66 0 3 -1.34 3 -3s-1.34 -3 -3 -3s-3 1.34 -3 3c0 0.24 0.04 0.47 0.09 0.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0 -3 1.34 -3 3s1.34 3 3 3c0.79 0 1.5 -0.31 2.04 -0.81l7.12 4.15c-0.05 0.21 -0.08 0.43 -0.08 0.66c0 1.61 1.31 2.91 2.92 2.91s2.92 -1.3 2.92 -2.91s-1.31 -2.92 -2.92 -2.92M18 4c0.55 0 1 0.45 1 1s-0.45 1 -1 1s-1 -0.45 -1 -1s0.45 -1 1 -1M6 13c-0.55 0 -1 -0.45 -1 -1s0.45 -1 1 -1s1 0.45 1 1s-0.45 1 -1 1m12 7c-0.55 0 -1 -0.45 -1 -1s0.45 -1 1 -1s1 0.45 1 1s-0.45 1 -1 1"
android:fillColor="#000000" />
</vector>

View File

@ -0,0 +1,34 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="128dp"
android:height="128dp"
android:viewportWidth="48"
android:viewportHeight="48">
<path
android:pathData="m37,22l-3,3l-11,-11l3,-3c1.5,-1.5 7,-4 11,0s1.5,9.5 0,11"
android:strokeLineJoin="round"
android:strokeWidth="4"
android:fillColor="#666666"
android:strokeColor="#666666"
android:strokeLineCap="round"/>
<path
android:pathData="m42,6l-5,5"
android:strokeLineJoin="round"
android:strokeWidth="4"
android:fillColor="#00000000"
android:strokeColor="#666666"
android:strokeLineCap="round"/>
<path
android:pathData="m11,26l3,-3l11,11l-3,3c-1.5,1.5 -7,4 -11,0s-1.5,-9.5 0,-11"
android:strokeLineJoin="round"
android:strokeWidth="4"
android:fillColor="#666666"
android:strokeColor="#666666"
android:strokeLineCap="round"/>
<path
android:pathData="m23,32l4,-4M6,42l5,-5m5,-12l4,-4"
android:strokeLineJoin="round"
android:strokeWidth="4"
android:fillColor="#00000000"
android:strokeColor="#666666"
android:strokeLineCap="round"/>
</vector>

View File

@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
android:tint="@color/text"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M512,427.7c-33.1,0 -60,26.9 -60,60v226.7c0,33.1 26.9,60 60,60s60,-26.9 60,-60V487.7c0,-33.1 -26.9,-60 -60,-60z"
android:fillColor="#515151"/>
<path
android:pathData="M512,309.7m-60,0a60,60 0,1 0,120 0,60 60,0 1,0 -120,0Z"
android:fillColor="#515151"/>
<path
android:pathData="M512,14C237,14 14,237 14,512s223,498 498,498 498,-223 498,-498S787,14 512,14zM512,910c-219.8,0 -398,-178.2 -398,-398S292.2,114 512,114 910,292.2 910,512 731.8,910 512,910z"
android:fillColor="#515151"/>
</vector>

View File

@ -0,0 +1,11 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="#80F2ECF6" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
</shape>
</item>
</selector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="46dp"
android:height="46dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="@color/text"
android:pathData="M244.8,226h203.3c17.8,0 31.8,14 31.8,31.6v508.6c0,17.6 -14,31.8 -31.8,31.8L244.8,798c-17.6,0 -31.6,-14.2 -31.6,-31.8L213.2,257.6c0,-17.6 14,-31.6 31.6,-31.6zM575.7,226h203.3c17.8,0 31.8,14 31.8,31.6v508.6c0,17.6 -14,31.8 -31.8,31.8L575.7,798c-17.6,0 -32,-14.2 -32,-31.8L543.6,257.6c0,-17.6 14.4,-31.6 32,-31.6zM747.1,289.2L607.2,289.2v445.4h139.9L747.1,289.2zM416.3,289.2L276.4,289.2v445.4h139.9L416.3,289.2z" />
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:viewportWidth="24"
android:viewportHeight="24"
android:width="26dp"
android:height="26dp">
<path
android:fillColor="#CCCCCC"
android:pathData="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12z" />
</vector>

View File

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="128dp"
android:height="128dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M6 19a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2V7H6zM8 9h8v10H8zm7.5 -5l-1 -1h-5l-1 1H5v2h14V4z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="24"
android:viewportHeight="24"
android:width="128dp"
android:height="128dp">
<path
android:pathData="M8 17v-2h8v2zm8 -7l-4 4l-4 -4h2.5V6h3v4zm-4 -8c5.5 0 10 4.5 10 10s-4.5 10 -10 10S2 17.5 2 12S6.5 2 12 2m0 2c-4.42 0 -8 3.58 -8 8s3.58 8 8 8s8 -3.58 8 -8s-3.58 -8 -8 -8"
android:fillColor="#000000" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
android:viewportWidth="24"
android:viewportHeight="24"
android:width="26dp"
android:height="26dp">
<path
android:pathData="M7.41 8.58L12 13.17l4.59 -4.59L18 10l-6 6l-6 -6z"
android:fillColor="#000000" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
android:viewportWidth="24"
android:viewportHeight="24"
android:width="128dp"
android:height="128dp">
<path
android:pathData="M16.5 12c2.5 0 4.5 2 4.5 4.5c0 0.88 -0.25 1.71 -0.69 2.4l3.08 3.1L22 23.39l-3.12 -3.07c-0.69 0.43 -1.51 0.68 -2.38 0.68c-2.5 0 -4.5 -2 -4.5 -4.5s2 -4.5 4.5 -4.5m0 2a2.5 2.5 0 0 0 -2.5 2.5a2.5 2.5 0 0 0 2.5 2.5a2.5 2.5 0 0 0 2.5 -2.5a2.5 2.5 0 0 0 -2.5 -2.5M9 4l2 2h8a2 2 0 0 1 2 2v3.81A6.48 6.48 0 0 0 16.5 10a6.5 6.5 0 0 0 -6.5 6.5c0 1.29 0.37 2.5 1 3.5H3a2 2 0 0 1 -2 -2V6c0 -1.11 0.89 -2 2 -2z"
android:fillColor="#000000" />
</vector>

View File

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M995,538.7c-13.8,-8.9 -30.3,-12 -46.4,-8.5l-182.9,39.3c-28.2,6.1 -48.6,31.4 -48.6,60.2v224.6c0,21.8 -17.7,39.5 -39.6,39.5 -21.8,0 -39.5,-17.7 -39.5,-39.5s17.7,-39.6 39.5,-39.6c15.4,0 27.8,-12.4 27.8,-27.8s-12.4,-27.8 -27.8,-27.8c-52.4,0 -95.1,42.7 -95.1,95.2 0,52.4 42.7,95.1 95.1,95.1 52.5,0 95.1,-42.7 95.1,-95.1V629.8c0,-2.9 2,-5.3 4.8,-5.9l182.9,-39.3c1.9,-0.5 3.6,0.2 4.5,0.8 1,0.6 2.2,1.8 2.7,5V814c0,21.8 -17.7,39.6 -39.6,39.6 -10.5,0 -20.5,-4.1 -27.9,-11.6 -7.5,-7.5 -11.6,-17.4 -11.6,-28 0,-21.8 17.7,-39.6 39.6,-39.6 15.4,0 27.8,-12.4 27.8,-27.8s-12.4,-27.8 -27.8,-27.8c-52.5,0 -95.1,42.7 -95.1,95.1 0,25.4 9.9,49.3 27.9,67.3s41.8,27.9 67.2,27.9c52.5,0 95.1,-42.7 95.1,-95.1V590.5c0,-4.4 -0.5,-8.7 -1.4,-12.9 -3.4,-16.1 -12.9,-29.9 -26.7,-38.9z"
android:fillColor="#000000"/>
<path
android:pathData="M338.3,315.1c35.3,-63.9 90.4,-114.1 158.6,-143.6 81.4,-35.2 171.7,-36.6 254.1,-3.9 106.7,42.3 183,134.9 204.1,247.8 3.1,16.7 17.7,28.4 34.1,28.4 2.1,0 4.3,-0.2 6.4,-0.6 18.9,-3.5 31.3,-21.7 27.8,-40.5C997.9,266.2 905.7,154.1 776.6,103c-99.7,-39.5 -208.8,-37.8 -307.3,4.7 -92.5,40 -165.1,111.6 -206.4,202.8 -48.9,3.6 -96.2,19.8 -137.8,48C62.2,400.9 19.7,465.3 5.3,539.7c-14.4,74.4 1,150 43.5,212.9 52.9,78.3 140.8,125 235.2,125h153.3c19.2,0 34.7,-15.6 34.7,-34.7s-15.6,-34.7 -34.7,-34.7H284c-71.3,0 -137.7,-35.3 -177.7,-94.4C74.2,666.3 62.6,609.3 73.5,553c10.9,-56.2 43,-104.8 90.5,-136.9 47.5,-32.1 104.5,-43.7 160.8,-32.8 56.2,10.9 104.8,43 136.9,90.5 10.7,15.9 32.3,20.1 48.2,9.3 15.9,-10.7 20.1,-32.3 9.3,-48.2 -42.4,-62.8 -106.6,-105.3 -180.9,-119.8z"
android:fillColor="#000000"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M512,0a512,512 0,1 0,512 512A512.4,512.4 0,0 0,512 0zM512,938.1A554.5,554.5 0,0 1,390.5 745.4a775.4,775.4 0,0 1,121.5 -9.5,725.5 725.5,0 0,1 117.2,9.5 544.1,544.1 0,0 1,-117.2 192.7zM512,666.5a834,834 0,0 0,-143.6 12.6,661.3 661.3,0 0,1 -20.4,-133.2h321.5a681.2,681.2 0,0 1,-19.5 130.2,790.6 790.6,0 0,0 -138,-9.5zM71.2,545.8h208.3a728.5,728.5 0,0 0,22.6 149.3,450 450,0 0,0 -151.9,71.6 439.5,439.5 0,0 1,-79 -220.9zM507.7,85.9a554.1,554.1 0,0 1,120.2 190.5,683 683,0 0,1 -115.9,10 722.9,722.9 0,0 1,-121.9 -10.4,542.8 542.8,0 0,1 117.6,-190zM512,355.8a749.3,749.3 0,0 0,137.1 -13,661.3 661.3,0 0,1 21.3,134.5L348.9,477.3a680.8,680.8 0,0 1,20.4 -134.5,787.5 787.5,0 0,0 142.8,13zM279.4,475.6h-208.3a439.5,439.5 0,0 1,81.1 -221.3,462.1 462.1,0 0,0 149.7,72.5 748.5,748.5 0,0 0,-22.6 148.8zM739.8,547.6l213,3a439.5,439.5 0,0 1,-79.8 216.9A466.4,466.4 0,0 0,718.1 694.2a748,748 0,0 0,21.7 -146.7zM739.8,478.2a728.5,728.5 0,0 0,-23.4 -151.4,477.3 477.3,0 0,0 153.6,-75.1 439.5,439.5 0,0 1,83.3 228.7zM826.6,199.6a417.8,417.8 0,0 1,-130.2 61.6,650.8 650.8,0 0,0 -103.7,-183.1 441.7,441.7 0,0 1,232.1 121.5zM422.2,78.1A642.6,642.6 0,0 0,322.4 260.3a397.5,397.5 0,0 1,-125.4 -58.6A442.1,442.1 0,0 1,422.2 78.1zM194,819.2a384,384 0,0 1,130.2 -58.6A650.8,650.8 0,0 0,425.2 945.9a442.1,442.1 0,0 1,-231.3 -126.7zM596.2,945.9a643.5,643.5 0,0 0,101.5 -185.7,401.8 401.8,0 0,1 130.2,60.3 441.7,441.7 0,0 1,-231.7 125.4z"
android:fillColor="@color/text"/>
</vector>

Some files were not shown because too many files have changed in this diff Show More