Rename files
This commit is contained in:
@@ -15,7 +15,6 @@ import androidx.compose.foundation.clickable
|
|||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.offset
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
@@ -61,8 +60,6 @@ fun Scaffold(
|
|||||||
tabIndex = tabIndex,
|
tabIndex = tabIndex,
|
||||||
onTabChanged = onTabChanged,
|
onTabChanged = onTabChanged,
|
||||||
tabColumnContent = tabColumnContent,
|
tabColumnContent = tabColumnContent,
|
||||||
// primaryIconButtonId = primaryIconButtonId,
|
|
||||||
// onPrimaryIconButtonClick = onPrimaryIconButtonClick,
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(LocalPlayerAwarePaddingValues.current)
|
.padding(LocalPlayerAwarePaddingValues.current)
|
||||||
)
|
)
|
||||||
@@ -111,29 +108,3 @@ fun Scaffold(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExperimentalAnimationApi
|
|
||||||
@Composable
|
|
||||||
fun SimpleScaffold(
|
|
||||||
topIconButtonId: Int,
|
|
||||||
onTopIconButtonClick: () -> Unit,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
content: @Composable () -> Unit
|
|
||||||
) {
|
|
||||||
val (colorPalette) = LocalAppearance.current
|
|
||||||
|
|
||||||
Row(
|
|
||||||
modifier = modifier
|
|
||||||
.background(colorPalette.background0)
|
|
||||||
.fillMaxSize()
|
|
||||||
) {
|
|
||||||
VerticalBar(
|
|
||||||
topIconButtonId = topIconButtonId,
|
|
||||||
onTopIconButtonClick = onTopIconButtonClick,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(LocalPlayerAwarePaddingValues.current)
|
|
||||||
)
|
|
||||||
|
|
||||||
content()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,34 +1,26 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components.themed
|
package it.vfsfitvnm.vimusic.ui.components.themed
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.offset
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.BasicText
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.draw.rotate
|
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.vimusic.ui.components.TabColumn
|
import it.vfsfitvnm.vimusic.ui.components.TabColumn
|
||||||
import it.vfsfitvnm.vimusic.ui.components.vertical
|
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||||
|
|
||||||
@SuppressLint("ModifierParameter")
|
|
||||||
@Composable
|
@Composable
|
||||||
fun VerticalBar(
|
fun VerticalBar(
|
||||||
topIconButtonId: Int,
|
topIconButtonId: Int,
|
||||||
@@ -43,16 +35,8 @@ fun VerticalBar(
|
|||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
// .width(Dimensions.verticalBarWidth)
|
|
||||||
.padding(vertical = 16.dp)
|
.padding(vertical = 16.dp)
|
||||||
) {
|
) {
|
||||||
// Box(
|
|
||||||
// modifier = Modifier
|
|
||||||
// .clip(RoundedCornerShape(16.dp))
|
|
||||||
// .clickable(onClick = onTopIconButtonClick)
|
|
||||||
// .background(color = colorPalette.background1)
|
|
||||||
// .size(48.dp)
|
|
||||||
// ) {
|
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(topIconButtonId),
|
painter = painterResource(topIconButtonId),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
@@ -61,10 +45,8 @@ fun VerticalBar(
|
|||||||
.clip(RoundedCornerShape(16.dp))
|
.clip(RoundedCornerShape(16.dp))
|
||||||
.clickable(onClick = onTopIconButtonClick)
|
.clickable(onClick = onTopIconButtonClick)
|
||||||
.padding(all = 12.dp)
|
.padding(all = 12.dp)
|
||||||
// .align(Alignment.Center)
|
|
||||||
.size(22.dp)
|
.size(22.dp)
|
||||||
)
|
)
|
||||||
// }
|
|
||||||
|
|
||||||
Spacer(
|
Spacer(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -80,58 +62,5 @@ fun VerticalBar(
|
|||||||
textStyle = typography.xs.semiBold,
|
textStyle = typography.xs.semiBold,
|
||||||
content = tabColumnContent,
|
content = tabColumnContent,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Spacer(
|
|
||||||
// modifier = Modifier
|
|
||||||
// .weight(1f)
|
|
||||||
// )
|
|
||||||
|
|
||||||
// primaryIconButtonId?.let {
|
|
||||||
// Box(
|
|
||||||
// modifier = Modifier
|
|
||||||
// .offset(x = 8.dp)
|
|
||||||
// .clip(RoundedCornerShape(16.dp))
|
|
||||||
// .clickable(onClick = onPrimaryIconButtonClick)
|
|
||||||
// .background(colorPalette.background1)
|
|
||||||
// .size(62.dp)
|
|
||||||
// ) {
|
|
||||||
// Image(
|
|
||||||
// painter = painterResource(primaryIconButtonId),
|
|
||||||
// contentDescription = null,
|
|
||||||
// colorFilter = ColorFilter.tint(colorPalette.text),
|
|
||||||
// modifier = Modifier
|
|
||||||
// .align(Alignment.Center)
|
|
||||||
// .size(20.dp)
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("ModifierParameter")
|
|
||||||
@Composable
|
|
||||||
fun VerticalBar(
|
|
||||||
topIconButtonId: Int,
|
|
||||||
onTopIconButtonClick: () -> Unit,
|
|
||||||
modifier: Modifier = Modifier
|
|
||||||
) {
|
|
||||||
val (colorPalette) = LocalAppearance.current
|
|
||||||
|
|
||||||
Column(
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
modifier = modifier
|
|
||||||
.width(Dimensions.verticalBarWidth)
|
|
||||||
.padding(vertical = 16.dp)
|
|
||||||
) {
|
|
||||||
Image(
|
|
||||||
painter = painterResource(topIconButtonId),
|
|
||||||
contentDescription = null,
|
|
||||||
colorFilter = ColorFilter.tint(colorPalette.textSecondary),
|
|
||||||
modifier = Modifier
|
|
||||||
.clip(RoundedCornerShape(16.dp))
|
|
||||||
.clickable(onClick = onTopIconButtonClick)
|
|
||||||
.padding(all = 12.dp)
|
|
||||||
.size(22.dp)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,25 +3,35 @@ package it.vfsfitvnm.vimusic.ui.screens.album
|
|||||||
import androidx.compose.animation.ExperimentalAnimationApi
|
import androidx.compose.animation.ExperimentalAnimationApi
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveableStateHolder
|
||||||
import it.vfsfitvnm.route.RouteHandler
|
import it.vfsfitvnm.route.RouteHandler
|
||||||
import it.vfsfitvnm.vimusic.R
|
import it.vfsfitvnm.vimusic.R
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.SimpleScaffold
|
import it.vfsfitvnm.vimusic.ui.components.themed.Scaffold
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.globalRoutes
|
import it.vfsfitvnm.vimusic.ui.screens.globalRoutes
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
@Composable
|
@Composable
|
||||||
fun AlbumScreen(browseId: String) {
|
fun AlbumScreen(browseId: String) {
|
||||||
|
val saveableStateHolder = rememberSaveableStateHolder()
|
||||||
|
|
||||||
RouteHandler(listenToGlobalEmitter = true) {
|
RouteHandler(listenToGlobalEmitter = true) {
|
||||||
globalRoutes()
|
globalRoutes()
|
||||||
|
|
||||||
host {
|
host {
|
||||||
SimpleScaffold(
|
Scaffold(
|
||||||
topIconButtonId = R.drawable.chevron_back,
|
topIconButtonId = R.drawable.chevron_back,
|
||||||
onTopIconButtonClick = pop,
|
onTopIconButtonClick = pop,
|
||||||
) {
|
tabIndex = 0,
|
||||||
|
onTabChanged = {},
|
||||||
|
tabColumnContent = { Item ->
|
||||||
|
Item(0, "Overview", R.drawable.sparkles)
|
||||||
|
}
|
||||||
|
) { currentTabIndex ->
|
||||||
|
saveableStateHolder.SaveableStateProvider(key = currentTabIndex) {
|
||||||
AlbumSongList(browseId = browseId)
|
AlbumSongList(browseId = browseId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,11 +54,13 @@ import it.vfsfitvnm.vimusic.ui.styling.shimmer
|
|||||||
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
||||||
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
||||||
import it.vfsfitvnm.vimusic.utils.center
|
import it.vfsfitvnm.vimusic.utils.center
|
||||||
|
import it.vfsfitvnm.vimusic.utils.color
|
||||||
import it.vfsfitvnm.vimusic.utils.enqueue
|
import it.vfsfitvnm.vimusic.utils.enqueue
|
||||||
import it.vfsfitvnm.vimusic.utils.forcePlayAtIndex
|
import it.vfsfitvnm.vimusic.utils.forcePlayAtIndex
|
||||||
import it.vfsfitvnm.vimusic.utils.forcePlayFromBeginning
|
import it.vfsfitvnm.vimusic.utils.forcePlayFromBeginning
|
||||||
import it.vfsfitvnm.vimusic.utils.medium
|
import it.vfsfitvnm.vimusic.utils.medium
|
||||||
import it.vfsfitvnm.vimusic.utils.secondary
|
import it.vfsfitvnm.vimusic.utils.secondary
|
||||||
|
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||||
import it.vfsfitvnm.vimusic.utils.thumbnail
|
import it.vfsfitvnm.vimusic.utils.thumbnail
|
||||||
|
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
@@ -66,12 +68,12 @@ import it.vfsfitvnm.vimusic.utils.thumbnail
|
|||||||
@Composable
|
@Composable
|
||||||
fun AlbumSongList(
|
fun AlbumSongList(
|
||||||
browseId: String,
|
browseId: String,
|
||||||
viewModel: AlbumViewModel = viewModel(
|
viewModel: AlbumSongListViewModel = viewModel(
|
||||||
key = browseId,
|
key = browseId,
|
||||||
factory = object : ViewModelProvider.Factory {
|
factory = object : ViewModelProvider.Factory {
|
||||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
return AlbumViewModel(browseId) as T
|
return AlbumSongListViewModel(browseId) as T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -175,7 +177,7 @@ fun AlbumSongList(
|
|||||||
startContent = {
|
startContent = {
|
||||||
BasicText(
|
BasicText(
|
||||||
text = "${index + 1}",
|
text = "${index + 1}",
|
||||||
style = typography.m.secondary.secondary.center,
|
style = typography.s.semiBold.center.color(colorPalette.textDisabled),
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -215,7 +217,7 @@ fun AlbumSongList(
|
|||||||
.size(20.dp)
|
.size(20.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} ?: viewModel.result?.exceptionOrNull()?.let { _ ->
|
} ?: viewModel.result?.exceptionOrNull()?.let {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.pointerInput(Unit) {
|
.pointerInput(Unit) {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class AlbumViewModel(browseId: String) : ViewModel() {
|
class AlbumSongListViewModel(browseId: String) : ViewModel() {
|
||||||
var result by mutableStateOf<Result<AlbumWithSongs?>?>(null)
|
var result by mutableStateOf<Result<AlbumWithSongs?>?>(null)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@@ -54,8 +54,8 @@ import it.vfsfitvnm.vimusic.utils.medium
|
|||||||
|
|
||||||
@ExperimentalFoundationApi
|
@ExperimentalFoundationApi
|
||||||
@Composable
|
@Composable
|
||||||
fun PlaylistsTab(
|
fun HomePlaylistList(
|
||||||
viewModel: PlaylistsTabViewModel = viewModel(),
|
viewModel: HomePlaylistListViewModel = viewModel(),
|
||||||
onBuiltInPlaylistClicked: (BuiltInPlaylist) -> Unit,
|
onBuiltInPlaylistClicked: (BuiltInPlaylist) -> Unit,
|
||||||
onPlaylistClicked: (Playlist) -> Unit,
|
onPlaylistClicked: (Playlist) -> Unit,
|
||||||
) {
|
) {
|
||||||
@@ -23,7 +23,7 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class PlaylistsTabViewModel(application: Application) : AndroidViewModel(application) {
|
class HomePlaylistListViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
var items by mutableStateOf(emptyList<PlaylistPreview>())
|
var items by mutableStateOf(emptyList<PlaylistPreview>())
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@@ -102,8 +102,8 @@ fun HomeScreen() {
|
|||||||
) { currentTabIndex ->
|
) { currentTabIndex ->
|
||||||
saveableStateHolder.SaveableStateProvider(key = currentTabIndex) {
|
saveableStateHolder.SaveableStateProvider(key = currentTabIndex) {
|
||||||
when (currentTabIndex) {
|
when (currentTabIndex) {
|
||||||
0 -> SongsTab()
|
0 -> HomeSongList()
|
||||||
1 -> PlaylistsTab(
|
1 -> HomePlaylistList(
|
||||||
onBuiltInPlaylistClicked = { builtInPlaylistRoute(it) },
|
onBuiltInPlaylistClicked = { builtInPlaylistRoute(it) },
|
||||||
onPlaylistClicked = { localPlaylistRoute(it.id) }
|
onPlaylistClicked = { localPlaylistRoute(it.id) }
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ import it.vfsfitvnm.vimusic.utils.semiBold
|
|||||||
@ExperimentalFoundationApi
|
@ExperimentalFoundationApi
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
@Composable
|
@Composable
|
||||||
fun SongsTab(
|
fun HomeSongList(
|
||||||
viewModel: SongsTabViewModel = viewModel()
|
viewModel: HomeSongListViewModel = viewModel()
|
||||||
) {
|
) {
|
||||||
val (colorPalette, typography) = LocalAppearance.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
@@ -23,7 +23,7 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class SongsTabViewModel(application: Application) : AndroidViewModel(application) {
|
class HomeSongListViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
var items by mutableStateOf(emptyList<DetailedSong>())
|
var items by mutableStateOf(emptyList<DetailedSong>())
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@@ -47,15 +47,15 @@ import it.vfsfitvnm.youtubemusic.models.NavigationEndpoint
|
|||||||
@ExperimentalFoundationApi
|
@ExperimentalFoundationApi
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
@Composable
|
@Composable
|
||||||
fun LibrarySearchTab(
|
fun LocalSongSearch(
|
||||||
textFieldValue: TextFieldValue,
|
textFieldValue: TextFieldValue,
|
||||||
onTextFieldValueChanged: (TextFieldValue) -> Unit,
|
onTextFieldValueChanged: (TextFieldValue) -> Unit,
|
||||||
viewModel: LibrarySearchTabViewModel = viewModel(
|
viewModel: LocalSongSearchViewModel = viewModel(
|
||||||
key = textFieldValue.text,
|
key = textFieldValue.text,
|
||||||
factory = object : ViewModelProvider.Factory {
|
factory = object : ViewModelProvider.Factory {
|
||||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
return LibrarySearchTabViewModel(textFieldValue.text) as T
|
return LocalSongSearchViewModel(textFieldValue.text) as T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -9,7 +9,7 @@ import it.vfsfitvnm.vimusic.Database
|
|||||||
import it.vfsfitvnm.vimusic.models.DetailedSong
|
import it.vfsfitvnm.vimusic.models.DetailedSong
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class LibrarySearchTabViewModel(text: String) : ViewModel() {
|
class LocalSongSearchViewModel(text: String) : ViewModel() {
|
||||||
var items by mutableStateOf(emptyList<DetailedSong>())
|
var items by mutableStateOf(emptyList<DetailedSong>())
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@@ -56,18 +56,18 @@ import it.vfsfitvnm.vimusic.utils.secondary
|
|||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun OnlineSearchTab(
|
fun OnlineSearch(
|
||||||
textFieldValue: TextFieldValue,
|
textFieldValue: TextFieldValue,
|
||||||
onTextFieldValueChanged: (TextFieldValue) -> Unit,
|
onTextFieldValueChanged: (TextFieldValue) -> Unit,
|
||||||
isOpenableUrl: Boolean,
|
isOpenableUrl: Boolean,
|
||||||
onSearch: (String) -> Unit,
|
onSearch: (String) -> Unit,
|
||||||
onUri: () -> Unit,
|
onUri: () -> Unit,
|
||||||
viewModel: OnlineSearchTabViewModel = viewModel(
|
viewModel: OnlineSearchViewModel = viewModel(
|
||||||
key = textFieldValue.text,
|
key = textFieldValue.text,
|
||||||
factory = object : ViewModelProvider.Factory {
|
factory = object : ViewModelProvider.Factory {
|
||||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
return OnlineSearchTabViewModel(textFieldValue.text) as T
|
return OnlineSearchViewModel(textFieldValue.text) as T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -11,7 +11,7 @@ import it.vfsfitvnm.youtubemusic.YouTube
|
|||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class OnlineSearchTabViewModel(text: String) : ViewModel() {
|
class OnlineSearchViewModel(text: String) : ViewModel() {
|
||||||
var history by mutableStateOf(emptyList<SearchQuery>())
|
var history by mutableStateOf(emptyList<SearchQuery>())
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ fun SearchScreen(initialTextInput: String, onSearch: (String) -> Unit, onUri: (U
|
|||||||
) { currentTabIndex ->
|
) { currentTabIndex ->
|
||||||
saveableStateHolder.SaveableStateProvider(currentTabIndex) {
|
saveableStateHolder.SaveableStateProvider(currentTabIndex) {
|
||||||
when (currentTabIndex) {
|
when (currentTabIndex) {
|
||||||
0 -> OnlineSearchTab(
|
0 -> OnlineSearch(
|
||||||
textFieldValue = textFieldValue,
|
textFieldValue = textFieldValue,
|
||||||
onTextFieldValueChanged = onTextFieldValueChanged,
|
onTextFieldValueChanged = onTextFieldValueChanged,
|
||||||
isOpenableUrl = isOpenableUrl,
|
isOpenableUrl = isOpenableUrl,
|
||||||
@@ -77,7 +77,7 @@ fun SearchScreen(initialTextInput: String, onSearch: (String) -> Unit, onUri: (U
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
1 -> LibrarySearchTab(
|
1 -> LocalSongSearch(
|
||||||
textFieldValue = textFieldValue,
|
textFieldValue = textFieldValue,
|
||||||
onTextFieldValueChanged = onTextFieldValueChanged
|
onTextFieldValueChanged = onTextFieldValueChanged
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ inline fun <I : YouTube.Item> ItemSearchResult(
|
|||||||
query: String,
|
query: String,
|
||||||
filter: String,
|
filter: String,
|
||||||
crossinline onSearchAgain: () -> Unit,
|
crossinline onSearchAgain: () -> Unit,
|
||||||
viewModel: ItemSearchResultViewModel<I> = viewModel(
|
viewModel: SearchResultViewModel<I> = viewModel(
|
||||||
key = query + filter,
|
key = query + filter,
|
||||||
factory = object : ViewModelProvider.Factory {
|
factory = object : ViewModelProvider.Factory {
|
||||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
return ItemSearchResultViewModel<I>(query, filter) as T
|
return SearchResultViewModel<I>(query, filter) as T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
@@ -11,7 +11,7 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class ItemSearchResultViewModel<T : YouTube.Item>(
|
class SearchResultViewModel<T : YouTube.Item>(
|
||||||
private val query: String,
|
private val query: String,
|
||||||
private val filter: String
|
private val filter: String
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
@@ -19,7 +19,7 @@ import it.vfsfitvnm.vimusic.utils.secondary
|
|||||||
|
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
@Composable
|
@Composable
|
||||||
fun AboutTab() {
|
fun About() {
|
||||||
val (colorPalette, typography) = LocalAppearance.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val uriHandler = LocalUriHandler.current
|
val uriHandler = LocalUriHandler.current
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ import it.vfsfitvnm.vimusic.utils.thumbnailRoundnessKey
|
|||||||
|
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
@Composable
|
@Composable
|
||||||
fun AppearanceSettingsTab() {
|
fun AppearanceSettings() {
|
||||||
val (colorPalette) = LocalAppearance.current
|
val (colorPalette) = LocalAppearance.current
|
||||||
|
|
||||||
var colorPaletteName by rememberPreference(colorPaletteNameKey, ColorPaletteName.Dynamic)
|
var colorPaletteName by rememberPreference(colorPaletteNameKey, ColorPaletteName.Dynamic)
|
||||||
@@ -30,7 +30,7 @@ import it.vfsfitvnm.vimusic.utils.rememberPreference
|
|||||||
@OptIn(ExperimentalCoilApi::class)
|
@OptIn(ExperimentalCoilApi::class)
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
@Composable
|
@Composable
|
||||||
fun CacheSettingsTab() {
|
fun CacheSettings() {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val (colorPalette) = LocalAppearance.current
|
val (colorPalette) = LocalAppearance.current
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
@@ -47,7 +47,7 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
|
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
@Composable
|
@Composable
|
||||||
fun OtherSettingsTab() {
|
fun OtherSettings() {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val (colorPalette) = LocalAppearance.current
|
val (colorPalette) = LocalAppearance.current
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ import it.vfsfitvnm.vimusic.utils.volumeNormalizationKey
|
|||||||
|
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
@Composable
|
@Composable
|
||||||
fun PlayerSettingsTab() {
|
fun PlayerSettings() {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val (colorPalette) = LocalAppearance.current
|
val (colorPalette) = LocalAppearance.current
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
@@ -52,11 +52,11 @@ fun SettingsScreen() {
|
|||||||
) { currentTabIndex ->
|
) { currentTabIndex ->
|
||||||
saveableStateHolder.SaveableStateProvider(currentTabIndex) {
|
saveableStateHolder.SaveableStateProvider(currentTabIndex) {
|
||||||
when (currentTabIndex) {
|
when (currentTabIndex) {
|
||||||
0 -> AppearanceSettingsTab()
|
0 -> AppearanceSettings()
|
||||||
1 -> PlayerSettingsTab()
|
1 -> PlayerSettings()
|
||||||
2 -> CacheSettingsTab()
|
2 -> CacheSettings()
|
||||||
3 -> OtherSettingsTab()
|
3 -> OtherSettings()
|
||||||
4 -> AboutTab()
|
4 -> About()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
15
app/src/main/res/drawable/sparkles.xml
Normal file
15
app/src/main/res/drawable/sparkles.xml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="512"
|
||||||
|
android:viewportHeight="512">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M208,512a24.84,24.84 0,0 1,-23.34 -16l-39.84,-103.6a16.06,16.06 0,0 0,-9.19 -9.19L32,343.34a25,25 0,0 1,0 -46.68l103.6,-39.84a16.06,16.06 0,0 0,9.19 -9.19L184.66,144a25,25 0,0 1,46.68 0l39.84,103.6a16.06,16.06 0,0 0,9.19 9.19l103,39.63A25.49,25.49 0,0 1,400 320.52a24.82,24.82 0,0 1,-16 22.82l-103.6,39.84a16.06,16.06 0,0 0,-9.19 9.19L231.34,496A24.84,24.84 0,0 1,208 512ZM274.85,257.16h0Z"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M88,176a14.67,14.67 0,0 1,-13.69 -9.4L57.45,122.76a7.28,7.28 0,0 0,-4.21 -4.21L9.4,101.69a14.67,14.67 0,0 1,0 -27.38L53.24,57.45a7.31,7.31 0,0 0,4.21 -4.21L74.16,9.79A15,15 0,0 1,86.23 0.11,14.67 14.67,0 0,1 101.69,9.4l16.86,43.84a7.31,7.31 0,0 0,4.21 4.21L166.6,74.31a14.67,14.67 0,0 1,0 27.38l-43.84,16.86a7.28,7.28 0,0 0,-4.21 4.21L101.69,166.6A14.67,14.67 0,0 1,88 176Z"/>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M400,256a16,16 0,0 1,-14.93 -10.26l-22.84,-59.37a8,8 0,0 0,-4.6 -4.6l-59.37,-22.84a16,16 0,0 1,0 -29.86l59.37,-22.84a8,8 0,0 0,4.6 -4.6L384.9,42.68a16.45,16.45 0,0 1,13.17 -10.57,16 16,0 0,1 16.86,10.15l22.84,59.37a8,8 0,0 0,4.6 4.6l59.37,22.84a16,16 0,0 1,0 29.86l-59.37,22.84a8,8 0,0 0,-4.6 4.6l-22.84,59.37A16,16 0,0 1,400 256Z"/>
|
||||||
|
</vector>
|
||||||
Reference in New Issue
Block a user