git fetch origin

This commit is contained in:
muqing 2024-07-22 20:54:14 +08:00
commit 04c1a63caa
226 changed files with 16789 additions and 0 deletions

16
.gitignore vendored Normal file
View File

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

6
.idea/compiler.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" />
</component>
</project>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
</selectionStates>
</component>
</project>

View File

@ -0,0 +1,3 @@
<component name="ProjectDictionaryState">
<dictionary name="19669" />
</component>

21
.idea/gradle.xml Normal file
View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="jbr-17" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/StatusBarUtil" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>

View File

@ -0,0 +1,27 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="AndroidLintHardcodedText" enabled="true" level="WARNING" enabled_by_default="true" editorAttributes="WARNING_ATTRIBUTES" />
<inspection_tool class="AutoCloseableResource" enabled="true" level="WARNING" enabled_by_default="true">
<option name="METHOD_MATCHER_CONFIG" value="java.util.Formatter,format,java.io.Writer,append,com.google.common.base.Preconditions,checkNotNull,org.hibernate.Session,close,java.io.PrintWriter,printf,java.io.PrintStream,printf,android.content.res.Resources.Theme,obtainStyledAttributes,android.content.Context,obtainStyledAttributes,okhttp3.Call,execute" />
</inspection_tool>
<inspection_tool class="DataFlowIssue" enabled="false" level="WARNING" enabled_by_default="false">
<option name="SUGGEST_NULLABLE_ANNOTATIONS" value="false" />
<option name="DONT_REPORT_TRUE_ASSERT_STATEMENTS" value="false" />
</inspection_tool>
<inspection_tool class="FieldMayBeFinal" enabled="true" level="INFORMATION" enabled_by_default="true" />
<inspection_tool class="IgnoreResultOfCall" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_reportAllNonLibraryCalls" value="false" />
<option name="callCheckString" value="java.io.InputStream,read|skip|available|markSupported,java.io.Reader,read|skip|ready|markSupported,java.lang.AbstractStringBuilder,capacity|codePointAt|codePointBefore|codePointCount|indexOf|lastIndexOf|offsetByCodePoints|substring|subSequence,java.lang.Boolean,.*,java.lang.Byte,.*,java.lang.Character,.*,java.lang.Double,.*,java.lang.Float,.*,java.lang.Integer,.*,java.lang.Long,.*,java.lang.Math,.*,java.lang.Object,equals|hashCode|toString,java.lang.Short,.*,java.lang.StrictMath,.*,java.lang.String,.*,java.lang.Thread,interrupted,java.math.BigDecimal,.*,java.math.BigInteger,.*,java.net.InetAddress,.*,java.net.URI,.*,java.nio.channels.AsynchronousChannelGroup,.*,java.nio.channels.Channel,isOpen,java.nio.channels.FileChannel,open|map|lock|tryLock|write,java.nio.channels.ScatteringByteChannel,read,java.nio.channels.SocketChannel,open|socket|isConnected|isConnectionPending,java.util.Arrays,.*,java.util.Collections,(?!addAll).*,java.util.List,of,java.util.Map,of|ofEntries|entry,java.util.Set,of,java.util.UUID,.*,java.util.concurrent.BlockingQueue,offer|remove,java.util.concurrent.CountDownLatch,await|getCount,java.util.concurrent.ExecutorService,awaitTermination|isShutdown|isTerminated,java.util.concurrent.ForkJoinPool,awaitQuiescence,java.util.concurrent.Semaphore,tryAcquire|availablePermits|isFair|hasQueuedThreads|getQueueLength|getQueuedThreads,java.util.concurrent.locks.Condition,await|awaitNanos|awaitUntil,java.util.concurrent.locks.Lock,tryLock|newCondition,java.util.regex.Matcher,pattern|toMatchResult|start|end|group|groupCount|matches|find|lookingAt|quoteReplacement|replaceAll|replaceFirst|regionStart|regionEnd|hasTransparentBounds|hasAnchoringBounds|hitEnd|requireEnd,java.util.regex.Pattern,.*,java.util.stream.BaseStream,.*,java.util.stream.DoubleStream,.*,java.util.stream.IntStream,.*,java.util.stream.LongStream,.*,java.util.stream.Stream,.*" />
</inspection_tool>
<inspection_tool class="InnerClassMayBeStatic" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PrivatePropertyName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="PropertyName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
<option name="processCode" value="true" />
<option name="processLiterals" value="true" />
<option name="processComments" value="true" />
</inspection_tool>
<inspection_tool class="UnusedSymbol" enabled="true" level="INFORMATION" enabled_by_default="true" />
</profile>
</component>

View File

@ -0,0 +1,14 @@
<component name="InspectionProjectProfileManager">
<settings>
<list size="8">
<item index="0" class="java.lang.String" itemvalue="INFORMATION" />
<item index="1" class="java.lang.String" itemvalue="TEXT ATTRIBUTES" />
<item index="2" class="java.lang.String" itemvalue="TYPO" />
<item index="3" class="java.lang.String" itemvalue="SERVER PROBLEM" />
<item index="4" class="java.lang.String" itemvalue="WEAK WARNING" />
<item index="5" class="java.lang.String" itemvalue="INFO" />
<item index="6" class="java.lang.String" itemvalue="WARNING" />
<item index="7" class="java.lang.String" itemvalue="ERROR" />
</list>
</settings>
</component>

6
.idea/kotlinc.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.8.0" />
</component>
</project>

10
.idea/migrations.xml Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

52
.idea/misc.xml Normal file
View File

@ -0,0 +1,52 @@
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="androidx.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="15">
<item index="0" class="java.lang.String" itemvalue="com.android.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="org.jspecify.nullness.Nullable" />
<item index="2" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
<item index="3" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
<item index="4" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
<item index="6" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.Nullable" />
<item index="7" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="8" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
<item index="9" class="java.lang.String" itemvalue="jakarta.annotation.Nullable" />
<item index="10" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="11" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="12" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
<item index="13" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
<item index="14" class="java.lang.String" itemvalue="android.annotation.Nullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="14">
<item index="0" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
<item index="1" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
<item index="2" class="java.lang.String" itemvalue="jakarta.annotation.Nonnull" />
<item index="3" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
<item index="4" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
<item index="5" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
<item index="6" class="java.lang.String" itemvalue="org.jspecify.nullness.NonNull" />
<item index="7" class="java.lang.String" itemvalue="com.android.annotations.NonNull" />
<item index="8" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
<item index="10" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="11" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="12" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.NonNull" />
<item index="13" class="java.lang.String" itemvalue="android.annotation.NonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK" />
<component name="SuppressKotlinCodeStyleNotification">
<option name="disableForAll" value="true" />
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

47
README.md Normal file
View File

@ -0,0 +1,47 @@
## 云音乐是什么?
一个对接网易云的音乐播放器
* 内置集成作者自己写的歌词Lrc组件支持单行歌词和多行歌词支持悬浮窗歌词。
* 内置适配Android13的通知栏 (不完善请大佬请教)
* 对接了网易云的歌单,歌曲,搜索,二维码登录等其余功能。
* main.java-内api变量是网易云SDK后台服务器地址可变更
* http 是我服务器php接口的地址用于软件更新用或者其他功能个根据需要做出必须的更改或者删除
## 进度
* UI
* 歌单
* 音乐播放选择列表
* 音乐播放器控制界面
* 登陆
* 设置
* 侧滑栏内小功能
* 代码
* 适配主题和UI美化
* 维护接口(不完善)
* 蓝牙功能
* 通知栏控制
* 悬浮歌词功能
* 基本播放器功能(控制暂停 上下曲 播放歌单操作)
## 截图
<img alt="Screenshot_20240224_154259_com.muqingbfq.jpg" height="700" src="image%2FScreenshot_20240224_154259_com.muqingbfq.jpg" width="300"/>
<img alt="Screenshot_20240224_154302_com.muqingbfq.jpg" height="700" src="image%2FScreenshot_20240224_154302_com.muqingbfq.jpg" width="300"/>
<img alt="Screenshot_20240224_154306_com.muqingbfq.jpg" height="700" src="image%2FScreenshot_20240224_154306_com.muqingbfq.jpg" width="300"/>
## 在使用中有任何问题,欢迎反馈给我,可以用以下联系方式跟我交流
* QQ:1966944300
## 后台
* Github: [网易云音乐 API](https://github.com/Binaryify/NeteaseCloudMusicApi)
## 关于
在兴趣的驱动下,写一个`免费`的东西,有欣喜,也还有汗水,希望你喜欢我的作品,同时也能支持一下。
## 修改JAR的包
```javascript
[//]: # (主要修改内容MD3化)
com.github.QuadFlask:colorpicker:0.0.15
[//]: # (歌词做全局变量给悬浮窗歌词)
'com.github.wangchenyan:lrcview:2.2.1'
...

1
StatusBarUtil/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,25 @@
apply plugin: 'com.android.library'
version = "1.5.1"
android {
namespace 'com.jaeger.library'
compileSdk 34
resourcePrefix "statusbarutil_"
defaultConfig {
minSdkVersion 23
//noinspection ExpiredTargetSdkVersion
targetSdk 31
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
}

View File

@ -0,0 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jaeger.library">
<application />
</manifest>

View File

@ -0,0 +1,726 @@
package com.jaeger.library;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.LinearLayout;
import androidx.annotation.ColorInt;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.drawerlayout.widget.DrawerLayout;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* Created by Jaeger on 16/2/14.
* <p>
* Email: chjie.jaeger@gmail.com
* GitHub: <a href="https://github.com/laobie">...</a>
*/
public class StatusBarUtil {
public static final int DEFAULT_STATUS_BAR_ALPHA = 112;
private static final int FAKE_STATUS_BAR_VIEW_ID = R.id.statusbarutil_fake_status_bar_view;
private static final int FAKE_TRANSLUCENT_VIEW_ID = R.id.statusbarutil_translucent_view;
private static final int TAG_KEY_HAVE_SET_OFFSET = -123;
/**
* 设置状态栏颜色
*
* @param activity 需要设置的 activity
* @param color 状态栏颜色值
*/
public static void setColor(Activity activity, @ColorInt int color) {
setColor(activity, color, DEFAULT_STATUS_BAR_ALPHA);
}
/**
* 设置状态栏颜色
*
* @param activity 需要设置的activity
* @param color 状态栏颜色值
* @param statusBarAlpha 状态栏透明度
*/
public static void setColor(Activity activity, @ColorInt int color, @IntRange(from = 0, to = 255) int statusBarAlpha) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
activity.getWindow().setStatusBarColor(calculateStatusColor(color, statusBarAlpha));
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
View fakeStatusBarView = decorView.findViewById(FAKE_STATUS_BAR_VIEW_ID);
if (fakeStatusBarView != null) {
if (fakeStatusBarView.getVisibility() == View.GONE) {
fakeStatusBarView.setVisibility(View.VISIBLE);
}
fakeStatusBarView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha));
} else {
decorView.addView(createStatusBarView(activity, color, statusBarAlpha));
}
setRootView(activity);
}
}
/**
* 为滑动返回界面设置状态栏颜色
*
* @param activity 需要设置的activity
* @param color 状态栏颜色值
*/
public static void setColorForSwipeBack(Activity activity, int color) {
setColorForSwipeBack(activity, color, DEFAULT_STATUS_BAR_ALPHA);
}
/**
* 为滑动返回界面设置状态栏颜色
*
* @param activity 需要设置的activity
* @param color 状态栏颜色值
* @param statusBarAlpha 状态栏透明度
*/
public static void setColorForSwipeBack(Activity activity, @ColorInt int color,
@IntRange(from = 0, to = 255) int statusBarAlpha) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
ViewGroup contentView = ((ViewGroup) activity.findViewById(android.R.id.content));
View rootView = contentView.getChildAt(0);
int statusBarHeight = getStatusBarHeight(activity);
if (rootView instanceof CoordinatorLayout) {
final CoordinatorLayout coordinatorLayout = (CoordinatorLayout) rootView;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
coordinatorLayout.setFitsSystemWindows(false);
contentView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha));
boolean isNeedRequestLayout = contentView.getPaddingTop() < statusBarHeight;
if (isNeedRequestLayout) {
contentView.setPadding(0, statusBarHeight, 0, 0);
coordinatorLayout.post(coordinatorLayout::requestLayout);
}
} else {
coordinatorLayout.setStatusBarBackgroundColor(calculateStatusColor(color, statusBarAlpha));
}
} else {
contentView.setPadding(0, statusBarHeight, 0, 0);
contentView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha));
}
setTransparentForWindow(activity);
}
}
/**
* 设置状态栏纯色 不加半透明效果
*
* @param activity 需要设置的 activity
* @param color 状态栏颜色值
*/
public static void setColorNoTranslucent(Activity activity, @ColorInt int color) {
setColor(activity, color, 0);
}
/**
* 设置状态栏颜色(5.0以下无半透明效果,不建议使用)
*
* @param activity 需要设置的 activity
* @param color 状态栏颜色值
*/
@Deprecated
public static void setColorDiff(Activity activity, @ColorInt int color) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
return;
}
transparentStatusBar(activity);
ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);
// 移除半透明矩形,以免叠加
View fakeStatusBarView = contentView.findViewById(FAKE_STATUS_BAR_VIEW_ID);
if (fakeStatusBarView != null) {
if (fakeStatusBarView.getVisibility() == View.GONE) {
fakeStatusBarView.setVisibility(View.VISIBLE);
}
fakeStatusBarView.setBackgroundColor(color);
} else {
contentView.addView(createStatusBarView(activity, color));
}
setRootView(activity);
}
/**
* 使状态栏半透明
* <p>
* 适用于图片作为背景的界面,此时需要图片填充到状态栏
*
* @param activity 需要设置的activity
*/
public static void setTranslucent(Activity activity) {
setTranslucent(activity, DEFAULT_STATUS_BAR_ALPHA);
}
/**
* 使状态栏半透明
* <p>
* 适用于图片作为背景的界面,此时需要图片填充到状态栏
*
* @param activity 需要设置的activity
* @param statusBarAlpha 状态栏透明度
*/
public static void setTranslucent(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
return;
}
setTransparent(activity);
addTranslucentView(activity, statusBarAlpha);
}
/**
* 针对根布局是 CoordinatorLayout, 使状态栏半透明
* <p>
* 适用于图片作为背景的界面,此时需要图片填充到状态栏
*
* @param activity 需要设置的activity
* @param statusBarAlpha 状态栏透明度
*/
public static void setTranslucentForCoordinatorLayout(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
return;
}
transparentStatusBar(activity);
addTranslucentView(activity, statusBarAlpha);
}
/**
* 设置状态栏全透明
*
* @param activity 需要设置的activity
*/
public static void setTransparent(Activity activity) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
return;
}
transparentStatusBar(activity);
setRootView(activity);
}
/**
* 使状态栏透明(5.0以上半透明效果,不建议使用)
* <p>
* 适用于图片作为背景的界面,此时需要图片填充到状态栏
*
* @param activity 需要设置的activity
*/
@Deprecated
public static void setTranslucentDiff(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// 设置状态栏透明
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
setRootView(activity);
}
}
/**
* 为DrawerLayout 布局设置状态栏变色
*
* @param activity 需要设置的activity
* @param drawerLayout DrawerLayout
* @param color 状态栏颜色值
*/
public static void setColorForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color) {
setColorForDrawerLayout(activity, drawerLayout, color, DEFAULT_STATUS_BAR_ALPHA);
}
/**
* 为DrawerLayout 布局设置状态栏颜色,纯色
*
* @param activity 需要设置的activity
* @param drawerLayout DrawerLayout
* @param color 状态栏颜色值
*/
public static void setColorNoTranslucentForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color) {
setColorForDrawerLayout(activity, drawerLayout, color, 0);
}
/**
* 为DrawerLayout 布局设置状态栏变色
*
* @param activity 需要设置的activity
* @param drawerLayout DrawerLayout
* @param color 状态栏颜色值
* @param statusBarAlpha 状态栏透明度
*/
public static void setColorForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color,
@IntRange(from = 0, to = 255) int statusBarAlpha) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
} else {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
// 生成一个状态栏大小的矩形
// 添加 statusBarView 到布局中
ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0);
View fakeStatusBarView = contentLayout.findViewById(FAKE_STATUS_BAR_VIEW_ID);
if (fakeStatusBarView != null) {
if (fakeStatusBarView.getVisibility() == View.GONE) {
fakeStatusBarView.setVisibility(View.VISIBLE);
}
fakeStatusBarView.setBackgroundColor(color);
} else {
contentLayout.addView(createStatusBarView(activity, color), 0);
}
// 内容布局不是 LinearLayout ,设置padding top
if (!(contentLayout instanceof LinearLayout) && contentLayout.getChildAt(1) != null) {
contentLayout.getChildAt(1)
.setPadding(contentLayout.getPaddingLeft(), getStatusBarHeight(activity) + contentLayout.getPaddingTop(),
contentLayout.getPaddingRight(), contentLayout.getPaddingBottom());
}
// 设置属性
setDrawerLayoutProperty(drawerLayout, contentLayout);
addTranslucentView(activity, statusBarAlpha);
}
/**
* 设置 DrawerLayout 属性
*
* @param drawerLayout DrawerLayout
* @param drawerLayoutContentLayout DrawerLayout 的内容布局
*/
private static void setDrawerLayoutProperty(DrawerLayout drawerLayout, ViewGroup drawerLayoutContentLayout) {
ViewGroup drawer = (ViewGroup) drawerLayout.getChildAt(1);
drawerLayout.setFitsSystemWindows(false);
drawerLayoutContentLayout.setFitsSystemWindows(false);
drawerLayoutContentLayout.setClipToPadding(true);
drawer.setFitsSystemWindows(false);
}
/**
* 为DrawerLayout 布局设置状态栏变色(5.0以下无半透明效果,不建议使用)
*
* @param activity 需要设置的activity
* @param drawerLayout DrawerLayout
* @param color 状态栏颜色值
*/
@Deprecated
public static void setColorForDrawerLayoutDiff(Activity activity, DrawerLayout drawerLayout, @ColorInt int color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
// 生成一个状态栏大小的矩形
ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0);
View fakeStatusBarView = contentLayout.findViewById(FAKE_STATUS_BAR_VIEW_ID);
if (fakeStatusBarView != null) {
if (fakeStatusBarView.getVisibility() == View.GONE) {
fakeStatusBarView.setVisibility(View.VISIBLE);
}
fakeStatusBarView.setBackgroundColor(calculateStatusColor(color, DEFAULT_STATUS_BAR_ALPHA));
} else {
// 添加 statusBarView 到布局中
contentLayout.addView(createStatusBarView(activity, color), 0);
}
// 内容布局不是 LinearLayout ,设置padding top
if (!(contentLayout instanceof LinearLayout) && contentLayout.getChildAt(1) != null) {
contentLayout.getChildAt(1).setPadding(0, getStatusBarHeight(activity), 0, 0);
}
// 设置属性
setDrawerLayoutProperty(drawerLayout, contentLayout);
}
}
/**
* DrawerLayout 布局设置状态栏透明
*
* @param activity 需要设置的activity
* @param drawerLayout DrawerLayout
*/
public static void setTranslucentForDrawerLayout(Activity activity, DrawerLayout drawerLayout) {
setTranslucentForDrawerLayout(activity, drawerLayout, DEFAULT_STATUS_BAR_ALPHA);
}
/**
* DrawerLayout 布局设置状态栏透明
*
* @param activity 需要设置的activity
* @param drawerLayout DrawerLayout
*/
public static void setTranslucentForDrawerLayout(Activity activity, DrawerLayout drawerLayout,
@IntRange(from = 0, to = 255) int statusBarAlpha) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
return;
}
setTransparentForDrawerLayout(activity, drawerLayout);
addTranslucentView(activity, statusBarAlpha);
}
/**
* DrawerLayout 布局设置状态栏透明
*
* @param activity 需要设置的activity
* @param drawerLayout DrawerLayout
*/
public static void setTransparentForDrawerLayout(Activity activity, DrawerLayout drawerLayout) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
} else {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0);
// 内容布局不是 LinearLayout ,设置padding top
if (!(contentLayout instanceof LinearLayout) && contentLayout.getChildAt(1) != null) {
contentLayout.getChildAt(1).setPadding(0, getStatusBarHeight(activity), 0, 0);
}
// 设置属性
setDrawerLayoutProperty(drawerLayout, contentLayout);
}
/**
* DrawerLayout 布局设置状态栏透明(5.0以上半透明效果,不建议使用)
*
* @param activity 需要设置的activity
* @param drawerLayout DrawerLayout
*/
@Deprecated
public static void setTranslucentForDrawerLayoutDiff(Activity activity, DrawerLayout drawerLayout) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// 设置状态栏透明
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
// 设置内容布局属性
ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0);
contentLayout.setFitsSystemWindows(true);
contentLayout.setClipToPadding(true);
// 设置抽屉布局属性
ViewGroup vg = (ViewGroup) drawerLayout.getChildAt(1);
vg.setFitsSystemWindows(false);
// 设置 DrawerLayout 属性
drawerLayout.setFitsSystemWindows(false);
}
}
/**
* 为头部是 ImageView 的界面设置状态栏全透明
*
* @param activity 需要设置的activity
* @param needOffsetView 需要向下偏移的 View
*/
public static void setTransparentForImageView(Activity activity, View needOffsetView) {
setTranslucentForImageView(activity, 0, needOffsetView);
}
/**
* 为头部是 ImageView 的界面设置状态栏透明(使用默认透明度)
*
* @param activity 需要设置的activity
* @param needOffsetView 需要向下偏移的 View
*/
public static void setTranslucentForImageView(Activity activity, View needOffsetView) {
setTranslucentForImageView(activity, DEFAULT_STATUS_BAR_ALPHA, needOffsetView);
}
/**
* 为头部是 ImageView 的界面设置状态栏透明
*
* @param activity 需要设置的activity
* @param statusBarAlpha 状态栏透明度
* @param needOffsetView 需要向下偏移的 View
*/
public static void setTranslucentForImageView(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha,
View needOffsetView) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
return;
}
setTransparentForWindow(activity);
addTranslucentView(activity, statusBarAlpha);
if (needOffsetView != null) {
Object haveSetOffset = needOffsetView.getTag(TAG_KEY_HAVE_SET_OFFSET);
if (haveSetOffset != null && (Boolean) haveSetOffset) {
return;
}
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) needOffsetView.getLayoutParams();
layoutParams.setMargins(layoutParams.leftMargin, layoutParams.topMargin + getStatusBarHeight(activity),
layoutParams.rightMargin, layoutParams.bottomMargin);
needOffsetView.setTag(TAG_KEY_HAVE_SET_OFFSET, true);
}
}
/**
* fragment 头部是 ImageView 的设置状态栏透明
*
* @param activity fragment 对应的 activity
* @param needOffsetView 需要向下偏移的 View
*/
public static void setTranslucentForImageViewInFragment(Activity activity, View needOffsetView) {
setTranslucentForImageViewInFragment(activity, DEFAULT_STATUS_BAR_ALPHA, needOffsetView);
}
/**
* fragment 头部是 ImageView 的设置状态栏透明
*
* @param activity fragment 对应的 activity
* @param needOffsetView 需要向下偏移的 View
*/
public static void setTransparentForImageViewInFragment(Activity activity, View needOffsetView) {
setTranslucentForImageViewInFragment(activity, 0, needOffsetView);
}
/**
* fragment 头部是 ImageView 的设置状态栏透明
*
* @param activity fragment 对应的 activity
* @param statusBarAlpha 状态栏透明度
* @param needOffsetView 需要向下偏移的 View
*/
public static void setTranslucentForImageViewInFragment(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha,
View needOffsetView) {
setTranslucentForImageView(activity, statusBarAlpha, needOffsetView);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
clearPreviousSetting(activity);
}
}
/**
* 隐藏伪状态栏 View
*
* @param activity 调用的 Activity
*/
public static void hideFakeStatusBarView(Activity activity) {
ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
View fakeStatusBarView = decorView.findViewById(FAKE_STATUS_BAR_VIEW_ID);
if (fakeStatusBarView != null) {
fakeStatusBarView.setVisibility(View.GONE);
}
View fakeTranslucentView = decorView.findViewById(FAKE_TRANSLUCENT_VIEW_ID);
if (fakeTranslucentView != null) {
fakeTranslucentView.setVisibility(View.GONE);
}
}
@TargetApi(Build.VERSION_CODES.M)
public static void setLightMode(Activity activity) {
setMIUIStatusBarDarkIcon(activity, true);
setMeizuStatusBarDarkIcon(activity, true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
}
@TargetApi(Build.VERSION_CODES.M)
public static void setDarkMode(Activity activity) {
setMIUIStatusBarDarkIcon(activity, false);
setMeizuStatusBarDarkIcon(activity, false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
}
/**
* 修改 MIUI V6 以上状态栏颜色
*/
private static void setMIUIStatusBarDarkIcon(@NonNull Activity activity, boolean darkIcon) {
Class<? extends Window> clazz = activity.getWindow().getClass();
try {
Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
int darkModeFlag = field.getInt(layoutParams);
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
extraFlagField.invoke(activity.getWindow(), darkIcon ? darkModeFlag : 0, darkModeFlag);
} catch (Exception e) {
//e.printStackTrace();
}
}
/**
* 修改魅族状态栏字体颜色 Flyme 4.0
*/
private static void setMeizuStatusBarDarkIcon(@NonNull Activity activity, boolean darkIcon) {
try {
WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags");
darkFlag.setAccessible(true);
meizuFlags.setAccessible(true);
int bit = darkFlag.getInt(null);
int value = meizuFlags.getInt(lp);
if (darkIcon) {
value |= bit;
} else {
value &= ~bit;
}
meizuFlags.setInt(lp, value);
activity.getWindow().setAttributes(lp);
} catch (Exception e) {
//e.printStackTrace();
}
}
///////////////////////////////////////////////////////////////////////////////////
@TargetApi(Build.VERSION_CODES.KITKAT)
private static void clearPreviousSetting(Activity activity) {
ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
View fakeStatusBarView = decorView.findViewById(FAKE_STATUS_BAR_VIEW_ID);
if (fakeStatusBarView != null) {
decorView.removeView(fakeStatusBarView);
ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
rootView.setPadding(0, 0, 0, 0);
}
}
/**
* 添加半透明矩形条
*
* @param activity 需要设置的 activity
* @param statusBarAlpha 透明值
*/
private static void addTranslucentView(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha) {
ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);
View fakeTranslucentView = contentView.findViewById(FAKE_TRANSLUCENT_VIEW_ID);
if (fakeTranslucentView != null) {
if (fakeTranslucentView.getVisibility() == View.GONE) {
fakeTranslucentView.setVisibility(View.VISIBLE);
}
fakeTranslucentView.setBackgroundColor(Color.argb(statusBarAlpha, 0, 0, 0));
} else {
contentView.addView(createTranslucentStatusBarView(activity, statusBarAlpha));
}
}
/**
* 生成一个和状态栏大小相同的彩色矩形条
*
* @param activity 需要设置的 activity
* @param color 状态栏颜色值
* @return 状态栏矩形条
*/
private static View createStatusBarView(Activity activity, @ColorInt int color) {
return createStatusBarView(activity, color, 0);
}
/**
* 生成一个和状态栏大小相同的半透明矩形条
*
* @param activity 需要设置的activity
* @param color 状态栏颜色值
* @param alpha 透明值
* @return 状态栏矩形条
*/
private static View createStatusBarView(Activity activity, @ColorInt int color, int alpha) {
// 绘制一个和状态栏一样高的矩形
View statusBarView = new View(activity);
LinearLayout.LayoutParams params =
new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));
statusBarView.setLayoutParams(params);
statusBarView.setBackgroundColor(calculateStatusColor(color, alpha));
statusBarView.setId(FAKE_STATUS_BAR_VIEW_ID);
return statusBarView;
}
/**
* 设置根布局参数
*/
private static void setRootView(Activity activity) {
ViewGroup parent = (ViewGroup) activity.findViewById(android.R.id.content);
for (int i = 0, count = parent.getChildCount(); i < count; i++) {
View childView = parent.getChildAt(i);
if (childView instanceof ViewGroup) {
childView.setFitsSystemWindows(true);
((ViewGroup) childView).setClipToPadding(true);
}
}
}
/**
* 设置透明
*/
private static void setTransparentForWindow(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
activity.getWindow()
.getDecorView()
.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
activity.getWindow()
.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
}
/**
* 使状态栏透明
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
private static void transparentStatusBar(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
} else {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
}
/**
* 创建半透明矩形 View
*
* @param alpha 透明值
* @return 半透明 View
*/
private static View createTranslucentStatusBarView(Activity activity, int alpha) {
// 绘制一个和状态栏一样高的矩形
View statusBarView = new View(activity);
LinearLayout.LayoutParams params =
new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));
statusBarView.setLayoutParams(params);
statusBarView.setBackgroundColor(Color.argb(alpha, 0, 0, 0));
statusBarView.setId(FAKE_TRANSLUCENT_VIEW_ID);
return statusBarView;
}
/**
* 获取状态栏高度
*
* @param context context
* @return 状态栏高度
*/
private static int getStatusBarHeight(Context context) {
// 获得状态栏高度
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
return context.getResources().getDimensionPixelSize(resourceId);
}
/**
* 计算状态栏颜色
*
* @param color color值
* @param alpha alpha值
* @return 最终的状态栏颜色
*/
private static int calculateStatusColor(@ColorInt int color, int alpha) {
if (alpha == 0) {
return color;
}
float a = 1 - alpha / 255f;
int red = color >> 16 & 0xff;
int green = color >> 8 & 0xff;
int blue = color & 0xff;
red = (int) (red * a + 0.5);
green = (int) (green * a + 0.5);
blue = (int) (blue * a + 0.5);
return 0xff << 24 | red << 16 | green << 8 | blue;
}
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="id" name="statusbarutil_fake_status_bar_view" />
<item type="id" name="statusbarutil_translucent_view" />
</resources>

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

78
app/build.gradle Normal file
View File

@ -0,0 +1,78 @@
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 33
defaultConfig {
applicationId "com.muqingbfq"
minSdk 23
//noinspection ExpiredTargetSdkVersion,OldTargetApi
targetSdk 33
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.6.1'
implementation 'com.google.android.material:material:1.9.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 "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'
//
implementation project(path: ':StatusBarUtil')
// api project(path: ':lrcview')
//
api "com.github.cy745:EaseView:e11c3208a9"
api "androidx.dynamicanimation:dynamicanimation-ktx:1.0.0-alpha03"
}

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,89 @@
<?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"/>
<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:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.muqing"
android:usesCleartextTraffic="true"
android:preserveLegacyExternalStorage="true"
android:requestLegacyExternalStorage="true"
tools:targetApi="s">
<activity
android:name=".home"
android:exported="true">
<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" />
<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.floating" />
<service android:name=".mq.FloatingLyricsService" />
<receiver
android:name=".MyButtonClickReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
</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,50 @@
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(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 +
'}';
}
}

View File

@ -0,0 +1,170 @@
package com.muqingbfq;
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.AudioAttributes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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.mpatric.mp3agic.ID3v2;
import com.mpatric.mp3agic.Mp3File;
import com.muqingbfq.fragment.bflb_db;
import com.muqingbfq.fragment.mp3;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wj;
import java.io.IOException;
public class MediaPlayer extends android.media.MediaPlayer {
// 每秒更新一次进度
@SuppressLint("UnsafeOptInUsageError")
public MediaPlayer() {
setOnErrorListener((mediaPlayer, i, i1) -> {
if (bfqkz.list.isEmpty()) {
return false;
}
//针对错误进行相应的处理
bfqkz.list.remove(bfqkz.xm);
bfqkz.xm = bfqkz.list.get(bfqkz.getmti());
new bfqkz.mp3(com.muqingbfq.api.
url.hq(bfqkz.xm));
return false;
});
setOnCompletionListener(mediaPlayer -> {
if (bfqkz.list.isEmpty()) {
return;
}
bfq_an.xyq();
});
setAudioAttributes(new AudioAttributes
.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build());
// main.handler.post(updateSeekBar); // 在播放开始时启动更新进度
}
@Override
public void pause() throws IllegalStateException {
if (isPlaying()) {
super.pause();
// bfq.isPlaying = false;
}
if (bfqkz.notify != null) {
bfqkz.notify.tzl_button();
}
}
@Override
public void start() throws IllegalStateException {
if (bfqkz.xm == null) {
if (bfqkz.list != null && !bfqkz.list.isEmpty()) {
bfq_an.xyq();
}
return;
}
super.start();
if (bfqkz.notify != null) {
bfqkz.notify.tzl_button();
}
// bfq.isPlaying = true;
}
public void setDataSource(MP3 mp3) throws IOException {
reset();
super.setDataSource(mp3.url);
prepare();
start();
bfqkz.xm = mp3;
main.handler.post(() -> {
bfui();
if (bfqkz.notify != null) {
bfqkz.notify.tzl();
}
});
new Thread() {
@Override
public void run() {
super.run();
if (bfqkz.lishi_list.size() >= 100) {
bfqkz.lishi_list.remove(0);
}
bfqkz.lishi_list.remove(bfqkz.xm);
if (!bfqkz.lishi_list.contains(bfqkz.xm)) {
bfqkz.lishi_list.add(0, bfqkz.xm);
wj.xrwb(wj.gd + "mp3_hc.json", new com.google.gson.Gson().toJson(bfqkz.lishi_list));
}
wj.setMP3ToFile(bfqkz.xm);
}
}.start();
}
public void DataSource(MP3 path) throws Exception {
reset();
super.setDataSource(path.url);
prepare();
setTX();
}
public void setTX() {
Glide.with(main.application)
.asBitmap()
.load(bfqkz.xm.picurl)
.listener(new RequestListener<Bitmap>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model,
@NonNull Target<Bitmap> target,
boolean isFirstResource) {
Bitmap bitmap = null;
try {
Mp3File mp3file = new Mp3File(bfqkz.xm.picurl);
if (mp3file.hasId3v2Tag()) {
ID3v2 id3v2Tag = mp3file.getId3v2Tag();
byte[] albumImage = id3v2Tag.getAlbumImage();
bitmap =
BitmapFactory.decodeByteArray(albumImage, 0, albumImage.length);
}
} catch (Exception a) {
gj.sc(getClass() + " yc:" + a);
}
if (bfqkz.notify != null) {
bfqkz.notify.setbitmap(bitmap);
}
return false;
}
@Override
public boolean onResourceReady(@NonNull Bitmap bitmap, @NonNull Object model, Target<Bitmap> target,
@NonNull DataSource dataSource,
boolean isFirstResource) {
if (bfqkz.notify != null) {
bfqkz.notify.setbitmap(bitmap);
}
return false;
}
})
.submit();
}
@SuppressLint("NotifyDataSetChanged")
public void bfui() {
setTX();
if (bflb_db.adapter != null) {
// bflb_db.adapter.
bflb_db.adapter.notifyDataSetChanged();
}
if (mp3.adapter != null) {
mp3.adapter.notifyDataSetChanged();
}
}
}

View File

@ -0,0 +1,213 @@
package com.muqingbfq;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.provider.Settings;
import android.view.KeyEvent;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.muqingbfq.mq.FloatingLyricsService;
import com.muqingbfq.mq.wj;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
public class MyButtonClickReceiver extends BroadcastReceiver {
private final Timer timer = new Timer();
private static int clickCount;
public MyButtonClickReceiver() {
super();
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
int bluetoothState = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, 0);
//蓝牙断开
if (bluetoothState == BluetoothAdapter.STATE_DISCONNECTED) {
receiverPause();
}
return;
}
if (action.equals("android.intent.action.HEADSET_PLUG")) {
if (intent.hasExtra("state")) {
if (intent.getIntExtra("state", 2) == 0) {
//拔出
if (bfqkz.mt.isPlaying()) {
receiverPause();
}
} else if (intent.getIntExtra("state", 2) == 1) {
receiverPlay();
//插入
}
}
return;
}
if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
KeyEvent keyEvent = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK && keyEvent.getAction() == KeyEvent.ACTION_UP) {
clickCount = clickCount + 1;
if (clickCount == 1) {
HeadsetTimerTask headsetTimerTask = new HeadsetTimerTask();
timer.schedule(headsetTimerTask, 500);
}
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_NEXT && keyEvent.getAction() == KeyEvent.ACTION_UP) {
handler(2);
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PREVIOUS && keyEvent.getAction() == KeyEvent.ACTION_UP) {
handler(3);
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PAUSE && keyEvent.getAction() == KeyEvent.ACTION_UP) {
handler(4);
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY && keyEvent.getAction() == KeyEvent.ACTION_UP) {
handler(5);
}
return;
}
switch (action) {
case "kg":
playOrPause();
break;
case "syq":
bfq_an.syq();
break;
case "xyq":
bfq_an.xyq();
break;
case "lrc":
if (FloatingLyricsService.lei == null) {
if (!Settings.canDrawOverlays(main.application)) {
// 无权限需要申请权限
main.application.startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + main.application.getPackageName())));
} else {
main.application.startService(
new Intent(main.application, FloatingLyricsService.class));
}
return;
}
FloatingLyricsService lei = FloatingLyricsService.lei;
if (lei.setup.i == 1) {
lei.setyc();
} else {
lei.setup.i = 0;
lei.baocun();
main.application.stopService(
new Intent(main.application, FloatingLyricsService.class));
}
break;
case "like":
try {
Gson gson = new Gson();
Type type = new TypeToken<List<MP3>>() {
}.getType();
List<MP3> list = gson.fromJson(wj.dqwb(wj.gd + "mp3_like.json"), type);
if (list == null) {
list = new ArrayList<>();
}
if (bfqkz.like_bool) {
list.remove(bfqkz.xm);
bfqkz.like_bool = false;
} else {
if (!list.contains(bfqkz.xm)) {
list.add(bfqkz.xm);
bfqkz.like_bool = true;
}
}
wj.xrwb(wj.gd + "mp3_like.json", gson.toJson(list));
} catch (Exception e) {
e.printStackTrace();
}
break;
}
// 处理按钮点击事件的逻辑
}
class HeadsetTimerTask extends TimerTask {
@Override
public void run() {
try {
if (clickCount == 1) {
handler(1);
} else if (clickCount == 2) {
handler(2);
} else if (clickCount >= 3) {
handler(3);
}
clickCount = 0;
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void handler(int a) {
switch (a) {
case 1:
playOrPause();
break;
case 2:
playNext();
break;
case 3:
playPrevious();
break;
case 4:
receiverPause();
break;
case 5:
receiverPlay();
break;
default:
break;
}
}
// * 对蓝牙 播放
public void receiverPlay() {
bfqkz.mt.start();
}
// * 对蓝牙 暂停
public void receiverPause() {
bfqkz.mt.pause();
}
/**
* 对蓝牙 播放-暂停
*/
public static void playOrPause() {
if (bfqkz.mt == null) {
return;
}
// gj.sc(isMusicServiceBound);播放/暂停按钮点击事件 if (isMusicServiceBound)
if (bfqkz.mt.isPlaying()) {
bfqkz.mt.pause();
} else {
bfqkz.mt.start();
}
bfqkz.notify.tzl();
}
/**
* 对蓝牙 下一首
*/
public void playNext() {
bfq_an.xyq();
}
/**
* 对蓝牙 上一首
*/
public void playPrevious() {
bfq_an.syq();
}
}

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,185 @@
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.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 AppCompatActivity<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 -> {
new Thread() {
@Override
public void run() {
super.run();
int jianchagengxin = gj.jianchagengxin(activity_about_software.this);
if (jianchagengxin == 400) {
gj.xcts(activity_about_software.this, "无网络");
} else if (jianchagengxin == 0) {
gj.xcts(activity_about_software.this, "已经是最新的客户端了");
}
}
}.start();
});
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);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
viewById.setText(Html.fromHtml(stringBuilder.toString(), Html.FROM_HTML_MODE_LEGACY));
} else {
viewById.setText(Html.fromHtml(stringBuilder.toString()));
}
open.close();
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
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,352 @@
package com.muqingbfq;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
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.DefaultItemAnimator;
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.dialog.MaterialAlertDialogBuilder;
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.fragment.search;
import com.muqingbfq.mq.FragmentActivity;
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.Iterator;
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());
}
class VH extends RecyclerView.ViewHolder {
public VH(@NonNull View itemView) {
super(itemView);
}
}
@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 RecyclerView.Adapter<VH>() {
@NonNull
@Override
public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new VH(LayoutInflater.from(parent.getContext())
.inflate(R.layout.view_search_item, 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 -> {
binding.searchview.setText(s);
start(s);
});
}
@Override
public int getItemCount() {
return list.size();
}
});
//设置项点击监听
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;
});
}
public void dismiss() {
binding.searchview.hide();
}
private void addSearchRecord(String name) {
try {
if (!binding.xxbj1.isShown()) {
binding.xxbj1.setVisibility(View.VISIBLE);
}
int existingIndex = json_list.indexOf(name);
if (existingIndex != -1) {
// 交换两个元素的位置
json_list.remove(name);
json_list.add(0, name);
binding.listRecycler.getAdapter().notifyItemMoved(existingIndex, 0);
} else {
// json_list.remove(name);
json_list.add(0, name);
binding.listRecycler.getAdapter().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);
addSearchRecord(name);
}
}
class SearchRecordAdapter extends RecyclerView.Adapter<SearchRecordAdapter.ViewHolder> {
public SearchRecordAdapter() {
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);
}
}
if (json_list.isEmpty()) {
binding.xxbj1.setVisibility(View.INVISIBLE);
}
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 ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(ListTextBinding.inflate(LayoutInflater.from(parent.getContext()),
parent, false));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
String keyword = json_list.get(position);
holder.binding.getRoot().setText(keyword);
holder.binding.getRoot().setOnClickListener(v -> {
binding.toolbar.setText(keyword);
start(keyword);
});
holder.binding.getRoot().setOnCloseIconClickListener(view -> {
json_list.remove(keyword);
notifyItemRemoved(holder.getAdapterPosition());
wj.xrwb(wj.filesdri + wj.lishi_json, new Gson().toJson(json_list));
});
}
@Override
public int getItemCount() {
return json_list.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
ListTextBinding binding;
public ViewHolder(ListTextBinding itemView) {
super(itemView.getRoot());
binding = itemView;
}
}
}
@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,76 @@
package com.muqingbfq.adapter;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.muqingbfq.MP3;
import com.muqingbfq.R;
import com.muqingbfq.api.url;
import com.muqingbfq.bfqkz;
import com.muqingbfq.databinding.ListMp3ImageBinding;
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<>();
@NonNull
@Override
public VH<ListMp3ImageBinding> onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new VH<>(ListMp3ImageBinding.inflate(
LayoutInflater.from(parent.getContext()), parent, false));
}
int position_wei;
@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);
if (bfqkz.xm != null && x.id.equals(bfqkz.xm.id)) {
holder.binding.getRoot().setCardBackgroundColor(
gj.getThemeColor(holder.itemView.getContext(), com.google.android.material.R.attr.colorSurfaceVariant));
} else {
holder.binding.getRoot().setCardBackgroundColor(ContextCompat
.getColor(holder.itemView.getContext(), android.R.color.transparent));
}
holder.itemView.setOnClickListener(view -> {
if (bfqkz.xm == null || !bfqkz.xm.id.equals(x.id)) {
bfqkz.xm = x;
new url(x);
notifyDataSetChanged();
} else if (!bfqkz.mt.isPlaying()) {
bfqkz.mt.start();
}
if (!bfqkz.list.contains(x)) {
bfqkz.list.add(0, x);
}
// bfqkz.list.addAll(list);
// bfq.start(getContext());
});
Glide.with(holder.itemView.getContext()).load(x.picurl)
.apply(new RequestOptions().placeholder(R.drawable.ic_launcher_foreground))
.error(R.drawable.ic_launcher_foreground)
.into(holder.binding.imageView);
}
@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,182 @@
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.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 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);
getLrc(x.id);
Media.loadLyric();
try {
if (wj.cz(x.id)) {
x.url = x.id;
return x;
} else if (wj.cz(wj.mp3 + x.id)) {
x.url = wj.mp3 + x.id;
return x;
} else if (wj.cz(wj.filesdri + "hc/" + x.id)) {
x.url = wj.filesdri + "hc/" + x.id;
return x;
}
String level = "standard";
boolean wiFiConnected = gj.isWiFiConnected();
if (wiFiConnected) {
level = "exhigh";
}
String hq = wl.hq(api + "?id=" + x.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"));
x.url = jsonObject.getString("url");
return x;
} catch (JSONException e) {
gj.sc("url hq :" + e);
}
return null;
}
@Override
public void run() {
super.run();
com.muqingbfq.bfqkz.mp3(hq(x));
}
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,603 @@
package com.muqingbfq;
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.BitmapFactory;
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.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.animation.LinearInterpolator;
import android.widget.SeekBar;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
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.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.jaeger.library.StatusBarUtil;
import com.mpatric.mp3agic.ID3v2;
import com.mpatric.mp3agic.Mp3File;
import com.muqingbfq.api.FileDownloader;
import com.muqingbfq.databinding.ActivityBfqBinding;
import com.muqingbfq.fragment.Media;
import com.muqingbfq.mq.AppCompatActivity;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wj;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class bfq extends AppCompatActivity<ActivityBfqBinding>
implements GestureDetector.OnGestureListener {
public String lrc;
public MP3 mp3;
public boolean isplay = true;
GestureDetector gestureDetector;
int seekbarH = 0;
private void lrc(View v) {
// 隐藏view2并显示view1的动画效果
v.animate()
.alpha(0.0f)
.setDuration(500)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
v.setVisibility(View.GONE);
binding.cardview.setVisibility(View.VISIBLE);
binding.cardview.setAlpha(0.0f);
binding.cardview.animate().alpha(1.0f).setDuration(500).setListener(null);
}
});
}
@SuppressLint("ClickableViewAccessibility")
private void setLrc() {
DisplayMetrics dm = getResources().getDisplayMetrics();
ViewGroup.LayoutParams layoutParams = binding.cardview.getLayoutParams();
if (!gj.isTablet(this)) {
layoutParams.height = (int) (dm.widthPixels / 1.3f);
layoutParams.width = (int) (dm.widthPixels / 1.3f);
binding.lrcView.setOnClickListener(this::lrc);
binding.lrcView.setOnSingerClickListener(() -> lrc(binding.lrcView));
// binding.lrcView.setTextGravity(GRAVITY_LEFT)
} else {
layoutParams.height = (int) (dm.heightPixels / 2.0f);
layoutParams.width = (int) (dm.heightPixels / 2.0f);
}
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 -> {
bfqkz.mt.seekTo((int) time);
return false;
});
binding.tdt.setThumb(null);
binding.tdt.post(() -> seekbarH = binding.tdt.getHeight());
binding.tdt.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// 当进度发生变化时执行操作
setTime_b(bfq_an.getTime(progress));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
// 当开始拖动滑块时执行操作
// 创建 ValueAnimator 对象实现进度条高度的平滑过渡
ValueAnimator animator = ValueAnimator.ofInt(seekbarH,
seekbarH + 30);
animator.addUpdateListener(animation -> {
seekBar.getLayoutParams().height = (int) animation.getAnimatedValue();
seekBar.requestLayout();
});
animator.setDuration(200); // 设置动画持续时间为 200 毫秒
animator.start(); // 开始执行动画
isplay = false;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
// 当停止拖动滑块时执行操作
isplay = true;
// 创建 ValueAnimator 对象实现恢复进度条高度的平滑过渡
ValueAnimator animator = ValueAnimator.ofInt(seekbarH + 30,
seekbarH);
animator.addUpdateListener(animation -> {
seekBar.getLayoutParams().height = (int) animation.getAnimatedValue();
seekBar.requestLayout();
});
animator.setDuration(200); // 设置动画持续时间为 200 毫秒
animator.start(); // 开始执行动画
bfqkz.mt.seekTo(seekBar.getProgress());
}
});
}
public static void startactivity(Context context, MP3 mp3) {
gj.sc(mp3.toString());
Intent intent = new Intent(context, bfq.class);
intent.putExtra("MP3", mp3);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(intent);
}
ObjectAnimator rotateAnimation;
private void Animation() {
if (bfqkz.mt.isPlaying()) {
if (rotateAnimation.isPaused()) {
rotateAnimation.resume();
} else {
rotateAnimation.start();
}
} else {
rotateAnimation.pause();
}
}
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
StatusBarUtil.setTransparent(this);
setContentView();
gestureDetector = new GestureDetector(this, this);
setLrc();
rotateAnimation = ObjectAnimator.ofFloat(binding.cardview
, "rotation", 0f, 360f);
rotateAnimation.setDuration(30000); // 设置动画持续时间单位为毫秒
rotateAnimation.setRepeatCount(ObjectAnimator.INFINITE); // 设置重复次数为无限
rotateAnimation.setInterpolator(new LinearInterpolator()); // 设置插值器这里使用线性插值器
rotateAnimation.start();
binding.kg.setOnClickListener(v -> {
if (bfqkz.mt.isPlaying()) {
bfqkz.mt.pause();
setbf(false);
} else {
bfqkz.mt.start();
setbf(true);
}
Animation();
});
binding.xyq.setOnClickListener(v -> bfq_an.xyq());
binding.syq.setOnClickListener(v -> bfq_an.syq());
binding.image1.setOnClickListener(new toolbar());
binding.image2.setOnClickListener(new toolbar());
binding.bfqListMp3.
setOnClickListener(view1 -> com.muqingbfq.fragment.bflb_db.start(this));
binding.control.setOnClickListener(new bfq_an.control(binding.control));
binding.like.setOnClickListener(view1 -> {
try {
Gson gson = new Gson();
Type type = new TypeToken<List<MP3>>() {
}.getType();
List<MP3> list = gson.fromJson(wj.dqwb(wj.gd + "mp3_like.json"), type);
if (list == null) {
list = new ArrayList<>();
}
if (bfqkz.like_bool) {
list.remove(bfqkz.xm);
setlike(false);
} else {
if (!list.contains(bfqkz.xm)) {
list.add(bfqkz.xm);
setlike(true);
}
}
bfqkz.like_bool = !bfqkz.like_bool;
wj.xrwb(wj.gd + "mp3_like.json", gson.toJson(list));
} catch (Exception e) {
gj.sc(e);
}
});
binding.download.setOnClickListener(view -> {
if (wj.cz(wj.mp3 + bfqkz.xm.id)) {
gj.ts(this, "你已经下载过这首歌曲了");
return;
}
if (bfqkz.xm != null) {
new FileDownloader(bfq.this).downloadFile(bfqkz.xm);
}
});
Intent intent = getIntent();
mp3 = (MP3) intent.getSerializableExtra("MP3");
new thread().start();
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;
});
}
private class toolbar implements View.OnClickListener {
@Override
public void onClick(View v) {
if (v.getId() == R.id.image1) {
finish();
} else if (v.getId() == R.id.image2) {
com.muqingbfq.mq.gj.fx(v.getContext(),
"音乐名称:" + mp3.name +
"\n 作者:" + mp3.zz +
"\n 链接https://music.163.com/#/song?id=" + mp3.id);
}
}
}
class thread extends Thread {
@Override
public void run() {
super.run();
if (mp3 != null) {
if (bfqkz.xm == null || !bfqkz.xm.equals(mp3)) {
bfqkz.xm = mp3;
bfqkz.mp3(com.muqingbfq.api.url.hq(mp3));
}
}
if (binding == null) {
return;
}
main.handler.post(() -> {
if (mp3 != null) {
sx();
}
setbf(bfqkz.mt.isPlaying());
Animation();
});
// main.handler.post(runnable);
}
}
public void sx() {
setname(mp3.name);
setzz(mp3.zz);
bfq_an.islike();
int duration = bfqkz.mt.getDuration();
setMax(duration);
gj.sc(duration);
setTime_a(bfq_an.getTime(duration));
int position = bfqkz.mt.getCurrentPosition();
Progress(position);
setImageBitmap();
}
public void setname(String str) {
binding.name.setText(str);
}
public void setzz(String str) {
binding.zz.setText(str);
}
public void kgsetImageResource(int a) {
if (binding == null) {
return;
}
binding.kg.setImageResource(a);
}
@Override
protected ActivityBfqBinding getViewBindingObject(LayoutInflater layoutInflater) {
return ActivityBfqBinding.inflate(layoutInflater);
}
public void setlike(boolean bool) {
if (bool) {
binding.like.setImageTintList(ContextCompat.
getColorStateList(binding.getRoot().getContext(), android.R.color.holo_red_dark));
} else {
binding.like.setImageTintList(ColorStateList.valueOf(ColorTint));
}
islike = bool;
}
Runnable runnable = new Runnable() {
@Override
public void run() {
if (isplay) {
int position = bfqkz.mt.getCurrentPosition();
Progress(position);
}
if (mp3 != null && !mp3.equals(bfqkz.xm) && binding != null) {
mp3 = bfqkz.xm;
setname(mp3.name);
setzz(mp3.zz);
bfq_an.islike();
int duration = bfqkz.mt.getDuration();
setMax(duration);
gj.sc(duration);
setTime_a(bfq_an.getTime(duration));
int position = bfqkz.mt.getCurrentPosition();
Progress(position);
setImageBitmap();
}
if (bfqkz.mt.isPlaying() != isPlaying) {
setbf(bfqkz.mt.isPlaying());
}
if (bfqkz.like_bool != islike) {
setlike(bfqkz.like_bool);
}
if (!Objects.equals(bfqkz.lrc, lrc)) {
lrc = bfqkz.lrc;
String[] strings = Media.loadLyric();
binding.lrcView.loadLyric(strings[0], strings[1]);
}
main.handler.postDelayed(this, 1000); // 每秒更新一次进度
}
};
public boolean islike = false;
public boolean isPlaying = false;
public void setbf(boolean bool) {
if (bool) {
//开始
kgsetImageResource(R.drawable.bf);
} else {
//暂停
kgsetImageResource(R.drawable.zt);
}
isPlaying = bool;
}
public void setImageBitmap() {
if (binding == null) {
return;
}
if (wj.cz(bfqkz.xm.picurl)) {
try {
Mp3File mp3file = new Mp3File(bfqkz.xm.picurl);
if (mp3file.hasId3v2Tag()) {
ID3v2 id3v2Tag = mp3file.getId3v2Tag();
byte[] albumImage = id3v2Tag.getAlbumImage();
Bitmap bitmap = BitmapFactory.
decodeByteArray(albumImage, 0, albumImage.length);
binding.cardview.imageView.setImageBitmap(bitmap);
color(bitmap);
}
return;
} catch (Exception a) {
gj.sc(getClass() + " yc:" + a);
}
}
if (!isFinishing()) {
Glide.with(this)
.asBitmap()
.load(mp3.picurl)
.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 false;
}
@Override
public boolean onResourceReady(@NonNull Bitmap resource,
@NonNull Object model, Target<Bitmap> target,
@NonNull DataSource dataSource,
boolean isFirstResource) {
color(resource);
binding.cardview.imageView.setImageBitmap(resource);
return true;
}
}).into(binding.cardview.imageView);
}
}
private void color(Bitmap bitmap) {
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 int ColorTint = Color.WHITE;
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);*/
}
@Override
public void finish() {
super.finish();
}
@Override
protected void onStart() {
super.onStart();
main.handler.post(runnable);
}
@Override
protected void onStop() {
super.onStop();
main.handler.removeCallbacks(runnable);
}
public void setTime_a(String str) {
binding.timeA.setText(str);
}
public void setTime_b(String str) {
binding.timeB.setText(str);
}
public void setMax(int max) {
binding.tdt.setMax(Math.max(0, max));
}
public void Progress(int progress) {
int min = Math.min(progress, binding.tdt.getMax());
binding.tdt.setProgress(min);
binding.lrcView.updateTime(min, true);
}
@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;
}
private void switchViews(final View view1, final View view2) {
// 隐藏view1并显示view2的动画效果
if (binding.cardview.getVisibility() == View.VISIBLE) {
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(null);
}
});
}
}
// 判断触摸点是否在视图范围内的辅助方法
@Override
public boolean onScroll(@NonNull 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(@NonNull MotionEvent e1, @NonNull MotionEvent e2,
float velocityX, float velocityY) {
return false;
}
}

View File

@ -0,0 +1,141 @@
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 {
public static void syq() {
if (bfqkz.list.isEmpty()) {
return;
}
bfqkz.mt.pause();
int i = bfqkz.list.indexOf(bfqkz.xm) - 1;
if (i < 0) {
i = 0;
}
bfqkz.xm = bfqkz.list.get(i);
new url(bfqkz.xm);
}
public static void xyq() {
if (bfqkz.list.isEmpty()) {
return;
}
bfqkz.mt.pause();
// gj.sc(bfqkz.list.get(bfqkz.getmti()));
new url(bfqkz.list.get(bfqkz.getmti()));
}
public static class control implements View.OnClickListener {
ImageView imageView;
public control(ImageView imageView) {
this.imageView = imageView;
setImage(-1);
}
private void setImage(int i) {
gj.sc(bfqkz.ms);
bfqkz.mt.setLooping(bfqkz.ms == 0);
switch (bfqkz.ms) {
case 0:
imageView.setImageResource(R.drawable.mt_xh);
if (i == -1) {
break;
}
if (!bfqkz.list_baocun.isEmpty()) {
bfqkz.list.clear();
bfqkz.list.addAll(bfqkz.list_baocun);
}
break;
case 1:
imageView.setImageResource(R.drawable.mt_sx);
if (i == -1) {
break;
}
if (!bfqkz.list_baocun.isEmpty()) {
bfqkz.list.clear();
bfqkz.list.addAll(bfqkz.list_baocun);
}
break;
case 2:
imageView.setImageResource(R.drawable.mt_sj);
if (i == -1) {
break;
}
bfqkz.list_baocun.clear();
bfqkz.list_baocun.addAll(bfqkz.list);
Collections.shuffle(bfqkz.list);
break;
}
}
@Override
public void onClick(View v) {
if (bfqkz.ms == 2) {
bfqkz.ms = 0;
} else {
bfqkz.ms++;
}
setImage(bfqkz.ms);
main.edit.putInt("ms", bfqkz.ms);
main.edit.commit();
}
}
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,190 @@
package com.muqingbfq;
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.ComponentName;
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.BluetoothMusicController;
import com.muqingbfq.mq.gj;
import java.util.ArrayList;
import java.util.List;
public class bfqkz extends MediaBrowserServiceCompat {
public final static MediaPlayer mt = new MediaPlayer();
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 com.muqingbfq.mq.NotificationManagerCompat notify;
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 static void mp3(MP3 mp3) {
try {
if (mp3 == null) {
return;
}
if (TextUtils.isEmpty(mp3.url)) {
//针对错误进行相应的处理
bfqkz.list.remove(bfqkz.xm);
bfq_an.xyq();
return;
}
if (TextUtils.isEmpty(mp3.picurl)) {
mp3.picurl = url.picurl(mp3.id);
}
mt.setDataSource(mp3);
} catch (Exception e) {
gj.sc("bfqkz mp3(" + mp3 + ") :" + e);
}
}
public static class mp3 extends Thread {
MP3 mp3;
public mp3(MP3 mp3) {
this.mp3 = mp3;
start();
}
@Override
public void run() {
super.run();
mp3(mp3);
}
}
public MediaSessionCompat mSession;
public PlaybackStateCompat.Builder playback;
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);
mSession = new MediaSessionCompat(this, "MediaSessionCompat",
home.componentName, pendingIntent);
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);
}
class callback extends MediaSessionCompat.Callback {
@Override
public void onPlay() {
super.onPlay();
if (playback.build().getState() == PlaybackStateCompat.STATE_PAUSED) {
mt.start();
playback.setState(PlaybackStateCompat.STATE_PLAYING, 0, 1.0f)
.build();
mSession.setPlaybackState(playback.build());
}
gj.sc(this.getClass());
}
@Override
public void onPause() {
super.onPause();
if (playback.build().getState() == PlaybackStateCompat.STATE_PLAYING) {
mt.pause();
playback.setState(PlaybackStateCompat.STATE_PAUSED, 0, 1.0f)
.build();
mSession.setPlaybackState(playback.build());
}
}
@SuppressLint("SwitchIntDef")
@Override
public void onPlayFromUri(Uri uri, Bundle extras) {
try {
switch (playback.build().getState()) {
case PlaybackStateCompat.STATE_PLAYING:
case PlaybackStateCompat.STATE_PAUSED:
case PlaybackStateCompat.STATE_NONE:
// mp3(uri);/
playback.setState(PlaybackStateCompat.STATE_CONNECTING, 0, 1.0f)
.build();
mSession.setPlaybackState(playback.build());
//我们可以保存当前播放音乐的信息以便客户端刷新UI
mSession.setMetadata(new MediaMetadataCompat.Builder()
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, extras.getString("title"))
.build()
);
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
@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,139 @@
package com.muqingbfq.fragment;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.muqingbfq.MP3;
import com.muqingbfq.R;
import com.muqingbfq.api.url;
import com.muqingbfq.bfqkz;
import com.muqingbfq.databinding.FragmentBflbDbBinding;
import com.muqingbfq.databinding.ListMp3ABinding;
import com.muqingbfq.list.MyViewHoder;
import com.muqingbfq.yc;
import java.util.Collections;
public class bflb_db extends BottomSheetDialog {
public static RecyclerView.Adapter<MyViewHoder> adapter;
FragmentBflbDbBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = FragmentBflbDbBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
try {
binding.lb.setAdapter(new spq());
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.getAdapterPosition();
int toPosition = target.getAdapterPosition();
// 在这里处理数据集的移动
Collections.swap(bfqkz.list,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() {
int i = bfqkz.list.indexOf(bfqkz.xm);
if (i == -1) {
i = 0;
}
return i;
}
public bflb_db(Context context) {
super(context);
}
public static void start(Context context) {
new bflb_db(context).show();
}
private class spq extends RecyclerView.Adapter<MyViewHoder> {
public spq() {
adapter = this;
}
@NonNull
@Override
public MyViewHoder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new MyViewHoder(ListMp3ABinding.
inflate(getLayoutInflater(),parent,false));
}
@Override
public void onBindViewHolder(@NonNull MyViewHoder holder, int position) {
MP3 x = bfqkz.list.get(position);
holder.bindingA.name.setText(x.name);
holder.bindingA.zz.setText(String.format(" · %s", x.zz));
int color = ContextCompat.getColor(holder.getContext(), R.color.text);
if (bfqkz.xm != null && x.id.equals(bfqkz.xm.id)) {
color = ContextCompat.getColor(holder.getContext(), R.color.text_cz);
}
holder.bindingA.name.setTextColor(color);
holder.bindingA.zz.setTextColor(color);
holder.itemView.setOnClickListener(view -> {
if (bfqkz.xm != x) {
bfqkz.xm = x;
new url(x);
}
});
holder.bindingA.delete.setOnClickListener(v -> {
bfqkz.list.remove(holder.getAdapterPosition());
notifyItemRemoved(holder.getAdapterPosition());
});
}
@Override
public int getItemCount() {
// binding.textView.setText(String.valueOf(bfqkz.list.size()));
return bfqkz.list.size();
}
}
@Override
public void dismiss() {
super.dismiss();
adapter = null;
}
}

View File

@ -0,0 +1,152 @@
package com.muqingbfq.fragment;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.muqingbfq.MP3;
import com.muqingbfq.R;
import com.muqingbfq.bfq;
import com.muqingbfq.bfq_an;
import com.muqingbfq.bfqkz;
import com.muqingbfq.databinding.FragmentBfqDbBinding;
import java.util.Objects;
public class bfq_db extends Fragment implements GestureDetector.OnGestureListener {
FragmentBfqDbBinding binding;
private GestureDetector gestureDetector;
@SuppressLint("ClickableViewAccessibility")
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentBfqDbBinding.inflate(inflater, container, false);
// 获取当前活动的主题
binding.kg.setOnClickListener(v -> {
if (bfqkz.mt.isPlaying()) {
bfqkz.mt.pause();
} else {
bfqkz.mt.start();
}
setkg(bfqkz.mt.isPlaying());
});
binding.txb.setOnClickListener(view -> bflb_db.start(getContext()));
gestureDetector = new GestureDetector(getContext(), this);
binding.getRoot().setOnTouchListener((view, motionEvent) -> {
gestureDetector.onTouchEvent(motionEvent);
if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
binding.linearLayout.setTranslationX(0);
// binding.getRoot().setAlpha(1.0f);
} else if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
// binding.getRoot().setAlpha(0.2f);
}
return false;
});
return binding.getRoot();
}
@Override
public void onResume() {
super.onResume();
handler.post(runnable);
}
@Override
public void onPause() {
super.onPause();
handler.removeCallbacks(runnable);
}
MP3 mp3;
boolean isPlaying = false, isvisible = false;
Handler handler = new Handler();
Runnable runnable = new Runnable() {
@Override
public void run() {
if (!Objects.equals(mp3, bfqkz.xm)) {
mp3 = bfqkz.xm;
setname(mp3.name, " - " + mp3.zz);
}
if (bfqkz.mt.isPlaying() != isPlaying) {
setkg(bfqkz.mt.isPlaying());
}
if (isvisible != bfqkz.list.isEmpty()) {
isvisible = bfqkz.list.isEmpty();
if (isvisible) {
binding.getRoot().setVisibility(View.GONE);
} else {
binding.getRoot().setVisibility(View.VISIBLE);
}
}
handler.postDelayed(this, 1000);
}
};
public void setkg(boolean bool) {
if (bool) {
binding.kg.setImageResource(R.drawable.bf);
} else {
binding.kg.setImageResource(R.drawable.zt);
}
isPlaying = bool;
}
public void setname(String a,String b) {
binding.textview1.setText(a);
binding.textview2.setText(b);
}
@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);
return true;
}
@Override
public boolean onScroll(@Nullable MotionEvent motionEvent, @NonNull MotionEvent motionEvent1,
float v, float v1) {
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 (distance > threshold) {
// 向左滑动
// 在这里添加你的逻辑代码
bfq_an.xyq();
} else if (distance < -threshold) {
// 向右滑动
// 在这里添加你的逻辑代码
bfq_an.syq();
}
return true;
}
}

View File

@ -0,0 +1,352 @@
package com.muqingbfq.fragment;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Intent;
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.os.Bundle;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.palette.graphics.Palette;
import androidx.recyclerview.widget.GridLayoutManager;
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.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.muqingbfq.R;
import com.muqingbfq.XM;
import com.muqingbfq.api.playlist;
import com.muqingbfq.api.resource;
import com.muqingbfq.bfqkz;
import com.muqingbfq.databinding.ActivityGdBinding;
import com.muqingbfq.databinding.ListGdBBinding;
import com.muqingbfq.databinding.ListGdBinding;
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;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class gd extends com.muqingbfq.mq.FragmentActivity<ActivityGdBinding> {
public static String gdid;
private final List<XM> list = new ArrayList<>();
public baseadapter 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());
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getViewBinding().getRoot());
setToolbar();
Intent intent = getIntent();
binding.title.setText(intent.getStringExtra("name"));
adapter = new baseadapter(this, list);
k = (int) (getResources().getDisplayMetrics().widthPixels / getResources().getDisplayMetrics().density + 0.5f);
GridLayoutManager gridLayoutManager = new GridLayoutManager(this, k / 120);
binding.lb.setLayoutManager(gridLayoutManager);
binding.lb.setAdapter(adapter);
String id = intent.getStringExtra("id");
new start(id);
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
ActivityCompat.finishAfterTransition(this);
}
return true;
}
@Override
protected ActivityGdBinding getViewBindingObject(LayoutInflater layoutInflater) {
return ActivityGdBinding.inflate(layoutInflater);
}
@SuppressLint("NotifyDataSetChanged")
class start extends Thread {
String id;
public start(String id) {
binding.recyclerview1Bar.setVisibility(View.VISIBLE);
this.id = id;
list.clear();
start();
}
@Override
public void run() {
super.run();
if (id.equals("排行榜")) {
resource.leaderboard(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");
list.add(new XM(id, name, coverImgUrl));
}
} catch (Exception e) {
gj.sc(e);
}
}
main.handler.post(() -> {
adapter.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 static class baseadapter extends RecyclerView.Adapter<VH> {
Activity context;
public List<XM> list;
public baseadapter(Activity context, List<XM> list) {
this.context = context;
this.list = list;
}
boolean bool = false;
public baseadapter(Activity context, List<XM> list, boolean bool) {
this.context = context;
this.list = list;
this.bool = bool;
}
public void setonlong(int position) {
XM xm = list.get(position);
gj.sc(xm.name);
String[] stringArray = context.getResources()
.getStringArray(R.array.gd_list);
if (!wj.cz(wj.gd + xm.id)) {
stringArray = new String[]{"下载歌单"};
}
String[] finalStringArray = stringArray;
new MaterialAlertDialogBuilder(context).
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();
}
@NonNull
@Override
public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (bool) {
return new VH(ListGdBBinding.bind(LayoutInflater.from(context)
.inflate(R.layout.list_gd_b, parent, false)));
}
return new VH(ListGdBinding.bind(LayoutInflater.from(context)
.inflate(R.layout.list_gd, parent, false)));
}
@Override
public void onBindViewHolder(@NonNull VH holder, int position) {
XM xm = list.get(position);
holder.itemView.setOnClickListener(new CARD(position));
Drawable color_kg = ContextCompat.getDrawable(context, R.drawable.zt);
if (xm.id.equals(gdid)) {
color_kg = ContextCompat.getDrawable(context, R.drawable.bf);
}
if (bool) {
holder.bindingB.text1.setText(xm.name);
holder.bindingB.text2.setText(xm.message);
Glide.with(holder.itemView.getContext())
.load(xm.picurl)
.apply(new RequestOptions()
.placeholder(R.drawable.ic_launcher_foreground)
.error(R.drawable.ic_launcher_foreground))
.into(holder.bindingB.image);
holder.bindingB.kg.setOnClickListener(new KG(this, xm.id));
} else {
holder.binding.text1.setText(xm.name);
holder.binding.kg.setImageDrawable(color_kg);
holder.binding.kg.setOnClickListener(new KG(this, xm.id));
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 false;
}
@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.itemView.setOnLongClickListener(v -> {
setonlong(position);
return false;
});
}
class KG implements View.OnClickListener {
RecyclerView.Adapter adapter;
String id;
public KG(RecyclerView.Adapter adapter, String id) {
this.adapter = adapter;
this.id = id;
}
@Override
public void onClick(View v) {
new Thread() {
@SuppressLint("NotifyDataSetChanged")
@Override
public void run() {
super.run();
boolean an = playlist.hq(bfqkz.list, id);
if (bfqkz.ms == 2) {
Collections.shuffle(bfqkz.list);
}
main.handler.post(() -> {
if (an) {
com.muqingbfq.bfq_an.xyq();
((ImageView) v).setImageResource(R.drawable.bf);
com.muqingbfq.fragment.gd.gdid = id;
}
adapter.notifyDataSetChanged();
});
}
}.start();
}
}
@Override
public int getItemCount() {
return list.size();
}
class CARD implements View.OnClickListener {
int position;
public CARD(int position) {
this.position = position;
}
@Override
public void onClick(View view) {
XM xm = list.get(position);
mp3.start(context, new String[]{xm.id, xm.name}, view);
}
}
}
static class VH extends RecyclerView.ViewHolder {
public ListGdBinding binding;
public VH(@NonNull ListGdBinding itemView) {
super(itemView.getRoot());
binding = itemView;
}
ListGdBBinding bindingB;
public VH(@NonNull ListGdBBinding itemView) {
super(itemView.getRoot());
bindingB = itemView;
}
}
}

View File

@ -0,0 +1,117 @@
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.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);
}
@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);
binding.recyclerview1.setAdapter(new gd.baseadapter(getActivity(), list));
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);
}
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();
}
}

View File

@ -0,0 +1,336 @@
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.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 androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.muqingbfq.MP3;
import com.muqingbfq.R;
import com.muqingbfq.api.FileDownloader;
import com.muqingbfq.api.playlist;
import com.muqingbfq.bfq;
import com.muqingbfq.bfq_an;
import com.muqingbfq.bfqkz;
import com.muqingbfq.databinding.ActivityMp3Binding;
import com.muqingbfq.databinding.ListMp3Binding;
import com.muqingbfq.list.MyViewHoder;
import com.muqingbfq.main;
import com.muqingbfq.mq.FragmentActivity;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wj;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
public class mp3 extends FragmentActivity<ActivityMp3Binding> {
private List<MP3> list = new ArrayList<>();
private List<MP3> list_ys = new ArrayList<>();
public static 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());
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getViewBinding().getRoot());
setToolbar();
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) {
}
});
}
@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;
}
@Override
public void onBackPressed() {
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);
}
}
@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 static class Adapter extends RecyclerView.Adapter<MyViewHoder> implements Filterable {
private List<MP3> list;
private List<MP3> list_ys;
public Adapter(List<MP3> list) {
this.list = list;
list_ys = list;
}
@NonNull
@Override
public MyViewHoder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new MyViewHoder(ListMp3Binding.bind(LayoutInflater.from(parent.getContext()).
inflate(R.layout.list_mp3,
parent, false)));
}
@Override
public void onBindViewHolder(@NonNull MyViewHoder holder, int position) {
MP3 x = list.get(position);
holder.binding.text1.setText(String.valueOf(position + 1));
holder.binding.name.setText(x.name);
holder.binding.zz.setText(x.zz);
if (bfqkz.xm != null && x.id.equals(bfqkz.xm.id)) {
TypedValue typedValue = new TypedValue();
holder.itemView.getContext().getTheme().resolveAttribute(
com.google.android.material.R.attr.colorSurfaceVariant, typedValue, true);
int colorSurface = typedValue.data;
// 这里 colorSurface 就是你要找的颜色值
holder.binding.getRoot().setCardBackgroundColor(colorSurface);
}else{
holder.binding.getRoot().setCardBackgroundColor(ContextCompat
.getColor(holder.itemView.getContext(), android.R.color.transparent));
}
// holder.binding.zz.setTextColor(color);
holder.itemView.setOnClickListener(view -> {
if (bfqkz.list!=list) {
bfqkz.list.clear();
bfqkz.list.addAll(list);
}
bfq.startactivity(holder.getContext(), x);
});
holder.itemView.setOnLongClickListener(view -> {
List<String> stringList = new ArrayList<>();
boolean getlike = bfq_an.getlike(x);
if (getlike) {
stringList.add("取消喜欢");
} else {
stringList.add("喜欢歌曲");
}
if (wj.cz(wj.mp3 + x.id)) {
stringList.add("删除下载");
} else {
stringList.add("下载歌曲");
}
stringList.add("复制名字");
String[] array = stringList.toArray(new String[0]);
new MaterialAlertDialogBuilder(view.getContext()).
setItems(array, (dialog, id) -> {
switch (array[id]) {
case "下载歌曲":
new FileDownloader(view.getContext()).downloadFile(x);
break;
case "删除下载":
wj.sc(wj.mp3 + x.id);
/* if (sc&&) {
list.remove(position);
notifyItemRemoved(position);
}*/
break;
case "喜欢歌曲":
case "取消喜欢":
try {
Gson gson = new Gson();
Type type = new TypeToken<List<MP3>>() {
}.getType();
List<MP3> list = gson.fromJson(wj.dqwb(wj.gd + "mp3_like.json"), type);
if (list == null) {
list = new ArrayList<>();
}
if (list.contains(x))
list.remove(x);
else
list.add(x);
wj.xrwb(wj.gd + "mp3_like.json", gson.toJson(list));
} catch (Exception e) {
e.printStackTrace();
}
break;
case "复制名字":
gj.fz(view.getContext(), x.name);
break;
}
}).show();
return false;
});
}
@Override
public int getItemCount() {
return list.size();
}
@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,230 @@
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.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;
@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 com.muqingbfq.fragment.mp3.Adapter(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 com.muqingbfq.fragment.gd.baseadapter(getActivity(),
list, true));
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();
}
}
List<Fragment> fragments=new ArrayList<>();
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,70 @@
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.home;
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://rust.coldmint.top/ftp/muqing/");
} 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,450 @@
package com.muqingbfq.fragment;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.graphics.drawable.Drawable;
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.core.content.ContextCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
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.bfqkz;
import com.muqingbfq.databinding.FragmentWdBinding;
import com.muqingbfq.databinding.ListGdBBinding;
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.ArrayList;
import java.util.Collections;
import java.util.List;
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, "开发中", ""}
};
@SuppressLint("StaticFieldLeak")
public static baseadapter adaper;
@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}, holder.textView);
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(main.sp.getString("Cookie", "")).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) {
new threadLogin(main.sp.getString("Cookie", ""));
}
// ...
}
});
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) {
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();
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);
}
}
@SuppressLint("NotifyDataSetChanged")
public void sx() {
adaper.list.clear();
new Thread() {
@Override
public void run() {
super.run();
try {
File file = new File(wj.filesdri + "gd");
File[] files = file.listFiles();
for (File a : files) {
String id = a.getName();
if (id.endsWith(".json")) {
continue;
}
String dqwb = wj.dqwb(a.toString());
JSONObject jsonObject = new JSONObject(dqwb);
String name = jsonObject.getString("name");
String picUrl = jsonObject.getString("picUrl");
String message = jsonObject.getString("message");
adaper.list.add(new XM(id, name, message, picUrl));
}
main.handler.post(() -> {
adaper.notifyDataSetChanged();
if (adaper.list.isEmpty()) {
binding.recyclerview2Text.setVisibility(View.VISIBLE);
} else {
binding.recyclerview2Text.setVisibility(View.GONE);
}
});
} catch (Exception e) {
gj.sc(e);
}
}
}.start();
}
public static void addlist(XM xm) {
if (adaper != null) {
adaper.list.add(xm);
main.handler.post(() -> adaper.notifyItemChanged(adaper.list.size() - 1));
}
}
public static void removelist(XM xm) {
if (adaper != null) {
int i = adaper.list.indexOf(xm);
adaper.list.remove(xm);
adaper.notifyItemRemoved(i);
}
}
//登陆 获取用户信息 头像 昵称 签名
class threadLogin extends Thread {
String cookie;
public threadLogin(String cookie) {
this.cookie = cookie;
}
public void run() {
String hq = wl.hq("/user/account?cookie=" + 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);
});
}
}
}
class baseadapter extends RecyclerView.Adapter<gd.VH> {
public List<XM> list = new ArrayList<>();
@NonNull
@Override
public gd.VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new gd.VH(ListGdBBinding.bind(LayoutInflater.from(getContext())
.inflate(R.layout.list_gd_b, parent, false)));
}
@Override
public void onBindViewHolder(@NonNull gd.VH holder, int position) {
XM xm = list.get(position);
holder.itemView.setOnClickListener(v -> mp3.start(getActivity(), new String[]{xm.id, xm.name}, v));
holder.itemView.setOnLongClickListener(v -> {
String[] stringArray = {"更新歌单", "删除歌单"};
new MaterialAlertDialogBuilder(getContext()).
setItems(stringArray, (dialog, id) -> {
switch (stringArray[id]) {
case "更新歌单":
new Thread() {
@SuppressLint("NotifyDataSetChanged")
@Override
public void run() {
super.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);
xm.name = fh.name;
xm.picurl = fh.picurl;
xm.message = fh.message;
// json.put(fh.id, json);
wj.xrwb(wj.gd + xm.id, json.toString());
requireActivity().runOnUiThread(() -> notifyItemChanged(holder.getAdapterPosition()));
} catch (JSONException e) {
gj.sc("list gd onclick thear " + e);
}
}
}
}.start();
break;
case "删除歌单":
// 删除项目
try {
wj.sc(wj.gd + xm.id);
list.remove(xm);
notifyItemRemoved(position);
} catch (Exception e) {
gj.sc(e);
}
break;
}
// 在这里处理菜单项的点击事件
}).show();
return false;
});
holder.bindingB.text2.setText(xm.message);
holder.bindingB.text1.setText(xm.name);
holder.bindingB.kg.setOnClickListener(view1 -> {
ImageView tx = (ImageView) view1;
new Thread() {
@SuppressLint("NotifyDataSetChanged")
@Override
public void run() {
super.run();
boolean an = playlist.hq(bfqkz.list, xm.id);
if (bfqkz.ms == 2) {
Collections.shuffle(bfqkz.list);
}
main.handler.post(() -> {
if (an) {
com.muqingbfq.bfq_an.xyq();
tx.setImageResource(R.drawable.bf);
com.muqingbfq.fragment.gd.gdid = xm.id;
}
notifyDataSetChanged();
});
}
}.start();
});
Drawable color_kg = ContextCompat.getDrawable(getContext(), R.drawable.zt);
if (xm.id.equals(com.muqingbfq.fragment.gd.gdid)) {
color_kg = ContextCompat.getDrawable(getContext(), R.drawable.bf);
}
holder.bindingB.kg.setImageDrawable(color_kg);
Glide.with(holder.itemView.getContext())
.load(xm.picurl)
.apply(new RequestOptions()
.placeholder(R.drawable.ic_launcher_foreground)
.error(R.drawable.ic_launcher_foreground))
.into(holder.bindingB.image);
}
@Override
public int getItemCount() {
if (list.isEmpty()) {
binding.recyclerview2Text.setVisibility(View.VISIBLE);
} else {
binding.recyclerview2Text.setVisibility(View.GONE);
}
return list.size();
}
}
}

View File

@ -0,0 +1,239 @@
package com.muqingbfq;
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v4.media.MediaBrowserCompat;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.jaeger.library.StatusBarUtil;
import com.muqingbfq.databinding.ActivityHomeBinding;
import com.muqingbfq.fragment.gd_adapter;
import com.muqingbfq.fragment.wode;
import com.muqingbfq.mq.AppCompatActivity;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wl;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class home extends AppCompatActivity<ActivityHomeBinding> {
public MediaBrowserCompat mBrowser;
@Override
protected ActivityHomeBinding getViewBindingObject(LayoutInflater layoutInflater) {
return ActivityHomeBinding.inflate(layoutInflater);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.Theme_muqing);
super.onCreate(savedInstanceState);
wl.Cookie = main.sp.getString("Cookie", "");
if (wl.Cookie.isEmpty()) {
new Thread() {
@Override
public void run() {
super.run();
String hq = wl.hq("/register/anonimous");
try {
JSONObject jsonObject = new JSONObject(hq);
wl.setcookie(jsonObject.getString("cookie"));
home.this.runOnUiThread(() -> UI());
} catch (Exception e) {
com.muqingbfq.mq.gj.sc(e);
}
}
}.start();
} else {
UI();
}
}
@Override
protected void onResume() {
super.onResume();
}
public static ComponentName componentName;
public void toolbar() {
// binding.bar.setupWithDrawer
setSupportActionBar(binding.toolbar);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, binding.chct, binding.toolbar, R.string.app_name, R.string.app_name);
binding.chct.addDrawerListener(toggle);
toggle.syncState();
binding.toolbar.setOnClickListener(v -> activity_search.start(home.this, v));
}
public void UI() {
StatusBarUtil.setTransparent(home.this);
setContentView();
toolbar();
//初始化侧滑
binding.chb.setNavigationItemSelectedListener(item -> {
com.muqingbfq.fragment.sz.switch_sz(home.this, item.getItemId());
return false;
});
//初始化播放器组件
// 启动Service
if (componentName == null) {
componentName = new ComponentName(getApplicationContext(), bfqkz.class);
mBrowser = new MediaBrowserCompat(
getApplicationContext(), componentName
,//绑定服务端
browserConnectionCallback,//设置连接回调
null
);
mBrowser.connect();
}
//检测更新
new gj.jianchagengxin(home.this);
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.setSaveEnabled(false);
// ViewPager2 绑定到 TabLayou
binding.tablayout.setOnItemSelectedListener(item -> {
int itemId = item.getItemId();
if (itemId == R.id.a) {
binding.viewPager.setCurrentItem(0);
} else if (itemId == R.id.c) {
binding.viewPager.setCurrentItem(1);
}
return true;
});
binding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
switch (position) {
case 0:
binding.tablayout.setSelectedItemId(R.id.a);
break;
case 1:
binding.tablayout.setSelectedItemId(R.id.c);
break;
}
}
});
}
@Override
protected void onPause() {
super.onPause();
//在销毁 Activity 之前系统会先调用 onDestroy()系统调用此回调的原因如下
// 保存列表数据
SharedPreferences sharedPreferences = getSharedPreferences("list", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
String jsonList = new com.google.gson.Gson().toJson(bfqkz.list);
editor.putString("listData", jsonList);
editor.apply();
}
@Override
public void onBackPressed() {
moveTaskToBack(true);
}
/**
* 连接状态的回调接口连接成功时会调用onConnected()方法
*/
private final MediaBrowserCompat.ConnectionCallback browserConnectionCallback =
new MediaBrowserCompat.ConnectionCallback() {
@Override
public void onConnected() {
//必须在确保连接成功的前提下执行订阅的操作
if (mBrowser.isConnected()) {
//mediaId即为MediaBrowserService.onGetRoot的返回值
//若Service允许客户端连接则返回结果不为null其值为数据内容层次结构的根ID
//若拒绝连接则返回null
String mediaId = mBrowser.getRoot();
//Browser通过订阅的方式向Service请求数据发起订阅请求需要两个参数其一为mediaId
//而如果该mediaId已经被其他Browser实例订阅则需要在订阅之前取消mediaId的订阅者
//虽然订阅一个 已被订阅的mediaId 时会取代原Browser的订阅回调但却无法触发onChildrenLoaded回调
//ps虽然基本的概念是这样的但是Google在官方demo中有这么一段注释...
// This is temporary: A bug is being fixed that will make subscribe
// consistently call onChildrenLoaded initially, no matter if it is replacing an existing
// subscriber or not. Currently this only happens if the mediaID has no previous
// subscriber or if the media content changes on the service side, so we need to
// unsubscribe first.
//大概的意思就是现在这里还有BUG即只要发送订阅请求就会触发onChildrenLoaded回调
//所以无论怎样我们发起订阅请求之前都需要先取消订阅
mBrowser.unsubscribe(mediaId);
//之前说到订阅的方法还需要一个参数即设置订阅回调SubscriptionCallback
//当Service获取数据后会将数据发送回来此时会触发SubscriptionCallback.onChildrenLoaded回调
mBrowser.subscribe(mediaId, browserSubscriptionCallback);
}
gj.sc("连接成功");
}
@Override
public void onConnectionFailed() {
gj.sc("连接失败!");
}
};
/**
* 向媒体服务器(MediaBrowserService)发起数据订阅请求的回调接口
*/
private final MediaBrowserCompat.SubscriptionCallback browserSubscriptionCallback =
new MediaBrowserCompat.SubscriptionCallback() {
@Override
public void onChildrenLoaded(@NonNull String parentId,
@NonNull List<MediaBrowserCompat.MediaItem> children) {
gj.sc("onChildrenLoaded------");
}
};
@Override
public void finish() {
super.finish();
// 断开连接并释放资源
if (mBrowser != null && mBrowser.isConnected()) {
mBrowser.disconnect();
}
}
@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) {
startActivity(new Intent(this, activity_search.class));
}
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,218 @@
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 androidx.annotation.NonNull;
import com.muqingbfq.databinding.ActivityUserLogsBinding;
import com.muqingbfq.main;
import com.muqingbfq.mq.AppCompatActivity;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wl;
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(view -> new CloudUser());
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);
}
});
}
//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();
}
@Override
public void onBackPressed() {
finish(false);
}
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");
new user_message(nickname, signature, avatarUrl);
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,71 @@
package com.muqingbfq.login;
import com.google.gson.Gson;
import com.muqingbfq.R;
import com.muqingbfq.main;
import com.muqingbfq.mq.gj;
import com.muqingbfq.mq.wj;
public class user_message{
public String name,qiangming, picurl;
public user_message() {
wj.sc(wj.filesdri + "user.mq");
}
public user_message(String nickname, String signature, String avatarUrl) {
name = nickname;
qiangming = signature;
picurl = avatarUrl;
String s = new Gson().toJson(new user_logs.USER(name, qiangming, picurl));
wj.xrwb(wj.filesdri + "user.mq", s);
}
public string get() throws Exception {
/* JSONObject post = wl.jsonpost("/php/user.php?action=getSpaceInfo",
new String[]{
"account"
},
new String[]{
main.account
});
gj.sc(post);
if (!TextUtils.isEmpty(post.toString()) &&
post.getInt("code") == 0) {
JSONObject data = post.getJSONObject("data");
String headIcon = data.getString("headIcon");//头像
String account = data.getString("account");//账号
String userName = data.getString("userName");//名称
String introduce = data.getString("introduce");//签名
String cover = data.getString("cover");//背景
if (headIcon.startsWith("..")) {
headIcon = "https://rust.coldmint.top" + headIcon.substring(2);
}
if (cover.startsWith("..")) {
cover = "https://rust.coldmint.top" + cover.substring(2);
}
String gender = data.getString("gender");*/
return new string(new String[]{
name, qiangming, picurl
});
}
public static class string {
private final String[] strings;
public string(String[] strings) {
this.strings = strings;
}
public String picurl() {
return strings[2];
}
public String qianming() {
return strings[1];
}
public String userName() {
return strings[0];
}
}
}

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,169 @@
package com.muqingbfq;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.text.TextUtils;
import android.view.LayoutInflater;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatDelegate;
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;
private int count = 0;
@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();
if (bfqkz.xm != null) {
new Thread() {
@Override
public void run() {
super.run();
MP3 hq = com.muqingbfq.api.url.hq(bfqkz.xm);
if (hq == null) {
return;
}
try {
bfqkz.mt.DataSource(hq);
} catch (Exception e) {
com.muqingbfq.mq.gj.sc(e);
}
}
}.start();
}
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(@NonNull Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(@NonNull Activity activity) {
if (count == 0) { //后台切换到前台
if (FloatingLyricsService.lei != null) {
stopService(new Intent(main.this, FloatingLyricsService.class));
}
}
count++;
}
@Override
public void onActivityResumed(@NonNull Activity activity) {
}
@Override
public void onActivityPaused(@NonNull Activity activity) {
}
@Override
public void onActivityStopped(@NonNull Activity activity) {
count--;
if (count == 0) { //后台切换到前台
new Thread(){
@Override
public void run() {
try {
sleep(1000);
} catch (InterruptedException e) {
gj.sc(e);
}
if (count != 0) {
return;
}
if (!FloatingLyricsService.get()) {
return;
}
if (Settings.canDrawOverlays(main.this)) {
startService(new Intent(main.this, FloatingLyricsService.class));
}
super.run();
}
}.start();
}
}
@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
}
@Override
public void onActivityDestroyed(@NonNull Activity activity) {
}
});
}
}

View File

@ -0,0 +1,25 @@
package com.muqingbfq.mq;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.viewbinding.ViewBinding;
import com.jaeger.library.StatusBarUtil;
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() {
super.setContentView(getViewBinding().getRoot());
}
}

View File

@ -0,0 +1,46 @@
package com.muqingbfq.mq;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.content.ComponentName;
import android.content.Context;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.support.v4.media.session.MediaSessionCompat;
import com.muqingbfq.MyButtonClickReceiver;
public class BluetoothMusicController {
private Context context;
private MediaSessionCompat mediaSession;
public BluetoothMusicController(Context context) {
this.context = context;
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
intentFilter.addAction("android.intent.action.HEADSET_PLUG");
context.registerReceiver(new MyButtonClickReceiver(), intentFilter);
registerHeadsetReceiver();
}
public void stop() {
unregisterHeadsetReceiver();
}
// 注册媒体按钮事件接收器
@SuppressLint("ObsoleteSdkInt")
public void registerHeadsetReceiver() {
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
ComponentName name = new ComponentName(context.getPackageName(), MyButtonClickReceiver.class.getName());
audioManager.registerMediaButtonEventReceiver(name);
}
// 注销媒体按钮事件接收器
public void unregisterHeadsetReceiver() {
if (mediaSession != null) {
mediaSession.setActive(false);
mediaSession.release();
mediaSession = null;
}
}
}

View File

@ -0,0 +1,100 @@
package com.muqingbfq.mq;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;
import androidx.annotation.NonNull;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
import java.security.MessageDigest;
public class BlurGradientTransformation extends BitmapTransformation {
private static final String TAG = "BlurGradientTrans";
private RenderScript mRenderScript;
private ScriptIntrinsicBlur mScriptIntrinsicBlur;
private float mRadius = 25f;
private int[] mGradientColors = new int[]{0x66000000, 0xcc000000};
private float[] mGradientPositions = new float[]{0f, 1f};
public BlurGradientTransformation(Context context) {
super();
mRenderScript = RenderScript.create(context);
mScriptIntrinsicBlur = ScriptIntrinsicBlur.create(mRenderScript, Element.U8_4(mRenderScript));
}
public BlurGradientTransformation(Context context, float radius) {
this(context);
mRadius = radius;
}
@Override
protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
Bitmap source = pool.get(toTransform.getWidth(), toTransform.getHeight(), toTransform.getConfig());
if (source == null) {
source = Bitmap.createBitmap(toTransform.getWidth(), toTransform.getHeight(), toTransform.getConfig());
}
Canvas canvas = new Canvas(source);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(new BitmapShader(toTransform, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
canvas.drawRoundRect(new RectF(0, 0, toTransform.getWidth(), toTransform.getHeight()), 30f, 30f, paint);
Allocation input = Allocation.createFromBitmap(mRenderScript, source, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
Allocation output = Allocation.createTyped(mRenderScript, input.getType());
mScriptIntrinsicBlur.setInput(input);
mScriptIntrinsicBlur.setRadius(mRadius);
mScriptIntrinsicBlur.forEach(output);
output.copyTo(source);
// 绘制渐变色
Canvas canvas1 = new Canvas(source);
Paint paint1 = new Paint();
paint1.setAntiAlias(true);
paint1.setShader(new android.graphics.LinearGradient(0, 0, 0, source.getHeight(), mGradientColors, mGradientPositions, Shader.TileMode.CLAMP));
paint1.setXfermode(null);
canvas1.drawRect(new Rect(0, 0, source.getWidth(), source.getHeight()), paint1);
return source;
}
@Override
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
messageDigest.update("BlurGradientTransformation".getBytes());
}
@Override
public int hashCode() {
return BlurGradientTransformation.class.hashCode();
}
@Override
public boolean equals(Object obj) {
return obj instanceof BlurGradientTransformation;
}
public BlurGradientTransformation setRadius(float radius) {
mRadius = radius;
return this;
}
public BlurGradientTransformation setGradientColors(int[] colors) {
mGradientColors = colors;
return this;
}
public BlurGradientTransformation setGradientPositions(float[] positions) {
mGradientPositions = positions;
return this;
}
}

View File

@ -0,0 +1,167 @@
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());
}
public void setNegative(View.OnClickListener a) {
buttona.setOnClickListener(a);
}
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,257 @@
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 android.widget.ImageView;
import androidx.annotation.Nullable;
import com.dirror.lyricviewx.LyricEntry;
import com.dirror.lyricviewx.LyricViewX;
import com.google.android.material.card.MaterialCardView;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.muqingbfq.R;
import com.muqingbfq.bfqkz;
import com.muqingbfq.databinding.FloatLrcviewBinding;
import com.muqingbfq.main;
import java.io.File;
import java.lang.reflect.Type;
public class FloatingLyricsService extends Service implements View.OnClickListener, View.OnTouchListener {
private WindowManager windowManager;
FloatLrcviewBinding binding;
public Runnable updateSeekBar = new Runnable() {
@Override
public void run() {
int index = 0;
for (int i = 0; i < LyricViewX.lyricEntryList.size(); i++) {
LyricEntry lineLrc = LyricViewX.lyricEntryList.get(i);
if (lineLrc.time <= bfqkz.mt.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;
}
@Override
public void onCreate() {
super.onCreate();
lei = this;
File file = new File(wj.filesdri + "FloatingLyricsService.json");
try {
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);
}
// 创建悬浮窗歌词的 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.setOnClickListener(this);
// params.gravity = Gravity.CENTER;
// 获取 WindowManager 并将悬浮窗歌词添加到窗口中
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
windowManager.addView(binding.getRoot(), params);
if (setup.i == 2) {
setyc();
} else {
show();
}
/*
if (setup.i == 0)
setup.i = 1;
baocun();*/
handler.post(updateSeekBar); // 在播放开始时启动更新进度
} catch (Exception e) {
wj.sc(file.toString());
gj.sc(getClass() + ":" + e);
}
}
@Override
public void onDestroy() {
super.onDestroy();
// 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));
}
private int initialY;
private float initialTouchY;
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
// 记录触摸事件的初始位置和坐标
initialY = params.y;
initialTouchY = motionEvent.getRawY();
return true;
case MotionEvent.ACTION_MOVE:
// 计算触摸事件的偏移量将悬浮窗口的位置设置为初始位置加上偏移量
int offsetY = (int) (motionEvent.getRawY() - initialTouchY);
setup.Y = initialY + offsetY;
params.y = setup.Y;
windowManager.updateViewLayout(binding.getRoot(), params);
return true;
case MotionEvent.ACTION_UP:
baocun();
break;
}
return false;
}
@Override
public void onClick(View view) {
int id = view.getId();
if (id == R.id.kg) {
ImageView kg = (ImageView) view;
if (bfqkz.mt == null) {
return;
}
if (bfqkz.mt.isPlaying()) {
bfqkz.mt.pause();
kg.setImageResource(R.drawable.zt);
} else {
bfqkz.mt.start();
kg.setImageResource(R.drawable.bf);
}
} else if (id == R.id.lock) {
setyc();
}
}
public void setyc() {
setup.i = 2;
params.flags = lock();
binding.lock.setVisibility(View.GONE);
windowManager.updateViewLayout(binding.getRoot(), params);
baocun();
}
@SuppressLint("CheckResult")
public void show() {
setup.i = 1;
params.flags = lock();
binding.lock.setVisibility(View.VISIBLE);
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,53 @@
package com.muqingbfq.mq;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.viewbinding.ViewBinding;
import com.jaeger.library.StatusBarUtil;
import com.muqingbfq.R;
public abstract class FragmentActivity<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;
@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(int view) {
super.setContentView(view);
}
public void setContentView() {
binding = getViewBindingObject(getLayoutInflater());
setContentView(binding.getRoot());
setToolbar();
}
@Override
public void setContentView(View view) {
super.setContentView(view);
}
}

View File

@ -0,0 +1,176 @@
package com.muqingbfq.mq;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.os.Build;
import android.support.v4.media.MediaMetadataCompat;
import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import com.muqingbfq.MyButtonClickReceiver;
import com.muqingbfq.R;
import com.muqingbfq.bfqkz;
import com.muqingbfq.yc;
public class NotificationManagerCompat {
bfqkz context;
public NotificationCompat.Builder notificationBuilder;
public androidx.core.app.NotificationManagerCompat notificationManager;
private String name, zz;
public NotificationManagerCompat(bfqkz context) {
this.context = context;
name = context.getString(R.string.app_name);
zz = context.getString(R.string.zz);
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name,
NotificationManager.IMPORTANCE_LOW);
channel.setDescription(zz);
NotificationManager systemService = context.getSystemService(NotificationManager.class);
systemService.createNotificationChannel(channel);
if (!systemService.areNotificationsEnabled()) {
return;
}
}
// 适配12.0及以上
// 设置启动的程序如果存在则找出否则新的启动
Intent my = new Intent(context, MyButtonClickReceiver.class);
pendingIntent_kg = getBroadcast(context, my.
setAction("kg"));
pendingIntent_syq = getBroadcast(context, my.
setAction("syq"));
pendingIntent_xyq = getBroadcast(context, my.
setAction("xyq"));
pendingIntent_lrc = getBroadcast(context, my.
setAction("lrc"));
pendingIntent_like = getBroadcast(context, my.
setAction("like"));
style = new androidx.media.app.NotificationCompat.MediaStyle()
.setShowActionsInCompactView(1, 2, 3)
.setMediaSession(context.mSession.getSessionToken());
notificationManager = androidx.core.app.NotificationManagerCompat.from(context);
notificationBuilder = getNotificationBuilder(context)
.setSmallIcon(R.drawable.foreground)
.setPriority(NotificationCompat.PRIORITY_LOW)
.setOngoing(true).setColorized(true).setShowWhen(false)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setContentIntent(context.pendingIntent)
.setStyle(style);
tzl();
} catch (Exception e) {
yc.start(context, e);
}
}
androidx.media.app.NotificationCompat.MediaStyle style;
@SuppressLint("RestrictedApi")
public void tzl_button() {
if (notificationBuilder == null) {
return;
}
notificationBuilder.mActions.clear();
notificationBuilder
.addAction(R.drawable.like, "like", pendingIntent_like) // #0
.addAction(R.drawable.syq, "syq", pendingIntent_syq) // #0
.addAction(bfqkz.mt.isPlaying() ? R.drawable.bf : R.drawable.zt
, "kg", pendingIntent_kg) // #1
.addAction(R.drawable.xyq, "xyq", pendingIntent_xyq)
.addAction(R.drawable.lock, "lrc", pendingIntent_lrc)
.setOngoing(bfqkz.mt.isPlaying());
notificationManager_notify();
}
public void setbitmap(Bitmap bitmap) {
notificationBuilder
.setLargeIcon(bitmap);
context.builder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, name)
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, zz)
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, zz)
.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap)
.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, 100);
context.mSession.setMetadata(context.builder.build());
notificationManager_notify();
}
@SuppressLint("RestrictedApi")
public void tzl() {
if (notificationBuilder == null) {
return;
}
if (bfqkz.xm != null) {
name = bfqkz.xm.name;
zz = bfqkz.xm.zz;
}
notificationBuilder.mActions.clear();
notificationBuilder
.addAction(R.drawable.like, "like", pendingIntent_like) // #0
.addAction(R.drawable.syq, "syq", pendingIntent_syq) // #0
.addAction(bfqkz.mt.isPlaying() ? R.drawable.bf : R.drawable.zt
, "kg", pendingIntent_kg) // #1
.addAction(R.drawable.xyq, "xyq", pendingIntent_xyq)
.addAction(R.drawable.lock, "lrc", pendingIntent_lrc)
.setContentTitle(name)
.setContentText(zz)
.setOngoing(bfqkz.mt.isPlaying());
context.mSession.setMetadata(context.builder.build());
notificationManager_notify();
}
private PendingIntent pendingIntent_kg,
pendingIntent_syq,
pendingIntent_xyq,
pendingIntent_lrc,
pendingIntent_like;
private final String CHANNEL_ID = "MediaSessionCompat";
public void notificationManager_notify() {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
return;
}
notificationManager.notify(0, notificationBuilder.build());
}
private NotificationCompat.Builder getNotificationBuilder(Context context) {
// 适用于Android 8.0及以上版本
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
return new NotificationCompat.Builder(context, CHANNEL_ID);
}
private PendingIntent getBroadcast(Context context, Intent intent) {
int flag;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
flag = PendingIntent.FLAG_IMMUTABLE;
} else {
flag = PendingIntent.FLAG_UPDATE_CURRENT;
}
return PendingIntent.getBroadcast(context, 0, intent, flag);
}
public static PendingIntent getActivity(Context context, Intent intent) {
int flag;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
flag = PendingIntent.FLAG_IMMUTABLE;
} else {
flag = PendingIntent.FLAG_UPDATE_CURRENT;
}
return PendingIntent.getActivity(context, 0, intent, flag);
}
}

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,172 @@
package com.muqingbfq.mq;
import android.annotation.SuppressLint;
import android.app.Service;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.IBinder;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.muqingbfq.R;
import com.muqingbfq.main;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
public class floating extends Service {
private static RecyclerView.Adapter<ViewHolder> lbspq;
class spq extends RecyclerView.Adapter<ViewHolder> {
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(new TextView(parent.getContext()));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
String s = list.get(position);
holder.textView.setText(s);
}
@Override
public int getItemCount() {
return list.size();
}
}
public static void start(Context context) {
if (Settings.canDrawOverlays(context)) {
context.startService(new Intent(context, floating.class));
}
}
public static void end(Context context) {
Intent serviceIntent = new Intent(context, floating.class);
context.stopService(serviceIntent);
}
public static List<String> list;
private WindowManager windowManager;
private View view;
private View image, layout;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@SuppressLint("NotifyDataSetChanged")
public static void addtext(String str) {
if (lbspq == null || list == null) {
return;
}
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss", Locale.CHINA); // 创建一个 SimpleDateFormat 对象指定时间格式
String formattedDate = sdf.format(new Date()); // 格式化当前时间
list.add(0, formattedDate + ": " + str);
main.handler.post(lbspq::notifyDataSetChanged);
}
@SuppressLint("NotifyDataSetChanged")
@Override
public void onCreate() {
super.onCreate();
list = new ArrayList<>();
lbspq = new spq();
view = LayoutInflater.from(this).inflate(R.layout.floating_sc, null);
layout = view.findViewById(R.id.view1);
ViewGroup.LayoutParams layoutParams = layout.getLayoutParams();
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
layoutParams.height = displayMetrics.heightPixels - displayMetrics.heightPixels / 2 / 2;
layoutParams.width = displayMetrics.widthPixels - displayMetrics.widthPixels / 2 / 2;
layout.setLayoutParams(layoutParams);
layout.setVisibility(View.GONE);
image = view.findViewById(R.id.image);
image.setOnClickListener(vw -> {
layout.setVisibility(View.VISIBLE);
vw.setVisibility(View.GONE);
});
view.findViewById(R.id.text4).setOnClickListener(view -> {
layout.setVisibility(View.GONE);
image.setVisibility(View.VISIBLE);
});
RecyclerView recyclerView = view.findViewById(R.id.list);
recyclerView.setAdapter(lbspq);
addtext("Android stdio 2022.3.1版-调试器");
//清空按钮
view.findViewById(R.id.text1).setOnClickListener(view -> {
list.clear();
lbspq.notifyDataSetChanged();
});
//复制按钮
view.findViewById(R.id.text2).setOnClickListener(view -> {
// 获取剪贴板管理器
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
clipboard.setPrimaryClip(ClipData.newPlainText("label", list.get(0)));
gj.ts(this,"成功复制了第一个数据");
});
//关闭按钮
view.findViewById(R.id.text3).setOnClickListener(view -> stopSelf());
int i = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
WindowManager.LayoutParams.TYPE_PHONE,
i,
PixelFormat.TRANSLUCENT
);
params.x = -displayMetrics.widthPixels;
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
windowManager.addView(view, params);
}
@Override
public void onDestroy() {
super.onDestroy();
if (view != null && windowManager != null) {
lbspq = null;
list = null;
windowManager.removeView(view);
}
}
private static class ViewHolder extends RecyclerView.ViewHolder {
public TextView textView;
public ViewHolder(View itemview) {
super(itemview);
textView = (TextView) itemview;
textView.setTextColor(Color.WHITE);
textView.setOnLongClickListener(view -> {
// 获取剪贴板管理器
ClipboardManager clipboard = (ClipboardManager) view.getContext().
getSystemService(Context.CLIPBOARD_SERVICE);
clipboard.setPrimaryClip(ClipData.newPlainText("label", list.get(0)));
gj.ts(view.getContext(), "复制成功");
return false;
});
}
}
}

View File

@ -0,0 +1,200 @@
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;
}
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());
floating.addtext(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 class jianchagengxin extends Thread {
Context context;
public jianchagengxin(Context context) {
this.context = context;
if (!wj.cz(wj.filesdri + "gx.mq")) {
start();
}
}
@Override
public void run() {
super.run();
jianchagengxin(context);
}
}
public static int jianchagengxin(Context context) {
try {
String versionName = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0).versionName;
String hq = wl.get(main.http + "/muqingbfq?bb=" + versionName);
final JSONObject jsonObject = new JSONObject(hq);
boolean code = jsonObject.getInt("code") == 1;
String msg = jsonObject.getString("msg");
if (code) {
String url = jsonObject.getString("url");
String bb = jsonObject.getString("bb");
main.handler.post(() -> new MaterialAlertDialogBuilder(context)
.setTitle("更新" + bb)
.setMessage(msg)
.setNegativeButton("取消", null)
.setPositiveButton("更新", (dialogInterface, i) -> context.startActivity(new Intent(Intent.ACTION_VIEW,
Uri.parse(url))))
.show());
}
//1表示需要更新
return code ? 1 : 0;
} catch (Exception e) {
sc(e);
}
return 400;
}
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;
}
}

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,107 @@
package com.muqingbfq.mq;
import com.muqingbfq.XM;
import com.muqingbfq.main;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
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 JSONObject jsonpost(String str, String[][] a) {
try {
return new JSONObject(post(str, a));
} catch (JSONException 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;
}
public static class xz extends Thread {
String url;
XM x;
public xz(String url, XM x) {
this.url = url;
this.x = x;
start();
}
}
}

View File

@ -0,0 +1,261 @@
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.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.fragment.app.Fragment;
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();
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;
boolean is = true;
ActivityResultLauncher<Intent> LyricsService =
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
if (Settings.canDrawOverlays(getContext())) {
getContext().startService(new Intent(getContext(), FloatingLyricsService.class));
} else {
binding.switchA3.setChecked(false);
binding.slide1.setEnabled(true);
}
});
FloatingLyricsService.SETUP setup;
class ThreadLrc extends Thread {
@Override
public void run() {
super.run();
while (is) {
int index = 0;
for (int i = 0; i < LyricViewX.lyricEntryList.size(); i++) {
LyricEntry lineLrc = LyricViewX.lyricEntryList.get(i);
if (lineLrc.time <= bfqkz.mt.getCurrentPosition()) {
index = i;
} else {
break;
}
}
if (index < LyricViewX.lyricEntryList.size()) {
LyricEntry currentLrc = LyricViewX.lyricEntryList.get(index);
requireActivity().runOnUiThread(() -> {
if (currentLrc.secondText != null) {
binding.lrcViewMessage.setText(currentLrc.secondText);
} else {
binding.lrcViewMessage.setText("");
}
binding.lrcView.setText(currentLrc.text);
});
}
gj.sc("ThreadLrc");
try {
sleep(1000);
} catch (InterruptedException e) {
break;
}
}
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding = ActivitySzSetlrcBinding.inflate(inflater, container, false);
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);
}
new ThreadLrc().start();
}
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.slide1.setLabelFormatter(value -> String.valueOf((int) value));
binding.slide1.addOnChangeListener(this);
binding.slide1.addOnChangeListener(this);
binding.slide1.addOnSliderTouchListener(this);
return binding.getRoot();
}
@Override
public void onDestroy() {
super.onDestroy();
is = false;
}
@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,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;
}
}

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