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/app/src/main/java/com/example/harmonyhub/HarmonyHubApp.kt b/app/src/main/java/com/example/harmonyhub/HarmonyHubApp.kt
index 6f86996..d6c38c3 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)
}
}
@@ -275,8 +278,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)
@@ -490,6 +493,9 @@ fun HarmonyHubApp(
onBackButtonClicked = { navController.popBackStack() }
)
}
+ composable(route = HarmonyHubScreen.Selection.name) {
+ Nav5(navController)
+ }
}
}
@@ -626,8 +632,8 @@ fun Nav3(
authenticationMainViewModel.signOut()
parentNavController.navigate(HarmonyHubScreen.Login.name)
},
- onSettingsButtonClicked = {
- parentNavController.navigate(HarmonyHubScreen.Settings.name)
+ onSplitButtonClicked = {
+ parentNavController.navigate(HarmonyHubScreen.Selection.name)
},
navController = navController
)
@@ -722,7 +728,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 f569a66..419f09d 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
@@ -81,7 +81,7 @@ fun LibraryScreen(
onPlaylistButtonClicked: () -> Unit,
onArtistsFollowingButtonClicked: () -> Unit,
onLogoutButtonClicked: () -> Unit,
- onSettingsButtonClicked: () -> Unit,
+ onSplitButtonClicked: () -> Unit,
favoriteSongsViewModel: FavoriteSongsViewModel = hiltViewModel(),
userViewModel: UserDataViewModel = hiltViewModel(),
onAddToPlaylistClicked: () -> Unit,
@@ -118,7 +118,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
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")
+ }
+}