diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index a60e598..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -Audiofy \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index fdf8d99..f8467b4 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 17eabad..431935d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -9,6 +9,19 @@ plugins { kotlin("kapt") } +/** + * The secrets that needs to be added to BuildConfig at runtime. + */ +val secrets = arrayOf( + "IAP_BUY_ME_COFFEE", + "IAP_NO_ADS", + "PLACEMENT_BANNER_1", + "PLACEMENT_BANNER_2", + "PLACEMENT_INTERSTITIAL", + "UNITY_APP_ID", + "PLAY_CONSOLE_APP_RSA_KEY", +) + android { compileSdk = 34 namespace = "com.prime.media" @@ -16,14 +29,15 @@ android { applicationId = "com.prime.player" minSdk = 21 targetSdk = 34 - versionCode = 47 + versionCode = 48 versionName = "2.3.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { useSupportLibrary = true } - // Add necessary const to BuildConfig - // These filed will be provided in github - // secrets when released else defualt value will be used - secrets() + //Load secrets into BuildConfig + secrets.forEach { secret -> + val value = "\"" + (System.getenv(secret) ?: "no_value") + "\"" + buildConfigField("String", secret, value) + } } buildTypes { @@ -55,7 +69,7 @@ android { freeCompilerArgs = listOf("-Xopt-in=kotlin.RequiresOptIn", "-Xcontext-receivers") } buildFeatures { compose = true } - composeOptions { kotlinCompilerExtensionVersion = "1.5.1" } + composeOptions { kotlinCompilerExtensionVersion = "1.5.3" } packaging { resources { excludes += "/META-INF/{AL2.0,LGPL2.1}" } } } @@ -74,11 +88,11 @@ dependencies { implementation("androidx.compose.material:material-icons-extended:$compose_version") // The Accompanist Libraries implementation("io.coil-kt:coil-compose:2.4.0") - implementation("com.google.accompanist:accompanist-permissions:0.31.5-beta") + implementation("com.google.accompanist:accompanist-permissions:0.32.0") //Lottie implementation("com.airbnb.android:lottie-compose:6.1.0") // Preferences and other widgets - val toolkit_version = "1.0.9-beta" + val toolkit_version = "1.1.1" implementation("com.github.prime-zs.toolkit:preferences:$toolkit_version") implementation("com.github.prime-zs.toolkit:core-ktx:$toolkit_version") implementation("com.github.prime-zs.toolkit:material2:$toolkit_version") @@ -89,7 +103,7 @@ dependencies { implementation("com.google.firebase:firebase-analytics-ktx") implementation("com.google.firebase:firebase-crashlytics-ktx") // WindowSizeClasses - implementation("androidx.compose.material3:material3-window-size-class:1.2.0-alpha05") + implementation("androidx.compose.material3:material3-window-size-class:1.1.1") // Google Play InAppUpdate val in_app_update_version = "2.1.0" implementation("com.google.android.play:app-update:$in_app_update_version") @@ -105,15 +119,15 @@ dependencies { // Unity Ads implementation("com.unity3d.ads:unity-ads:4.8.0") // Compose navigation - implementation("androidx.navigation:navigation-compose:2.7.0") + implementation("androidx.navigation:navigation-compose:2.7.1") // Compose Downloadable fonts implementation("androidx.compose.ui:ui-text-google-fonts:1.5.0") // Hilt - implementation("com.google.dagger:hilt-android:2.47") - kapt("com.google.dagger:hilt-android-compiler:2.47") + implementation("com.google.dagger:hilt-android:2.48") + kapt("com.google.dagger:hilt-android-compiler:2.48") implementation("androidx.hilt:hilt-navigation-compose:1.0.0") // Room Database - val room_version = "2.6.0-alpha03" + val room_version = "2.6.0-beta01" implementation("androidx.room:room-runtime:$room_version") kapt("androidx.room:room-compiler:$room_version") implementation("androidx.room:room-ktx:$room_version") @@ -129,30 +143,4 @@ dependencies { implementation("androidx.media3:media3-exoplayer:$media3_version") // For exposing and controlling media sessions implementation("androidx.media3:media3-session:$media3_version") -} - -/** - * Init adn add git secrets to BuildConfig - */ -fun ApplicationDefaultConfig.secrets() { - var value = "\"" + (System.getenv("IAP_BUY_ME_COFFEE") ?: "empty") + "\"" - buildConfigField("String", "IAP_BUY_ME_COFFEE", value) - - value = "\"" + (System.getenv("IAP_NO_ADS") ?: "empty") + "\"" - buildConfigField("String", "IAP_NO_ADS", value) - - value = "\"" + (System.getenv("PLACEMENT_BANNER_1") ?: "empty") + "\"" - buildConfigField("String", "PLACEMENT_BANNER_1", value) - - value = "\"" + (System.getenv("PLACEMENT_BANNER_2") ?: "empty") + "\"" - buildConfigField("String", "PLACEMENT_BANNER_2", value) - - value = "\"" + (System.getenv("PLACEMENT_INTERSTITIAL") ?: "empty") + "\"" - buildConfigField("String", "PLACEMENT_INTERSTITIAL", value) - - value = "\"" + (System.getenv("UNITY_APP_ID") ?: "empty") + "\"" - buildConfigField("String", "UNITY_APP_ID", value) - - value = "\"" + (System.getenv("PLAY_CONSOLE_APP_RSA_KEY") ?: "empty") + "\"" - buildConfigField("String", "PLAY_CONSOLE_APP_RSA_KEY", value) } \ No newline at end of file diff --git a/app/src/main/java/com/prime/media/Home.kt b/app/src/main/java/com/prime/media/Home.kt index 00733d8..cd1c936 100644 --- a/app/src/main/java/com/prime/media/Home.kt +++ b/app/src/main/java/com/prime/media/Home.kt @@ -236,8 +236,8 @@ private fun Permission() { } Placeholder( iconResId = R.raw.lt_permission, - title = stringResource(R.string.storage_permission), - message = stringResource(R.string.storage_permission_message), + title = stringResource(R.string.permission_screen_title), + message = stringResource(R.string.permission_screen_desc), ) { OutlinedButton( onClick = { permission.launchPermissionRequest() }, @@ -251,8 +251,8 @@ private fun Permission() { } } -private val LightPrimaryColor = Color(0xFF17618D) -private val LightPrimaryVariantColor = Color(0xFF14547B) +private val LightPrimaryColor = Color(0xFF244285) +private val LightPrimaryVariantColor = Color(0xFF305EA5) private val LightSecondaryColor = Color(0xFF8B008B) private val LightSecondaryVariantColor = Color(0xFF7B0084) private val DarkPrimaryColor = Color(0xFFff8f00) @@ -297,7 +297,7 @@ fun Material( MaterialTheme( colors = colors, content = content, - typography = Typography(Settings.LatoFontFamily) + typography = Typography(Settings.DefaultFontFamily) ) } diff --git a/app/src/main/java/com/prime/media/MainActivity.kt b/app/src/main/java/com/prime/media/MainActivity.kt index fa9febd..38dafc6 100644 --- a/app/src/main/java/com/prime/media/MainActivity.kt +++ b/app/src/main/java/com/prime/media/MainActivity.kt @@ -1,7 +1,6 @@ package com.prime.media import android.animation.ObjectAnimator -import android.content.ActivityNotFoundException import android.content.Intent import android.content.pm.PackageManager import android.media.audiofx.AudioEffect @@ -10,7 +9,6 @@ import android.os.Build import android.os.Bundle import android.view.View import android.view.animation.AnticipateInterpolator -import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.material.icons.Icons @@ -241,7 +239,7 @@ class MainActivity : ComponentActivity(), SystemFacade { manager.requestUpdateFlow().collect { result -> when (result) { AppUpdateResult.NotAvailable -> - if (report) channel.show("The app is already updated to the latest version.") + if (report) channel.show(R.string.msg_no_new_update_available) is AppUpdateResult.InProgress -> { val state = result.installState @@ -270,9 +268,8 @@ class MainActivity : ComponentActivity(), SystemFacade { } // else show the toast. val res = channel.show( - title = "Update", - message = "An update has just been downloaded.", - action = "RESTART", + message = R.string.msg_new_update_downloaded, + action = R.string.update, duration = Duration.Indefinite, accent = Color.MetroGreen ) @@ -301,7 +298,7 @@ class MainActivity : ComponentActivity(), SystemFacade { override fun shareApp() { ShareCompat.IntentBuilder(this).setType("text/plain") .setChooserTitle(getString(R.string.app_name)) - .setText("Let me recommend you this application ${Audiofy.GOOGLE_STORE}").startChooser() + .setText(getString(R.string.share_app_desc_s, Audiofy.GOOGLE_STORE)).startChooser() } override fun onNewIntent(intent: Intent?) { @@ -317,8 +314,8 @@ class MainActivity : ComponentActivity(), SystemFacade { ) == PackageManager.PERMISSION_GRANTED if (!isPermitted) { show( - R.string.storage_permission_message, - R.string.storage_permission, + R.string.permission_screen_desc, + R.string.permission_screen_title, icon = Icons.TwoTone.Memory ) return @@ -327,7 +324,7 @@ class MainActivity : ComponentActivity(), SystemFacade { lifecycleScope.launch { val audio = runCatching { findAudio(data) }.getOrNull() if (audio == null) { - show(R.string.error_msg, R.string.error) + show(R.string.msg_unknown_error, R.string.error) return@launch } remote.set(listOf(audio.toMediaItem)) @@ -338,7 +335,7 @@ class MainActivity : ComponentActivity(), SystemFacade { override fun launchEqualizer(id: Int) { lifecycleScope.launch { if (id == AudioEffect.ERROR_BAD_VALUE) - return@launch show(R.string.error_msg, R.string.error) + return@launch show(R.string.msg_unknown_error, R.string.error) val result = kotlin.runCatching { startActivity( Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL).apply { @@ -351,7 +348,7 @@ class MainActivity : ComponentActivity(), SystemFacade { if (!result.isFailure) return@launch val res = channel.show( - message = R.string.equalizer_3rd_party_not_found_msg, + message = R.string.msg_3rd_party_equalizer_not_found, action = R.string.launch, accent = Color.OrientRed, duration = Duration.Short diff --git a/app/src/main/java/com/prime/media/console/Console.kt b/app/src/main/java/com/prime/media/console/Console.kt index 7a018db..bc71674 100644 --- a/app/src/main/java/com/prime/media/console/Console.kt +++ b/app/src/main/java/com/prime/media/console/Console.kt @@ -83,15 +83,17 @@ import androidx.media3.common.Player import com.prime.media.Material import com.prime.media.R import com.prime.media.caption2 +import com.prime.media.core.Anim import com.prime.media.core.ContentElevation import com.prime.media.core.ContentPadding -import com.prime.media.core.compose.AVDIconButton +import com.prime.media.core.LongDurationMills +import com.prime.media.core.MediumDurationMills +import com.prime.media.core.compose.AnimatedIconButton import com.prime.media.core.compose.Image import com.prime.media.core.compose.LocalSystemFacade import com.prime.media.core.compose.LottieAnimButton import com.prime.media.core.compose.LottieAnimation import com.prime.media.core.compose.marque -import com.prime.media.core.compose.rememberAnimatedVectorResource import com.prime.media.core.compose.shape.CompactDisk import com.prime.media.core.util.DateUtils import com.prime.media.darkShadowColor @@ -152,8 +154,9 @@ private fun PlayButton( id = R.raw.lt_play_pause, atEnd = !isPlaying, scale = 1.5f, - progressRange = 0.0f..0.5f, - duration = 1200 + progressRange = 0.0f..0.29f, + duration = Anim.MediumDurationMills, + easing = LinearEasing ) } } @@ -295,7 +298,7 @@ private fun Vertical( // Signature Text( text = stringResource(id = R.string.app_name), - fontFamily = FontFamily.Cursive, + fontFamily = Settings.DancingScriptFontFamily, fontWeight = FontWeight.Bold, fontSize = 70.sp, modifier = Modifier @@ -491,7 +494,7 @@ private fun Vertical( ) val mode = state.repeatMode - AVDIconButton( + AnimatedIconButton( id = R.drawable.avd_repeat_more_one_all, onClick = { state.cycleRepeatMode();facade.launchReviewFlow(); }, atEnd = mode == Player.REPEAT_MODE_ALL, diff --git a/app/src/main/java/com/prime/media/core/compose/Delegates.kt b/app/src/main/java/com/prime/media/core/compose/Delegates.kt index 4c8f113..b80f3b0 100644 --- a/app/src/main/java/com/prime/media/core/compose/Delegates.kt +++ b/app/src/main/java/com/prime/media/core/compose/Delegates.kt @@ -10,6 +10,8 @@ import androidx.compose.animation.EnterTransition import androidx.compose.animation.ExitTransition import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.core.AnimationConstants +import androidx.compose.animation.core.Easing +import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.MutableTransitionState import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween @@ -149,14 +151,15 @@ inline fun LottieAnimation( atEnd: Boolean = false, scale: Float = 1f, progressRange: ClosedFloatingPointRange = 0f..1f, - duration: Int = -1 + duration: Int = -1, + easing: Easing = FastOutSlowInEasing ) { val composition by rememberLottieComposition(spec = LottieCompositionSpec.RawRes(id)) val duration2 = composition?.duration?.roundToLong() ?: AnimationConstants.LongDurationMills val progress by animateFloatAsState( targetValue = if (atEnd) progressRange.start else progressRange.endInclusive, label = "Lottie $id", - animationSpec = tween(if (duration == -1) duration2.toInt() else duration) + animationSpec = tween(if (duration == -1) duration2.toInt() else duration, easing = easing) ) LottieAnimation( composition = composition, @@ -285,7 +288,7 @@ inline fun LottieAnimButton( */ @OptIn(ExperimentalAnimationGraphicsApi::class) @Composable -inline fun AVDIconButton( +inline fun AnimatedIconButton( @DrawableRes id: Int, noinline onClick: () -> Unit, modifier: Modifier = Modifier, diff --git a/app/src/main/java/com/prime/media/core/compose/Snackbar.kt b/app/src/main/java/com/prime/media/core/compose/Snackbar.kt index 4c7286a..a3d374d 100644 --- a/app/src/main/java/com/prime/media/core/compose/Snackbar.kt +++ b/app/src/main/java/com/prime/media/core/compose/Snackbar.kt @@ -411,9 +411,9 @@ private fun Snackbar2( text = { Label( text = data.message.value, - color = LocalContentColor.current.copy(ContentAlpha.medium), + color = LocalContentColor.current, style = MaterialTheme.typography.body2, - maxLines = 4, + maxLines = 5, ) }, overlineText = composableOrNull(data.title != null) { diff --git a/app/src/main/java/com/prime/media/core/compose/core-ktx.kt b/app/src/main/java/com/prime/media/core/compose/core-ktx.kt index 42376db..cc3e996 100644 --- a/app/src/main/java/com/prime/media/core/compose/core-ktx.kt +++ b/app/src/main/java/com/prime/media/core/compose/core-ktx.kt @@ -25,7 +25,6 @@ import androidx.compose.ui.unit.dp import androidx.navigation.NavHostController import androidx.navigation.compose.currentBackStackEntryAsState import com.primex.core.Text -import com.primex.core.resolve private const val TAG = "ComposeUtil" @@ -76,11 +75,6 @@ val LocalWindowSizeClass = staticCompositionLocalOf { val NavHostController.current @Composable inline get() = currentBackStackEntryAsState().value?.destination?.route -inline fun Resources.stringResource(res: Text) = resolve(res) - -@JvmName("stringResource1") -inline fun Resources.stringResource(res: Text?) = resolve(res) - /** * @return [content] if [condition] is true else null */ diff --git a/app/src/main/java/com/prime/media/core/playback/Playback.kt b/app/src/main/java/com/prime/media/core/playback/Playback.kt index 4ea9e22..0e237b4 100644 --- a/app/src/main/java/com/prime/media/core/playback/Playback.kt +++ b/app/src/main/java/com/prime/media/core/playback/Playback.kt @@ -336,7 +336,7 @@ class Playback : MediaLibraryService(), Callback, Player.Listener { override fun onPlayerError(error: PlaybackException) { // make a simple toast - Toast.makeText(this, getString(R.string.unplayable_file), Toast.LENGTH_SHORT).show() + Toast.makeText(this, getString(R.string.msg_unplayable_file), Toast.LENGTH_SHORT).show() //player.seekToNextMediaItem() } } \ No newline at end of file diff --git a/app/src/main/java/com/prime/media/directory/Action.kt b/app/src/main/java/com/prime/media/directory/Action.kt index 9f6a80f..a373864 100644 --- a/app/src/main/java/com/prime/media/directory/Action.kt +++ b/app/src/main/java/com/prime/media/directory/Action.kt @@ -1,9 +1,11 @@ package com.prime.media.directory +import androidx.annotation.StringRes import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.* import androidx.compose.runtime.Stable import androidx.compose.ui.graphics.vector.ImageVector +import com.prime.media.R import com.primex.core.Text /** @@ -25,21 +27,23 @@ sealed class Action(val id: String, val title: Text, val icon: ImageVector) { */ constructor(id: String, title: String, icon: ImageVector) : this(id, Text(title), icon) - object Play : Action("action_play", "Play", Icons.Outlined.PlayArrow) - object Shuffle : Action("action_shuffle", "Shuffle", Icons.Outlined.Shuffle) - object Share : Action("action_share", "Share", Icons.Outlined.Share) - object Delete : Action("action_delete", "Delete", Icons.Outlined.Delete) + constructor(id: String, @StringRes title: Int, icon: ImageVector):this(id, Text(title), icon) + + object Play : Action("action_play", R.string.play, Icons.Outlined.PlayArrow) + object Shuffle : Action("action_shuffle", R.string.shuffle, Icons.Outlined.Shuffle) + object Share : Action("action_share", R.string.share, Icons.Outlined.Share) + object Delete : Action("action_delete", R.string.delete, Icons.Outlined.Delete) object PlaylistAdd : - Action("action_add_to_playlist", "Add to Playlist", Icons.Outlined.PlaylistAdd) + Action("action_add_to_playlist", R.string.add_to_playlist, Icons.Outlined.PlaylistAdd) - object Make : Action("action_create", "Create", Icons.Outlined.AddCircle) - object Edit : Action("action_edit", "Edit", Icons.Outlined.Edit) - object GoToArtist : Action("action_go_to_artist", "Go to Artist", Icons.Outlined.Person) - object GoToAlbum : Action("action_go_to_album", "Go to Album", Icons.Outlined.Album) - object Properties : Action("action_properties", "Properties", Icons.Outlined.Info) - object SelectAll : Action("action_select_all", "Select All", Icons.Outlined.SelectAll) - object AddToQueue : Action("action_add_to_queue", "Add to Queue", Icons.Outlined.AddToQueue) - object PlayNext : Action("action_play_next", "Play Next", Icons.Outlined.QueuePlayNext) + object Make : Action("action_create", R.string.create, Icons.Outlined.AddCircle) + object Edit : Action("action_edit", R.string.edit, Icons.Outlined.Edit) + object GoToArtist : Action("action_go_to_artist", R.string.go_to_artist, Icons.Outlined.Person) + object GoToAlbum : Action("action_go_to_album", R.string.go_to_album, Icons.Outlined.Album) + object Properties : Action("action_properties", R.string.properties, Icons.Outlined.Info) + object SelectAll : Action("action_select_all", R.string.select_all, Icons.Outlined.SelectAll) + object AddToQueue : Action("action_add_to_queue", R.string.add_to_queue, Icons.Outlined.AddToQueue) + object PlayNext : Action("action_play_next", R.string.play_next, Icons.Outlined.QueuePlayNext) /** * Check if this `Action` instance is equal to another object. @@ -84,20 +88,20 @@ sealed class Action(val id: String, val title: Text, val icon: ImageVector) { @Stable sealed class GroupBy(id: String, title: Text, icon: ImageVector) : Action(id, title, icon) { private constructor(id: String, title: String, icon: ImageVector) : this(id, Text(title), icon) - + private constructor(id: String, @StringRes title: Int, icon: ImageVector):this(id, Text(title), icon) /** * GroupBy the title/Name of the item. */ - object None : GroupBy(ORDER_BY_NONE, "None", Icons.Outlined.FilterNone) - object Name : GroupBy(ORDER_BY_NAME, "Name", Icons.Outlined.Title) + object None : GroupBy(ORDER_BY_NONE, R.string.none, Icons.Outlined.FilterNone) + object Name : GroupBy(ORDER_BY_NAME, R.string.name, Icons.Outlined.Title) object DateModified : - GroupBy(ORDER_BY_DATE_MODIFIED, "Date Modified", Icons.Outlined.AccessTime) + GroupBy(ORDER_BY_DATE_MODIFIED, R.string.date_modified, Icons.Outlined.AccessTime) - object DateAdded : GroupBy(ORDER_BY_DATE_ADDED, "Date Added", Icons.Outlined.CalendarMonth) - object Artist : GroupBy(ORDER_BY_ARTIST, "Artist", Icons.Outlined.Person) - object Album : GroupBy(ORDER_BY_ALBUM, "Album", Icons.Outlined.Album) - object Folder : GroupBy(ORDER_BY_FOLDER, "Folder", Icons.Outlined.Folder) - object Length : GroupBy(ORDER_BY_LENGTH, "Length", Icons.Outlined.AvTimer) + object DateAdded : GroupBy(ORDER_BY_DATE_ADDED, R.string.date_added, Icons.Outlined.CalendarMonth) + object Artist : GroupBy(ORDER_BY_ARTIST, R.string.artist, Icons.Outlined.Person) + object Album : GroupBy(ORDER_BY_ALBUM, R.string.album, Icons.Outlined.Album) + object Folder : GroupBy(ORDER_BY_FOLDER, R.string.folder, Icons.Outlined.Folder) + object Length : GroupBy(ORDER_BY_LENGTH, R.string.length, Icons.Outlined.AvTimer) companion object { private const val ORDER_BY_NONE = "order_by_none" @@ -145,9 +149,10 @@ sealed class GroupBy(id: String, title: Text, icon: ImageVector) : Action(id, ti @Stable sealed class ViewType(id: String, title: Text, icon: ImageVector) : Action(id, title, icon) { private constructor(id: String, title: String, icon: ImageVector) : this(id, Text(title), icon) + private constructor(id: String, @StringRes title: Int, icon: ImageVector):this(id, Text(title), icon) - object List : ViewType(VIEW_TYPE_LIST, "List", Icons.Outlined.List) - object Grid : ViewType(VIEW_TYPE_GRID, "Grid", Icons.Outlined.GridView) + object List : ViewType(VIEW_TYPE_LIST, R.string.list, Icons.Outlined.List) + object Grid : ViewType(VIEW_TYPE_GRID, R.string.grid, Icons.Outlined.GridView) companion object { val VIEW_TYPE_LIST = "view_type_list" diff --git a/app/src/main/java/com/prime/media/directory/playlists/Members.kt b/app/src/main/java/com/prime/media/directory/playlists/Members.kt index 52f70a3..e956d44 100644 --- a/app/src/main/java/com/prime/media/directory/playlists/Members.kt +++ b/app/src/main/java/com/prime/media/directory/playlists/Members.kt @@ -33,7 +33,6 @@ import com.prime.media.core.util.addDistinct import com.prime.media.directory.* import com.prime.media.directory.dialogs.Playlists import com.prime.media.impl.Repository -import com.prime.media.core.db.toMediaItem import com.prime.media.core.util.toMediaItem import com.primex.core.* import com.primex.material2.* @@ -237,7 +236,7 @@ class MembersViewModel @Inject constructor( clear() // show warning show( - R.string.warning_queue_add_experimental, + R.string.msg_queue_add_experimental_warning, R.string.warning, ResourcesCompat.ID_NULL, Icons.Outlined.Warning, @@ -254,8 +253,8 @@ class MembersViewModel @Inject constructor( return@launch val count = remote.add(*audios.toTypedArray(), index = index) show( - buildPluralResource(id = R.plurals.queue_update_msg, count, count, audios.size), - buildTextResource(if (count == 0) R.string.error_status_uncertain else R.string.success), + buildPluralResource(id = R.plurals.msg_queue_updated_dd, count, count, audios.size), + buildTextResource(if (count == 0) R.string.msg_error_status_uncertain else R.string.success), null, Icons.Outlined.Queue, if (count == 0) Color.RedViolet else Color.MetroGreen diff --git a/app/src/main/java/com/prime/media/directory/store/Albums.kt b/app/src/main/java/com/prime/media/directory/store/Albums.kt index ff25c01..3f3a96b 100644 --- a/app/src/main/java/com/prime/media/directory/store/Albums.kt +++ b/app/src/main/java/com/prime/media/directory/store/Albums.kt @@ -1,3 +1,5 @@ +@file:OptIn(ExperimentalTextApi::class) + package com.prime.media.directory.store import android.provider.MediaStore @@ -13,6 +15,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.ExperimentalTextApi import androidx.compose.ui.unit.dp import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope @@ -30,6 +33,7 @@ import com.prime.media.directory.* import com.prime.media.small2 import com.primex.core.Rose import com.primex.core.Text +import com.primex.core.textResource import com.primex.material2.Label import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.* @@ -67,7 +71,7 @@ class AlbumsViewModel @Inject constructor( init { // emit the name to meta //TODO: Add other fields in future versions. - meta = MetaData(Text("Albums")) + meta = MetaData(Text(R.string.albums)) } override fun toggleViewType() { @@ -103,8 +107,7 @@ class AlbumsViewModel @Inject constructor( .catch { // any exception. toaster.show( - "Some unknown error occured!.", - "Error", + R.string.msg_unknown_error, leading = Icons.Outlined.Error, accent = Color.Rose, duration = Channel.Duration.Indefinite @@ -159,7 +162,7 @@ fun Album( // Subtitle Label( - text = "Year: ${value.firstYear}", + text = textResource(R.string.albums_scr_year_d, value.firstYear), style = Material.typography.caption2 ) } diff --git a/app/src/main/java/com/prime/media/directory/store/Audios.kt b/app/src/main/java/com/prime/media/directory/store/Audios.kt index 40bae15..ca07e46 100644 --- a/app/src/main/java/com/prime/media/directory/store/Audios.kt +++ b/app/src/main/java/com/prime/media/directory/store/Audios.kt @@ -13,11 +13,9 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.outlined.* import androidx.compose.runtime.* import androidx.compose.runtime.snapshots.SnapshotStateList -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.scale @@ -248,10 +246,10 @@ class AudiosViewModel @Inject constructor( GroupBy.None -> mapOf(Text("") to list) GroupBy.Length -> list.groupBy { audio -> when { - audio.duration < TimeUnit.MINUTES.toMillis(2) -> Text(R.string.list_title_less_then_2_mins) - audio.duration < TimeUnit.MINUTES.toMillis(5) -> Text(R.string.list_title_less_than_5_mins) - audio.duration < TimeUnit.MINUTES.toMillis(10) -> Text(R.string.list_title_less_than_10_mins) - else -> Text(R.string.list_title_greater_than_10_mins) + audio.duration < TimeUnit.MINUTES.toMillis(2) -> Text(R.string.audios_scr_less_then_2_mins) + audio.duration < TimeUnit.MINUTES.toMillis(5) -> Text(R.string.audios_scr_less_than_5_mins) + audio.duration < TimeUnit.MINUTES.toMillis(10) -> Text(R.string.audios_scr_less_than_10_mins) + else -> Text(R.string.audios_scr_greater_than_10_mins) } } @@ -458,7 +456,7 @@ class AudiosViewModel @Inject constructor( clear() // show warning show( - R.string.warning_queue_add_experimental, + R.string.msg_queue_add_experimental_warning, R.string.warning, ResourcesCompat.ID_NULL, Icons.Outlined.Warning, @@ -475,8 +473,8 @@ class AudiosViewModel @Inject constructor( return@launch val count = remote.add(*audios.toTypedArray(), index = index) show( - buildPluralResource(id = R.plurals.queue_update_msg, count, count, audios.size), - buildTextResource(if (count == 0) R.string.error_status_uncertain else R.string.success), + buildPluralResource(id = R.plurals.msg_queue_updated_dd, count, count, audios.size), + buildTextResource(if (count == 0) R.string.msg_error_status_uncertain else R.string.success), null, Icons.Outlined.Queue, if (count == 0) Color.RedViolet else Color.MetroGreen @@ -504,8 +502,8 @@ class AudiosViewModel @Inject constructor( clear() val isTrashEnabled = preferences.value(Settings.TRASH_CAN_ENABLED) val res = show( - buildTextResource(if (isTrashEnabled) R.string.trash_files_warning_msg else R.string.delete_files_warning_msg, list.size), - buildTextResource(R.string.alert), + buildTextResource(if (isTrashEnabled) R.string.msg_trash_files_warning_d else R.string.msg_delete_files_warning_d, list.size), + null, buildTextResource(if (isTrashEnabled) R.string.trash else R.string.delete), Icons.Outlined.WarningAmber, accent = Color.Rose, @@ -528,28 +526,28 @@ class AudiosViewModel @Inject constructor( // show appropriate message when (result) { -2 -> show( - R.string.delete_dialog_show_msg, + R.string.msg_showing_delete_dialog, R.string.confirm, leading = Icons.Outlined.DeleteForever, accent = Color.Rose, ) -3 -> show( - R.string.deleting_process_cancelled, + R.string.msg_deleting_process_cancelled, R.string.cancelled, leading = Icons.Outlined.Cancel, ) // handle general case -1 -> show( - R.string.delete_audio_error, + R.string.msg_delete_unknown_error, R.string.error, leading = Icons.Outlined.Error, accent = Color.Rose ) else -> show( - buildTextResource(id = R.string.delete_success_msg, result, uris.size), - buildTextResource(R.string.success), + buildTextResource(id = R.string.msg_delete_success_ss, result, uris.size), + null, null, Icons.Outlined.Delete, Color.MetroGreen diff --git a/app/src/main/java/com/prime/media/directory/store/Folders.kt b/app/src/main/java/com/prime/media/directory/store/Folders.kt index 1d63acc..ebe6119 100644 --- a/app/src/main/java/com/prime/media/directory/store/Folders.kt +++ b/app/src/main/java/com/prime/media/directory/store/Folders.kt @@ -2,7 +2,6 @@ package com.prime.media.directory.store import android.provider.MediaStore import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.grid.GridCells @@ -115,7 +114,7 @@ class FoldersViewModel @Inject constructor( val list = preferences.value(Settings.BLACKLISTED_FILES) val name = PathUtils.name(path) val response = show( - Text(R.string.block_folder_warning_msg, name), + Text(R.string.msg_block_folder_warning_s, name), Text(id = R.string.warning), Text(id = R.string.add), Icons.Outlined.Block, @@ -127,14 +126,14 @@ class FoldersViewModel @Inject constructor( val result = preferences.block(path) if (result > 0) show( - Text(R.string.block_success_msg, name), - Text(R.string.blacklist), + Text(R.string.msg_block_success_s, name), + Text(R.string.pref_blacklist), leading = Icons.Outlined.Block, accent = Color.Rose, duration = Channel.Duration.Short, ) else - show(R.string.error_msg, R.string.error) + show(R.string.msg_unknown_error, R.string.error) } } } diff --git a/app/src/main/java/com/prime/media/impl/ConsoleViewModel.kt b/app/src/main/java/com/prime/media/impl/ConsoleViewModel.kt index c2ec619..2c8244b 100644 --- a/app/src/main/java/com/prime/media/impl/ConsoleViewModel.kt +++ b/app/src/main/java/com/prime/media/impl/ConsoleViewModel.kt @@ -23,10 +23,8 @@ import com.prime.media.core.db.Playlist import com.prime.media.core.playback.Playback import com.prime.media.core.playback.Remote import com.prime.media.core.util.MainHandler -import com.primex.core.Amber -import com.primex.core.Text +import com.primex.core.OrientRed import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch @@ -91,7 +89,7 @@ class ConsoleViewModel @Inject constructor( override fun remove(context: Context, key: Uri) { viewModelScope.launch { val removed = remote.remove(key) - val msg = if (removed) R.string.track_remove_msg else R.string.track_remove_error_msg + val msg = if (removed) R.string.msg_track_will_be_removed else R.string.msg_track_remove_error Toast.makeText(context, msg, Toast.LENGTH_SHORT).show() } } @@ -104,8 +102,7 @@ class ConsoleViewModel @Inject constructor( override fun clear(context: Context) { viewModelScope.launch { - val msg = "The playing queue will be cleared shortly." - Toast.makeText(context, msg, Toast.LENGTH_SHORT).show() + Toast.makeText(context, R.string.msg_clearing_playing_queue, Toast.LENGTH_SHORT).show() remote.clear() } } @@ -125,8 +122,7 @@ class ConsoleViewModel @Inject constructor( viewModelScope.launch { // currently not available. toaster.show( - title = R.string.coming_soon, - message = R.string.coming_soon_msg, + message = R.string.msg_feature_coming_soon, leading = Icons.Outlined.MoreTime ) } @@ -149,9 +145,9 @@ class ConsoleViewModel @Inject constructor( this@ConsoleViewModel.favourite = !favourite && res if (!res) toaster.show( - message = Text("An error occurred while adding/removing the item to favourite playlist"), - title = Text("Favourites"), - leading = R.drawable.ic_heart + message = R.string.msg_error_fav_playlist_update, + leading = R.drawable.ic_heart, + accent = Color.OrientRed ) } } diff --git a/app/src/main/java/com/prime/media/impl/LibraryViewModel.kt b/app/src/main/java/com/prime/media/impl/LibraryViewModel.kt index e7ba14b..4db9f59 100644 --- a/app/src/main/java/com/prime/media/impl/LibraryViewModel.kt +++ b/app/src/main/java/com/prime/media/impl/LibraryViewModel.kt @@ -90,7 +90,7 @@ class LibraryViewModel @Inject constructor( // item will be added to the playlist, initiating playback from this item's index. // If the user decides otherwise, the item will be added to the queue following the current queue order. val res = channel.show( - R.string.library_recent_click_msg, + R.string.msg_library_recent_click, action = R.string.reset, leading = Icons.Outlined.Message, accent = Color.MetroGreen @@ -99,8 +99,7 @@ class LibraryViewModel @Inject constructor( val file = files?.find { it.uri == uri } if (files == null || file == null) { channel.show( - R.string.error_msg, - R.string.error, + R.string.msg_unknown_error, leading = Icons.Outlined.Error, accent = Color.Rose ) @@ -126,7 +125,7 @@ class LibraryViewModel @Inject constructor( val item = files?.find { it.id == id } if (files == null || item == null) { channel.show( - R.string.error_msg, + R.string.msg_unknown_error, R.string.error, leading = Icons.Outlined.Error, accent = Color.Rose @@ -139,7 +138,7 @@ class LibraryViewModel @Inject constructor( if (isAlreadyInPlaylist) return@launch val res = channel.show( - R.string.library_msg_recently_added_click, + R.string.msg_library_recently_added_click, action = R.string.reset, leading = Icons.Outlined.ClearAll, accent = Color.DahliaYellow diff --git a/app/src/main/java/com/prime/media/impl/SettingsViewModel.kt b/app/src/main/java/com/prime/media/impl/SettingsViewModel.kt index 07b67e8..b0a424b 100644 --- a/app/src/main/java/com/prime/media/impl/SettingsViewModel.kt +++ b/app/src/main/java/com/prime/media/impl/SettingsViewModel.kt @@ -39,8 +39,8 @@ class SettingsViewModel @Inject constructor( preferences[Settings.NIGHT_MODE].map { Preference( value = it, - title = Text(R.string.app_theme), - summery = Text(R.string.app_theme_summery), + title = Text(R.string.pref_app_theme), + summery = Text(R.string.pref_app_theme_summery), vector = Icons.Outlined.Lightbulb ) }.asComposeState() @@ -51,8 +51,8 @@ class SettingsViewModel @Inject constructor( preferences[Settings.COLOR_STATUS_BAR].map { Preference( vector = null, - title = Text(R.string.color_status_bar), - summery = Text(R.string.color_stutus_bar_summery), + title = Text(R.string.pref_color_system_bars), + summery = Text(R.string.pref_color_system_bars_summery), value = it ) }.asComposeState() @@ -62,8 +62,8 @@ class SettingsViewModel @Inject constructor( preferences[Settings.HIDE_STATUS_BAR].map { Preference( value = it, - title = Text(R.string.immersive_view), - summery = Text(R.string.immersive_view_summery), + title = Text(R.string.pref_hide_status_bar), + summery = Text(R.string.pref_hide_status_bar_summery), vector = Icons.Outlined.HideImage ) }.asComposeState() @@ -73,8 +73,8 @@ class SettingsViewModel @Inject constructor( preferences[Settings.FORCE_COLORIZE].map { Preference( value = it, - title = Text(R.string.force_accent_color), - summery = Text(R.string.force_aacent_color_summery) + title = Text(R.string.pref_force_accent_color), + summery = Text(R.string.pref_force_accent_color_summery) ) }.asComposeState() } @@ -82,8 +82,8 @@ class SettingsViewModel @Inject constructor( override val minTrackLength: Preference by with(preferences) { preferences[Settings.MIN_TRACK_LENGTH_SECS].map { Preference( - title = Text(R.string.minimum_track_length), - summery = Text(R.string.minimum_track_length_summery), + title = Text(R.string.pref_minimum_track_length), + summery = Text(R.string.pref_minimum_track_length_summery), value = it ) }.asComposeState() @@ -92,8 +92,8 @@ class SettingsViewModel @Inject constructor( override val recentPlaylistLimit: Preference by with(preferences) { preferences[Settings.RECENT_PLAYLIST_LIMIT].map { Preference( - title = Text(R.string.recent_playlist_size), - summery = Text(R.string.recent_playlist_size_summery), + title = Text(R.string.pref_recent_playlist_size), + summery = Text(R.string.pref_recent_playlist_size_summery), value = it ) }.asComposeState() @@ -102,8 +102,8 @@ class SettingsViewModel @Inject constructor( override val fetchArtworkFromMS: Preference by with(preferences) { preferences[Settings.USE_LEGACY_ARTWORK_METHOD].map { Preference( - title = Text(R.string.fetch_artwork_from_mediastore), - summery = Text(R.string.fetch_artwork_from_mediastore_summery), + title = Text(R.string.pref_fetch_artwork_from_mediastore), + summery = Text(R.string.pref_fetch_artwork_from_mediastore_summery), value = it ) }.asComposeState() @@ -112,8 +112,8 @@ class SettingsViewModel @Inject constructor( override val enableTrashCan: Preference by with(preferences) { preferences[Settings.TRASH_CAN_ENABLED].map { Preference( - title = Text(R.string.enable_trash_can), - summery = Text(R.string.enable_trash_can_summery, isHtml = true), + title = Text(R.string.pref_enable_trash_can), + summery = Text(R.string.pref_enable_trash_can_summery, isHtml = true), value = it ) }.asComposeState() @@ -121,8 +121,8 @@ class SettingsViewModel @Inject constructor( override val excludedFiles: Preference?> by with(preferences) { preferences[Settings.BLACKLISTED_FILES].map { Preference( - title = Text(R.string.blacklist), - summery = Text(R.string.blacklist_summery), + title = Text(R.string.pref_blacklist), + summery = Text(R.string.pref_blacklist_summery), value = it ) }.asComposeState() @@ -130,8 +130,8 @@ class SettingsViewModel @Inject constructor( override val gaplessPlayback: Preference by with(preferences) { preferences[Settings.TRASH_CAN_ENABLED].map { Preference( - title = Text(R.string.enable_gapless_playback), - summery = Text(R.string.enable_gapless_playback_summery), + title = Text(R.string.pref_enable_gapless_playback), + summery = Text(R.string.pref_enable_gapless_playback_summery), value = it ) }.asComposeState() @@ -139,8 +139,8 @@ class SettingsViewModel @Inject constructor( override val crossfadeTime: Preference by with(preferences) { preferences[Settings.RECENT_PLAYLIST_LIMIT].map { Preference( - title = Text(R.string.crossfade_time), - summery = Text(R.string.crossfade_time_summery), + title = Text(R.string.pref_crossfade_time), + summery = Text(R.string.pref_crossfade_time_summery), value = it ) }.asComposeState() @@ -162,7 +162,7 @@ class SettingsViewModel @Inject constructor( val res = blacklist.remove(path) val name = PathUtils.name(path) if (res) - Toast.makeText(context, "$name has been successfully removed from blacklist", Toast.LENGTH_SHORT).show() + Toast.makeText(context, context.getString(R.string.msg_blacklist_item_remove_success_s, name), Toast.LENGTH_SHORT).show() else Toast.makeText(context, R.string.error, Toast.LENGTH_SHORT).show() preferences[Settings.BLACKLISTED_FILES] = blacklist diff --git a/app/src/main/java/com/prime/media/library/Library.kt b/app/src/main/java/com/prime/media/library/Library.kt index b93ee35..ad94ff7 100644 --- a/app/src/main/java/com/prime/media/library/Library.kt +++ b/app/src/main/java/com/prime/media/library/Library.kt @@ -1,4 +1,5 @@ @file:Suppress("CrossfadeLabel", "FunctionName") +@file:OptIn(ExperimentalTextApi::class, ExperimentalTextApi::class) package com.prime.media.library @@ -28,14 +29,11 @@ import androidx.compose.material.TopAppBar import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Folder import androidx.compose.material.icons.outlined.Album -import androidx.compose.material.icons.outlined.Audiotrack import androidx.compose.material.icons.outlined.FavoriteBorder -import androidx.compose.material.icons.outlined.Folder import androidx.compose.material.icons.outlined.Grain import androidx.compose.material.icons.outlined.GraphicEq import androidx.compose.material.icons.outlined.NavigateNext import androidx.compose.material.icons.outlined.Person -import androidx.compose.material.icons.outlined.PlaylistAdd import androidx.compose.material.icons.outlined.PlaylistPlay import androidx.compose.material.icons.twotone.Settings import androidx.compose.runtime.Composable @@ -49,8 +47,10 @@ import androidx.compose.ui.draw.scale import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.ExperimentalTextApi import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.BaselineShift @@ -64,6 +64,7 @@ import com.prime.media.R import com.prime.media.caption2 import com.prime.media.core.ContentElevation import com.prime.media.core.ContentPadding +import com.prime.media.core.billing.Banner import com.prime.media.core.billing.purchased import com.prime.media.core.compose.Image import com.prime.media.core.compose.KenBurns @@ -91,12 +92,13 @@ import com.prime.media.small2 import com.primex.core.gradient import com.primex.core.padding import com.primex.core.rememberState -import com.primex.core.stringHtmlResource +import com.primex.core.textResource import com.primex.core.withSpanStyle import com.primex.material2.IconButton import com.primex.material2.Label import com.primex.material2.OutlinedButton2 import com.primex.material2.Search +import com.primex.material2.Text private const val TAG = "Library" @@ -210,7 +212,7 @@ private fun TopBar(modifier: Modifier = Modifier) { // Formatted as html resource. title = { Text( - text = stringHtmlResource(id = R.string.title_audio_library_html), + text = textResource(id = R.string.library_title), style = Material.typography.h5, fontWeight = FontWeight.Light ) @@ -316,34 +318,34 @@ private fun Shortcuts( Shortcut( onAction = { navigator.navigate(Folders.direction()) }, icon = Icons.Default.Folder, - label = "Folders" + label = textResource(id = R.string.folders) ) Shortcut( onAction = { navigator.navigate(Genres.direction()) }, icon = Icons.Outlined.Grain, - label = "Genres" + label = textResource(id = R.string.genres) ) Shortcut( onAction = { navigator.navigate(Audios.direction(Audios.GET_EVERY)) }, icon = Icons.Outlined.GraphicEq, - label = "Audios" + label = textResource(id =R.string.audios) ) Shortcut( onAction = { navigator.navigate(Artists.direction()) }, icon = Icons.Outlined.Person, - label = "Artists" + label = textResource(id =R.string.artists) ) Shortcut( onAction = { navigator.navigate(Members.direction(Playback.PLAYLIST_FAVOURITE)) }, icon = Icons.Outlined.FavoriteBorder, - label = "Favourite" + label = textResource(id =R.string.favourite) ) Shortcut( onAction = { navigator.navigate(Playlists.direction()) }, icon = Icons.Outlined.PlaylistPlay, - label = "Playlists" + label = textResource(id = R.string.playlists) ) } ) @@ -401,7 +403,7 @@ private fun Tile( ) Text( - text = "Albums".uppercase(), + text = textResource(id = R.string.albums).toString().uppercase(), fontWeight = FontWeight.SemiBold, modifier = Modifier.padding(start = ContentPadding.normal), letterSpacing = 6.sp, @@ -539,12 +541,14 @@ private val OFFSET_Y_SEARCH = (-32).dp fun Library( viewModel: Library ) { + val res = LocalContext.current.resources + val purchase by purchase(id = BuildConfig.IAP_NO_ADS) Surface( modifier = Modifier.fillMaxSize(), color = Material.colors.background, content = { val navigator = LocalNavController.current - LazyColumn() { + LazyColumn(horizontalAlignment = Alignment.CenterHorizontally) { // The TopBar. // TODO: Maybe make it collapsable. TopBar(Modifier.statusBarsPadding()) @@ -562,8 +566,8 @@ fun Library( .fillMaxWidth() .offset(y = OFFSET_Y_SEARCH) .padding(horizontal = ContentPadding.medium), - title = "Shortcuts", - subtitle = "The faster way to get things done.", + title = res.getString(R.string.library_shortcuts), + subtitle = res.getString(R.string.library_shortcuts_tag_line), ) Shortcuts( @@ -575,14 +579,23 @@ fun Library( vertical = ContentPadding.small ) ) + + if (!purchase.purchased) + item { + Banner( + placementID = BuildConfig.PLACEMENT_BANNER_1, + modifier = Modifier.padding(ContentPadding.medium).offset(y = OFFSET_Y_SEARCH) + ) + } + // Recents. Header( modifier = Modifier .fillMaxWidth() .offset(y = OFFSET_Y_SEARCH) .padding(horizontal = ContentPadding.medium), - title = "Recent", - subtitle = "The recently played tracks.", + title = res.getString(R.string.library_recent), + subtitle = res.getString(R.string.library_recent_tag_line), onClick = { navigator.navigate(Members.direction(Playback.PLAYLIST_RECENT)) } ) @@ -608,8 +621,8 @@ fun Library( .fillMaxWidth() .offset(y = OFFSET_Y_SEARCH) .padding(horizontal = ContentPadding.medium), - title = "Recently Added", - subtitle = "The tracks that have been recently added", + title = res.getString(R.string.library_recently_added), + subtitle = res.getString(R.string.library_recently_added_tag_line), onClick = { navigator.navigate( Audios.direction( diff --git a/app/src/main/java/com/prime/media/settings/Blacklist.kt b/app/src/main/java/com/prime/media/settings/Blacklist.kt index 4540fab..7f19e49 100644 --- a/app/src/main/java/com/prime/media/settings/Blacklist.kt +++ b/app/src/main/java/com/prime/media/settings/Blacklist.kt @@ -73,7 +73,7 @@ private fun Blacklist( true -> Placeholder( title = "Empty", iconResId = R.raw.lt_empty_box, - message = stringResource(R.string.blacklist_empty_msg) + message = stringResource(R.string.blacklist_empty_desc) ) // Show actual list else -> LazyColumn() { @@ -96,7 +96,7 @@ fun Toolbar( modifier: Modifier = Modifier ) { TopAppBar( - title = { Label(text = stringResource(id = R.string.blacklist)) }, + title = { Label(text = stringResource(id = R.string.pref_blacklist)) }, modifier = modifier, actions = { IconButton(imageVector = Icons.Outlined.Close, onClick = onDismissRequest) }, navigationIcon = { diff --git a/app/src/main/java/com/prime/media/settings/Settings.kt b/app/src/main/java/com/prime/media/settings/Settings.kt index b02aa57..4d8610f 100644 --- a/app/src/main/java/com/prime/media/settings/Settings.kt +++ b/app/src/main/java/com/prime/media/settings/Settings.kt @@ -1,3 +1,5 @@ +@file:OptIn(ExperimentalTextApi::class) + package com.prime.media.settings import android.content.Intent @@ -51,6 +53,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.ExperimentalTextApi import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import com.prime.media.BuildConfig @@ -73,6 +76,7 @@ import com.primex.core.drawHorizontalDivider import com.primex.core.rememberState import com.primex.core.stringHtmlResource import com.primex.core.stringResource +import com.primex.core.textResource import com.primex.core.value import com.primex.material2.DropDownPreference import com.primex.material2.IconButton @@ -80,6 +84,7 @@ import com.primex.material2.Label import com.primex.material2.ListTile import com.primex.material2.Preference import com.primex.material2.SwitchPreference +import com.primex.material2.Text import com.primex.material2.neumorphic.NeumorphicTopAppBar private const val TAG = "Settings" @@ -115,7 +120,7 @@ private fun TopAppBar( private val RESERVE_PADDING = 56.dp @Composable -private inline fun PrefHeader(text: String) { +private inline fun PrefHeader(text: CharSequence) { val primary = MaterialTheme.colors.secondary Label( text = text, @@ -209,22 +214,22 @@ private inline fun ColumnScope.Body( private inline fun ColumnScope.FeedBack() { val facade = LocalSystemFacade.current Preference( - title = stringResource(R.string.feedback), - summery = stringResource(id = R.string.feedback_dialog_placeholder) + "\nTap to open feedback dialog.", + title = stringResource(R.string.pref_feedback), + summery = stringResource(id = R.string.pref_feedback_summery) + "\nTap to open feedback dialog.", icon = Icons.Outlined.Feedback, modifier = Modifier.clickable { facade.launchAppStore() } ) Preference( - title = stringResource(R.string.rate_us), - summery = stringResource(id = R.string.review_msg), + title = stringResource(R.string.pref_rate_us), + summery = stringResource(id = R.string.pref_review_summery), icon = Icons.Outlined.Star, modifier = Modifier.clickable { facade.launchAppStore() } ) Preference( - title = stringResource(R.string.spread_the_word), - summery = stringResource(R.string.spread_the_word_summery), + title = stringResource(R.string.pref_spread_the_word), + summery = stringResource(R.string.pref_spread_the_word_summery), icon = Icons.Outlined.Share, modifier = Modifier.clickable { facade.shareApp() } ) @@ -234,7 +239,7 @@ private inline fun ColumnScope.FeedBack() { private inline fun ColumnScope.AboutUs() { val provider = LocalSystemFacade.current Text( - text = stringHtmlResource(R.string.about_us_desc), + text = stringHtmlResource(R.string.pref_about_us_summery), style = MaterialTheme.typography.body2, modifier = Modifier .padding(start = RESERVE_PADDING, end = ContentPadding.xLarge) @@ -350,18 +355,20 @@ private fun GetToKnowUs(modifier: Modifier = Modifier) { modifier = modifier.offset(x = ContentPadding.normal), color = Color.Transparent, overline = { - com.primex.material2.Text( - text = "Audiofy", - style = Material.typography.h4, - fontWeight = FontWeight.Bold + Text( + text = textResource(id = R.string.app_name), + style = Material.typography.h3, + fontWeight = FontWeight.Bold, + fontFamily = Settings.DancingScriptFontFamily ) }, headline = { Text( - text = "v" + BuildConfig.VERSION_NAME + " by Zakir Sheikh", + text = textResource(R.string.pref_get_to_know_us_subttile_s, BuildConfig.VERSION_NAME), style = Material.typography.caption ) }, + centerAlign = true, leading = { Icon( painter = painterResource(id = R.drawable.ic_launcher_foreground), @@ -384,28 +391,28 @@ private fun GetToKnowUs(modifier: Modifier = Modifier) { imageVector = Icons.Outlined.AlternateEmail, onClick = { ctx.startActivity(FeedbackIntent) }, modifier = Modifier - .scale(0.7f) + .scale(0.85f) .border(ButtonDefaults.outlinedBorder, CircleShape) ) IconButton( imageVector = Icons.Outlined.DataObject, onClick = { ctx.startActivity(GithubIntent) }, modifier = Modifier - .scale(0.7f) + .scale(0.85f) .border(ButtonDefaults.outlinedBorder, CircleShape) ) IconButton( imageVector = Icons.Outlined.BugReport, onClick = { ctx.startActivity(GitHubIssuesPage) }, modifier = Modifier - .scale(0.7f) + .scale(0.85f) .border(ButtonDefaults.outlinedBorder, CircleShape) ) IconButton( imageVector = Icons.Outlined.SupportAgent, onClick = { ctx.startActivity(TelegramIntent) }, modifier = Modifier - .scale(0.7f) + .scale(0.85f) .border(ButtonDefaults.outlinedBorder, CircleShape) ) } @@ -422,14 +429,14 @@ private fun Compact(state: Settings) { .padding(it) .verticalScroll(rememberScrollState()) ) { - PrefHeader(text = "Get to Know Us") + PrefHeader(text = textResource(R.string.pref_get_to_know_us)) GetToKnowUs(modifier = Modifier.padding(start = ContentPadding.normal)) Body(state) - PrefHeader(text = "General") + PrefHeader(text = textResource(R.string.general)) General(state = state) - PrefHeader(text = "Feedback") + PrefHeader(text = textResource(R.string.feedback)) FeedBack() - PrefHeader(text = stringResource(R.string.about_us)) + PrefHeader(text = textResource(R.string.about_us)) AboutUs() // Add the necessary padding. val padding = LocalWindowPadding.current diff --git a/app/src/main/java/com/prime/media/settings/ViewState.kt b/app/src/main/java/com/prime/media/settings/ViewState.kt index b3dd0df..81ac1e3 100644 --- a/app/src/main/java/com/prime/media/settings/ViewState.kt +++ b/app/src/main/java/com/prime/media/settings/ViewState.kt @@ -78,7 +78,8 @@ interface Settings : Blacklist { */ val MINI_PLAYER_HEIGHT = 68.dp - val LatoFontFamily = FontFamily("Roboto") + val DefaultFontFamily = FontFamily("Roboto") + val DancingScriptFontFamily = FontFamily("Dancing Script") /** * Retrieves/Sets The [NightMode] Strategy diff --git a/app/src/main/res/values-night/theme.xml b/app/src/main/res/values-night/theme.xml index 22ab607..0aba940 100644 --- a/app/src/main/res/values-night/theme.xml +++ b/app/src/main/res/values-night/theme.xml @@ -1,10 +1,10 @@ - +