From 2ebdd4b155c97220cc4c8062b2c3e649e0223d97 Mon Sep 17 00:00:00 2001 From: Dat Trxng Date: Fri, 13 Dec 2024 16:08:18 +0700 Subject: [PATCH 1/2] update Split --- .idea/deploymentTargetSelector.xml | 18 +-- .idea/misc.xml | 2 +- .../com/example/harmonyhub/HarmonyHubApp.kt | 70 +++++++-- .../com/example/harmonyhub/MainActivity.kt | 1 + .../ui/components/NavigationDrawer.kt | 17 ++- .../example/harmonyhub/ui/home/HomeScreen.kt | 10 +- .../harmonyhub/ui/library/LibraryScreen.kt | 4 +- .../ui/library/SongSelectionScreen.kt | 139 ++++++++++++++++++ .../harmonyhub/ui/library/SplitMusicScreen.kt | 40 +++++ 9 files changed, 253 insertions(+), 48 deletions(-) create mode 100644 app/src/main/java/com/example/harmonyhub/ui/library/SongSelectionScreen.kt create mode 100644 app/src/main/java/com/example/harmonyhub/ui/library/SplitMusicScreen.kt diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml index e6a98c4..ff1b812 100644 --- a/.idea/deploymentTargetSelector.xml +++ b/.idea/deploymentTargetSelector.xml @@ -4,29 +4,15 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index b2c751a..8978d23 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,6 @@ - + diff --git a/app/src/main/java/com/example/harmonyhub/HarmonyHubApp.kt b/app/src/main/java/com/example/harmonyhub/HarmonyHubApp.kt index 66fc1a2..c1caa56 100644 --- a/app/src/main/java/com/example/harmonyhub/HarmonyHubApp.kt +++ b/app/src/main/java/com/example/harmonyhub/HarmonyHubApp.kt @@ -59,6 +59,8 @@ import com.example.harmonyhub.ui.library.AlbumScreen import com.example.harmonyhub.ui.library.ArtistScreen import com.example.harmonyhub.ui.library.ChartsScreen import com.example.harmonyhub.ui.library.PlaylistSongListScreen +import com.example.harmonyhub.ui.library.SelectionScreen +import com.example.harmonyhub.ui.library.SplitMusicScreen import com.example.harmonyhub.ui.play.NowPlayingBar import com.example.harmonyhub.ui.play.PlayScreen import com.example.harmonyhub.ui.profile.FavoriteFriendScreen @@ -93,7 +95,8 @@ enum class HarmonyHubScreen(@StringRes val title: Int, val icon: ImageVector) { ), Friends(title = R.string.friends, icon = Icons.Default.AccountBox), Album(title = R.string.album, icon = Icons.Default.AccountBox), - FavoriteFriend(title = R.string.favorite, icon = Icons.Default.AccountBox) + FavoriteFriend(title = R.string.favorite, icon = Icons.Default.AccountBox), + Selection(title = R.string.favorite, icon = Icons.Default.AccountBox) } object CurrentSong { @@ -144,16 +147,16 @@ fun HarmonyHubApp( ) { Column { // Kiểm tra nếu CurrentSong.currentSong không null - CurrentSong.currentSong?.let { currentSong -> - NowPlayingBar( - song = currentSong, - isPlaying = true, - onPlayPauseClick = { /* Handle play/pause logic */ }, - onNextClick = { /* Handle next song logic */ }, - onPreviousClick = { /* Handle previous song logic */ }, - onBarClick = { /* Handle bar click logic */ } - ) - } +// CurrentSong.currentSong?.let { currentSong -> +// NowPlayingBar( +// song = currentSong, +// isPlaying = true, +// onPlayPauseClick = { /* Handle play/pause logic */ }, +// onNextClick = { /* Handle next song logic */ }, +// onPreviousClick = { /* Handle previous song logic */ }, +// onBarClick = { /* Handle bar click logic */ } +// ) +// } BottomNavigationBar(navController = navController) } } @@ -274,8 +277,8 @@ fun HarmonyHubApp( authenticationMainViewModel.signOut() navController.navigate(HarmonyHubScreen.Login.name) }, - onSettingsButtonClicked = { - navController.navigate(HarmonyHubScreen.Settings.name) + onSplitButtonClicked = { + navController.navigate(HarmonyHubScreen.Selection.name) }, onPlaySongClicked = { navController.navigate(HarmonyHubScreen.Play.name) @@ -489,6 +492,9 @@ fun HarmonyHubApp( onBackButtonClicked = { navController.popBackStack() } ) } + composable(route = HarmonyHubScreen.Selection.name) { + Nav5(navController) + } } } @@ -625,8 +631,8 @@ fun Nav3( authenticationMainViewModel.signOut() parentNavController.navigate(HarmonyHubScreen.Login.name) }, - onSettingsButtonClicked = { - parentNavController.navigate(HarmonyHubScreen.Settings.name) + onSplitButtonClicked = { + parentNavController.navigate(HarmonyHubScreen.Selection.name) }, navController = navController ) @@ -720,7 +726,39 @@ fun Nav3( } } } - +@Composable +fun Nav5( + parentNavController: NavHostController +) { + val navController = rememberNavController() + NavHost(navController = navController, startDestination = HarmonyHubScreen.Selection.name) { + composable(route = HarmonyHubScreen.Selection.name) { + SelectionScreen( + navController, + onBackButtonClicked = {parentNavController.popBackStack()} + ) + } + composable( + route = "SplitMusic?url1={selectedUrls[0]}&url2={selectedUrls[1]}", + arguments = listOf( + navArgument(name = "selectedUrls[0]") { + type = NavType.StringType + nullable = true + }, + navArgument(name = "selectedUrls[1]") { + type = NavType.StringType + nullable = true + } + ) + ) { backStackEntry -> + SplitMusicScreen( + url1 = backStackEntry.arguments?.getString("selectedUrls[0]"), + url2 = backStackEntry.arguments?.getString("selectedUrls[1]"), + onBackButtonClicked = {navController.popBackStack()} + ) + } + } +} //@OptIn(ExperimentalMaterial3Api::class) //@Composable //fun HarmonyHubAppbar( diff --git a/app/src/main/java/com/example/harmonyhub/MainActivity.kt b/app/src/main/java/com/example/harmonyhub/MainActivity.kt index 15ea172..095b5fc 100644 --- a/app/src/main/java/com/example/harmonyhub/MainActivity.kt +++ b/app/src/main/java/com/example/harmonyhub/MainActivity.kt @@ -6,6 +6,7 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.core.view.WindowCompat +import com.example.harmonyhub.ui.library.SelectionScreen import com.example.harmonyhub.ui.theme.HarmonyHubTheme import dagger.hilt.android.AndroidEntryPoint diff --git a/app/src/main/java/com/example/harmonyhub/ui/components/NavigationDrawer.kt b/app/src/main/java/com/example/harmonyhub/ui/components/NavigationDrawer.kt index 44ac763..0acb8ae 100644 --- a/app/src/main/java/com/example/harmonyhub/ui/components/NavigationDrawer.kt +++ b/app/src/main/java/com/example/harmonyhub/ui/components/NavigationDrawer.kt @@ -19,6 +19,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ExitToApp import androidx.compose.material.icons.filled.AccountCircle +import androidx.compose.material.icons.filled.Build import androidx.compose.material.icons.filled.ExitToApp import androidx.compose.material.icons.filled.Settings import androidx.compose.material3.DrawerValue @@ -50,7 +51,7 @@ import java.time.format.TextStyle @Composable fun AppScaffoldWithDrawer( onProfileClicked: () -> Unit, - onSettingsClicked: () -> Unit, + onSplitClicked: () -> Unit, onLogoutClicked: () -> Unit, content: @Composable (onOpenDrawer: () -> Unit) -> Unit ) { @@ -72,9 +73,9 @@ fun AppScaffoldWithDrawer( scope.launch { drawerState.close() } onProfileClicked() }, - onSettingsClicked = { + onSplitClicked = { scope.launch { drawerState.close() } - onSettingsClicked() + onSplitClicked() }, onLogoutClicked = { scope.launch { drawerState.close() } @@ -93,7 +94,7 @@ fun AppScaffoldWithDrawer( @Composable fun DrawerContent( onProfileClicked: () -> Unit, - onSettingsClicked: () -> Unit, + onSplitClicked: () -> Unit, onLogoutClicked: () -> Unit, userDataViewModel: UserDataViewModel = hiltViewModel() ) { @@ -166,17 +167,17 @@ fun DrawerContent( } TextButton( - onClick = onSettingsClicked + onClick = onSplitClicked ) { Row { Icon( - imageVector = Icons.Default.Settings, - contentDescription = "Settings", + imageVector = Icons.Default.Build, + contentDescription = "Split", tint = Color.White ) Spacer(modifier = Modifier.width(16.dp)) Text( - text = "Cài đặt", + text = "Tách nhạc", style = androidx.compose.ui.text.TextStyle( fontFamily = NotoSans, fontWeight = FontWeight.Bold, diff --git a/app/src/main/java/com/example/harmonyhub/ui/home/HomeScreen.kt b/app/src/main/java/com/example/harmonyhub/ui/home/HomeScreen.kt index 62d6541..de7e3c9 100644 --- a/app/src/main/java/com/example/harmonyhub/ui/home/HomeScreen.kt +++ b/app/src/main/java/com/example/harmonyhub/ui/home/HomeScreen.kt @@ -100,7 +100,7 @@ fun HomeScreen( onLibraryButtonClicked: () -> Unit, onProfileButtonClicked: () -> Unit, onLogoutButtonClicked: () -> Unit, - onSettingsButtonClicked: () -> Unit, + onSplitButtonClicked: () -> Unit, modifier: Modifier = Modifier, viewModel: HomeViewModel = viewModel(factory = HomeViewModel.Factory), userDataViewModel: UserDataViewModel = hiltViewModel(), @@ -128,7 +128,7 @@ fun HomeScreen( onLibraryButtonClicked, onProfileButtonClicked, onLogoutButtonClicked, - onSettingsButtonClicked, + onSplitButtonClicked, modifier, username.value.toString(), popularItems, @@ -146,7 +146,7 @@ fun MainHomeScreen( onLibraryButtonClicked: () -> Unit, onProfileButtonClicked: () -> Unit, onLogoutButtonClicked: () -> Unit, - onSettingsButtonClicked: () -> Unit, + onSplitButtonClicked: () -> Unit, modifier: Modifier = Modifier, nameUser : String, resPopularItem: ResponseHomeScreenData @@ -154,7 +154,7 @@ fun MainHomeScreen( //Main UI AppScaffoldWithDrawer( onProfileClicked = onProfileButtonClicked, - onSettingsClicked = onSettingsButtonClicked, + onSplitClicked = onSplitButtonClicked, onLogoutClicked = onLogoutButtonClicked ) { onOpenDrawer -> Column( @@ -190,7 +190,7 @@ fun MainHomeScreen( ) } Row { - IconButton(onClick = { onSettingsButtonClicked() }) { + IconButton(onClick = { onSplitButtonClicked() }) { Icon( imageVector = Icons.Default.Settings, contentDescription = "Settings", diff --git a/app/src/main/java/com/example/harmonyhub/ui/library/LibraryScreen.kt b/app/src/main/java/com/example/harmonyhub/ui/library/LibraryScreen.kt index 00ee649..6bbeb65 100644 --- a/app/src/main/java/com/example/harmonyhub/ui/library/LibraryScreen.kt +++ b/app/src/main/java/com/example/harmonyhub/ui/library/LibraryScreen.kt @@ -79,7 +79,7 @@ fun LibraryScreen( onPlaylistButtonClicked: () -> Unit, onArtistsFollowingButtonClicked: () -> Unit, onLogoutButtonClicked: () -> Unit, - onSettingsButtonClicked: () -> Unit, + onSplitButtonClicked: () -> Unit, favoriteSongsViewModel: FavoriteSongsViewModel = hiltViewModel(), userViewModel: UserDataViewModel = hiltViewModel(), onAddToPlaylistClicked: () -> Unit, @@ -117,7 +117,7 @@ fun LibraryScreen( AppScaffoldWithDrawer( onProfileClicked = onProfileButtonClicked, - onSettingsClicked = onSettingsButtonClicked, + onSplitClicked = onSplitButtonClicked, onLogoutClicked = onLogoutButtonClicked ) { onOpenDrawer -> Column( diff --git a/app/src/main/java/com/example/harmonyhub/ui/library/SongSelectionScreen.kt b/app/src/main/java/com/example/harmonyhub/ui/library/SongSelectionScreen.kt new file mode 100644 index 0000000..f7e756e --- /dev/null +++ b/app/src/main/java/com/example/harmonyhub/ui/library/SongSelectionScreen.kt @@ -0,0 +1,139 @@ +package com.example.harmonyhub.ui.library + + +import android.util.Log +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.Button +import androidx.compose.material3.Checkbox +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.navigation.NavHostController +import com.example.harmonyhub.data.SongRepository +import com.example.harmonyhub.ui.components.Song +import com.example.harmonyhub.ui.components.SongCard + + + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SelectionScreen( + navController: NavHostController, + onBackButtonClicked :() -> Unit +) { + val songs: List = SongRepository.allSongs + var query by remember { mutableStateOf("") } + val selectedSongs = remember { mutableStateMapOf() } + val selectedUrls = remember { mutableStateListOf() } + + val filteredSongs = songs.filter { song -> + song.name.contains(query, ignoreCase = true) || song.artist.contains(query, ignoreCase = true) + } + Column(modifier = Modifier.fillMaxSize().padding(16.dp)) { + // Nút quay lại + IconButton( + onClick = { onBackButtonClicked() }, + modifier = Modifier.padding(bottom = 16.dp) + ) { + Icon(imageVector = Icons.Filled.ArrowBack, contentDescription = "Quay lại") + } + + // Thanh tìm kiếm + TextField( + value = query, + onValueChange = { query = it }, + label = { Text("Tìm kiếm bài hát") }, + modifier = Modifier.fillMaxWidth().padding(bottom = 16.dp), + colors = androidx.compose.material3.TextFieldDefaults.textFieldColors( + focusedIndicatorColor = Color.Cyan, + unfocusedIndicatorColor = Color.Gray + ) + ) + + Text( + text = "Chọn bài hát yêu thích", + fontSize = 20.sp, + color = Color.White, + modifier = Modifier.padding(bottom = 16.dp) + ) + + LazyColumn( + modifier = Modifier.weight(1f) + ) { + items(filteredSongs) { song -> + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp) + ) { + SongCard( + song = song, + more = null, // Không cần nút More + onSongClick = { + // Toggle trạng thái CheckBox khi nhấn vào SongCard + if (selectedUrls.size < 2 || (selectedSongs[song.id] == true)) { + selectedSongs[song.id] = !(selectedSongs[song.id] ?: false) + if (selectedSongs[song.id] == true) { + selectedUrls.add(song.url) // Thêm URL vào danh sách + } else { + selectedUrls.remove(song.url) // Xoá URL khỏi danh sách + } + } + }, + onMoreClick = {} + ) + Spacer(modifier = Modifier.width(8.dp)) + Checkbox( + + checked = selectedSongs[song.id] ?: false, + onCheckedChange = { isChecked -> + if (selectedUrls.size >= 2) { + selectedUrls.clear() + } + if (isChecked) { + if (selectedUrls.size < 2) { // Kiểm tra nếu số lượng chưa đạt 2 + selectedSongs[song.id] = true + selectedUrls.add(song.url) + } + } else { + selectedSongs[song.id] = false + selectedUrls.remove(song.url) + } + } + ) + + } + } + } + + // Nút xác nhận + Spacer(modifier = Modifier.height(16.dp)) + Button( + onClick = { + if (selectedUrls.size == 2) { + Log.d("SelectionScreen", "URL 1: ${selectedUrls[0]}, URL 2: ${selectedUrls[1]}") + navController.navigate("SplitMusic?url1=${selectedUrls[0]}&url2=${selectedUrls[1]}") + } + }, + enabled = selectedUrls.isNotEmpty() + ) { + Text(text = "Xác nhận", fontSize = 16.sp) + } + } +} + + + + diff --git a/app/src/main/java/com/example/harmonyhub/ui/library/SplitMusicScreen.kt b/app/src/main/java/com/example/harmonyhub/ui/library/SplitMusicScreen.kt new file mode 100644 index 0000000..3c34d72 --- /dev/null +++ b/app/src/main/java/com/example/harmonyhub/ui/library/SplitMusicScreen.kt @@ -0,0 +1,40 @@ +package com.example.harmonyhub.ui.library + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun SplitMusicScreen( + url1 : String?, + url2 : String?, + onBackButtonClicked :() -> Unit + +){ + Column { + IconButton( + onClick = { onBackButtonClicked() }, + modifier = Modifier.padding(bottom = 16.dp) + ) { + Icon(imageVector = Icons.Filled.ArrowBack, contentDescription = "Quay lại") + } + if (url1 != null) { + Text( + text = url1 + ) + } + if (url2 != null) { + Text( + text = url2 + ) + } + } + +} \ No newline at end of file From aa07927d4974a12709f21f1cbedc54f2969fe8ac Mon Sep 17 00:00:00 2001 From: lan Date: Sun, 15 Dec 2024 00:39:59 +0700 Subject: [PATCH 2/2] add formatTimer unit test --- .../harmonyhub/ui/play/PlayScreenTest.kt | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 app/src/test/java/com/example/harmonyhub/ui/play/PlayScreenTest.kt diff --git a/app/src/test/java/com/example/harmonyhub/ui/play/PlayScreenTest.kt b/app/src/test/java/com/example/harmonyhub/ui/play/PlayScreenTest.kt new file mode 100644 index 0000000..bbfb4fe --- /dev/null +++ b/app/src/test/java/com/example/harmonyhub/ui/play/PlayScreenTest.kt @@ -0,0 +1,33 @@ +package com.example.harmonyhub.ui.play; + +import org.junit.Assert.assertEquals + +import org.junit.Test; + + +public class PlayScreenTest { + + @Test + fun testFormatTime1() { + // Test the formatTime function + assertEquals(formatTime(0), "00:00") + } + + @Test + fun testFormatTime2() { + // Test the formatTime function + assertEquals(formatTime(60000), "01:00") + } + + @Test + fun testFormatTime3() { + // Test the formatTime function + assertEquals(formatTime(61000), "01:01") + } + + @Test + fun testFormatTime4() { + // Test the formatTime function + assertEquals(formatTime(3599999), "59:59") + } +}