├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── drawable
│ │ │ │ ├── bet.png
│ │ │ │ ├── bfc.png
│ │ │ │ ├── bgm.png
│ │ │ │ ├── mall.png
│ │ │ │ ├── music.png
│ │ │ │ ├── discuss.png
│ │ │ │ ├── icon_down.png
│ │ │ │ ├── icon_like.png
│ │ │ │ ├── icon_look.png
│ │ │ │ ├── icon_rank.png
│ │ │ │ ├── icon_up.png
│ │ │ │ ├── play_all.png
│ │ │ │ ├── certificate.png
│ │ │ │ ├── icon_daily.png
│ │ │ │ ├── icon_music.png
│ │ │ │ ├── icon_parise.png
│ │ │ │ ├── icon_radio.png
│ │ │ │ ├── icon_broadcast.png
│ │ │ │ ├── icon_collect.png
│ │ │ │ ├── icon_dislike.png
│ │ │ │ ├── icon_late_play.png
│ │ │ │ ├── icon_playlist.png
│ │ │ │ ├── icon_song_left.png
│ │ │ │ ├── icon_song_more.png
│ │ │ │ ├── icon_song_play.png
│ │ │ │ ├── icon_triangle.png
│ │ │ │ ├── icon_parise_fill.png
│ │ │ │ ├── icon_play_songs.png
│ │ │ │ ├── icon_song_pause.png
│ │ │ │ ├── icon_song_right.png
│ │ │ │ ├── icon_download_black.png
│ │ │ │ ├── icon_song_comment.png
│ │ │ │ ├── icon_song_download.png
│ │ │ │ ├── icon_song_play_type_1.png
│ │ │ │ ├── icon_event_video_b_play.png
│ │ │ │ └── ic_compose.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.webp
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.webp
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.webp
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.webp
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.webp
│ │ │ ├── values
│ │ │ │ ├── ic_launcher_background.xml
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── themes.xml
│ │ │ ├── xml
│ │ │ │ └── network_security_config.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── values-v31
│ │ │ │ └── themes.xml
│ │ │ ├── anim
│ │ │ │ ├── slide_in_down.xml
│ │ │ │ └── slide_out_down.xml
│ │ │ ├── values-night
│ │ │ │ └── themes.xml
│ │ │ ├── layout
│ │ │ │ └── activity_net_ease_music_splash.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── navigation
│ │ │ │ └── nav_graph.xml
│ │ ├── proto
│ │ │ ├── music_settings.proto
│ │ │ └── cookie_store.proto
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── mrlin
│ │ │ │ └── composemany
│ │ │ │ ├── repository
│ │ │ │ ├── entity
│ │ │ │ │ ├── LikeList.kt
│ │ │ │ │ ├── EmptyResponse.kt
│ │ │ │ │ ├── MusicData.kt
│ │ │ │ │ ├── MusicUrl.kt
│ │ │ │ │ ├── Song.kt
│ │ │ │ │ ├── BannerData.kt
│ │ │ │ │ ├── MV.kt
│ │ │ │ │ ├── LyricData.kt
│ │ │ │ │ ├── PlayListData.kt
│ │ │ │ │ ├── Album.kt
│ │ │ │ │ ├── RecommendData.kt
│ │ │ │ │ ├── User.kt
│ │ │ │ │ └── CommentData.kt
│ │ │ │ ├── db
│ │ │ │ │ ├── MusicDatabase.kt
│ │ │ │ │ └── UserDao.kt
│ │ │ │ ├── store
│ │ │ │ │ ├── CookieStoreSerializer.kt
│ │ │ │ │ └── MusicSettingsSerializer.kt
│ │ │ │ └── NetEaseMusicApi.kt
│ │ │ │ ├── ComposeManyApp.kt
│ │ │ │ ├── ui
│ │ │ │ ├── theme
│ │ │ │ │ ├── Color.kt
│ │ │ │ │ ├── Shape.kt
│ │ │ │ │ ├── Type.kt
│ │ │ │ │ └── Theme.kt
│ │ │ │ └── component
│ │ │ │ │ ├── Layout.kt
│ │ │ │ │ └── Panel.kt
│ │ │ │ ├── state
│ │ │ │ └── ViewState.kt
│ │ │ │ ├── utils
│ │ │ │ ├── NumberHelper.kt
│ │ │ │ ├── ModifierHelper.kt
│ │ │ │ └── ViewModelHelper.kt
│ │ │ │ ├── pages
│ │ │ │ ├── music
│ │ │ │ │ ├── MusicSplashActivity.kt
│ │ │ │ │ ├── widgets
│ │ │ │ │ │ ├── Buttons.kt
│ │ │ │ │ │ ├── Avatar.kt
│ │ │ │ │ │ ├── CustomBanner.kt
│ │ │ │ │ │ ├── PlayWidget.kt
│ │ │ │ │ │ ├── PlayListWidget.kt
│ │ │ │ │ │ └── CollapsingAppBar.kt
│ │ │ │ │ ├── Routes.kt
│ │ │ │ │ ├── playsong
│ │ │ │ │ │ ├── SongViewModel.kt
│ │ │ │ │ │ ├── CommentsViewModel.kt
│ │ │ │ │ │ └── PlaySongFragment.kt
│ │ │ │ │ ├── playlist
│ │ │ │ │ │ └── MusicPlayListViewModel.kt
│ │ │ │ │ ├── login
│ │ │ │ │ │ └── MusicLogin.kt
│ │ │ │ │ ├── home
│ │ │ │ │ │ ├── MusicHomeViewModel.kt
│ │ │ │ │ │ ├── MusicHomeFragment.kt
│ │ │ │ │ │ ├── Mine.kt
│ │ │ │ │ │ ├── Discovery.kt
│ │ │ │ │ │ └── MusicHome.kt
│ │ │ │ │ └── PlaySongsViewModel.kt
│ │ │ │ ├── mall
│ │ │ │ │ ├── MallScreen.kt
│ │ │ │ │ ├── MallActivity.kt
│ │ │ │ │ └── category
│ │ │ │ │ │ └── MallHome.kt
│ │ │ │ └── fund
│ │ │ │ │ └── FundViewModel.kt
│ │ │ │ ├── net
│ │ │ │ ├── PersistCookieJar.kt
│ │ │ │ └── PersistentCookieStore.kt
│ │ │ │ ├── di
│ │ │ │ ├── EnumRetrofitConverterFactory.kt
│ │ │ │ └── AppModule.kt
│ │ │ │ ├── MainViewModel.kt
│ │ │ │ └── MainActivity.kt
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── mrlin
│ │ │ └── composemany
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── mrlin
│ │ └── composemany
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
├── schemas
│ └── com.mrlin.composemany.repository.db.MusicDatabase
│ │ └── 1.json
└── build.gradle
├── ks
└── composemany.jks
├── screenshots
├── lyric.jpg
├── main.png
├── comments.png
├── fund_main.png
├── music_main.jpg
├── play_list.jpeg
├── song_play.png
└── floor_comment.jpg
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── settings.gradle
├── gradle.properties
├── .gitignore
├── gradlew.bat
├── README.md
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /release/
--------------------------------------------------------------------------------
/ks/composemany.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/ks/composemany.jks
--------------------------------------------------------------------------------
/screenshots/lyric.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/screenshots/lyric.jpg
--------------------------------------------------------------------------------
/screenshots/main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/screenshots/main.png
--------------------------------------------------------------------------------
/screenshots/comments.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/screenshots/comments.png
--------------------------------------------------------------------------------
/screenshots/fund_main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/screenshots/fund_main.png
--------------------------------------------------------------------------------
/screenshots/music_main.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/screenshots/music_main.jpg
--------------------------------------------------------------------------------
/screenshots/play_list.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/screenshots/play_list.jpeg
--------------------------------------------------------------------------------
/screenshots/song_play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/screenshots/song_play.png
--------------------------------------------------------------------------------
/screenshots/floor_comment.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/screenshots/floor_comment.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/bet.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bfc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/bfc.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bgm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/bgm.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/mall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/mall.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/drawable/music.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/music.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/discuss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/discuss.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_down.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_like.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_like.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_look.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_look.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_rank.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_rank.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_up.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/play_all.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/play_all.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/certificate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/certificate.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_daily.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_daily.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_music.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_music.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_parise.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_parise.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_radio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_radio.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_broadcast.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_broadcast.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_collect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_collect.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_dislike.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_dislike.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_late_play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_late_play.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_playlist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_playlist.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_song_left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_song_left.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_song_more.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_song_more.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_song_play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_song_play.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_triangle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_triangle.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_parise_fill.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_parise_fill.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_play_songs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_play_songs.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_song_pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_song_pause.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_song_right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_song_right.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_download_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_download_black.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_song_comment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_song_comment.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_song_download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_song_download.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_song_play_type_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_song_play_type_1.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_event_video_b_play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/drawable/icon_event_video_b_play.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mr-lin930819/ComposeMany/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ComposeMany
3 | NetEaseMusicActivity
4 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/network_security_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/proto/music_settings.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option java_package = "com.mrlin.composemany";
4 | option java_multiple_files = true;
5 |
6 | message MusicSettings {
7 | int64 user_account_id = 1;
8 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/repository/entity/LikeList.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.repository.entity
2 |
3 | data class LikeList(
4 | val ids: List,
5 | val checkPoint: Long,
6 | val code: Int,
7 | )
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/repository/entity/EmptyResponse.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.repository.entity
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class EmptyResponse(
6 | @SerializedName("code")
7 | val code: Int = 200
8 | )
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Mar 03 23:40:58 CST 2021
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/repository/entity/MusicData.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.repository.entity
2 |
3 | data class MusicData(
4 | val mvid: Long,
5 | val picUrl: String? = null,
6 | val songName: String,
7 | val artists: String,
8 | val index: Int? = null,
9 | val musicId: Long = 0,
10 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/ComposeManyApp.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany
2 |
3 | import android.app.Application
4 | import dagger.hilt.android.HiltAndroidApp
5 |
6 | /*********************************
7 | * 应用
8 | * @author mrlin
9 | * 创建于 2021年08月19日
10 | ******************************** */
11 | @HiltAndroidApp
12 | class ComposeManyApp: Application()
--------------------------------------------------------------------------------
/app/src/main/res/values-v31/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/repository/entity/MusicUrl.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.repository.entity
2 |
3 | /*********************************
4 | * 音乐地址
5 | * @author mrlin
6 | * 创建于 2021年08月26日
7 | ******************************** */
8 | data class MusicUrlData(
9 | val data: List,
10 | )
11 |
12 | data class MusicUrl(
13 | val url: UrlString,
14 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/ui/theme/Color.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.ui.theme
2 |
3 | import androidx.compose.ui.graphics.Color
4 | import androidx.compose.ui.graphics.colorspace.ColorSpaces
5 |
6 | val Teal200 = Color(0xFF0339DA)
7 | val Blue200 = Color(0xFF81D4FA)
8 | val Blue500 = Color(0xFF2196F3)
9 | val Blue700 = Color(0xFF1976D2)
10 |
11 | val LightGray = Color(0xFFEBEBEB)
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/ui/theme/Shape.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.ui.theme
2 |
3 | import androidx.compose.foundation.shape.RoundedCornerShape
4 | import androidx.compose.material.Shapes
5 | import androidx.compose.ui.unit.dp
6 |
7 | val Shapes = Shapes(
8 | small = RoundedCornerShape(4.dp),
9 | medium = RoundedCornerShape(4.dp),
10 | large = RoundedCornerShape(0.dp)
11 | )
--------------------------------------------------------------------------------
/app/src/main/res/anim/slide_in_down.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/slide_out_down.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/state/ViewState.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.state
2 |
3 | /*********************************
4 | * 界面状态
5 | * @author mrlin
6 | * 创建于 2021年08月19日
7 | ******************************** */
8 | abstract class ViewState {
9 | object Normal : ViewState()
10 |
11 | class Busy(val message: String? = null) : ViewState()
12 |
13 | class Error(val reason: String) : ViewState()
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/repository/entity/Song.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.repository.entity
2 |
3 | import android.os.Parcelable
4 | import kotlinx.parcelize.Parcelize
5 |
6 | @Parcelize
7 | data class Song(
8 | //歌曲id
9 | val id: Long,
10 | //歌曲名称
11 | val name: String? = null,
12 | //演唱者
13 | val artists: String? = null,
14 | //歌曲图片
15 | val picUrl: String? = null,
16 | ) : Parcelable
17 |
--------------------------------------------------------------------------------
/app/src/test/java/com/mrlin/composemany/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/utils/NumberHelper.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.utils
2 |
3 | import java.text.DecimalFormat
4 |
5 | /**
6 | * 数字简略显示文本
7 | */
8 | internal fun Long.simpleNumText(): String {
9 | return when (this) {
10 | in 0..1_0000 -> this.toString()
11 | in 1_0000..1_0000_0000 -> "${DecimalFormat("0.##").format(this.toDouble() / 1_0000f)}万"
12 | else -> "${DecimalFormat("0.##").format(this.toFloat() / 1_0000_0000f)}亿"
13 | }
14 | }
--------------------------------------------------------------------------------
/app/src/main/proto/cookie_store.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option java_package = "com.mrlin.composemany";
4 | option java_multiple_files = true;
5 |
6 | message CookieStore {
7 | map cookieCache = 1;
8 | map hosts = 2;
9 | }
10 |
11 | message CookieInfo {
12 | string name = 1;
13 | string value = 2;
14 | int64 expiresAt = 3;
15 | string domain = 4;
16 | string path = 5;
17 | bool secure = 6;
18 | bool httpOnly = 7;
19 | bool hostOnly = 8;
20 | bool persistent = 9;
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/pages/music/MusicSplashActivity.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.pages.music
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.mrlin.composemany.R
6 | import dagger.hilt.android.AndroidEntryPoint
7 | @AndroidEntryPoint
8 | class MusicSplashActivity : AppCompatActivity() {
9 |
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | setContentView(R.layout.activity_net_ease_music_splash)
13 | }
14 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | maven { url 'https://maven.aliyun.com/repository/public/' }
4 | maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
5 | gradlePluginPortal()
6 | google()
7 | mavenCentral()
8 | }
9 | }
10 | dependencyResolutionManagement {
11 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
12 | repositories {
13 | google()
14 | mavenCentral()
15 | }
16 | }
17 | rootProject.name = "ComposeMany"
18 | include ':app'
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/repository/db/MusicDatabase.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.repository.db
2 |
3 | import androidx.room.Database
4 | import androidx.room.RoomDatabase
5 | import com.mrlin.composemany.repository.entity.User
6 |
7 | /*********************************
8 | * 音乐功能数据库
9 | * @author mrlin
10 | * 创建于 2021年08月20日
11 | ******************************** */
12 | @Database(version = 1, exportSchema = true, entities = [
13 | User::class
14 | ])
15 | abstract class MusicDatabase : RoomDatabase() {
16 | abstract fun userDao(): UserDao
17 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF81D4FA
7 | #FF2196F3
8 | #FF1976D2
9 | #FF03DAC5
10 | #FF018786
11 | #FF000000
12 | #FFFFFFFF
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/utils/ModifierHelper.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.utils
2 |
3 | import androidx.compose.ui.ExperimentalComposeUiApi
4 | import androidx.compose.ui.Modifier
5 | import androidx.compose.ui.input.key.*
6 |
7 | /*********************************
8 | * Modifier类辅助
9 | * @author mrlin
10 | * 创建于 2021年10月27日
11 | ******************************** */
12 | @OptIn(ExperimentalComposeUiApi::class)
13 | fun Modifier.onHandleBack(onBackPressed: (() -> Unit)?): Modifier {
14 | return onKeyEvent {
15 | if (it.key == Key.Back && it.type == KeyEventType.KeyUp) {
16 | onBackPressed?.invoke()
17 | }
18 | true
19 | }
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/repository/db/UserDao.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.repository.db
2 |
3 | import androidx.room.Dao
4 | import androidx.room.Insert
5 | import androidx.room.OnConflictStrategy
6 | import androidx.room.Query
7 | import com.mrlin.composemany.repository.entity.User
8 |
9 | /*********************************
10 | * 用户数据库操作
11 | * @author mrlin
12 | * 创建于 2021年08月20日
13 | ******************************** */
14 | @Dao
15 | interface UserDao {
16 | @Insert(onConflict = OnConflictStrategy.REPLACE)
17 | suspend fun insert(user: User)
18 |
19 | @Query("SELECT * FROM User WHERE ua_id=(:accountId)")
20 | suspend fun findUser(accountId: Long): User?
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/repository/entity/BannerData.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.repository.entity
2 |
3 | /*********************************
4 | * banner数据
5 | * @author mrlin
6 | * 创建于 2021年08月23日
7 | ******************************** */
8 | data class BannerData(
9 | var banners: List? = null,
10 | var code: Int = 0,
11 | ) {
12 | companion object {
13 | const val TYPE_PC = 0
14 | const val TYPE_ANDROID = 1
15 | const val TYPE_IPHONE = 2
16 | const val TYPE_IPAD = 3
17 | }
18 |
19 | data class Banner(
20 | var pic: String? = null,
21 | var typeTitle: String? = null,
22 | var targetId: Long = 0,
23 | )
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/pages/mall/MallScreen.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.pages.mall
2 |
3 | import androidx.annotation.DrawableRes
4 | import com.mrlin.composemany.R
5 |
6 | sealed class MallScreen(val route: String, @DrawableRes val iconRes: Int = R.drawable.icon_song_more) {
7 | object Home : MallScreen("mall/home", R.drawable.icon_song_more) {
8 | object Main : MallScreen("mall/home/main")
9 | }
10 | object Category : MallScreen("mall/category", R.drawable.icon_song_download)
11 | object ShopCart : MallScreen("mall/shopCart", R.drawable.icon_song_play_type_1)
12 | object Mine : MallScreen("mall/mine", R.drawable.icon_dislike)
13 |
14 | object Detail: MallScreen("mall/detail")
15 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/net/PersistCookieJar.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.net
2 |
3 | import android.content.Context
4 | import androidx.datastore.core.DataStore
5 | import com.mrlin.composemany.CookieStore
6 | import okhttp3.Cookie
7 | import okhttp3.CookieJar
8 | import okhttp3.HttpUrl
9 |
10 | /**
11 | * cookie持久化
12 | */
13 | class PersistCookieJar constructor(cookieStore: DataStore) : CookieJar {
14 | private val cookieStore = PersistentCookieStore(cookieDataStore = cookieStore)
15 | override fun saveFromResponse(url: HttpUrl, cookies: List) {
16 | cookies.forEach { cookieStore.add(url, it) }
17 | }
18 |
19 | override fun loadForRequest(url: HttpUrl): List {
20 | return cookieStore.get(url = url)
21 | }
22 |
23 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/mrlin/composemany/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.mrlin.composemany", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/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/main/java/com/mrlin/composemany/pages/fund/FundViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.pages.fund
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import kotlinx.coroutines.delay
6 | import kotlinx.coroutines.flow.MutableStateFlow
7 | import kotlinx.coroutines.flow.StateFlow
8 | import kotlinx.coroutines.launch
9 | import java.text.SimpleDateFormat
10 | import java.util.*
11 |
12 | class FundViewModel : ViewModel() {
13 | private val _time = MutableStateFlow("")
14 | val time: StateFlow = _time
15 |
16 | fun runTimer() = viewModelScope.launch {
17 | while (true) {
18 | delay(1000)
19 | _time.tryEmit(timeFormat.format(Date()))
20 | }
21 | }
22 |
23 | companion object {
24 | val timeFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA)
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/pages/music/widgets/Buttons.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.pages.music.widgets
2 |
3 | import androidx.annotation.DrawableRes
4 | import androidx.compose.material.Icon
5 | import androidx.compose.material.IconButton
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.Modifier
8 | import androidx.compose.ui.graphics.Color
9 | import androidx.compose.ui.res.painterResource
10 |
11 | /**
12 | * 界面操作的小按键
13 | */
14 | @Composable
15 | fun MiniButton(
16 | @DrawableRes iconRes: Int,
17 | modifier: Modifier = Modifier,
18 | tint: Color = Color.LightGray,
19 | onClick: () -> Unit = { }
20 | ) {
21 | IconButton(onClick = onClick, modifier = modifier) {
22 | Icon(
23 | painter = painterResource(id = iconRes),
24 | contentDescription = null,
25 | tint = tint,
26 | )
27 | }
28 | }
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/utils/ViewModelHelper.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.utils
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.mrlin.composemany.state.ViewState
6 | import kotlinx.coroutines.CoroutineScope
7 | import kotlinx.coroutines.flow.MutableStateFlow
8 | import kotlinx.coroutines.launch
9 |
10 | /**
11 | * 进行繁忙任务
12 | */
13 | internal fun ViewModel.busyWork(
14 | state: MutableStateFlow,
15 | work: suspend CoroutineScope.() -> Any
16 | ) = viewModelScope.launch {
17 | state.emit(ViewState.Busy())
18 | try {
19 | when (val result = work()) {
20 | is ViewState -> state.tryEmit(result)
21 | else -> state.tryEmit(ViewState.Normal)
22 | }
23 | } catch (t: Throwable) {
24 | state.tryEmit(ViewState.Error(t.message.orEmpty()))
25 | t.printStackTrace()
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/repository/entity/MV.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.repository.entity
2 |
3 | /**
4 | * MV数据
5 | */
6 | data class MVData (
7 | var updateTime: Long = 0,
8 | var data: List? = null,
9 | var hasMore: Boolean? = null,
10 | var code: Int = 0,
11 | ) {
12 | data class MV (
13 | var id: Long = 0,
14 | var cover: String? = null,
15 | var name: String? = null,
16 | var playCount: Long = 0,
17 | var briefDesc: String? = null,
18 | var desc: String? = null,
19 | var artistName: String? = null,
20 | var artistId: Long = 0,
21 | var duration: Long = 0,
22 | var mark: Int = 0,
23 | var lastRank: Int = 0,
24 | var score: Int = 0,
25 | var subed: Boolean? = null,
26 | var artists: List? = null,
27 | )
28 |
29 | data class Artist (
30 | val id: Long = 0,
31 | val name: String = ""
32 | )
33 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_net_ease_music_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/pages/music/Routes.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.pages.music
2 |
3 | import androidx.navigation.NavDirections
4 | import com.mrlin.composemany.NavGraphDirections
5 | import com.mrlin.composemany.pages.music.playsong.PlaySongFragmentDirections
6 | import com.mrlin.composemany.repository.entity.Recommend
7 | import com.mrlin.composemany.repository.entity.Song
8 |
9 | /*********************************
10 | * 音乐功能界面路由
11 | * @author mrlin
12 | * 创建于 2021年08月23日
13 | ******************************** */
14 | abstract class MusicScreen(val directions: NavDirections) {
15 | //歌单列表
16 | class PlayList(recommend: Recommend) :
17 | MusicScreen(NavGraphDirections.toMusicPlayListFragment(recommend))
18 |
19 | //歌曲播放
20 | class PlaySong : MusicScreen(NavGraphDirections.toPlaySongFragment())
21 |
22 | //歌曲评论
23 | class SongComment(song: Song) :
24 | MusicScreen(PlaySongFragmentDirections.actionPlaySongFragmentToCommentsFragment(song))
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/repository/store/CookieStoreSerializer.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.repository.store
2 |
3 | import androidx.datastore.core.CorruptionException
4 | import androidx.datastore.core.Serializer
5 | import com.google.protobuf.InvalidProtocolBufferException
6 | import com.mrlin.composemany.CookieStore
7 | import java.io.InputStream
8 | import java.io.OutputStream
9 |
10 | @Suppress("BlockingMethodInNonBlockingContext")
11 | object CookieStoreSerializer : Serializer {
12 | override suspend fun readFrom(input: InputStream): CookieStore {
13 | try {
14 | return CookieStore.parseFrom(input)
15 | } catch (exception: InvalidProtocolBufferException) {
16 | throw CorruptionException("Cannot read proto.", exception)
17 | }
18 | }
19 |
20 | override suspend fun writeTo(t: CookieStore, output: OutputStream) {
21 | t.writeTo(output)
22 | }
23 |
24 | override val defaultValue: CookieStore
25 | get() = CookieStore.getDefaultInstance()
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/ui/component/Layout.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.ui.component
2 |
3 | import androidx.compose.foundation.layout.*
4 | import androidx.compose.foundation.shape.CornerSize
5 | import androidx.compose.material.Card
6 | import androidx.compose.material.MaterialTheme
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.ui.Alignment
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.unit.dp
11 |
12 | @Composable
13 | fun TitleRow(modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit) = Row(
14 | modifier = modifier
15 | .fillMaxWidth()
16 | .padding(8.dp),
17 | horizontalArrangement = Arrangement.SpaceBetween,
18 | verticalAlignment = Alignment.CenterVertically,
19 | content = content
20 | )
21 |
22 | @Composable
23 | fun TopCard(content: @Composable () -> Unit) = Card(
24 | Modifier
25 | .fillMaxWidth()
26 | .padding(8.dp),
27 | shape = MaterialTheme.shapes.medium.copy(all = CornerSize(10.dp)),
28 | content = content
29 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/pages/music/widgets/Avatar.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.pages.music.widgets
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.foundation.layout.size
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.ui.Modifier
7 | import androidx.compose.ui.platform.LocalDensity
8 | import androidx.compose.ui.unit.Dp
9 | import androidx.compose.ui.unit.dp
10 | import coil.compose.rememberImagePainter
11 | import coil.transform.CircleCropTransformation
12 | import com.mrlin.composemany.repository.entity.limitSize
13 |
14 | /*********************************
15 | * 头像
16 | * @author mrlin
17 | * 创建于 2021年09月08日
18 | ******************************** */
19 | @Composable
20 | fun CircleAvatar(url: String?, size: Dp = 36.dp) {
21 | val sizePx = with(LocalDensity.current) { size.roundToPx() }
22 | Image(painter = rememberImagePainter(url?.limitSize(sizePx), builder = {
23 | transformations(CircleCropTransformation())
24 | }), contentDescription = null, modifier = Modifier.size(size = size))
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/ui/component/Panel.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.ui.component
2 |
3 | import androidx.compose.foundation.layout.Row
4 | import androidx.compose.foundation.layout.padding
5 | import androidx.compose.material.Divider
6 | import androidx.compose.material.MaterialTheme
7 | import androidx.compose.material.Text
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.ui.Alignment
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.tooling.preview.Preview
12 | import androidx.compose.ui.unit.dp
13 |
14 | @Composable
15 | fun TitleDivider(title: String) {
16 | Row(verticalAlignment = Alignment.CenterVertically) {
17 | Divider(Modifier.weight(1.0f))
18 | Text(
19 | text = title,
20 | style = MaterialTheme.typography.caption,
21 | modifier = Modifier.padding(8.dp)
22 | )
23 | Divider(Modifier.weight(1.0f))
24 | }
25 | }
26 |
27 | @Preview(showBackground = true)
28 | @Composable
29 | fun TitleDividerPreview() {
30 | TitleDivider(title = "测试")
31 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/repository/entity/LyricData.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.repository.entity
2 |
3 | import java.util.regex.Pattern
4 |
5 | data class LyricData(
6 | val lrc: Lrc,
7 | ) {
8 | data class Lrc(
9 | val version: Int,
10 | val lyric: String,
11 | ) {
12 | /**
13 | * 解析歌词为列表数据
14 | */
15 | fun parseToList(): List> {
16 | val lyrics = mutableListOf>()
17 | val pattern = Pattern.compile("\\[(\\d{1,2}):(\\d{1,2}).(\\d{1,3})](.+)")
18 | val matcher = pattern.matcher(lyric)
19 | while (matcher.find()) {
20 | val min = matcher.group(1)?.toIntOrNull() ?: 0
21 | val sec = matcher.group(2)?.toIntOrNull() ?: 0
22 | val mill = "0.${matcher.group(3)}".toFloatOrNull() ?: 0f
23 | val time = min * 60 * 1000 + sec * 1000 + (mill * 1000).toInt()
24 | val text = matcher.group(4).orEmpty()
25 | lyrics.add(time to text)
26 | }
27 | lyrics.sortBy { it.first }
28 | return lyrics
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/di/EnumRetrofitConverterFactory.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.di
2 |
3 | import com.google.gson.annotations.SerializedName
4 | import retrofit2.Converter
5 | import retrofit2.Retrofit
6 | import java.lang.reflect.Type
7 |
8 | /*********************************
9 | * 枚举的序列化
10 | * @author mrlin
11 | * 创建于 2021年09月08日
12 | ******************************** */
13 | class EnumRetrofitConverterFactory : Converter.Factory() {
14 | override fun stringConverter(
15 | type: Type,
16 | annotations: Array,
17 | retrofit: Retrofit
18 | ): Converter<*, String>? {
19 | if (type is Class<*> && type.isEnum) {
20 | return Converter { value -> getSerializedNameValue(value as Enum<*>) }
21 | }
22 | return null
23 | }
24 |
25 | private fun > getSerializedNameValue(e: E): String {
26 | try {
27 | return e.javaClass.getField(e.name).getAnnotation(SerializedName::class.java)?.value.orEmpty()
28 | } catch (exception: NoSuchFieldException) {
29 | exception.printStackTrace()
30 | }
31 | return ""
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/repository/store/MusicSettingsSerializer.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.repository.store
2 |
3 | import androidx.datastore.core.CorruptionException
4 | import androidx.datastore.core.Serializer
5 | import com.google.protobuf.InvalidProtocolBufferException
6 | import com.mrlin.composemany.MusicSettings
7 | import java.io.InputStream
8 | import java.io.OutputStream
9 |
10 | /*********************************
11 | *
12 | * @author mrlin
13 | * 创建于 2021年08月20日
14 | ******************************** */
15 | @Suppress("BlockingMethodInNonBlockingContext")
16 | object MusicSettingsSerializer: Serializer {
17 | override val defaultValue: MusicSettings
18 | get() = MusicSettings.getDefaultInstance()
19 |
20 | override suspend fun readFrom(input: InputStream): MusicSettings {
21 | try {
22 | return MusicSettings.parseFrom(input)
23 | } catch (exception: InvalidProtocolBufferException) {
24 | throw CorruptionException("Cannot read proto.", exception)
25 | }
26 | }
27 |
28 | override suspend fun writeTo(t: MusicSettings, output: OutputStream) {
29 | t.writeTo(output)
30 | }
31 |
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/pages/music/playsong/SongViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.pages.music.playsong
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.mrlin.composemany.repository.NetEaseMusicApi
6 | import com.mrlin.composemany.repository.entity.Song
7 | import com.mrlin.composemany.repository.entity.SongCommentData
8 | import dagger.hilt.android.lifecycle.HiltViewModel
9 | import kotlinx.coroutines.flow.MutableStateFlow
10 | import kotlinx.coroutines.flow.StateFlow
11 | import kotlinx.coroutines.launch
12 | import retrofit2.await
13 | import javax.inject.Inject
14 |
15 | /**
16 | * 歌曲页面
17 | */
18 | @HiltViewModel
19 | class SongViewModel @Inject constructor(private val musicApi: NetEaseMusicApi) : ViewModel() {
20 | private val _songComment = MutableStateFlow(SongCommentData())
21 |
22 | val songComment: StateFlow = _songComment
23 |
24 | fun loadComment(song: Song) = viewModelScope.launch {
25 | try {
26 | val comment = musicApi.songCommentData(song.id, offset = 0, limit = 1).await()
27 | _songComment.value = comment
28 | } catch (t: Throwable) {
29 |
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/ui/theme/Type.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.ui.theme
2 |
3 | import androidx.compose.material.Typography
4 | import androidx.compose.ui.graphics.Color
5 | import androidx.compose.ui.text.TextStyle
6 | import androidx.compose.ui.text.font.FontFamily
7 | import androidx.compose.ui.text.font.FontWeight
8 | import androidx.compose.ui.unit.sp
9 |
10 | // Set of Material typography styles to start with
11 | val Typography = Typography(
12 | body1 = TextStyle(
13 | fontFamily = FontFamily.Default,
14 | fontWeight = FontWeight.Normal,
15 | fontSize = 16.sp
16 | ),
17 | caption = TextStyle(
18 | fontWeight = FontWeight.Normal,
19 | fontSize = 12.sp,
20 | letterSpacing = 0.4.sp,
21 | color = Color.Gray
22 | )
23 | /* Other default text styles to override
24 | button = TextStyle(
25 | fontFamily = FontFamily.Default,
26 | fontWeight = FontWeight.W500,
27 | fontSize = 14.sp
28 | ),
29 | caption = TextStyle(
30 | fontFamily = FontFamily.Default,
31 | fontWeight = FontWeight.Normal,
32 | fontSize = 12.sp
33 | )
34 | */
35 | )
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
--------------------------------------------------------------------------------
/app/src/main/java/com/mrlin/composemany/repository/entity/PlayListData.kt:
--------------------------------------------------------------------------------
1 | package com.mrlin.composemany.repository.entity
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | /**
6 | * 播放列表数据
7 | */
8 | data class PlayListData(
9 | val code: Int,
10 | val playlist: PlayList,
11 | )
12 |
13 | /**
14 | * 个人歌单
15 | */
16 | data class MyPlayListData(
17 | val code: Int,
18 | val playlist: List,
19 | )
20 |
21 | data class PlayList(
22 | val tracks: List