11package com.ljyh.mei.ui.screen.local
22
3- import androidx.activity.compose.rememberLauncherForActivityResult
4- import androidx.activity.result.contract.ActivityResultContracts
3+ import android.app.Activity
54import androidx.compose.foundation.layout.Box
65import androidx.compose.foundation.layout.Column
76import androidx.compose.foundation.layout.PaddingValues
@@ -16,8 +15,10 @@ import androidx.compose.foundation.lazy.items
1615import androidx.compose.material.icons.Icons
1716import androidx.compose.material.icons.automirrored.rounded.ArrowBack
1817import androidx.compose.material.icons.rounded.MusicNote
18+ import androidx.compose.material.icons.rounded.Refresh
1919import androidx.compose.material3.ExperimentalMaterial3Api
2020import androidx.compose.material3.Icon
21+ import androidx.compose.material3.IconButton
2122import androidx.compose.material3.MaterialTheme
2223import androidx.compose.material3.Scaffold
2324import androidx.compose.material3.Text
@@ -27,6 +28,7 @@ import androidx.compose.material3.TextButton
2728import androidx.compose.material3.TopAppBar
2829import androidx.compose.material3.TopAppBarScrollBehavior
2930import androidx.compose.runtime.Composable
31+ import androidx.compose.runtime.LaunchedEffect
3032import androidx.compose.runtime.collectAsState
3133import androidx.compose.runtime.getValue
3234import androidx.compose.runtime.mutableStateOf
@@ -41,9 +43,6 @@ import androidx.hilt.navigation.compose.hiltViewModel
4143import com.ljyh.mei.di.AppDatabase
4244import com.ljyh.mei.data.model.room.Playlist
4345import com.ljyh.mei.data.model.room.PlaylistType
44- import com.ljyh.mei.data.model.room.ScanFolder
45- import com.ljyh.mei.data.model.room.Song
46- import com.ljyh.mei.data.model.room.SourceType
4746import com.ljyh.mei.ui.local.LocalNavController
4847import com.ljyh.mei.ui.local.LocalPlayerAwareWindowInsets
4948import com.ljyh.mei.ui.screen.Screen
@@ -52,13 +51,23 @@ import com.ljyh.mei.ui.screen.local.component.AlbumRow
5251import com.ljyh.mei.ui.screen.local.component.ArtistRow
5352import com.ljyh.mei.ui.screen.local.component.EmptyLocalMusic
5453import com.ljyh.mei.ui.screen.local.component.FolderItem
55- import com.ljyh.mei.ui.screen.local.component.LibraryStats
5654import com.ljyh.mei.ui.screen.local.component.ManagementCard
5755import com.ljyh.mei.ui.screen.local.component.ManagementCards
5856import com.ljyh.mei.ui.screen.local.component.ScanProgressCard
5957import com.ljyh.mei.ui.screen.local.component.SectionHeader
58+ import com.ljyh.mei.utils.PermissionsUtils
6059import kotlinx.coroutines.launch
6160
61+ private val ARTIST_SEPARATORS = Regex (" [、/;|&]" )
62+
63+ private fun splitArtists (artist : String ): List <String > {
64+ if (artist.isBlank()) return emptyList()
65+ return artist.split(ARTIST_SEPARATORS )
66+ .map { it.trim() }
67+ .filter { it.isNotEmpty() }
68+ .ifEmpty { listOf (artist.trim()) }
69+ }
70+
6271@OptIn(ExperimentalMaterial3Api ::class )
6372@Composable
6473fun LocalMusicScreen (
@@ -70,24 +79,24 @@ fun LocalMusicScreen(
7079 val db = AppDatabase .getDatabase(context)
7180
7281 val localSongs by db.songDao().getLocalSongs().collectAsState(initial = emptyList())
73- val artists by db.songDao().getLocalArtists().collectAsState(initial = emptyList())
7482 val albums by db.songDao().getLocalAlbums().collectAsState(initial = emptyList())
7583 val scanFolders by db.scanFolderDao().getAll().collectAsState(initial = emptyList())
7684 val scanState by viewModel.scanState.collectAsState()
85+ val hasPermission by viewModel.hasPermission.collectAsState()
86+
87+ val artists = remember(localSongs) {
88+ localSongs.flatMap { song ->
89+ splitArtists(song.artist)
90+ }.distinct().sorted()
91+ }
7792
7893 var showCreatePlaylistDialog by remember { mutableStateOf(false ) }
7994 var newPlaylistName by remember { mutableStateOf(" " ) }
8095 val scope = rememberCoroutineScope()
8196
82- val folderPickerLauncher = rememberLauncherForActivityResult(
83- contract = ActivityResultContracts .OpenDocumentTree ()
84- ) { uri ->
85- if (uri != null ) {
86- context.contentResolver.takePersistableUriPermission(
87- uri,
88- android.content.Intent .FLAG_GRANT_READ_URI_PERMISSION
89- )
90- viewModel.scanFolderUri(uri)
97+ LaunchedEffect (hasPermission) {
98+ if (hasPermission) {
99+ viewModel.scanAllMusic()
91100 }
92101 }
93102
@@ -107,6 +116,18 @@ fun LocalMusicScreen(
107116 )
108117 }
109118 },
119+ actions = {
120+ IconButton (
121+ onClick = { viewModel.scanAllMusic() },
122+ enabled = ! scanState.isScanning && hasPermission
123+ ) {
124+ Icon (
125+ imageVector = Icons .Rounded .Refresh ,
126+ tint = MaterialTheme .colorScheme.onSurface,
127+ contentDescription = " 重新扫描"
128+ )
129+ }
130+ },
110131 scrollBehavior = scrollBehavior
111132 )
112133 }
@@ -125,20 +146,33 @@ fun LocalMusicScreen(
125146 ScanProgressCard (scanState)
126147 }
127148
128- if (localSongs.isEmpty() && ! scanState.isScanning) {
149+ if (! hasPermission) {
150+ Box (
151+ modifier = Modifier .fillMaxSize(),
152+ contentAlignment = Alignment .Center
153+ ) {
154+ EmptyLocalMusic (
155+ onAddFolder = {
156+ val activity = context as ? Activity
157+ if (activity != null ) {
158+ PermissionsUtils .checkAndRequestFilesPermissions(activity)
159+ viewModel.checkPermission()
160+ }
161+ }
162+ )
163+ }
164+ } else if (localSongs.isEmpty() && ! scanState.isScanning) {
129165 Box (
130166 modifier = Modifier .fillMaxSize(),
131167 contentAlignment = Alignment .Center
132168 ) {
133- EmptyLocalMusic (onAddFolder = { folderPickerLauncher.launch( null ) })
169+ EmptyLocalMusic (onAddFolder = { viewModel.scanAllMusic( ) })
134170 }
135171 } else {
136172 LazyColumn (
137173 modifier = Modifier .fillMaxSize(),
138174 contentPadding = PaddingValues (bottom = 16 .dp)
139175 ) {
140- item { LibraryStats (localSongs) }
141-
142176 item { SectionHeader (" 歌曲" , " ${localSongs.size} 首" ) }
143177 item {
144178 ManagementCard (
@@ -203,7 +237,7 @@ fun LocalMusicScreen(
203237 item { SectionHeader (" 管理" , null ) }
204238 item {
205239 ManagementCards (
206- onAddFolder = { folderPickerLauncher.launch( null ) },
240+ onAddFolder = { viewModel.scanAllMusic( ) },
207241 onCreatePlaylist = { showCreatePlaylistDialog = true }
208242 )
209243 }
0 commit comments