├── .gitignore ├── .idea ├── .gitignore ├── compiler.xml ├── gradle.xml └── misc.xml ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── quietfall │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── quietfall │ │ │ ├── AddMusicListActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── MusicListActivity.java │ │ │ ├── MusicPlayActivity.java │ │ │ ├── database │ │ │ └── ListSqliteHelper.java │ │ │ ├── entity │ │ │ ├── LinkInfo.java │ │ │ ├── ListInfo.java │ │ │ ├── Music.java │ │ │ └── MusicList.java │ │ │ ├── fragment │ │ │ ├── AboutFragment.java │ │ │ └── HomeFragment.java │ │ │ ├── service │ │ │ └── MusicService.java │ │ │ └── utils │ │ │ ├── HttpUtils.java │ │ │ └── ToastUtil.java │ └── res │ │ ├── drawable │ │ ├── about1.png │ │ ├── about2.png │ │ ├── add.png │ │ ├── back.png │ │ ├── btn_selector.xml │ │ ├── btn_shape_normal.xml │ │ ├── btn_shape_pressed.xml │ │ ├── home1.png │ │ ├── home2.png │ │ ├── ic_launcher_background.xml │ │ ├── ic_launcher_foreground.xml │ │ ├── item_selector.xml │ │ ├── last.png │ │ ├── logo.jpg │ │ ├── love.png │ │ ├── loved.png │ │ ├── menu.png │ │ ├── next.png │ │ ├── order.png │ │ ├── pause.png │ │ ├── play.png │ │ ├── random.png │ │ └── repeat.png │ │ ├── layout │ │ ├── activity_add_music_list.xml │ │ ├── activity_main.xml │ │ ├── activity_music_list.xml │ │ ├── activity_music_play.xml │ │ ├── fragment_about.xml │ │ ├── fragment_home.xml │ │ ├── list_item.xml │ │ ├── music_list_item.xml │ │ └── title_layout.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── values-night │ │ └── themes.xml │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml │ └── test │ └── java │ └── com │ └── quietfall │ └── ExampleUnitTest.java ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle.kts /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.application") 3 | } 4 | 5 | android { 6 | namespace = "com.quietfall" 7 | compileSdk = 33 8 | 9 | defaultConfig { 10 | applicationId = "com.quietfall" 11 | minSdk = 28 12 | targetSdk = 33 13 | versionCode = 1 14 | versionName = "1.0" 15 | 16 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 17 | } 18 | 19 | buildTypes { 20 | release { 21 | isMinifyEnabled = false 22 | proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") 23 | } 24 | } 25 | compileOptions { 26 | sourceCompatibility = JavaVersion.VERSION_1_8 27 | targetCompatibility = JavaVersion.VERSION_1_8 28 | } 29 | } 30 | 31 | dependencies { 32 | 33 | implementation ("com.google.code.gson:gson:2.10.1") 34 | implementation("com.squareup.okhttp3:okhttp:4.10.0") 35 | implementation("com.github.bumptech.glide:glide:3.7.0") 36 | implementation("androidx.appcompat:appcompat:1.6.1") 37 | implementation("com.google.android.material:material:1.8.0") 38 | implementation("androidx.constraintlayout:constraintlayout:2.1.4") 39 | testImplementation("junit:junit:4.13.2") 40 | androidTestImplementation("androidx.test.ext:junit:1.1.5") 41 | androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") 42 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/com/quietfall/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.quietfall; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | assertEquals("com.quietfall", appContext.getPackageName()); 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 18 | 22 | 23 | 26 | 29 | 32 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/quietfall/AddMusicListActivity.java: -------------------------------------------------------------------------------- 1 | package com.quietfall; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | 5 | import android.content.ContentValues; 6 | import android.content.Intent; 7 | import android.graphics.Bitmap; 8 | import android.os.Build; 9 | import android.os.Bundle; 10 | import android.util.Log; 11 | import android.view.ViewGroup; 12 | import android.webkit.WebResourceError; 13 | import android.webkit.WebResourceRequest; 14 | import android.webkit.WebSettings; 15 | import android.webkit.WebView; 16 | import android.webkit.WebViewClient; 17 | 18 | import com.quietfall.database.ListSqliteHelper; 19 | import com.quietfall.entity.MusicList; 20 | import com.quietfall.utils.HttpUtils; 21 | import com.quietfall.utils.ToastUtil; 22 | 23 | import java.io.IOException; 24 | import java.util.List; 25 | import java.util.regex.Matcher; 26 | import java.util.regex.Pattern; 27 | 28 | public class AddMusicListActivity extends AppCompatActivity { 29 | private final String TAG = "qf"; 30 | private WebView webview; 31 | private WebSettings webSettings; 32 | private String url; 33 | private String starUrl; 34 | private static final String ID_REGEX = "(fid=)(\\d*)(&|$)"; 35 | private static final Pattern ID_PATTERN; 36 | private ListSqliteHelper mHelper; 37 | 38 | static { 39 | ID_PATTERN = Pattern.compile(ID_REGEX); 40 | } 41 | 42 | @Override 43 | protected void onCreate(Bundle savedInstanceState) { 44 | super.onCreate(savedInstanceState); 45 | setContentView(R.layout.activity_add_music_list); 46 | Intent intent = getIntent(); 47 | String uid = intent.getStringExtra("uid"); 48 | url = "https://space.bilibili.com/" + uid + "/favlist"; 49 | webview = findViewById(R.id.webview); 50 | 51 | webSettings = webview.getSettings(); 52 | webSettings.setJavaScriptEnabled(true); 53 | webSettings.setJavaScriptCanOpenWindowsAutomatically(true); 54 | 55 | webSettings.setUseWideViewPort(true);//支持viewport 56 | // webSettings.setLoadWithOverviewMode(true);//自适应屏幕 57 | webSettings.setBuiltInZoomControls(true); 58 | webSettings.setDisplayZoomControls(false); 59 | webSettings.setSupportZoom(true);//支持缩放 60 | 61 | webSettings.setUserAgentString("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0"); 62 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 63 | webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE); 64 | } 65 | webSettings.setDomStorageEnabled(true); 66 | 67 | 68 | webview.loadUrl(url); 69 | 70 | 71 | webview.setWebViewClient(new WebViewClient() { 72 | @Override 73 | public boolean shouldOverrideUrlLoading(WebView view, String url) { 74 | view.loadUrl(url); 75 | return true; 76 | } 77 | 78 | @Override 79 | public void onLoadResource(WebView view, String url) { 80 | super.onLoadResource(view, url); 81 | String thisUrl = view.getUrl(); 82 | if (!thisUrl.equals(starUrl)) { 83 | starUrl = thisUrl; 84 | if (thisUrl.contains("fid")) { 85 | 86 | Matcher matcher = ID_PATTERN.matcher(thisUrl); 87 | if (matcher.find()) { 88 | //id为收藏夹官方id 89 | String id = matcher.group(2); 90 | ToastUtil.show(AddMusicListActivity.this, "已选择收藏夹" + matcher.group(2)); 91 | new Thread() { 92 | @Override 93 | public void run() { 94 | super.run(); 95 | String name = HttpUtils.getListNameById(id); 96 | Log.d(TAG, "AddMusicListActivity获取批量数据失败获取到收藏夹名字: " + name); 97 | long result = mHelper.insert(new MusicList(name, id)); 98 | Log.d(TAG, "AddMusicListActivity插入单个收藏夹信息返回结果: " + result); 99 | mHelper.createMusicListTable(id); 100 | List valuesList = null; 101 | try { 102 | valuesList = HttpUtils.getColumnById(id, HttpUtils.getCountById(id)); 103 | } catch (IOException e) { 104 | Log.d(TAG, "AddMusicListActivity获取批量数据失败run: error"); 105 | } 106 | mHelper.insertSomeMusic(valuesList, id); 107 | finish(); 108 | 109 | } 110 | }.start(); 111 | } 112 | } 113 | } 114 | } 115 | }); 116 | 117 | } 118 | 119 | @Override 120 | protected void onStart() { 121 | super.onStart(); 122 | mHelper = ListSqliteHelper.getInstance(this); 123 | mHelper.openWriteLink(); 124 | mHelper.openReadLink(); 125 | } 126 | 127 | @Override 128 | protected void onStop() { 129 | super.onStop(); 130 | // mHelper.closeLink(); 131 | } 132 | 133 | @Override 134 | protected void onDestroy() { 135 | super.onDestroy(); 136 | /** 137 | * 避免内存泄露,界面销毁时做如下处理 138 | */ 139 | if (webview != null) { 140 | webview.loadDataWithBaseURL(null, "", "text/html", "utf-8", null); 141 | webview.clearHistory(); 142 | 143 | ((ViewGroup) webview.getParent()).removeView(webview); 144 | webview.destroy(); 145 | webview = null; 146 | } 147 | } 148 | } -------------------------------------------------------------------------------- /app/src/main/java/com/quietfall/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.quietfall; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | import androidx.fragment.app.FragmentManager; 5 | import androidx.fragment.app.FragmentTransaction; 6 | 7 | import android.app.AlertDialog; 8 | import android.content.DialogInterface; 9 | import android.content.Intent; 10 | import android.os.Bundle; 11 | import android.view.View; 12 | import android.widget.AdapterView; 13 | import android.widget.BaseAdapter; 14 | import android.widget.EditText; 15 | import android.widget.ImageView; 16 | import android.widget.ListView; 17 | import android.widget.SimpleAdapter; 18 | 19 | import com.quietfall.database.ListSqliteHelper; 20 | import com.quietfall.entity.MusicList; 21 | import com.quietfall.fragment.AboutFragment; 22 | import com.quietfall.fragment.HomeFragment; 23 | import com.quietfall.utils.ToastUtil; 24 | 25 | import java.util.ArrayList; 26 | import java.util.HashMap; 27 | import java.util.List; 28 | import java.util.Map; 29 | 30 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 31 | 32 | private ListView lv_list; 33 | private ListSqliteHelper mHelper; 34 | private FragmentTransaction ft; 35 | private FragmentManager fm; 36 | private boolean isHome; 37 | private boolean isAbout; 38 | private ImageView iv_home; 39 | private ImageView iv_about; 40 | 41 | 42 | @Override 43 | protected void onCreate(Bundle savedInstanceState) { 44 | super.onCreate(savedInstanceState); 45 | setContentView(R.layout.activity_main); 46 | 47 | 48 | /*findViewById(R.id.iv_add) 49 | .setOnClickListener(this);*/ 50 | iv_home = findViewById(R.id.iv_home); 51 | iv_about = findViewById(R.id.iv_about); 52 | 53 | 54 | 55 | iv_about.setOnClickListener(this); 56 | iv_home.setOnClickListener(this); 57 | isHome = true; 58 | isAbout = false; 59 | 60 | } 61 | 62 | /*private void initList() { 63 | List musicListList = mHelper.queryAll(); 64 | if (musicListList.size() == 0) { 65 | lv_list.setVisibility(View.GONE); 66 | } else { 67 | lv_list.setVisibility(View.VISIBLE); 68 | } 69 | List> list = new ArrayList<>(); 70 | for (int i = 0; i < musicListList.size(); i++) { 71 | Map map = new HashMap<>(); 72 | map.put("desc", musicListList.get(i).name); 73 | list.add(map); 74 | } 75 | 76 | SimpleAdapter listAdapter = new SimpleAdapter(this, list, R.layout.list_item, new String[]{"desc"}, new int[]{R.id.tv_desc}); 77 | lv_list.setAdapter(listAdapter); 78 | lv_list.setOnItemClickListener(new AdapterView.OnItemClickListener() { 79 | @Override 80 | public void onItemClick(AdapterView adapterView, View view, int i, long l) { 81 | //i从0开始 82 | int id = i + 1; 83 | MusicList musicList = mHelper.queryListById(id); 84 | ToastUtil.show(getApplicationContext(),musicList.name); 85 | Intent intent = new Intent(MainActivity.this,MusicListActivity.class); 86 | intent.putExtra("fid",musicList.fid); 87 | intent.putExtra("name",musicList.name); 88 | startActivity(intent); 89 | } 90 | }); 91 | }*/ 92 | 93 | @Override 94 | protected void onStart() { 95 | super.onStart(); 96 | fm = getSupportFragmentManager(); 97 | ft = fm.beginTransaction(); 98 | ft.replace(R.id.content, new HomeFragment()); 99 | ft.commit(); 100 | mHelper = ListSqliteHelper.getInstance(this); 101 | mHelper.openReadLink(); 102 | mHelper.openWriteLink(); 103 | /*initList();*/ 104 | 105 | } 106 | 107 | 108 | @Override 109 | protected void onStop() { 110 | super.onStop(); 111 | } 112 | 113 | @Override 114 | protected void onDestroy() { 115 | super.onDestroy(); 116 | // mHelper.closeLink(); 117 | } 118 | 119 | @Override 120 | public void onClick(View view) { 121 | /*Intent intent = new Intent(this, AddMusicListActivity.class); 122 | AlertDialog.Builder builder = new AlertDialog.Builder(this); 123 | EditText et_uid = new EditText(this); 124 | builder.setTitle("请输入收藏夹主人的Uid"); 125 | builder.setView(et_uid); 126 | builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { 127 | @Override 128 | public void onClick(DialogInterface dialogInterface, int i) { 129 | String uid = et_uid.getText().toString(); 130 | if (uid == null || uid.isEmpty()) 131 | { 132 | return; 133 | } 134 | intent.putExtra("uid",uid); 135 | startActivity(intent); 136 | } 137 | }); 138 | builder.setNegativeButton("取消",null); 139 | builder.show();*/ 140 | int id = view.getId(); 141 | if (id == R.id.iv_home) { 142 | if (isAbout) { 143 | isAbout = false; 144 | isHome = true; 145 | iv_home.setImageResource(R.drawable.home2); 146 | iv_about.setImageResource(R.drawable.about1); 147 | ft = fm.beginTransaction(); 148 | ft.remove(fm.findFragmentById(R.id.content)); 149 | ft.replace(R.id.content, new HomeFragment()); 150 | ft.commit(); 151 | 152 | 153 | } 154 | } 155 | if (id == R.id.iv_about) 156 | { 157 | if (isHome) 158 | { 159 | isHome = false; 160 | isAbout = true; 161 | iv_about.setImageResource(R.drawable.about2); 162 | iv_home.setImageResource(R.drawable.home1); 163 | ft = fm.beginTransaction(); 164 | ft.remove(fm.findFragmentById(R.id.content)); 165 | ft.replace(R.id.content, new AboutFragment()); 166 | ft.commit(); 167 | } 168 | } 169 | 170 | } 171 | } -------------------------------------------------------------------------------- /app/src/main/java/com/quietfall/MusicListActivity.java: -------------------------------------------------------------------------------- 1 | package com.quietfall; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | 5 | import android.content.Intent; 6 | import android.database.sqlite.SQLiteDatabase; 7 | import android.os.Bundle; 8 | import android.view.View; 9 | import android.widget.AdapterView; 10 | import android.widget.ListView; 11 | import android.widget.SimpleAdapter; 12 | import android.widget.TextView; 13 | 14 | import com.quietfall.database.ListSqliteHelper; 15 | import com.quietfall.entity.Music; 16 | 17 | import java.util.ArrayList; 18 | import java.util.HashMap; 19 | import java.util.List; 20 | import java.util.Map; 21 | 22 | public class MusicListActivity extends AppCompatActivity { 23 | 24 | private ListView lv_music_list; 25 | private ListSqliteHelper mHelper; 26 | //接受intent传来的收藏夹id 27 | private String mId; 28 | 29 | @Override 30 | protected void onCreate(Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | setContentView(R.layout.activity_music_list); 33 | TextView title_title = findViewById(R.id.title_title); 34 | 35 | lv_music_list = findViewById(R.id.lv_music_list); 36 | Intent intent = getIntent(); 37 | mId = intent.getStringExtra("fid"); 38 | title_title.setText("歌曲列表--"+intent.getStringExtra("name")); 39 | 40 | } 41 | 42 | private void initList() { 43 | List musicList = mHelper.musicQueryAll(mId); 44 | if (musicList.size() == 0) 45 | { 46 | lv_music_list.setVisibility(View.GONE); 47 | } 48 | else { 49 | lv_music_list.setVisibility(View.VISIBLE); 50 | } 51 | List> dataList = new ArrayList<>(); 52 | for (int i = 0; i < musicList.size(); i++) { 53 | Map map = new HashMap<>(); 54 | map.put("desc",musicList.get(i).title); 55 | map.put("up_name",musicList.get(i).upName); 56 | dataList.add(map); 57 | } 58 | SimpleAdapter adapter = new SimpleAdapter(getApplicationContext(),dataList,R.layout.music_list_item,new String[]{"desc","up_name"},new int[]{R.id.tv_desc,R.id.tv_up_name}); 59 | lv_music_list.setAdapter(adapter); 60 | lv_music_list.setOnItemClickListener(new AdapterView.OnItemClickListener() { 61 | @Override 62 | public void onItemClick(AdapterView adapterView, View view, int i, long l) { 63 | Intent intent = new Intent(MusicListActivity.this, MusicPlayActivity.class); 64 | int id = i + 1; 65 | Music music = mHelper.musicQueryById(mId,id); 66 | intent.putExtra("fid",mId); 67 | intent.putExtra("id",music.id); 68 | intent.putExtra("title",music.title); 69 | intent.putExtra("up_name",music.upName); 70 | intent.putExtra("cover",music.cover); 71 | intent.putExtra("duration",music.duration); 72 | intent.putExtra("bv",music.bv); 73 | intent.putExtra("cid",music.cid); 74 | startActivity(intent); 75 | } 76 | }); 77 | 78 | } 79 | 80 | @Override 81 | protected void onStart() { 82 | super.onStart(); 83 | mHelper = ListSqliteHelper.getInstance(this); 84 | mHelper.openReadLink(); 85 | mHelper.openWriteLink(); 86 | initList(); 87 | } 88 | 89 | 90 | public void back(View view) { 91 | onBackPressed(); 92 | } 93 | 94 | 95 | } -------------------------------------------------------------------------------- /app/src/main/java/com/quietfall/MusicPlayActivity.java: -------------------------------------------------------------------------------- 1 | package com.quietfall; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.appcompat.app.AppCompatActivity; 5 | 6 | import android.annotation.SuppressLint; 7 | import android.content.BroadcastReceiver; 8 | import android.content.ComponentName; 9 | import android.content.Context; 10 | import android.content.Intent; 11 | import android.content.IntentFilter; 12 | import android.content.ServiceConnection; 13 | import android.os.Bundle; 14 | import android.os.Handler; 15 | import android.os.IBinder; 16 | import android.os.Message; 17 | import android.util.Log; 18 | import android.view.View; 19 | import android.widget.ImageView; 20 | import android.widget.SeekBar; 21 | import android.widget.TextView; 22 | 23 | import com.bumptech.glide.Glide; 24 | import com.bumptech.glide.load.resource.drawable.GlideDrawable; 25 | import com.bumptech.glide.request.RequestListener; 26 | import com.bumptech.glide.request.target.Target; 27 | import com.quietfall.database.ListSqliteHelper; 28 | import com.quietfall.entity.Music; 29 | import com.quietfall.service.MusicService; 30 | import com.quietfall.utils.HttpUtils; 31 | 32 | import java.util.Random; 33 | 34 | public class MusicPlayActivity extends AppCompatActivity implements View.OnClickListener { 35 | private MusicService.MusicController mMusicController; 36 | ServiceConnection mServiceConnection = new ServiceConnection() { 37 | @Override 38 | public void onServiceConnected(ComponentName componentName, IBinder iBinder) { 39 | 40 | mMusicController = (MusicService.MusicController) iBinder; 41 | 42 | } 43 | 44 | @Override 45 | public void onServiceDisconnected(ComponentName componentName) { 46 | 47 | } 48 | }; 49 | private Intent intent; 50 | 51 | private static final String TAG = "qf"; 52 | private static String mTitle; 53 | private static String mUpName; 54 | private static String mCover; 55 | private static Long mDuration; 56 | private static String mBv; 57 | private static Long mCid; 58 | private static String mFid; 59 | private static String mUrl; 60 | 61 | private TextView tv_title; 62 | private TextView tv_up_name; 63 | private static ImageView iv_cover; 64 | private TextView title_title; 65 | private TextView tv_duration; 66 | private static TextView tv_time; 67 | private ImageView iv_play; 68 | private static ListSqliteHelper mHelper; 69 | public static SeekBar sb_progress; 70 | private static int randomId; 71 | //是否绑定服务 72 | private boolean isBind = false; 73 | //是否正在播放 74 | private boolean isPlay = false; 75 | //是否第一次播放 76 | private boolean first = true; 77 | public static String nextUrl = null; 78 | public static final String ACTION_NEXT = "com.quietfall.MusicPlayActivity.ACTION_NEXT"; 79 | public static final String ACTION_LAST = "com.quietfall.MusicPlayActivity.ACTION_LAST"; 80 | // 定位下一首 81 | private static final int LOCATE_NEXT = 0; 82 | //随机定位 83 | private static final int LOCATE_RANDOM = 1; 84 | //单曲循环 85 | private static final int LOCATE_REPEAT = 2; 86 | public static int LOCATE_MODE = LOCATE_NEXT; 87 | @SuppressLint("HandlerLeak") 88 | public static Handler handler = new Handler() { 89 | @Override 90 | public void handleMessage(@NonNull Message msg) { 91 | super.handleMessage(msg); 92 | if (msg.what == MusicService.HANDLER_WHAT) { 93 | Bundle bundle = (Bundle) msg.obj; 94 | int duration = bundle.getInt("duration"); 95 | int progress = bundle.getInt("currentPosition"); 96 | sb_progress.setMax(duration); 97 | sb_progress.setProgress(progress); 98 | int min = progress / 1000 / 60; 99 | int sec = progress / 1000 % 60; 100 | 101 | String sSec = sec < 10 ? "0" + sec : String.valueOf(sec); 102 | tv_time.setText(min + ":" + sSec); 103 | 104 | } 105 | if (msg.what == MusicService.HANDLER_WHAT_END) { 106 | sb_progress.setProgress(0); 107 | 108 | } 109 | 110 | 111 | } 112 | }; 113 | //广播接收器 114 | private BroadcastReceiver completionReceiver = new BroadcastReceiver() { 115 | @Override 116 | public void onReceive(Context context, Intent intent) { 117 | if (intent.getAction().equals(MusicService.ACTION_PLAYBACK_COMPLETED)) { 118 | setNext(LOCATE_MODE); 119 | init(); 120 | setNextUrl(MusicPlayActivity.LOCATE_MODE); 121 | } 122 | if (intent.getAction().equals(ACTION_NEXT)) { 123 | Log.d(TAG, "onReceive: "); 124 | mMusicController.play(nextUrl); 125 | setNext(LOCATE_NEXT); 126 | init(); 127 | if (!isPlay) { 128 | isPlay = true; 129 | first =false; 130 | iv_play.setImageResource(R.drawable.pause); 131 | } 132 | setNextUrl(LOCATE_MODE); 133 | } 134 | if (intent.getAction().equals(ACTION_LAST)) 135 | { 136 | mUrl = lastUrl; 137 | mMusicController.play(lastUrl); 138 | init(); 139 | if (!isPlay) { 140 | isPlay = true; 141 | first =false; 142 | iv_play.setImageResource(R.drawable.pause); 143 | } 144 | setNextUrl(LOCATE_MODE); 145 | } 146 | } 147 | }; 148 | 149 | 150 | // 在需要加载图片的地方调用 151 | 152 | 153 | private static int mId; 154 | private ImageView iv_mode; 155 | private ImageView iv_next; 156 | private ImageView iv_last; 157 | private String lastUrl; 158 | 159 | 160 | @Override 161 | protected void onCreate(Bundle savedInstanceState) { 162 | super.onCreate(savedInstanceState); 163 | setContentView(R.layout.activity_music_play); 164 | /*============= 165 | * 获取控件 166 | */ 167 | sb_progress = findViewById(R.id.sb_progress); 168 | iv_play = findViewById(R.id.iv_play); 169 | title_title = findViewById(R.id.title_title); 170 | tv_title = findViewById(R.id.tv_title); 171 | tv_up_name = findViewById(R.id.tv_up_name); 172 | iv_cover = findViewById(R.id.iv_cover); 173 | tv_duration = findViewById(R.id.tv_duration); 174 | tv_time = findViewById(R.id.tv_time); 175 | iv_mode = findViewById(R.id.iv_mode); 176 | iv_next = findViewById(R.id.iv_next); 177 | iv_last = findViewById(R.id.iv_last); 178 | 179 | /*============= 180 | * 设置控件 181 | */ 182 | iv_play.setOnClickListener(this); 183 | iv_mode.setOnClickListener(this); 184 | iv_next.setOnClickListener(this); 185 | iv_last.setOnClickListener(this); 186 | sb_progress.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { 187 | @Override 188 | public void onProgressChanged(SeekBar seekBar, int i, boolean b) { 189 | 190 | } 191 | 192 | @Override 193 | public void onStartTrackingTouch(SeekBar seekBar) { 194 | 195 | } 196 | 197 | @Override 198 | public void onStopTrackingTouch(SeekBar seekBar) { 199 | int progress = seekBar.getProgress(); 200 | Log.d(TAG, "onStopTrackingTouch: " + progress / 1000); 201 | mMusicController.seekTo(progress); 202 | 203 | } 204 | }); 205 | 206 | 207 | /*============= 208 | * 获取数据 209 | */ 210 | intent = getIntent(); 211 | mFid = intent.getStringExtra("fid"); 212 | mId = intent.getIntExtra("id", 1); 213 | mTitle = intent.getStringExtra("title"); 214 | mUpName = intent.getStringExtra("up_name"); 215 | mCover = intent.getStringExtra("cover"); 216 | Log.d(TAG, "MusicPlayActivity接受到cover数据: " + mCover); 217 | mDuration = intent.getLongExtra("duration", 0L); 218 | mBv = intent.getStringExtra("bv"); 219 | mCid = intent.getLongExtra("cid", 0L); 220 | Log.d(TAG, "MusicPlayActivity接受到bv数据: " + mBv); 221 | Log.d(TAG, "MusicPlayActivity接受到cid数据: " + mCid); 222 | /*============= 223 | * 初始化 224 | */ 225 | 226 | init(); 227 | //绑定服务 228 | bind(); 229 | //注册广播接收器 230 | IntentFilter filter = new IntentFilter(); 231 | filter.addAction(MusicService.ACTION_PLAYBACK_COMPLETED); 232 | filter.addAction(ACTION_NEXT); 233 | filter.addAction(ACTION_LAST); 234 | 235 | registerReceiver(completionReceiver, filter); 236 | 237 | // setNextUrl(LOCATE_NEXT); 238 | } 239 | 240 | /** 241 | * 初始化 242 | */ 243 | 244 | private void init() { 245 | Long min = mDuration / 60; 246 | Long sec = mDuration % 60; 247 | String sSec = sec < 10 ? "0" + sec : String.valueOf(sec); 248 | tv_duration.setText(min + ":" + sSec); 249 | 250 | title_title.setText(mTitle); 251 | tv_title.setText(mTitle); 252 | tv_up_name.setText(mUpName); 253 | 254 | Glide.with(this).load(mCover).listener(new RequestListener() { 255 | 256 | @Override 257 | public boolean onException(Exception e, String model, Target target, boolean isFirstResource) { 258 | Log.d(TAG, "Glide监听onException: "); 259 | e.printStackTrace(); 260 | return false; 261 | } 262 | 263 | @Override 264 | public boolean onResourceReady(GlideDrawable resource, String model, Target target, boolean isFromMemoryCache, boolean isFirstResource) { 265 | Log.d(TAG, "Glide监听onResourceReady:"); 266 | return false; 267 | } 268 | }).into(iv_cover); 269 | 270 | 271 | } 272 | 273 | /** 274 | * 绑定服务 275 | */ 276 | public void bind() { 277 | if (!isBind) { 278 | Intent intent = new Intent(this, MusicService.class); 279 | bindService(intent, mServiceConnection, BIND_AUTO_CREATE); 280 | isBind = true; 281 | } 282 | 283 | } 284 | 285 | /** 286 | * 解绑服务 287 | */ 288 | public void unBind() { 289 | if (isBind) { 290 | unbindService(mServiceConnection); 291 | isBind = false; 292 | } 293 | } 294 | 295 | private void setNext(int mode) { 296 | if (mode == LOCATE_NEXT) { 297 | mId = mId + 1; 298 | Music music = mHelper.musicQueryById(mFid, mId); 299 | // Log.d(TAG, "run: " + music); 300 | if (music.id == null) { 301 | mId = 1; 302 | } 303 | music = mHelper.musicQueryById(mFid, mId); 304 | mTitle = music.title; 305 | mUpName = music.upName; 306 | mCover = music.cover; 307 | mDuration = music.duration; 308 | mBv = music.bv; 309 | mCid = music.cid; 310 | } 311 | if (mode == LOCATE_REPEAT) { 312 | return; 313 | } 314 | if (mode == LOCATE_RANDOM) { 315 | mId = randomId; 316 | Music music = mHelper.musicQueryById(mFid, randomId); 317 | mUpName = music.upName; 318 | mCover = music.cover; 319 | mDuration = music.duration; 320 | mBv = music.bv; 321 | mCid = music.cid; 322 | } 323 | mUrl = nextUrl; 324 | 325 | } 326 | 327 | 328 | /** 329 | * 设置下一首歌曲的源地址url 330 | * 331 | * @return 332 | */ 333 | public static void setNextUrl(int mode) { 334 | 335 | new Thread() { 336 | @Override 337 | public void run() { 338 | super.run(); 339 | if (mode == LOCATE_NEXT) { 340 | 341 | Music music = mHelper.musicQueryById(mFid, mId + 1); 342 | Log.d(TAG, "run: " + music); 343 | if (music.id == null) { 344 | music = mHelper.musicQueryById(mFid, 1); 345 | } 346 | String url = HttpUtils.getLinkByBvAndCid(music.bv, music.cid); 347 | nextUrl = url; 348 | return; 349 | } 350 | if (mode == LOCATE_REPEAT) { 351 | nextUrl = mUrl; 352 | return; 353 | } 354 | if (mode == LOCATE_RANDOM) { 355 | Long count = HttpUtils.getCountById(mFid); 356 | Random random = new Random(); // 创建一个Random对象 357 | int lowerBound = 1; // 下限 358 | int upperBound = Math.toIntExact(count); // 上限 359 | 360 | // 生成并打印一个[lowerBound, upperBound]之间的随机整数 361 | int randomInt = random.nextInt(upperBound - lowerBound + 1) + lowerBound; 362 | randomId = randomInt; 363 | Music music = mHelper.musicQueryById(mFid, randomId); 364 | String url = HttpUtils.getLinkByBvAndCid(music.bv, music.cid); 365 | nextUrl = url; 366 | } 367 | } 368 | }.start(); 369 | } 370 | 371 | interface OnUrlSetListener { 372 | void onUrlSet(); 373 | } 374 | 375 | private void setNextUrl(int mode, OnUrlSetListener listener) { 376 | new Thread() { 377 | @Override 378 | public void run() { 379 | super.run(); 380 | if (mode == LOCATE_NEXT) { 381 | 382 | Music music = mHelper.musicQueryById(mFid, mId + 1); 383 | Log.d(TAG, "run: " + music); 384 | if (music.id == null) { 385 | music = mHelper.musicQueryById(mFid, 1); 386 | } 387 | String url = HttpUtils.getLinkByBvAndCid(music.bv, music.cid); 388 | nextUrl = url; 389 | 390 | } else if (mode == LOCATE_REPEAT) { 391 | nextUrl = mUrl; 392 | 393 | } else if (mode == LOCATE_RANDOM) { 394 | Long count = HttpUtils.getCountById(mFid); 395 | Random random = new Random(); // 创建一个Random对象 396 | int lowerBound = 1; // 下限 397 | int upperBound = Math.toIntExact(count); // 上限 398 | 399 | // 生成并打印一个[lowerBound, upperBound]之间的随机整数 400 | int randomInt = random.nextInt(upperBound - lowerBound + 1) + lowerBound; 401 | randomId = randomInt; 402 | Music music = mHelper.musicQueryById(mFid, randomId); 403 | String url = HttpUtils.getLinkByBvAndCid(music.bv, music.cid); 404 | nextUrl = url; 405 | 406 | } 407 | listener.onUrlSet(); 408 | } 409 | 410 | }.start(); 411 | 412 | 413 | } 414 | 415 | /** 416 | * 设置上一首歌曲的url 417 | */ 418 | private void setLastUrl(OnUrlSetListener listener) 419 | { 420 | new Thread(){ 421 | @Override 422 | public void run() { 423 | super.run(); 424 | Long count = HttpUtils.getCountById(mFid); 425 | --mId; 426 | 427 | Music music = mHelper.musicQueryById(mFid,mId); 428 | if (mId == 0) 429 | { 430 | mId = Math.toIntExact(count); 431 | } 432 | music = mHelper.musicQueryById(mFid,mId); 433 | String url = HttpUtils.getLinkByBvAndCid(music.bv,music.cid); 434 | lastUrl = url; 435 | mTitle = music.title; 436 | mUpName = music.upName; 437 | mCover = music.cover; 438 | mDuration = music.duration; 439 | mBv = music.bv; 440 | mCid = music.cid; 441 | listener.onUrlSet(); 442 | 443 | } 444 | }.start(); 445 | 446 | 447 | } 448 | 449 | 450 | public void back(View view) { 451 | onBackPressed(); 452 | } 453 | 454 | /** 455 | * 播放音乐 456 | * 1.如果是第一次播放,则开始播放,取消第一次播放的状态,并设置正在播放状态 457 | * 2.如果不是第一次播放(暂停后播放),将图标设置为暂停,并设置正在播放状态 458 | * 3.如果正在播放,将图标设置为播放,取消正在播放状态 459 | */ 460 | private void playMusic() { 461 | if (first) { 462 | new Thread() { 463 | @Override 464 | public void run() { 465 | super.run(); 466 | mUrl = HttpUtils.getLinkByBvAndCid(mBv, mCid); 467 | setNextUrl(LOCATE_MODE); 468 | //Log.d(TAG, "MusicPlayActivity的onClick视频原链接 " + mUrl); 469 | 470 | mMusicController.play(mUrl); 471 | } 472 | }.start(); 473 | first = false; 474 | iv_play.setImageResource(R.drawable.pause); 475 | isPlay = true; 476 | return; 477 | } 478 | if (isPlay) { 479 | iv_play.setImageResource(R.drawable.play); 480 | isPlay = false; 481 | mMusicController.pause(); 482 | } else { 483 | iv_play.setImageResource(R.drawable.pause); 484 | isPlay = true; 485 | mMusicController.continuePlay(); 486 | 487 | } 488 | Log.d(TAG, "playMusic: "); 489 | 490 | } 491 | 492 | @Override 493 | public void onClick(View view) { 494 | int id = view.getId(); 495 | if (id == R.id.iv_play) { 496 | playMusic(); 497 | return; 498 | } 499 | if (id == R.id.iv_mode) { 500 | if (LOCATE_MODE == LOCATE_NEXT) { 501 | //实现单曲循环的功能 502 | iv_mode.setImageResource(R.drawable.repeat); 503 | LOCATE_MODE = LOCATE_REPEAT; 504 | setNextUrl(LOCATE_REPEAT); 505 | return; 506 | } 507 | if (LOCATE_MODE == LOCATE_REPEAT) { 508 | //实现随机播放的功能 509 | iv_mode.setImageResource(R.drawable.random); 510 | LOCATE_MODE = LOCATE_RANDOM; 511 | setNextUrl(LOCATE_RANDOM); 512 | return; 513 | } 514 | if (LOCATE_MODE == LOCATE_RANDOM) { 515 | //实现循环播放的功能 516 | iv_mode.setImageResource(R.drawable.order); 517 | LOCATE_MODE = LOCATE_NEXT; 518 | setNextUrl(LOCATE_NEXT); 519 | return; 520 | } 521 | 522 | } 523 | if (id == R.id.iv_next) { 524 | 525 | setNextUrl(LOCATE_NEXT, new OnUrlSetListener() { 526 | @Override 527 | public void onUrlSet() { 528 | Log.d(TAG, "onUrlSet: "); 529 | Intent intent1 = new Intent(ACTION_NEXT); 530 | sendBroadcast(intent1); 531 | } 532 | }); 533 | 534 | 535 | } 536 | if (id == R.id.iv_last) { 537 | setLastUrl(new OnUrlSetListener() { 538 | @Override 539 | public void onUrlSet() { 540 | Intent intent1 = new Intent(ACTION_LAST); 541 | sendBroadcast(intent1); 542 | } 543 | }); 544 | 545 | } 546 | 547 | } 548 | 549 | @Override 550 | protected void onStart() { 551 | super.onStart(); 552 | mHelper = ListSqliteHelper.getInstance(this); 553 | mHelper.openWriteLink(); 554 | mHelper.openReadLink(); 555 | setNextUrl(LOCATE_NEXT); 556 | 557 | } 558 | 559 | @Override 560 | protected void onStop() { 561 | super.onStop(); 562 | // unBind(); 563 | } 564 | 565 | @Override 566 | protected void onDestroy() { 567 | super.onDestroy(); 568 | // 外部类Activity生命周期结束时,同时清空消息队列 & 结束Handler生命周期,防止内存泄露 569 | handler.removeCallbacksAndMessages(null); 570 | unregisterReceiver(completionReceiver); 571 | } 572 | } -------------------------------------------------------------------------------- /app/src/main/java/com/quietfall/database/ListSqliteHelper.java: -------------------------------------------------------------------------------- 1 | package com.quietfall.database; 2 | 3 | import android.content.ContentValues; 4 | import android.content.Context; 5 | import android.database.Cursor; 6 | import android.database.sqlite.SQLiteDatabase; 7 | import android.database.sqlite.SQLiteOpenHelper; 8 | import android.util.Log; 9 | 10 | import androidx.annotation.Nullable; 11 | 12 | import com.quietfall.entity.Music; 13 | import com.quietfall.entity.MusicList; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | /** 19 | * 管理歌单列表的 20 | */ 21 | public class ListSqliteHelper extends SQLiteOpenHelper { 22 | private static final String DB_NAME = "main.db"; 23 | //存放歌单数据的表名 24 | private static final String TABLE_LIST_NAME = "list"; 25 | //存放音乐数据的表名 26 | private static final Integer DB_VERSION = 1; 27 | private static ListSqliteHelper mHelper = null; 28 | private SQLiteDatabase mWDB = null; 29 | private SQLiteDatabase mRDB = null; 30 | 31 | 32 | private ListSqliteHelper(@Nullable Context context) { 33 | super(context, DB_NAME, null, DB_VERSION); 34 | } 35 | 36 | public static ListSqliteHelper getInstance(Context context) { 37 | if (mHelper == null) { 38 | mHelper = new ListSqliteHelper(context); 39 | } 40 | return mHelper; 41 | } 42 | 43 | @Override 44 | public void onCreate(SQLiteDatabase db) { 45 | String sql = "CREATE TABLE IF NOT EXISTS " + TABLE_LIST_NAME + " (" + 46 | "_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," + 47 | " fid VARCHAR NOT NULL," + 48 | " name VARCHAR NOT NULL);"; 49 | db.execSQL(sql); 50 | 51 | } 52 | public SQLiteDatabase openReadLink() 53 | { 54 | if (mRDB == null || !mRDB.isOpen()) 55 | { 56 | mRDB = mHelper.getReadableDatabase(); 57 | } 58 | return mRDB; 59 | } 60 | public SQLiteDatabase openWriteLink() 61 | { 62 | if (mWDB == null || !mWDB.isOpen()) 63 | { 64 | mWDB = mHelper.getWritableDatabase(); 65 | } 66 | return mWDB; 67 | } 68 | public void closeLink() 69 | { 70 | if (mRDB != null && mRDB.isOpen()) 71 | { 72 | mRDB.close(); 73 | mRDB = null; 74 | } 75 | if (mWDB != null && mWDB.isOpen()) 76 | { 77 | mWDB.close(); 78 | mWDB = null; 79 | } 80 | } 81 | 82 | @Override 83 | public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) { 84 | 85 | } 86 | /** 87 | * =============================================================================================================== 88 | * 歌单操作 89 | */ 90 | 91 | /** 92 | * 列表中插入歌单 93 | * @param list 94 | * @return 95 | */ 96 | public long insert(MusicList list) 97 | { 98 | ContentValues values = new ContentValues(); 99 | values.put("name",list.name); 100 | values.put("fid",list.fid); 101 | return mWDB.insert(TABLE_LIST_NAME,null,values); 102 | } 103 | 104 | /** 105 | * 查询所有歌单 106 | * @return 107 | */ 108 | public List queryAll() 109 | { 110 | List musicListList = new ArrayList<>(); 111 | Cursor cursor = mRDB.query(TABLE_LIST_NAME,null,null,null,null,null,null); 112 | while (cursor.moveToNext()) 113 | { 114 | MusicList musicList = new MusicList(); 115 | musicList.id = cursor.getInt(0); 116 | musicList.name = cursor.getString(2); 117 | musicList.fid = cursor.getString(1); 118 | musicListList.add(musicList); 119 | } 120 | return musicListList; 121 | } 122 | /** 123 | * 创建每个歌单对应的音乐表 124 | * @param id 125 | * @return 126 | */ 127 | public String createMusicListTable(String id) 128 | { 129 | String tableName = "music_list_"+id; 130 | String sql = "CREATE TABLE IF NOT EXISTS " + tableName + " (" + 131 | "_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," + 132 | " title VARCHAR NOT NULL," + 133 | " up_name VARCHAR NOT NULL," + 134 | " bv VARCHAR NOT NULL," + 135 | " cid UNSIGNED BIG INT NOT NULL," + 136 | " duration UNSIGNED BIG INT NOT NULL," + 137 | " cover VARCHAR NOT NULL);"; 138 | mWDB.execSQL(sql); 139 | 140 | return tableName; 141 | } 142 | 143 | /** 144 | * 通过id寻找歌单信息 145 | * 这里的id是Sqlite中的_id 146 | * @return 147 | */ 148 | public MusicList queryListById(Integer iid) 149 | { 150 | MusicList musicList = null; 151 | String id = String.valueOf(iid); 152 | Cursor cursor = mRDB.query(TABLE_LIST_NAME, null, "_id=?", new String[]{id}, null, null, null); 153 | if (cursor.moveToNext()) 154 | { 155 | musicList = new MusicList(); 156 | musicList.id= cursor.getInt(0); 157 | musicList.fid = cursor.getString(1); 158 | musicList.name = cursor.getString(2); 159 | } 160 | return musicList; 161 | } 162 | /** 163 | * =============================================================================================================== 164 | * 165 | */ 166 | /** 167 | * =============================================================================================================== 168 | * 歌单歌曲操作 169 | */ 170 | 171 | /** 172 | * 批量插入数据 173 | * @param valuesList 174 | * @return 175 | */ 176 | public long insertSomeMusic(List valuesList,String id) 177 | { 178 | String tableName = "music_list_"+id; 179 | long count = 0L; 180 | for (ContentValues values : valuesList) { 181 | if (mWDB.insert(tableName,null,values) != -1) 182 | { 183 | ++count; 184 | } 185 | } 186 | Log.d("qf", "insertSomeMusic: "+count); 187 | if (count < valuesList.size()) 188 | { 189 | return -1; 190 | } 191 | return count; 192 | 193 | } 194 | 195 | /** 196 | * 查询歌单中所有音乐信息 197 | * @param id 198 | * @return 199 | */ 200 | public List musicQueryAll(String id) 201 | { 202 | List list = new ArrayList<>(); 203 | String tableName = "music_list_"+id; 204 | Cursor cursor = mRDB.query(tableName, null, null, null, null, null, null, null); 205 | while (cursor.moveToNext()) 206 | { 207 | Music music = new Music(); 208 | music.id= cursor.getInt(0); 209 | music.title = cursor.getString(1); 210 | music.upName = cursor.getString(2); 211 | music.bv = cursor.getString(3); 212 | music.cid = cursor.getLong(4); 213 | music.duration = cursor.getLong(5); 214 | music.cover = cursor.getString(6); 215 | list.add(music); 216 | } 217 | return list; 218 | 219 | } 220 | 221 | /** 222 | * 根据id查询音乐信息 223 | * @param id 224 | * @return 225 | */ 226 | public Music musicQueryById(String fid,Integer id) 227 | { 228 | String tableName = "music_list_"+fid; 229 | String sid = String.valueOf(id); 230 | Music music = new Music(); 231 | Cursor cursor = mRDB.query(tableName, null, "_id=?", new String[]{sid}, null, null, null, null); 232 | if (cursor.moveToNext()) 233 | { 234 | music.id= cursor.getInt(0); 235 | music.title = cursor.getString(1); 236 | music.upName = cursor.getString(2); 237 | music.bv = cursor.getString(3); 238 | music.cid = cursor.getLong(4); 239 | music.duration = cursor.getLong(5); 240 | music.cover = cursor.getString(6); 241 | } 242 | return music; 243 | 244 | } 245 | 246 | } 247 | -------------------------------------------------------------------------------- /app/src/main/java/com/quietfall/entity/LinkInfo.java: -------------------------------------------------------------------------------- 1 | package com.quietfall.entity; 2 | 3 | import java.util.List; 4 | 5 | public class LinkInfo { 6 | private Integer code; 7 | private String message; 8 | private Integer ttl; 9 | private DataDTO data; 10 | 11 | public Integer getCode() { 12 | return code; 13 | } 14 | 15 | public void setCode(Integer code) { 16 | this.code = code; 17 | } 18 | 19 | public String getMessage() { 20 | return message; 21 | } 22 | 23 | public void setMessage(String message) { 24 | this.message = message; 25 | } 26 | 27 | public Integer getTtl() { 28 | return ttl; 29 | } 30 | 31 | public void setTtl(Integer ttl) { 32 | this.ttl = ttl; 33 | } 34 | 35 | public DataDTO getData() { 36 | return data; 37 | } 38 | 39 | public void setData(DataDTO data) { 40 | this.data = data; 41 | } 42 | 43 | public static class DataDTO { 44 | private String from; 45 | private String result; 46 | private String message; 47 | private Integer quality; 48 | private String format; 49 | private Integer timelength; 50 | private String acceptFormat; 51 | private List acceptDescription; 52 | private List acceptQuality; 53 | private Integer videoCodecid; 54 | private String seekParam; 55 | private String seekType; 56 | private List durl; 57 | private List supportFormats; 58 | private Object highFormat; 59 | private Integer lastPlayTime; 60 | private Integer lastPlayCid; 61 | 62 | public String getFrom() { 63 | return from; 64 | } 65 | 66 | public void setFrom(String from) { 67 | this.from = from; 68 | } 69 | 70 | public String getResult() { 71 | return result; 72 | } 73 | 74 | public void setResult(String result) { 75 | this.result = result; 76 | } 77 | 78 | public String getMessage() { 79 | return message; 80 | } 81 | 82 | public void setMessage(String message) { 83 | this.message = message; 84 | } 85 | 86 | public Integer getQuality() { 87 | return quality; 88 | } 89 | 90 | public void setQuality(Integer quality) { 91 | this.quality = quality; 92 | } 93 | 94 | public String getFormat() { 95 | return format; 96 | } 97 | 98 | public void setFormat(String format) { 99 | this.format = format; 100 | } 101 | 102 | public Integer getTimelength() { 103 | return timelength; 104 | } 105 | 106 | public void setTimelength(Integer timelength) { 107 | this.timelength = timelength; 108 | } 109 | 110 | public String getAcceptFormat() { 111 | return acceptFormat; 112 | } 113 | 114 | public void setAcceptFormat(String acceptFormat) { 115 | this.acceptFormat = acceptFormat; 116 | } 117 | 118 | public List getAcceptDescription() { 119 | return acceptDescription; 120 | } 121 | 122 | public void setAcceptDescription(List acceptDescription) { 123 | this.acceptDescription = acceptDescription; 124 | } 125 | 126 | public List getAcceptQuality() { 127 | return acceptQuality; 128 | } 129 | 130 | public void setAcceptQuality(List acceptQuality) { 131 | this.acceptQuality = acceptQuality; 132 | } 133 | 134 | public Integer getVideoCodecid() { 135 | return videoCodecid; 136 | } 137 | 138 | public void setVideoCodecid(Integer videoCodecid) { 139 | this.videoCodecid = videoCodecid; 140 | } 141 | 142 | public String getSeekParam() { 143 | return seekParam; 144 | } 145 | 146 | public void setSeekParam(String seekParam) { 147 | this.seekParam = seekParam; 148 | } 149 | 150 | public String getSeekType() { 151 | return seekType; 152 | } 153 | 154 | public void setSeekType(String seekType) { 155 | this.seekType = seekType; 156 | } 157 | 158 | public List getDurl() { 159 | return durl; 160 | } 161 | 162 | public void setDurl(List durl) { 163 | this.durl = durl; 164 | } 165 | 166 | public List getSupportFormats() { 167 | return supportFormats; 168 | } 169 | 170 | public void setSupportFormats(List supportFormats) { 171 | this.supportFormats = supportFormats; 172 | } 173 | 174 | public Object getHighFormat() { 175 | return highFormat; 176 | } 177 | 178 | public void setHighFormat(Object highFormat) { 179 | this.highFormat = highFormat; 180 | } 181 | 182 | public Integer getLastPlayTime() { 183 | return lastPlayTime; 184 | } 185 | 186 | public void setLastPlayTime(Integer lastPlayTime) { 187 | this.lastPlayTime = lastPlayTime; 188 | } 189 | 190 | public Integer getLastPlayCid() { 191 | return lastPlayCid; 192 | } 193 | 194 | public void setLastPlayCid(Integer lastPlayCid) { 195 | this.lastPlayCid = lastPlayCid; 196 | } 197 | 198 | public static class DurlDTO { 199 | private Integer order; 200 | private Integer length; 201 | private Integer size; 202 | private String ahead; 203 | private String vhead; 204 | private String url; 205 | private List backupUrl; 206 | 207 | public Integer getOrder() { 208 | return order; 209 | } 210 | 211 | public void setOrder(Integer order) { 212 | this.order = order; 213 | } 214 | 215 | public Integer getLength() { 216 | return length; 217 | } 218 | 219 | public void setLength(Integer length) { 220 | this.length = length; 221 | } 222 | 223 | public Integer getSize() { 224 | return size; 225 | } 226 | 227 | public void setSize(Integer size) { 228 | this.size = size; 229 | } 230 | 231 | public String getAhead() { 232 | return ahead; 233 | } 234 | 235 | public void setAhead(String ahead) { 236 | this.ahead = ahead; 237 | } 238 | 239 | public String getVhead() { 240 | return vhead; 241 | } 242 | 243 | public void setVhead(String vhead) { 244 | this.vhead = vhead; 245 | } 246 | 247 | public String getUrl() { 248 | return url; 249 | } 250 | 251 | public void setUrl(String url) { 252 | this.url = url; 253 | } 254 | 255 | public List getBackupUrl() { 256 | return backupUrl; 257 | } 258 | 259 | public void setBackupUrl(List backupUrl) { 260 | this.backupUrl = backupUrl; 261 | } 262 | } 263 | 264 | public static class SupportFormatsDTO { 265 | private Integer quality; 266 | private String format; 267 | private String newDescription; 268 | private String displayDesc; 269 | private String superscript; 270 | private Object codecs; 271 | 272 | public Integer getQuality() { 273 | return quality; 274 | } 275 | 276 | public void setQuality(Integer quality) { 277 | this.quality = quality; 278 | } 279 | 280 | public String getFormat() { 281 | return format; 282 | } 283 | 284 | public void setFormat(String format) { 285 | this.format = format; 286 | } 287 | 288 | public String getNewDescription() { 289 | return newDescription; 290 | } 291 | 292 | public void setNewDescription(String newDescription) { 293 | this.newDescription = newDescription; 294 | } 295 | 296 | public String getDisplayDesc() { 297 | return displayDesc; 298 | } 299 | 300 | public void setDisplayDesc(String displayDesc) { 301 | this.displayDesc = displayDesc; 302 | } 303 | 304 | public String getSuperscript() { 305 | return superscript; 306 | } 307 | 308 | public void setSuperscript(String superscript) { 309 | this.superscript = superscript; 310 | } 311 | 312 | public Object getCodecs() { 313 | return codecs; 314 | } 315 | 316 | public void setCodecs(Object codecs) { 317 | this.codecs = codecs; 318 | } 319 | } 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /app/src/main/java/com/quietfall/entity/ListInfo.java: -------------------------------------------------------------------------------- 1 | package com.quietfall.entity; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | import java.util.List; 6 | 7 | public class ListInfo { 8 | @Override 9 | public String toString() { 10 | return "ListInfo{" + 11 | "code=" + code + 12 | ", message='" + message + '\'' + 13 | ", ttl=" + ttl + 14 | ", data=" + data + 15 | '}'; 16 | } 17 | 18 | private Long code; 19 | private String message; 20 | private Long ttl; 21 | private DataDTO data; 22 | 23 | public Long getCode() { 24 | return code; 25 | } 26 | 27 | public void setCode(Long code) { 28 | this.code = code; 29 | } 30 | 31 | public String getMessage() { 32 | return message; 33 | } 34 | 35 | public void setMessage(String message) { 36 | this.message = message; 37 | } 38 | 39 | public Long getTtl() { 40 | return ttl; 41 | } 42 | 43 | public void setTtl(Long ttl) { 44 | this.ttl = ttl; 45 | } 46 | 47 | public DataDTO getData() { 48 | return data; 49 | } 50 | 51 | public void setData(DataDTO data) { 52 | this.data = data; 53 | } 54 | 55 | public static class DataDTO { 56 | private InfoDTO info; 57 | private List medias; 58 | private Boolean hasMore; 59 | private Long ttl; 60 | 61 | public InfoDTO getInfo() { 62 | return info; 63 | } 64 | 65 | public void setInfo(InfoDTO info) { 66 | this.info = info; 67 | } 68 | 69 | public List getMedias() { 70 | return medias; 71 | } 72 | 73 | public void setMedias(List medias) { 74 | this.medias = medias; 75 | } 76 | 77 | public Boolean getHasMore() { 78 | return hasMore; 79 | } 80 | 81 | public void setHasMore(Boolean hasMore) { 82 | this.hasMore = hasMore; 83 | } 84 | 85 | public Long getTtl() { 86 | return ttl; 87 | } 88 | 89 | public void setTtl(Long ttl) { 90 | this.ttl = ttl; 91 | } 92 | 93 | public static class InfoDTO { 94 | private Long id; 95 | private Long fid; 96 | private Long mid; 97 | private Long attr; 98 | private String title; 99 | private String cover; 100 | private UpperDTO upper; 101 | @SerializedName("cover_type") 102 | private Long coverType; 103 | private CntInfoDTO cntInfo; 104 | private Long type; 105 | private String intro; 106 | private Long ctime; 107 | private Long mtime; 108 | private Long state; 109 | private Long favState; 110 | private Long likeState; 111 | @SerializedName("media_count") 112 | private Long mediaCount; 113 | 114 | public Long getId() { 115 | return id; 116 | } 117 | 118 | public void setId(Long id) { 119 | this.id = id; 120 | } 121 | 122 | public Long getFid() { 123 | return fid; 124 | } 125 | 126 | public void setFid(Long fid) { 127 | this.fid = fid; 128 | } 129 | 130 | public Long getMid() { 131 | return mid; 132 | } 133 | 134 | public void setMid(Long mid) { 135 | this.mid = mid; 136 | } 137 | 138 | public Long getAttr() { 139 | return attr; 140 | } 141 | 142 | public void setAttr(Long attr) { 143 | this.attr = attr; 144 | } 145 | 146 | public String getTitle() { 147 | return title; 148 | } 149 | 150 | public void setTitle(String title) { 151 | this.title = title; 152 | } 153 | 154 | public String getCover() { 155 | return cover; 156 | } 157 | 158 | public void setCover(String cover) { 159 | this.cover = cover; 160 | } 161 | 162 | public UpperDTO getUpper() { 163 | return upper; 164 | } 165 | 166 | public void setUpper(UpperDTO upper) { 167 | this.upper = upper; 168 | } 169 | 170 | public Long getCoverType() { 171 | return coverType; 172 | } 173 | 174 | public void setCoverType(Long coverType) { 175 | this.coverType = coverType; 176 | } 177 | 178 | public CntInfoDTO getCntInfo() { 179 | return cntInfo; 180 | } 181 | 182 | public void setCntInfo(CntInfoDTO cntInfo) { 183 | this.cntInfo = cntInfo; 184 | } 185 | 186 | public Long getType() { 187 | return type; 188 | } 189 | 190 | public void setType(Long type) { 191 | this.type = type; 192 | } 193 | 194 | public String getIntro() { 195 | return intro; 196 | } 197 | 198 | public void setIntro(String intro) { 199 | this.intro = intro; 200 | } 201 | 202 | public Long getCtime() { 203 | return ctime; 204 | } 205 | 206 | public void setCtime(Long ctime) { 207 | this.ctime = ctime; 208 | } 209 | 210 | public Long getMtime() { 211 | return mtime; 212 | } 213 | 214 | public void setMtime(Long mtime) { 215 | this.mtime = mtime; 216 | } 217 | 218 | public Long getState() { 219 | return state; 220 | } 221 | 222 | public void setState(Long state) { 223 | this.state = state; 224 | } 225 | 226 | public Long getFavState() { 227 | return favState; 228 | } 229 | 230 | public void setFavState(Long favState) { 231 | this.favState = favState; 232 | } 233 | 234 | public Long getLikeState() { 235 | return likeState; 236 | } 237 | 238 | public void setLikeState(Long likeState) { 239 | this.likeState = likeState; 240 | } 241 | 242 | public Long getMediaCount() { 243 | return mediaCount; 244 | } 245 | 246 | public void setMediaCount(Long mediaCount) { 247 | this.mediaCount = mediaCount; 248 | } 249 | 250 | public static class UpperDTO { 251 | private Long mid; 252 | private String name; 253 | private String face; 254 | private Boolean followed; 255 | private Long vipType; 256 | private Long vipStatue; 257 | 258 | public Long getMid() { 259 | return mid; 260 | } 261 | 262 | public void setMid(Long mid) { 263 | this.mid = mid; 264 | } 265 | 266 | public String getName() { 267 | return name; 268 | } 269 | 270 | public void setName(String name) { 271 | this.name = name; 272 | } 273 | 274 | public String getFace() { 275 | return face; 276 | } 277 | 278 | public void setFace(String face) { 279 | this.face = face; 280 | } 281 | 282 | public Boolean getFollowed() { 283 | return followed; 284 | } 285 | 286 | public void setFollowed(Boolean followed) { 287 | this.followed = followed; 288 | } 289 | 290 | public Long getVipType() { 291 | return vipType; 292 | } 293 | 294 | public void setVipType(Long vipType) { 295 | this.vipType = vipType; 296 | } 297 | 298 | public Long getVipStatue() { 299 | return vipStatue; 300 | } 301 | 302 | public void setVipStatue(Long vipStatue) { 303 | this.vipStatue = vipStatue; 304 | } 305 | } 306 | 307 | public static class CntInfoDTO { 308 | private Long collect; 309 | private Long play; 310 | private Long thumbUp; 311 | private Long share; 312 | 313 | public Long getCollect() { 314 | return collect; 315 | } 316 | 317 | public void setCollect(Long collect) { 318 | this.collect = collect; 319 | } 320 | 321 | public Long getPlay() { 322 | return play; 323 | } 324 | 325 | public void setPlay(Long play) { 326 | this.play = play; 327 | } 328 | 329 | public Long getThumbUp() { 330 | return thumbUp; 331 | } 332 | 333 | public void setThumbUp(Long thumbUp) { 334 | this.thumbUp = thumbUp; 335 | } 336 | 337 | public Long getShare() { 338 | return share; 339 | } 340 | 341 | public void setShare(Long share) { 342 | this.share = share; 343 | } 344 | } 345 | } 346 | 347 | public static class MediasDTO { 348 | private Long id; 349 | private Long type; 350 | private String title; 351 | private String cover; 352 | private String intro; 353 | private Long page; 354 | private Long duration; 355 | private UpperDTO upper; 356 | private Long attr; 357 | private CntInfoDTO cntInfo; 358 | private String link; 359 | private Long ctime; 360 | private Long pubtime; 361 | private Long favTime; 362 | private String bvId; 363 | private String bvid; 364 | private Object season; 365 | private Object ogv; 366 | private UgcDTO ugc; 367 | 368 | public Long getId() { 369 | return id; 370 | } 371 | 372 | public void setId(Long id) { 373 | this.id = id; 374 | } 375 | 376 | public Long getType() { 377 | return type; 378 | } 379 | 380 | public void setType(Long type) { 381 | this.type = type; 382 | } 383 | 384 | public String getTitle() { 385 | return title; 386 | } 387 | 388 | public void setTitle(String title) { 389 | this.title = title; 390 | } 391 | 392 | public String getCover() { 393 | return cover; 394 | } 395 | 396 | public void setCover(String cover) { 397 | this.cover = cover; 398 | } 399 | 400 | public String getIntro() { 401 | return intro; 402 | } 403 | 404 | public void setIntro(String intro) { 405 | this.intro = intro; 406 | } 407 | 408 | public Long getPage() { 409 | return page; 410 | } 411 | 412 | public void setPage(Long page) { 413 | this.page = page; 414 | } 415 | 416 | public Long getDuration() { 417 | return duration; 418 | } 419 | 420 | public void setDuration(Long duration) { 421 | this.duration = duration; 422 | } 423 | 424 | public UpperDTO getUpper() { 425 | return upper; 426 | } 427 | 428 | public void setUpper(UpperDTO upper) { 429 | this.upper = upper; 430 | } 431 | 432 | public Long getAttr() { 433 | return attr; 434 | } 435 | 436 | public void setAttr(Long attr) { 437 | this.attr = attr; 438 | } 439 | 440 | public CntInfoDTO getCntInfo() { 441 | return cntInfo; 442 | } 443 | 444 | public void setCntInfo(CntInfoDTO cntInfo) { 445 | this.cntInfo = cntInfo; 446 | } 447 | 448 | public String getLink() { 449 | return link; 450 | } 451 | 452 | public void setLink(String link) { 453 | this.link = link; 454 | } 455 | 456 | public Long getCtime() { 457 | return ctime; 458 | } 459 | 460 | public void setCtime(Long ctime) { 461 | this.ctime = ctime; 462 | } 463 | 464 | public Long getPubtime() { 465 | return pubtime; 466 | } 467 | 468 | public void setPubtime(Long pubtime) { 469 | this.pubtime = pubtime; 470 | } 471 | 472 | public Long getFavTime() { 473 | return favTime; 474 | } 475 | 476 | public void setFavTime(Long favTime) { 477 | this.favTime = favTime; 478 | } 479 | 480 | public String getBvId() { 481 | return bvId; 482 | } 483 | 484 | public void setBvId(String bvId) { 485 | this.bvId = bvId; 486 | } 487 | 488 | public String getBvid() { 489 | return bvid; 490 | } 491 | 492 | public void setBvid(String bvid) { 493 | this.bvid = bvid; 494 | } 495 | 496 | public Object getSeason() { 497 | return season; 498 | } 499 | 500 | public void setSeason(Object season) { 501 | this.season = season; 502 | } 503 | 504 | public Object getOgv() { 505 | return ogv; 506 | } 507 | 508 | public void setOgv(Object ogv) { 509 | this.ogv = ogv; 510 | } 511 | 512 | public UgcDTO getUgc() { 513 | return ugc; 514 | } 515 | 516 | public void setUgc(UgcDTO ugc) { 517 | this.ugc = ugc; 518 | } 519 | 520 | public static class UpperDTO { 521 | private Long mid; 522 | private String name; 523 | private String face; 524 | 525 | public Long getMid() { 526 | return mid; 527 | } 528 | 529 | public void setMid(Long mid) { 530 | this.mid = mid; 531 | } 532 | 533 | public String getName() { 534 | return name; 535 | } 536 | 537 | public void setName(String name) { 538 | this.name = name; 539 | } 540 | 541 | public String getFace() { 542 | return face; 543 | } 544 | 545 | public void setFace(String face) { 546 | this.face = face; 547 | } 548 | } 549 | 550 | public static class CntInfoDTO { 551 | private Long collect; 552 | private Long play; 553 | private Long danmaku; 554 | private Long vt; 555 | private Long playSwitch; 556 | private Long reply; 557 | private String viewText1; 558 | 559 | public Long getCollect() { 560 | return collect; 561 | } 562 | 563 | public void setCollect(Long collect) { 564 | this.collect = collect; 565 | } 566 | 567 | public Long getPlay() { 568 | return play; 569 | } 570 | 571 | public void setPlay(Long play) { 572 | this.play = play; 573 | } 574 | 575 | public Long getDanmaku() { 576 | return danmaku; 577 | } 578 | 579 | public void setDanmaku(Long danmaku) { 580 | this.danmaku = danmaku; 581 | } 582 | 583 | public Long getVt() { 584 | return vt; 585 | } 586 | 587 | public void setVt(Long vt) { 588 | this.vt = vt; 589 | } 590 | 591 | public Long getPlaySwitch() { 592 | return playSwitch; 593 | } 594 | 595 | public void setPlaySwitch(Long playSwitch) { 596 | this.playSwitch = playSwitch; 597 | } 598 | 599 | public Long getReply() { 600 | return reply; 601 | } 602 | 603 | public void setReply(Long reply) { 604 | this.reply = reply; 605 | } 606 | 607 | public String getViewText1() { 608 | return viewText1; 609 | } 610 | 611 | public void setViewText1(String viewText1) { 612 | this.viewText1 = viewText1; 613 | } 614 | } 615 | 616 | public static class UgcDTO { 617 | @SerializedName("first_cid") 618 | private Long firstCid; 619 | 620 | public Long getFirstCid() { 621 | return firstCid; 622 | } 623 | 624 | public void setFirstCid(Long firstCid) { 625 | this.firstCid = firstCid; 626 | } 627 | } 628 | } 629 | } 630 | } 631 | -------------------------------------------------------------------------------- /app/src/main/java/com/quietfall/entity/Music.java: -------------------------------------------------------------------------------- 1 | package com.quietfall.entity; 2 | 3 | public class Music { 4 | public Integer id; 5 | public Long duration; 6 | public Long cid; 7 | 8 | public String title; 9 | public String upName; 10 | public String bv; 11 | public String cover; 12 | 13 | 14 | @Override 15 | public String toString() { 16 | return "Music{" + 17 | "id=" + id + 18 | ", duration=" + duration + 19 | ", title='" + title + '\'' + 20 | ", upName='" + upName + '\'' + 21 | ", bv='" + bv + '\'' + 22 | ", cover='" + cover + '\'' + 23 | '}'; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/quietfall/entity/MusicList.java: -------------------------------------------------------------------------------- 1 | package com.quietfall.entity; 2 | 3 | /** 4 | * 歌单的基本信息:名字 5 | */ 6 | public class MusicList { 7 | public String name; 8 | public int id; 9 | public String fid; 10 | 11 | 12 | public MusicList(String name, String fid) { 13 | this.name = name; 14 | this.fid = fid; 15 | } 16 | 17 | @Override 18 | public String toString() { 19 | return "MusicList{" + 20 | "name='" + name + '\'' + 21 | ", id=" + id + 22 | '}'; 23 | } 24 | 25 | 26 | 27 | public MusicList() { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/quietfall/fragment/AboutFragment.java: -------------------------------------------------------------------------------- 1 | package com.quietfall.fragment; 2 | 3 | import android.os.Bundle; 4 | 5 | import androidx.fragment.app.Fragment; 6 | 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | 11 | import com.quietfall.R; 12 | 13 | public class AboutFragment extends Fragment { 14 | 15 | 16 | public AboutFragment() { 17 | // Required empty public constructor 18 | } 19 | 20 | 21 | @Override 22 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 23 | Bundle savedInstanceState) { 24 | // Inflate the layout for this fragment 25 | return inflater.inflate(R.layout.fragment_about, null); 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/quietfall/fragment/HomeFragment.java: -------------------------------------------------------------------------------- 1 | package com.quietfall.fragment; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.DialogInterface; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | 8 | import androidx.fragment.app.Fragment; 9 | 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.AdapterView; 14 | import android.widget.Button; 15 | import android.widget.EditText; 16 | import android.widget.ListView; 17 | import android.widget.SimpleAdapter; 18 | 19 | import com.quietfall.AddMusicListActivity; 20 | import com.quietfall.MainActivity; 21 | import com.quietfall.MusicListActivity; 22 | import com.quietfall.R; 23 | import com.quietfall.database.ListSqliteHelper; 24 | import com.quietfall.entity.MusicList; 25 | import com.quietfall.utils.ToastUtil; 26 | 27 | import java.util.ArrayList; 28 | import java.util.HashMap; 29 | import java.util.List; 30 | import java.util.Map; 31 | 32 | public class HomeFragment extends Fragment implements View.OnClickListener { 33 | private ListSqliteHelper mHelper; 34 | 35 | private ListView lv_list; 36 | 37 | public HomeFragment() { 38 | // Required empty public constructor 39 | } 40 | 41 | 42 | @Override 43 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 44 | Bundle savedInstanceState) { 45 | View view = inflater.inflate(R.layout.fragment_home,null); 46 | lv_list = view.findViewById(R.id.lv_list); 47 | Button btn_add = view.findViewById(R.id.btn_add); 48 | btn_add.setOnClickListener(this); 49 | initList(); 50 | 51 | return view; 52 | } 53 | private void initList() { 54 | mHelper = ListSqliteHelper.getInstance(getContext()); 55 | mHelper.openReadLink(); 56 | mHelper.openWriteLink(); 57 | List musicListList = mHelper.queryAll(); 58 | if (musicListList.size() == 0) { 59 | lv_list.setVisibility(View.GONE); 60 | } else { 61 | lv_list.setVisibility(View.VISIBLE); 62 | } 63 | List> list = new ArrayList<>(); 64 | for (int i = 0; i < musicListList.size(); i++) { 65 | Map map = new HashMap<>(); 66 | map.put("desc", musicListList.get(i).name); 67 | list.add(map); 68 | } 69 | 70 | SimpleAdapter listAdapter = new SimpleAdapter(getContext(), list, R.layout.list_item, new String[]{"desc"}, new int[]{R.id.tv_desc}); 71 | lv_list.setAdapter(listAdapter); 72 | lv_list.setOnItemClickListener(new AdapterView.OnItemClickListener() { 73 | @Override 74 | public void onItemClick(AdapterView adapterView, View view, int i, long l) { 75 | //i从0开始 76 | int id = i + 1; 77 | MusicList musicList = mHelper.queryListById(id); 78 | ToastUtil.show(getContext(),musicList.name); 79 | Intent intent = new Intent(getContext(), MusicListActivity.class); 80 | intent.putExtra("fid",musicList.fid); 81 | intent.putExtra("name",musicList.name); 82 | startActivity(intent); 83 | } 84 | }); 85 | } 86 | 87 | @Override 88 | public void onClick(View view) { 89 | Intent intent = new Intent(getContext(), AddMusicListActivity.class); 90 | AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); 91 | EditText et_uid = new EditText(getContext()); 92 | builder.setTitle("请输入收藏夹主人的Uid"); 93 | builder.setView(et_uid); 94 | builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { 95 | @Override 96 | public void onClick(DialogInterface dialogInterface, int i) { 97 | String uid = et_uid.getText().toString(); 98 | if (uid == null || uid.isEmpty()) 99 | { 100 | return; 101 | } 102 | intent.putExtra("uid",uid); 103 | startActivity(intent); 104 | } 105 | }); 106 | builder.setNegativeButton("取消",null); 107 | builder.show(); 108 | 109 | } 110 | } -------------------------------------------------------------------------------- /app/src/main/java/com/quietfall/service/MusicService.java: -------------------------------------------------------------------------------- 1 | package com.quietfall.service; 2 | 3 | import android.app.Service; 4 | import android.content.Intent; 5 | import android.media.MediaPlayer; 6 | import android.net.Uri; 7 | import android.os.Binder; 8 | import android.os.Bundle; 9 | import android.os.IBinder; 10 | import android.util.Log; 11 | 12 | import com.quietfall.MusicPlayActivity; 13 | 14 | import java.io.IOException; 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | import java.util.Timer; 18 | import java.util.TimerTask; 19 | 20 | public class MusicService extends Service { 21 | private MediaPlayer player; 22 | private Timer timer; 23 | private static final String TAG = "qf"; 24 | public static final int HANDLER_WHAT = 0; 25 | public static final int HANDLER_WHAT_END = 1; 26 | private final Object mediaPlayerLock = new Object(); // 创建一个锁对象 27 | public static final String ACTION_PLAYBACK_COMPLETED = "com.example.MusicService.ACTION_PLAYBACK_COMPLETED"; 28 | 29 | 30 | public MusicService() { 31 | } 32 | 33 | @Override 34 | public void onCreate() { 35 | super.onCreate(); 36 | player = new MediaPlayer(); 37 | } 38 | 39 | @Override 40 | public IBinder onBind(Intent intent) { 41 | return new MusicController(); 42 | } 43 | 44 | 45 | public class MusicController extends Binder implements MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener { 46 | /** 47 | * 开始播放url 48 | * 49 | * @param url 50 | */ 51 | public void play(String url) { 52 | synchronized (mediaPlayerLock) { // 使用synchronized关键字同步代码块 53 | try { 54 | if (player != null) { 55 | player.reset(); 56 | } 57 | Log.d(TAG, "play: "+url); 58 | 59 | Uri uri = Uri.parse(url); 60 | Map headers = new HashMap<>(); 61 | // 设置headers... 62 | headers.put("Referer", "https://www.bilibili.com"); 63 | headers.put("Sec-Fetch-Mode", "no-cors"); 64 | headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36"); 65 | 66 | player.setDataSource(getApplicationContext(), uri, headers); 67 | 68 | player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 69 | @Override 70 | public void onPrepared(MediaPlayer mp) { 71 | mp.start(); 72 | addTimer(); 73 | } 74 | }); 75 | 76 | player.prepareAsync(); // 异步准备播放,避免阻塞主线程 77 | player.setOnCompletionListener(this); 78 | player.setOnErrorListener(this); 79 | } catch (IOException e) { 80 | Log.e(TAG, "MusicService的play出错"); 81 | e.printStackTrace(); 82 | } 83 | } 84 | 85 | 86 | } 87 | 88 | /** 89 | * 定时返回数据 90 | */ 91 | private void addTimer() { 92 | if (timer == null) { 93 | timer = new Timer(); 94 | TimerTask task = new TimerTask() { 95 | @Override 96 | public void run() { 97 | if (player == null) { 98 | return; 99 | } 100 | //单位:ms 101 | int duration = player.getDuration(); 102 | int currentPosition = player.getCurrentPosition(); 103 | Bundle bundle = new Bundle(); 104 | bundle.putInt("duration", duration); 105 | bundle.putInt("currentPosition", currentPosition); 106 | MusicPlayActivity.handler.obtainMessage(HANDLER_WHAT, bundle).sendToTarget(); 107 | // Log.d(TAG, "MusicService的AddTimer的run: " + currentPosition/1000); 108 | } 109 | }; 110 | timer.schedule(task, 5, 500); 111 | } 112 | 113 | } 114 | 115 | public void pause() { 116 | synchronized (mediaPlayerLock) { 117 | if (player.isPlaying()) { 118 | player.pause(); 119 | } 120 | } 121 | } 122 | 123 | public void continuePlay() { 124 | synchronized (mediaPlayerLock) { 125 | if (!player.isPlaying()) { 126 | player.start(); 127 | } 128 | } 129 | } 130 | 131 | public void seekTo(int progress) { 132 | synchronized (mediaPlayerLock) { 133 | if (player != null) { 134 | player.seekTo(progress); 135 | } 136 | } 137 | } 138 | 139 | /** 140 | * 暂停 141 | */ 142 | /*public void pause() { 143 | player.pause(); 144 | } 145 | */ 146 | /** 147 | * 继续播放 148 | */ 149 | /* public void continuePlay() { 150 | player.start(); 151 | }*/ 152 | 153 | /** 154 | * 进度条定位 155 | * 156 | * @param 157 | */ /*public void seekTo(int progress) { 158 | player.seekTo(progress); 159 | }*/ 160 | @Override 161 | public void onCompletion(MediaPlayer mediaPlayer) { 162 | Intent intent = new Intent(ACTION_PLAYBACK_COMPLETED); 163 | sendBroadcast(intent); 164 | MusicPlayActivity.handler.obtainMessage(HANDLER_WHAT_END,null).sendToTarget(); 165 | String url = MusicPlayActivity.nextUrl; 166 | Log.d(TAG, "onCompletion: " + url); 167 | 168 | play(url); 169 | 170 | 171 | } 172 | 173 | @Override 174 | public boolean onError(MediaPlayer mediaPlayer, int i, int i1) { 175 | return true; 176 | } 177 | /* public void reset() 178 | { 179 | player.stop(); 180 | player = new MediaPlayer(); 181 | }*/ 182 | 183 | 184 | } 185 | 186 | @Override 187 | public void onDestroy() { 188 | super.onDestroy(); 189 | if (player == null) { 190 | return; 191 | } 192 | if (player.isPlaying()) { 193 | player.stop(); 194 | } 195 | player.release(); 196 | player = null; 197 | } 198 | } -------------------------------------------------------------------------------- /app/src/main/java/com/quietfall/utils/HttpUtils.java: -------------------------------------------------------------------------------- 1 | package com.quietfall.utils; 2 | 3 | import android.app.Application; 4 | import android.content.ContentValues; 5 | import android.content.Context; 6 | import android.util.Log; 7 | 8 | import androidx.annotation.NonNull; 9 | 10 | import com.google.gson.Gson; 11 | import com.quietfall.AddMusicListActivity; 12 | import com.quietfall.entity.LinkInfo; 13 | import com.quietfall.entity.ListInfo; 14 | 15 | import java.io.IOException; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | import okhttp3.Call; 20 | import okhttp3.Callback; 21 | import okhttp3.OkHttpClient; 22 | import okhttp3.Request; 23 | import okhttp3.Response; 24 | 25 | public class HttpUtils { 26 | private static final String TAG = "qf"; 27 | 28 | /** 29 | * 通过收藏夹id获取收藏夹名字,要求id为字符串 30 | * 31 | * @param id 32 | * @return 33 | */ 34 | public static String getListNameById(String id) { 35 | String name[] = new String[1]; 36 | String url = "https://api.bilibili.com/x/v3/fav/resource/list?media_id=" + id + "&pn=1&ps=20&keyword=&order=mtime&type=0&tid=0&platform=web"; 37 | OkHttpClient okHttpClient = new OkHttpClient(); 38 | Request request = new Request.Builder().url(url).build(); 39 | Call call = okHttpClient.newCall(request); 40 | try { 41 | Response response = call.execute(); 42 | String json = response.body().string(); 43 | Gson gson = new Gson(); 44 | ListInfo listInfo = gson.fromJson(json, ListInfo.class); 45 | try { 46 | name[0] = listInfo.getData().getInfo().getTitle(); 47 | } catch (Exception e) { 48 | Log.d(TAG, "HttpUtils的getListNameById出错"); 49 | e.printStackTrace(); 50 | } 51 | Log.d(TAG, "HttpUtils的getListNameById: " + name[0]); 52 | Log.d(TAG, "HttpUtils的getListNameById: " + json); 53 | 54 | } catch (IOException e) { 55 | Log.d(TAG, "HttpUtils的getListNameById出错"); 56 | e.printStackTrace(); 57 | } 58 | /*new Thread(){ 59 | @Override 60 | public void run() { 61 | super.run(); 62 | 63 | OkHttpClient okHttpClient = new OkHttpClient(); 64 | Request request = new Request.Builder().url(url).build(); 65 | Call call = okHttpClient.newCall(request); 66 | try { 67 | Response response = call.execute(); 68 | String json = response.body().string(); 69 | Gson gson = new Gson(); 70 | ListInfo listInfo = gson.fromJson(json, ListInfo.class); 71 | name[0] = listInfo.getData().getInfo().getTitle(); 72 | Log.d(TAG, "onResponse: "+name[0]); 73 | Log.d(TAG, "onResponse: "+json); 74 | 75 | } catch (IOException e) { 76 | throw new RuntimeException(e); 77 | } 78 | *//*call.enqueue(new Callback() { 79 | 80 | 81 | 82 | @Override 83 | public void onFailure(@NonNull Call call, @NonNull IOException e) { 84 | 85 | } 86 | 87 | @Override 88 | public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { 89 | if (response.isSuccessful()) 90 | { 91 | String json = response.body().string(); 92 | Gson gson = new Gson(); 93 | ListInfo listInfo = gson.fromJson(json, ListInfo.class); 94 | name[0] = listInfo.getData().getInfo().getTitle(); 95 | Log.d(TAG, "onResponse: "+name[0]); 96 | Log.d(TAG, "onResponse: "+json); 97 | 98 | } 99 | } 100 | });*//* 101 | } 102 | }.start();*/ 103 | return name[0]; 104 | } 105 | 106 | /** 107 | * 通过收藏夹id获取收藏夹视频数量 108 | * @param id 109 | * @return 110 | */ 111 | public static Long getCountById(String id) { 112 | Long mediaCount = null; 113 | String url = "https://api.bilibili.com/x/v3/fav/resource/list?media_id=" + id + "&pn=1&ps=20&keyword=&order=mtime&type=0&tid=0&platform=web"; 114 | OkHttpClient okHttpClient = new OkHttpClient(); 115 | Request request = new Request.Builder().url(url).build(); 116 | Call call = okHttpClient.newCall(request); 117 | try { 118 | Response response = call.execute(); 119 | String json = response.body().string(); 120 | Gson gson = new Gson(); 121 | ListInfo listInfo = gson.fromJson(json, ListInfo.class); 122 | Log.d(TAG, "com.quietfall.utils.HttpUtils.getCountById: " + listInfo.getData().getInfo().getMediaCount()); 123 | mediaCount = listInfo.getData().getInfo().getMediaCount(); 124 | } catch (Exception e) { 125 | e.printStackTrace(); 126 | } 127 | return mediaCount; 128 | 129 | } 130 | 131 | /** 132 | * 通过收藏夹id<批量>获取用于插入数据库中的ContentValues 133 | * 134 | * @param id 135 | * @return 136 | */ 137 | public static List getColumnById(String id, Long count) throws IOException { 138 | List list = new ArrayList<>(); 139 | 140 | OkHttpClient okHttpClient = new OkHttpClient(); 141 | Gson gson = new Gson(); 142 | try { 143 | for (int pn = 1; pn <= count / 20 + 1; pn++) { 144 | String url = "https://api.bilibili.com/x/v3/fav/resource/list?media_id=" + id + "&pn=" + pn + "&ps=20&keyword=&order=mtime&type=0&tid=0&platform=web"; 145 | Request request = new Request.Builder().url(url).build(); 146 | Call call = okHttpClient.newCall(request); 147 | Response response = call.execute(); 148 | String json = response.body().string(); 149 | ListInfo listInfo = gson.fromJson(json, ListInfo.class); 150 | for (ListInfo.DataDTO.MediasDTO media : listInfo.getData().getMedias()) { 151 | ContentValues values = new ContentValues(); 152 | String bvId = media.getBvid(); 153 | String title = media.getTitle(); 154 | String up_name = media.getUpper().getName(); 155 | String cover = media.getCover(); 156 | Long duration = media.getDuration(); 157 | Long cid = media.getUgc().getFirstCid(); 158 | values.put("title", title); 159 | values.put("up_name", up_name); 160 | values.put("cover", cover); 161 | values.put("bv", bvId); 162 | values.put("cid",cid); 163 | values.put("duration",duration); 164 | list.add(values); 165 | 166 | } 167 | } 168 | } catch (Exception e) { 169 | 170 | } 171 | 172 | /*call.enqueue(new Callback() { 173 | @Override 174 | public void onFailure(@NonNull Call call, @NonNull IOException e) { 175 | 176 | } 177 | 178 | @Override 179 | public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { 180 | if (response.isSuccessful()) 181 | { 182 | String json = response.body().string(); 183 | Gson gson = new Gson(); 184 | ListInfo listInfo = gson.fromJson(json, ListInfo.class); 185 | Log.d(TAG, "onResponse: "+listInfo.getData().getInfo().getTitle()); 186 | mediaCount[0] = listInfo.getData().getInfo().getMediaCount(); 187 | } 188 | } 189 | });*/ 190 | 191 | 192 | 193 | /* call.enqueue(new Callback() { 194 | @Override 195 | public void onFailure(@NonNull Call call, @NonNull IOException e) { 196 | 197 | } 198 | 199 | @Override 200 | public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { 201 | if (response.isSuccessful()) 202 | { 203 | String json = response.body().string(); 204 | Gson gson = new Gson(); 205 | ListInfo listInfo = gson.fromJson(json, ListInfo.class); 206 | for (ListInfo.DataDTO.MediasDTO media : listInfo.getData().getMedias()) { 207 | ContentValues values = new ContentValues(); 208 | String bvId = media.getBvId(); 209 | String url = "https://www.bilibili.com/video/"+bvId; 210 | String title = media.getTitle(); 211 | String up_name = media.getUpper().getName(); 212 | String cover = media.getCover(); 213 | values.put("title",title); 214 | values.put("up_name",up_name); 215 | values.put("cover",cover); 216 | values.put("url",url); 217 | list.add(values); 218 | 219 | } 220 | } 221 | 222 | } 223 | });*/ 224 | return list; 225 | } 226 | 227 | /** 228 | * 通过bv和cid获得原视频链接 229 | * @param bv 230 | * @param cid 231 | */ 232 | public static String getLinkByBvAndCid(String bv,Long cid){ 233 | String url = "https://api.bilibili.com/x/player/playurl?otype=json&fnver=0&fnval=2&player=1&qn=64&bvid="+bv+"&cid="+cid; 234 | OkHttpClient okHttpClient = new OkHttpClient(); 235 | Gson gson = new Gson(); 236 | Request request = new Request.Builder().url(url).build(); 237 | String srcLink = null; 238 | try { 239 | Response response = okHttpClient.newCall(request).execute(); 240 | String json = response.body().string(); 241 | LinkInfo linkInfo = gson.fromJson(json, LinkInfo.class); 242 | srcLink = linkInfo.getData().getDurl().get(0).getUrl(); 243 | } catch (IOException e) { 244 | Log.d(TAG, "HttpUtils的getLinkByBvAndCid:出错!!!"); 245 | e.printStackTrace(); 246 | } 247 | return srcLink; 248 | } 249 | 250 | } 251 | 252 | -------------------------------------------------------------------------------- /app/src/main/java/com/quietfall/utils/ToastUtil.java: -------------------------------------------------------------------------------- 1 | package com.quietfall.utils; 2 | 3 | import android.content.Context; 4 | import android.widget.Toast; 5 | 6 | public class ToastUtil { 7 | public static void show(Context context,String desc) 8 | { 9 | Toast.makeText(context,desc,Toast.LENGTH_SHORT).show(); 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/about1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuietFallHe/ListenB/5a894580229293dd0e4cde7363cfe3e386010b0e/app/src/main/res/drawable/about1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/about2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuietFallHe/ListenB/5a894580229293dd0e4cde7363cfe3e386010b0e/app/src/main/res/drawable/about2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuietFallHe/ListenB/5a894580229293dd0e4cde7363cfe3e386010b0e/app/src/main/res/drawable/add.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuietFallHe/ListenB/5a894580229293dd0e4cde7363cfe3e386010b0e/app/src/main/res/drawable/back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_shape_normal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_shape_pressed.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/home1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuietFallHe/ListenB/5a894580229293dd0e4cde7363cfe3e386010b0e/app/src/main/res/drawable/home1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/home2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuietFallHe/ListenB/5a894580229293dd0e4cde7363cfe3e386010b0e/app/src/main/res/drawable/home2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/item_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/last.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuietFallHe/ListenB/5a894580229293dd0e4cde7363cfe3e386010b0e/app/src/main/res/drawable/last.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuietFallHe/ListenB/5a894580229293dd0e4cde7363cfe3e386010b0e/app/src/main/res/drawable/logo.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/love.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuietFallHe/ListenB/5a894580229293dd0e4cde7363cfe3e386010b0e/app/src/main/res/drawable/love.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/loved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuietFallHe/ListenB/5a894580229293dd0e4cde7363cfe3e386010b0e/app/src/main/res/drawable/loved.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuietFallHe/ListenB/5a894580229293dd0e4cde7363cfe3e386010b0e/app/src/main/res/drawable/menu.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuietFallHe/ListenB/5a894580229293dd0e4cde7363cfe3e386010b0e/app/src/main/res/drawable/next.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuietFallHe/ListenB/5a894580229293dd0e4cde7363cfe3e386010b0e/app/src/main/res/drawable/order.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuietFallHe/ListenB/5a894580229293dd0e4cde7363cfe3e386010b0e/app/src/main/res/drawable/pause.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuietFallHe/ListenB/5a894580229293dd0e4cde7363cfe3e386010b0e/app/src/main/res/drawable/play.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/random.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuietFallHe/ListenB/5a894580229293dd0e4cde7363cfe3e386010b0e/app/src/main/res/drawable/random.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/repeat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuietFallHe/ListenB/5a894580229293dd0e4cde7363cfe3e386010b0e/app/src/main/res/drawable/repeat.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_add_music_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 17 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 15 | 26 | 27 | 32 | 33 | 42 | 43 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_music_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_music_play.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 23 | 24 | 32 | 33 | 40 | 41 | 46 | 47 | 51 | 52 | 58 | 59 | 65 | 66 | 67 | 68 | 69 | 75 | 76 | 83 | 84 | 91 | 92 | 99 | 100 | 107 | 108 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_about.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 25 | 35 | 45 | 55 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 |