Skip to content

Commit 080c5eb

Browse files
committed
feat: add explicit content setting and update UI components for better navigation, fix release proguard
1 parent eca7057 commit 080c5eb

23 files changed

Lines changed: 254 additions & 139 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ crowdin.yml
2323

2424
# Sentry Config File
2525
sentry.properties
26+
/.claude/

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ This project is following clean architecture and MVVM pattern (in UI, app module
108108

109109
### Dependencies graph
110110
<p float="left">
111-
<img src="https://github.com/maxrave-dev/SimpMusic/blob/dev/asset/dependencies_graph.svg?raw=true" width="300">
111+
<img src="https://github.com/maxrave-dev/SimpMusic/blob/dev/asset/dependencies_graph.svg?raw=true" width="800">
112112
</p>
113113

114114
## Support & Donations

app/build.gradle.kts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -287,9 +287,6 @@ dependencies {
287287
implementation(libs.koin.android)
288288
implementation(libs.koin.androidx.compose)
289289

290-
// Store5
291-
implementation(libs.store)
292-
293290
// Jetbrains Markdown
294291
api(libs.markdown)
295292

@@ -309,7 +306,7 @@ dependencies {
309306
./gradlew :app:exportLibraryDefinitions --no-daemon --no-configuration-cache --no-build-cache
310307
**/
311308
aboutLibraries {
312-
android.registerAndroidTasks = false
309+
android.registerAndroidTasks = true
313310
export {
314311
exportVariant = "fullRelease"
315312
prettyPrint = true

app/proguard-rules.pro

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,13 @@
178178
-dontwarn jdk.dynalink.linker.support.Guards
179179
-dontwarn jdk.dynalink.support.ChainedCallSite
180180

181+
-keep class org.apache.commons.io.** { *; }
182+
183+
#YtDlp
184+
-keep class com.yausername.** { *; }
185+
-keep class org.apache.commons.compress.archivers.zip.** { *; }
186+
-keepattributes SourceFile
187+
181188
## Rules for NewPipeExtractor
182189
-keep class org.schabi.newpipe.extractor.timeago.patterns.** { *; }
183190
-keep class org.mozilla.javascript.** { *; }

app/src/main/java/com/maxrave/simpmusic/ui/component/DropdownButton.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import androidx.compose.foundation.layout.wrapContentWidth
77
import androidx.compose.foundation.shape.RoundedCornerShape
88
import androidx.compose.material3.DropdownMenuItem
99
import androidx.compose.material3.ExperimentalMaterial3Api
10+
import androidx.compose.material3.ExposedDropdownMenuAnchorType
1011
import androidx.compose.material3.ExposedDropdownMenuBox
1112
import androidx.compose.material3.ExposedDropdownMenuDefaults
12-
import androidx.compose.material3.MenuAnchorType
1313
import androidx.compose.material3.OutlinedTextField
1414
import androidx.compose.material3.Text
1515
import androidx.compose.runtime.Composable
@@ -44,7 +44,7 @@ fun DropdownButton(
4444
OutlinedTextField(
4545
modifier =
4646
Modifier
47-
.menuAnchor(type = MenuAnchorType.PrimaryNotEditable)
47+
.menuAnchor(type = ExposedDropdownMenuAnchorType.PrimaryNotEditable)
4848
.widthIn(1.dp, Dp.Infinity),
4949
textStyle = typo.bodyMedium,
5050
readOnly = true,

app/src/main/java/com/maxrave/simpmusic/ui/component/GridLibraryPlaylist.kt

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,17 @@ import androidx.compose.foundation.lazy.grid.GridItemSpan
1818
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
1919
import androidx.compose.foundation.lazy.grid.items
2020
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
21-
import androidx.compose.foundation.lazy.rememberLazyListState
2221
import androidx.compose.foundation.shape.RoundedCornerShape
2322
import androidx.compose.material.icons.Icons
2423
import androidx.compose.material.icons.rounded.Add
2524
import androidx.compose.material3.Icon
26-
import androidx.compose.material3.OutlinedTextFieldDefaults.contentPadding
2725
import androidx.compose.material3.Text
2826
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
2927
import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults
3028
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
3129
import androidx.compose.runtime.Composable
3230
import androidx.compose.runtime.LaunchedEffect
33-
import androidx.compose.runtime.derivedStateOf
3431
import androidx.compose.runtime.getValue
35-
import androidx.compose.runtime.remember
3632
import androidx.compose.runtime.snapshotFlow
3733
import androidx.compose.ui.Alignment
3834
import androidx.compose.ui.Modifier
@@ -59,7 +55,6 @@ import com.maxrave.simpmusic.ui.navigation.destination.list.PodcastDestination
5955
import com.maxrave.simpmusic.ui.theme.seed
6056
import com.maxrave.simpmusic.ui.theme.typo
6157
import com.maxrave.simpmusic.ui.theme.white
62-
import kotlinx.coroutines.flow.combine
6358

6459
@Composable
6560
inline fun <reified T> GridLibraryPlaylist(
@@ -113,7 +108,7 @@ inline fun <reified T> GridLibraryPlaylist(
113108
) {
114109
Crossfade(targetState = data) { data ->
115110
val list = (data as? LocalResource.Success)?.data ?: emptyList()
116-
if (data is LocalResource.Success && list.isNotEmpty()) {
111+
if (data is LocalResource.Success) {
117112
LazyVerticalGrid(
118113
columns = GridCells.Adaptive(minSize = 125.dp),
119114
contentPadding = contentPadding,

app/src/main/java/com/maxrave/simpmusic/ui/component/LiquidGlassAppBottomNavigationBar.kt

Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import androidx.compose.animation.AnimatedVisibility
77
import androidx.compose.animation.animateColorAsState
88
import androidx.compose.animation.core.Animatable
99
import androidx.compose.animation.core.tween
10-
import androidx.compose.animation.fadeIn
11-
import androidx.compose.animation.fadeOut
1210
import androidx.compose.animation.slideInHorizontally
1311
import androidx.compose.animation.slideOutHorizontally
1412
import androidx.compose.foundation.layout.Box
@@ -53,11 +51,11 @@ import androidx.compose.runtime.mutableStateOf
5351
import androidx.compose.runtime.remember
5452
import androidx.compose.runtime.saveable.rememberSaveable
5553
import androidx.compose.runtime.setValue
56-
import androidx.compose.runtime.snapshotFlow
5754
import androidx.compose.ui.Alignment
5855
import androidx.compose.ui.Modifier
5956
import androidx.compose.ui.draw.blur
6057
import androidx.compose.ui.draw.clip
58+
import androidx.compose.ui.graphics.Color
6159
import androidx.compose.ui.graphics.asAndroidBitmap
6260
import androidx.compose.ui.graphics.rememberGraphicsLayer
6361
import androidx.compose.ui.layout.layoutId
@@ -123,21 +121,15 @@ fun LiquidGlassAppBottomNavigationBar(
123121
animationSpec = tween(1000),
124122
label = "CustomGrayColorAnimation",
125123
)
126-
127-
LaunchedEffect(Unit) {
128-
snapshotFlow { luminanceAnimation.value }.collect {
129-
Logger.d(TAG, "Luminance animation: ${it}")
130-
}
131-
}
132-
133124
LaunchedEffect(layer) {
134125
val buffer = IntBuffer.allocate(25)
135126
while (isActive) {
136127
try {
137128
withContext(Dispatchers.IO) {
138129
val imageBitmap = layer.toImageBitmap()
139130
val thumbnail =
140-
imageBitmap.asAndroidBitmap()
131+
imageBitmap
132+
.asAndroidBitmap()
141133
.scale(5, 5, false)
142134
.copy(Bitmap.Config.ARGB_8888, false)
143135
buffer.rewind()
@@ -154,16 +146,13 @@ fun LiquidGlassAppBottomNavigationBar(
154146
val b = (color and 0xFF) / 255f
155147
0.2126 * r + 0.7152 * g + 0.0722 * b
156148
} / 25
157-
Logger.d(TAG, "Average luminance: $averageLuminance")
158149
luminanceAnimation.animateTo(
159150
averageLuminance.coerceAtMost(0.8).toFloat(),
160-
tween(500)
151+
tween(500),
161152
)
162153
}
163154
}
164155

165-
166-
167156
val nowPlayingData by viewModel.nowPlayingState.collectAsStateWithLifecycle()
168157
// MiniPlayer visibility logic
169158
var isShowMiniPlayer by rememberSaveable {
@@ -219,7 +208,7 @@ fun LiquidGlassAppBottomNavigationBar(
219208

220209
var constraintSet by remember {
221210
mutableStateOf(
222-
decoupledConstraints(isShowMiniPlayer, isExpanded)
211+
decoupledConstraints(isShowMiniPlayer, isExpanded),
223212
)
224213
}
225214

@@ -272,9 +261,8 @@ fun LiquidGlassAppBottomNavigationBar(
272261
backdrop,
273262
layer,
274263
luminanceAnimation.value,
275-
CircleShape
276-
)
277-
.then(
264+
CircleShape,
265+
).then(
278266
if (!isExpanded) {
279267
Modifier.size(48.dp)
280268
} else {
@@ -300,18 +288,20 @@ fun LiquidGlassAppBottomNavigationBar(
300288
Box {
301289
if (selectedIndex == screen.ordinal) {
302290
Box(
303-
modifier = Modifier
304-
.size(buttonSize.first, buttonSize.second)
305-
.clip(CircleShape)
306-
.blur(8.dp)
291+
modifier =
292+
Modifier
293+
.size(buttonSize.first, buttonSize.second)
294+
.clip(CircleShape)
295+
.blur(8.dp),
307296
)
308297
}
309298
Button(
310-
modifier = Modifier.onGloballyPositioned {
311-
if (selectedIndex == screen.ordinal) {
312-
buttonSize = with(density) { it.size.width.toDp() to it.size.height.toDp() }
313-
}
314-
},
299+
modifier =
300+
Modifier.onGloballyPositioned {
301+
if (selectedIndex == screen.ordinal) {
302+
buttonSize = with(density) { it.size.width.toDp() to it.size.height.toDp() }
303+
}
304+
},
315305
onClick = {
316306
if (selectedIndex == screen.ordinal) {
317307
if (currentBackStackEntry?.destination?.hierarchy?.any {
@@ -372,7 +362,7 @@ fun LiquidGlassAppBottomNavigationBar(
372362
style =
373363
if (selectedIndex == screen.ordinal) {
374364
typo.bodySmall.copy(
375-
fontWeight = FontWeight.Bold
365+
fontWeight = FontWeight.Bold,
376366
)
377367
} else {
378368
typo.bodySmall.greyScale()
@@ -449,24 +439,31 @@ fun LiquidGlassAppBottomNavigationBar(
449439
Spacer(Modifier.size(12.dp))
450440
}
451441

442+
val searchColor by animateColorAsState(
443+
targetValue = if (luminanceAnimation.value > 0.6f) Color.Black else Color.White,
444+
label = "MiniPlayerTextColor",
445+
animationSpec = tween(500),
446+
)
447+
452448
AnimatedVisibility(
453449
visible = !isInSearchDestination && isExpanded,
454450
enter =
455451
slideInHorizontally(
456452
tween(100),
457-
) { it / 2 } + fadeIn(),
453+
) { it / 2 },
458454
exit =
459455
slideOutHorizontally(
460456
tween(100),
461-
) { -it / 2 } + fadeOut(),
457+
) { -it / 2 },
462458
) {
463459
FloatingActionButton(
464-
modifier = Modifier.drawBackdropCustomShape(
465-
backdrop,
466-
layer,
467-
luminanceAnimation.value,
468-
CircleShape
469-
),
460+
modifier =
461+
Modifier.drawBackdropCustomShape(
462+
backdrop,
463+
layer,
464+
luminanceAnimation.value,
465+
CircleShape,
466+
),
470467
elevation = FloatingActionButtonDefaults.elevation(0.dp, 0.dp, 0.dp, 0.dp),
471468
onClick = {
472469
previousSelectedIndex = selectedIndex
@@ -481,12 +478,12 @@ fun LiquidGlassAppBottomNavigationBar(
481478
},
482479
shape = CircleShape,
483480
containerColor = transparent,
484-
contentColor = transparent
481+
contentColor = transparent,
485482
) {
486483
Icon(
487484
Icons.Outlined.Search,
488485
"",
489-
tint = white
486+
tint = searchColor,
490487
)
491488
}
492489
}

app/src/main/java/com/maxrave/simpmusic/ui/screen/MiniPlayer.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import androidx.compose.animation.Animatable
44
import androidx.compose.animation.AnimatedContent
55
import androidx.compose.animation.Crossfade
66
import androidx.compose.animation.SizeTransform
7+
import androidx.compose.animation.animateColorAsState
78
import androidx.compose.animation.core.Animatable
89
import androidx.compose.animation.core.animateFloatAsState
10+
import androidx.compose.animation.core.tween
911
import androidx.compose.animation.fadeIn
1012
import androidx.compose.animation.fadeOut
1113
import androidx.compose.animation.slideInHorizontally
@@ -105,6 +107,12 @@ fun MiniPlayer(
105107
) {
106108
val isLiquidGlassEnabled by sharedViewModel.getEnableLiquidGlass().collectAsStateWithLifecycle(DataStoreManager.FALSE)
107109

110+
val textColor by animateColorAsState(
111+
targetValue = if (luminanceAnimation != null && luminanceAnimation > 0.6f) Color.Black else Color.White,
112+
label = "MiniPlayerTextColor",
113+
animationSpec = tween(500),
114+
)
115+
108116
val (songEntity, setSongEntity) =
109117
remember {
110118
mutableStateOf<SongEntity?>(null)
@@ -374,7 +382,7 @@ fun MiniPlayer(
374382
Text(
375383
text = (songEntity?.title ?: "").toString(),
376384
style = typo.labelSmall,
377-
color = Color.White,
385+
color = textColor,
378386
maxLines = 1,
379387
modifier =
380388
Modifier
@@ -400,7 +408,7 @@ fun MiniPlayer(
400408
text = (songEntity?.artistName?.connectArtists() ?: ""),
401409
style = typo.bodySmall,
402410
maxLines = 1,
403-
color = Color.White,
411+
color = textColor,
404412
modifier =
405413
Modifier
406414
.weight(1f)

app/src/main/java/com/maxrave/simpmusic/ui/screen/home/SettingScreen.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ fun SettingScreen(
204204
val limitPlayerCache by viewModel.playerCacheLimit.collectAsStateWithLifecycle()
205205
val fraction by viewModel.fraction.collectAsStateWithLifecycle()
206206
val lastCheckUpdate by viewModel.lastCheckForUpdate.collectAsStateWithLifecycle()
207+
val explicitContentEnabled by viewModel.explicitContentEnabled.collectAsStateWithLifecycle()
207208
val usingProxy by viewModel.usingProxy.collectAsStateWithLifecycle()
208209
val proxyType by viewModel.proxyType.collectAsStateWithLifecycle()
209210
val proxyHost by viewModel.proxyHost.collectAsStateWithLifecycle()
@@ -451,6 +452,11 @@ fun SettingScreen(
451452
smallSubtitle = true,
452453
switch = (sendData to { viewModel.setSendBackToGoogle(it) }),
453454
)
455+
SettingItem(
456+
title = stringResource(R.string.play_explicit_content),
457+
subtitle = stringResource(R.string.play_explicit_content_description),
458+
switch = (explicitContentEnabled to { viewModel.setExplicitContentEnabled(it) }),
459+
)
454460
SettingItem(
455461
title = stringResource(R.string.proxy),
456462
subtitle = stringResource(R.string.proxy_description),

0 commit comments

Comments
 (0)