Author SHA1 Message Date
Illusion 2063673a0d add german language in the config and gradle files 2024-07-27 22:06:35 +02:00
Sv443andIllusion 88866f61c8 feat: fastlane metadata chungus in german 2024-07-27 22:06:35 +02:00
Sv443andIllusion 773e0fa657 feat: german translation 2024-07-27 22:06:35 +02:00
Illusion 78a97cdc41 v1.1.0 release 2024-07-18 01:07:33 +02:00
Illusion d2b4cbb535 feat: setting to keep screen on 2024-07-16 06:50:36 +02:00
29 changed files with 236 additions and 110 deletions
-2
View File
@@ -1,4 +1,3 @@
*.iml
.gradle .gradle
/local.properties /local.properties
/.idea/caches /.idea/caches
@@ -7,7 +6,6 @@
/.idea/workspace.xml /.idea/workspace.xml
/.idea/navEditor.xml /.idea/navEditor.xml
/.idea/assetWizardSettings.xml /.idea/assetWizardSettings.xml
.DS_Store
/build /build
/captures /captures
.externalNativeBuild .externalNativeBuild
+3 -3
View File
@@ -22,8 +22,8 @@ android {
applicationId = "com.illusionman1212.lyricsgrabbr" applicationId = "com.illusionman1212.lyricsgrabbr"
minSdk = 23 minSdk = 23
targetSdk = 34 targetSdk = 34
versionCode = 6 versionCode = 7
versionName = "1.0.0" versionName = "1.1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables { vectorDrawables {
@@ -32,7 +32,7 @@ android {
signingConfig = signingConfigs.getByName("debug") signingConfig = signingConfigs.getByName("debug")
// https://developer.android.com/guide/topics/resources/app-languages#gradle-config // https://developer.android.com/guide/topics/resources/app-languages#gradle-config
resourceConfigurations.plus(listOf("en", "ar")) resourceConfigurations.plus(listOf("en", "ar", "de"))
} }
signingConfigs { signingConfigs {
@@ -5,7 +5,6 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
@@ -127,6 +126,7 @@ class MainActivity : AppCompatActivity() {
navController.popBackStack() navController.popBackStack()
}, },
lyricsViewModel = lyricsViewModel, lyricsViewModel = lyricsViewModel,
settingsViewModel = settingsViewModel
) )
} }
composable(Routes.Settings.route) { composable(Routes.Settings.route) {
@@ -2,6 +2,7 @@ package com.illusionman1212.lyricsgrabbr.data
import androidx.datastore.core.DataStore import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringSetPreferencesKey import androidx.datastore.preferences.core.stringSetPreferencesKey
@@ -16,6 +17,7 @@ enum class Theme {
data class SettingsPreferences( data class SettingsPreferences(
val appTheme: Int = Theme.SYSTEM.ordinal, val appTheme: Int = Theme.SYSTEM.ordinal,
val whitelist: Set<String> = emptySet(), val whitelist: Set<String> = emptySet(),
val keepScreenOn: Boolean = false,
) )
class SettingsPreferencesRepository( class SettingsPreferencesRepository(
@@ -24,6 +26,7 @@ class SettingsPreferencesRepository(
companion object { companion object {
private val APP_THEME = intPreferencesKey("app_theme") private val APP_THEME = intPreferencesKey("app_theme")
private val WHITELIST = stringSetPreferencesKey("apps_whitelist") private val WHITELIST = stringSetPreferencesKey("apps_whitelist")
private val KEEP_SCREEN_ON = booleanPreferencesKey("keep_screen_on")
} }
val preferences = dataStore.data.map { mapSettingsPreferences(it) } val preferences = dataStore.data.map { mapSettingsPreferences(it) }
@@ -40,6 +43,12 @@ class SettingsPreferencesRepository(
} }
} }
suspend fun toggleKeepScreenOn() {
dataStore.edit { prefs ->
prefs[KEEP_SCREEN_ON] = !(prefs[KEEP_SCREEN_ON] ?: false)
}
}
suspend fun removeFromWhitelist(packageName: String) { suspend fun removeFromWhitelist(packageName: String) {
dataStore.edit { prefs -> dataStore.edit { prefs ->
prefs[WHITELIST] = (prefs[WHITELIST]?.toMutableSet() ?: emptySet()) - packageName prefs[WHITELIST] = (prefs[WHITELIST]?.toMutableSet() ?: emptySet()) - packageName
@@ -50,6 +59,7 @@ class SettingsPreferencesRepository(
return SettingsPreferences( return SettingsPreferences(
prefs[APP_THEME] ?: Theme.SYSTEM.ordinal, prefs[APP_THEME] ?: Theme.SYSTEM.ordinal,
prefs[WHITELIST] ?: emptySet(), prefs[WHITELIST] ?: emptySet(),
prefs[KEEP_SCREEN_ON] ?: false,
) )
} }
} }
@@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.AlertDialogDefaults import androidx.compose.material3.AlertDialogDefaults
import androidx.compose.material3.BasicAlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
@@ -29,11 +30,11 @@ fun LGAlertDialog(
buttons: @Composable () -> Unit, buttons: @Composable () -> Unit,
content: @Composable () -> Unit content: @Composable () -> Unit
) { ) {
AlertDialog( BasicAlertDialog(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
properties = properties, properties = properties
) { ) {
Surface ( Surface(
modifier = Modifier.wrapContentHeight().wrapContentWidth(), modifier = Modifier.wrapContentHeight().wrapContentWidth(),
shape = MaterialTheme.shapes.large, shape = MaterialTheme.shapes.large,
tonalElevation = AlertDialogDefaults.TonalElevation tonalElevation = AlertDialogDefaults.TonalElevation
@@ -13,7 +13,6 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
@@ -58,7 +57,6 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.SpanStyle
@@ -74,6 +72,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogProperties
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.compose.currentStateAsState import androidx.lifecycle.compose.currentStateAsState
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
@@ -1,8 +1,14 @@
package com.illusionman1212.lyricsgrabbr.ui.screens package com.illusionman1212.lyricsgrabbr.ui.screens
import android.app.Activity
import android.view.WindowManager.LayoutParams
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
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.rememberScrollState import androidx.compose.foundation.rememberScrollState
@@ -10,7 +16,7 @@ import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.MusicNote import androidx.compose.material.icons.filled.MusicNote
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
@@ -23,10 +29,12 @@ import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontStyle
@@ -36,12 +44,13 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.illusionman1212.lyricsgrabbr.R import com.illusionman1212.lyricsgrabbr.R
import com.illusionman1212.lyricsgrabbr.ui.components.LGIconButton import com.illusionman1212.lyricsgrabbr.ui.components.LGIconButton
import com.illusionman1212.lyricsgrabbr.utils.mirror
import com.illusionman1212.lyricsgrabbr.viewmodels.LyricsViewModel import com.illusionman1212.lyricsgrabbr.viewmodels.LyricsViewModel
import com.illusionman1212.lyricsgrabbr.viewmodels.SettingsViewModel
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -50,13 +59,27 @@ fun LyricsPage(
lyricsViewModel: LyricsViewModel = viewModel( lyricsViewModel: LyricsViewModel = viewModel(
factory = LyricsViewModel.Factory factory = LyricsViewModel.Factory
), ),
settingsViewModel: SettingsViewModel,
) { ) {
val uiState = lyricsViewModel.uiState.collectAsStateWithLifecycle().value val uiState = lyricsViewModel.uiState.collectAsStateWithLifecycle().value
val settingsState = settingsViewModel.uiState.collectAsStateWithLifecycle().value
val context = LocalContext.current
LaunchedEffect(uiState.song, uiState.artist, uiState.url) { LaunchedEffect(uiState.song, uiState.artist, uiState.url) {
lyricsViewModel.fetchLyricsFromGenius() lyricsViewModel.fetchLyricsFromGenius()
} }
DisposableEffect(Unit) {
val window = (context as Activity).window
if (settingsState.keepScreenOn) {
window.addFlags(LayoutParams.FLAG_KEEP_SCREEN_ON)
}
onDispose {
window.clearFlags(LayoutParams.FLAG_KEEP_SCREEN_ON)
}
}
Scaffold( Scaffold(
topBar = { topBar = {
TopAppBar( TopAppBar(
@@ -82,8 +105,7 @@ fun LyricsPage(
onClick = goBack onClick = goBack
) { ) {
Icon( Icon(
modifier = Modifier.mirror(), imageVector = Icons.AutoMirrored.Filled.ArrowBack,
imageVector = Icons.Filled.ArrowBack,
contentDescription = stringResource( contentDescription = stringResource(
id = R.string.go_back id = R.string.go_back
) )
@@ -93,9 +115,19 @@ fun LyricsPage(
) )
}, },
) { padding -> ) { padding ->
Column(Modifier.padding(padding)) {
if (settingsState.keepScreenOn) {
Row(
Modifier
.background(MaterialTheme.colorScheme.secondaryContainer)
.fillMaxWidth(),
horizontalArrangement = Arrangement.Center,
) {
Text(stringResource(id = R.string.screen_will_stay_on).uppercase(), fontSize = 12.sp, color = MaterialTheme.colorScheme.onSecondaryContainer)
}
}
Column( Column(
Modifier Modifier
.padding(padding)
.fillMaxSize() .fillMaxSize()
.then( .then(
if (!uiState.isLoading && uiState.lyrics.isNotEmpty()) Modifier.verticalScroll( if (!uiState.isLoading && uiState.lyrics.isNotEmpty()) Modifier.verticalScroll(
@@ -117,7 +149,6 @@ fun LyricsPage(
} else if (uiState.lyrics.isEmpty()) { } else if (uiState.lyrics.isEmpty()) {
Instrumental() Instrumental()
} else { } else {
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
Column( Column(
Modifier.padding( Modifier.padding(
@@ -147,6 +178,7 @@ fun LyricsPage(
} }
} }
} }
}
} }
@Composable @Composable
@@ -18,6 +18,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Apps import androidx.compose.material.icons.filled.Apps
import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.ScreenLockPortrait
import androidx.compose.material.icons.outlined.Palette import androidx.compose.material.icons.outlined.Palette
import androidx.compose.material.icons.outlined.Translate import androidx.compose.material.icons.outlined.Translate
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
@@ -34,7 +35,6 @@ import androidx.compose.runtime.setValue
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.alpha import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@@ -97,12 +97,13 @@ fun SettingsPage(
) { ) {
Appearance(viewModel, uiState) Appearance(viewModel, uiState)
Listening(navigateToWhitelist) Listening(navigateToWhitelist)
PowerManagement(viewModel, uiState)
} }
} }
} }
@Composable @Composable
fun Appearance(viewModel: SettingsViewModel, uiState: SettingsState) { private fun Appearance(viewModel: SettingsViewModel, uiState: SettingsState) {
var themeOpenDialog by remember { mutableStateOf(false) } var themeOpenDialog by remember { mutableStateOf(false) }
var languageOpenDialog by remember { mutableStateOf(false) } var languageOpenDialog by remember { mutableStateOf(false) }
@@ -170,6 +171,20 @@ private fun Listening(navigateToWhitelist: () -> Unit) {
} }
} }
@Composable
private fun PowerManagement(viewModel: SettingsViewModel, uiState: SettingsState) {
SettingGroup(title = stringResource(id = R.string.power_management)) {
ToggleSetting(
title = stringResource(id = R.string.keep_device_awake_title),
description = stringResource(id = R.string.keep_device_awake_desc),
icon = Icons.Default.ScreenLockPortrait,
checked = uiState.keepScreenOn
) {
viewModel.toggleKeepScreenOn()
}
}
}
@Composable @Composable
fun ThemeDialog( fun ThemeDialog(
uiState: SettingsState, uiState: SettingsState,
@@ -311,7 +326,8 @@ fun DialogSetting(
@Composable @Composable
fun ToggleSetting( fun ToggleSetting(
title: String, title: String,
icon: Painter? = null, description: String? = null,
icon: ImageVector? = null,
checked: Boolean, checked: Boolean,
onClick: (Boolean) -> Unit) onClick: (Boolean) -> Unit)
{ {
@@ -326,11 +342,20 @@ fun ToggleSetting(
modifier = Modifier.padding(top = 8.dp, end = 24.dp, bottom = 8.dp), modifier = Modifier.padding(top = 8.dp, end = 24.dp, bottom = 8.dp),
) { ) {
if (icon != null) { if (icon != null) {
Icon(painter = icon, contentDescription = null, Modifier.width(56.dp)) Icon(imageVector = icon, contentDescription = null, Modifier.width(56.dp))
} else { } else {
Box(modifier = Modifier.width(56.dp)) Box(modifier = Modifier.width(56.dp))
} }
Text(text = title, color = MaterialTheme.colorScheme.onBackground, modifier = Modifier.weight(1.0f)) Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp)) {
Text(text = title, color = MaterialTheme.colorScheme.onBackground)
if (description != null) {
Text(
text = description,
color = ColorSecondaryLight,
fontSize = 14.sp,
)
}
}
Switch( Switch(
checked = checked, checked = checked,
onCheckedChange = null, onCheckedChange = null,
@@ -1,16 +0,0 @@
package com.illusionman1212.lyricsgrabbr.utils
import android.util.LayoutDirection
import androidx.compose.runtime.Stable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.core.text.layoutDirection
import java.util.Locale
@Stable
fun Modifier.mirror(): Modifier {
return if (Locale.getDefault().layoutDirection == LayoutDirection.RTL)
this.scale(scaleX = -1f, scaleY = 1f)
else
this
}
@@ -25,7 +25,7 @@ fun annotatedStringResource(
val spannedString = SpannedString(resources.getText(id)) val spannedString = SpannedString(resources.getText(id))
val resultBuilder = AnnotatedString.Builder() val resultBuilder = AnnotatedString.Builder()
resultBuilder.append(spannedString.toString()) resultBuilder.append(spannedString.toString())
spannedString.getSpans<Annotation>(0, spannedString.length, Annotation::class.java).forEach { annotation -> spannedString.getSpans(0, spannedString.length, Annotation::class.java).forEach { annotation ->
val spanStart = spannedString.getSpanStart(annotation) val spanStart = spannedString.getSpanStart(annotation)
val spanEnd = spannedString.getSpanEnd(annotation) val spanEnd = spannedString.getSpanEnd(annotation)
resultBuilder.addStringAnnotation( resultBuilder.addStringAnnotation(
@@ -96,7 +96,9 @@ class HomeViewModel(private val homeRepository: HomeRepository): ViewModel() {
} }
fun setSong(song: NotificationEvent) { fun setSong(song: NotificationEvent) {
_uiState.value = _uiState.value.copy(isLoading = true, notification = song, error = null) _uiState.update { state ->
state.copy(isLoading = true, notification = song, error = null)
}
} }
fun makeRequestToGenius(song: String, artist: String) { fun makeRequestToGenius(song: String, artist: String) {
@@ -41,12 +41,16 @@ class LyricsViewModel(private val lyricsRepository: LyricsRepository): ViewModel
} }
fun fetchLyricsFromGenius() { fun fetchLyricsFromGenius() {
_uiState.value = _uiState.value.copy(isLoading = true, lyrics = "") _uiState.update { state ->
state.copy(isLoading = true, lyrics = "")
}
viewModelScope.launch { viewModelScope.launch {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
val lyrics = lyricsRepository.fetchLyricsFromGenius(uiState.value.url) val lyrics = lyricsRepository.fetchLyricsFromGenius(uiState.value.url)
_uiState.value = _uiState.value.copy(isLoading = false, lyrics = lyrics) _uiState.update { state ->
state.copy(isLoading = false, lyrics = lyrics)
}
} }
} }
} }
@@ -30,6 +30,7 @@ data class SettingsState(
val appTheme: Int = Theme.SYSTEM.ordinal, val appTheme: Int = Theme.SYSTEM.ordinal,
val applications: Map<String, AppInfo> = emptyMap(), val applications: Map<String, AppInfo> = emptyMap(),
val whitelistSearchQuery: String = "", val whitelistSearchQuery: String = "",
val keepScreenOn: Boolean = false,
) )
class SettingsViewModel(private val settingsPrefsRepo: SettingsPreferencesRepository, context: Context): ViewModel() { class SettingsViewModel(private val settingsPrefsRepo: SettingsPreferencesRepository, context: Context): ViewModel() {
@@ -47,6 +48,12 @@ class SettingsViewModel(private val settingsPrefsRepo: SettingsPreferencesReposi
} }
} }
fun toggleKeepScreenOn() {
viewModelScope.launch(Dispatchers.IO) {
settingsPrefsRepo.toggleKeepScreenOn()
}
}
private suspend fun getWhitelistedApps(): Set<String> { private suspend fun getWhitelistedApps(): Set<String> {
return settingsPrefsRepo.preferences.first().whitelist return settingsPrefsRepo.preferences.first().whitelist
} }
@@ -73,10 +80,9 @@ class SettingsViewModel(private val settingsPrefsRepo: SettingsPreferencesReposi
) )
} }
immutablePackages = apps immutablePackages = apps
_uiState.update { _uiState.update { state ->
SettingsState( state.copy(
appTheme = uiState.value.appTheme, applications = apps
applications = apps,
) )
} }
} }
@@ -147,12 +153,15 @@ class SettingsViewModel(private val settingsPrefsRepo: SettingsPreferencesReposi
getPackages(context) getPackages(context)
viewModelScope.launch { viewModelScope.launch {
settingsPrefsRepo.preferences.collectLatest { settingsPrefsRepo.preferences.collectLatest {
_uiState.value = _uiState.value.copy( _uiState.update { state ->
state.copy(
appTheme = it.appTheme, appTheme = it.appTheme,
keepScreenOn = it.keepScreenOn,
) )
} }
} }
} }
}
companion object { companion object {
val Factory: ViewModelProvider.Factory = viewModelFactory { val Factory: ViewModelProvider.Factory = viewModelFactory {
-9
View File
@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M12,2C6.5,2 2,6.5 2,12s4.5,10 10,10s10,-4.5 10,-10S17.5,2 12,2zM16.057,16.406c-0.188,0 -0.282,-0.094 -0.47,-0.188c-1.411,-0.847 -3.198,-1.317 -5.079,-1.317c-1.035,0 -2.163,0.188 -3.104,0.376c-0.188,0 -0.376,0.094 -0.47,0.094c-0.376,0 -0.658,-0.282 -0.658,-0.658c0,-0.376 0.188,-0.658 0.564,-0.658c1.223,-0.282 2.446,-0.47 3.763,-0.47c2.163,0 4.139,0.564 5.832,1.505c0.188,0.188 0.376,0.282 0.376,0.658C16.621,16.218 16.339,16.406 16.057,16.406zM17.091,13.773c-0.188,0 -0.376,-0.094 -0.564,-0.188c-1.599,-1.035 -3.857,-1.599 -6.302,-1.599c-1.223,0 -2.352,0.188 -3.198,0.376c-0.188,0.094 -0.282,0.094 -0.47,0.094c-0.47,0 -0.753,-0.376 -0.753,-0.753c0,-0.47 0.188,-0.658 0.658,-0.847c1.129,-0.282 2.258,-0.564 3.857,-0.564c2.634,0 5.079,0.658 7.149,1.881c0.282,0.188 0.47,0.47 0.47,0.753C17.844,13.396 17.562,13.773 17.091,13.773zM18.314,10.762c-0.188,0 -0.282,-0.094 -0.564,-0.188c-1.881,-1.035 -4.609,-1.693 -7.243,-1.693c-1.317,0 -2.728,0.188 -3.951,0.47c-0.188,0 -0.282,0.094 -0.564,0.094C5.428,9.54 5.051,9.069 5.051,8.505c0,-0.564 0.282,-0.847 0.658,-0.941C7.215,7.188 8.814,7 10.507,7c2.916,0 5.926,0.658 8.278,1.881c0.282,0.188 0.564,0.47 0.564,0.941C19.255,10.386 18.878,10.762 18.314,10.762z"/>
</vector>
+5 -4
View File
@@ -5,7 +5,6 @@
<!-- General --> <!-- General -->
<string name="go_back">رجوع</string> <string name="go_back">رجوع</string>
<string name="cancel">إلغاء</string> <string name="cancel">إلغاء</string>
<string name="confirm">تأكيد</string>
<string name="timeout">لقد انتهت مهلة الطلب، حاول مرة أخرى لاحقًا</string> <string name="timeout">لقد انتهت مهلة الطلب، حاول مرة أخرى لاحقًا</string>
<string name="generic_error">لقد حدث خطأ، حاول مرة أخرى لاحقاً</string> <string name="generic_error">لقد حدث خطأ، حاول مرة أخرى لاحقاً</string>
<string name="retry">أعد المحاولة</string> <string name="retry">أعد المحاولة</string>
@@ -33,16 +32,18 @@
<string name="theme_dark">ليلي</string> <string name="theme_dark">ليلي</string>
<string name="theme_system">استخدم مظهر النظام</string> <string name="theme_system">استخدم مظهر النظام</string>
<string name="language">اللغة</string> <string name="language">اللغة</string>
<string name="_default">الإفتراضي</string> <string name="_default">استخدم لغة النظام</string>
<string name="listening">الإستماع</string> <string name="listening">الإستماع</string>
<string name="whitelist">القائمة البيضاء</string>
<string name="whitelist_apps">تطبيقات القائمة البيضاء</string> <string name="whitelist_apps">تطبيقات القائمة البيضاء</string>
<string name="whitelist_desc">اختر التطبيقات التي سيستمع التطبيق إلى إشعاراتها</string> <string name="whitelist_desc">اختر التطبيقات التي سيستمع التطبيق إلى إشعاراتها</string>
<string name="search">بحث</string> <string name="search">بحث</string>
<string name="clear">مسح</string> <string name="clear">مسح</string>
<string name="power_management">إدارة إستخدام الطافة</string>
<string name="keep_device_awake_title">أبق الجهاز مستيقظا</string>
<string name="keep_device_awake_desc">أبق الجهاز مستيقظا على صفحة كلمات الأغاني (يزيد من استخدام البطارية)</string>
<string name="screen_will_stay_on">ستبقى الشاشة على قيد التشغيل</string>
<!-- Lyrics --> <!-- Lyrics -->
<string name="lyrics">كلمات الأغنية</string>
<string name="instrumental">هذه الأغنية موسيقية</string> <string name="instrumental">هذه الأغنية موسيقية</string>
<!-- Notification --> <!-- Notification -->
+54
View File
@@ -0,0 +1,54 @@
<resources>
<string name="app_name" translatable="false">Lyrics Grabbr</string>
<!-- General -->
<string name="go_back">Zurück</string>
<string name="cancel">Abbrechen</string>
<string name="timeout">Anfrage ist abgelaufen, bitte versuche es später erneut</string>
<string name="generic_error">Ein Fehler ist aufgetreten, bitte versuche es später erneut</string>
<string name="retry">Erneut versuchen</string>
<!-- Home -->
<string name="no_supported_player">Keinen unterstützten Player gefunden</string>
<string name="open_settings">Einstellungen öffnen</string>
<string name="notification_listen_permission">Berechtigung zum Auslesen von Benachrichtigungen</string>
<string name="notification_listen_desc">Diese App benötigt die Berechtigung zum Auslesen von Benachrichtigungen, um ordnungsgemäß zu funktionieren. Bitte erteile diese Berechtigung auf dem nächsten Bildschirm.\nBITTE BEACHTEN: der einzige Weg den Dienst zu stoppen ist die Berechtigung zum Auslesen von Benachrichtigungen zu widerrufen.</string>
<string name="no_results">Keine Ergebnisse gefunden</string>
<string name="found_results">%1$d Ergebnis(se) gefunden</string>
<string name="powered_by">Verwendet <annotation href="https://github.com/sv443/geniURL">geniURL</annotation></string>
<string name="open_song_page">Seite des Songs öffnen</string>
<string name="open_artist_page">Seite des Künstlers öffnen</string>
<string name="notification_post_permission">Berechtigung für Benachrichtigungen erforderlich</string>
<string name="notification_post_permission_desc">Lyrics Grabbr benötigt die Berechtigung Benachrichtigungen zu lesen, um einen Vordergrunddienst zum Abhören zu starten und kann nicht ohne diese funktionieren.</string>
<string name="notification_post_permission_not_granted">Berechtigung zum Abhören von Benachrichtigungen nicht erteilt, daher wird die App wird nicht ordnungsgemäß funktionieren.</string>
<string name="grant_permission">Berechtigung erteilen</string>
<!-- Settings -->
<string name="settings">Einstellungen</string>
<string name="appearance">Aussehen</string>
<string name="theme">Farbschema</string>
<string name="theme_light">Hell</string>
<string name="theme_dark">Dunkel</string>
<string name="theme_system">Systemstandard</string>
<string name="language">Sprache</string>
<string name="_default">Systemsprache</string>
<string name="listening">Erlaubt</string>
<string name="whitelist_apps">Erlaubte Apps</string>
<string name="whitelist_desc">Wähle aus, welchen Apps Lyrics Grabbr zuhören soll</string>
<string name="search">Suche</string>
<string name="clear">Löschen</string>
<string name="power_management">Energieeinstellungen</string>
<string name="keep_device_awake_title">Gerät wachhalten</string>
<string name="keep_device_awake_desc">Gerät auf der Songtext-Seite wachhalten (erhöht den Batterieverbrauch)</string>
<string name="screen_will_stay_on">Bildschirm bleibt an</string>
<!-- Lyrics -->
<string name="instrumental">Dies ist ein instrumentaler Song</string>
<!-- Notification -->
<string name="service_running">Dienst läuft</string>
<string name="stop_service">Dienst anhalten</string>
<string name="service_notif_desc_init">Spiele Songs mit einem unterstützten Player, um Songtexte zu erhalten</string>
<string name="service_notif_desc_playing">Für den Songtext antippen</string>
<string name="now_playing">Es läuft %1$s von %2$s</string>
</resources>
+5 -4
View File
@@ -4,7 +4,6 @@
<!-- General --> <!-- General -->
<string name="go_back">Go Back</string> <string name="go_back">Go Back</string>
<string name="cancel">Cancel</string> <string name="cancel">Cancel</string>
<string name="confirm">Confirm</string>
<string name="timeout">Request has timed out, try again later</string> <string name="timeout">Request has timed out, try again later</string>
<string name="generic_error">An error has occurred, try again later</string> <string name="generic_error">An error has occurred, try again later</string>
<string name="retry">Retry</string> <string name="retry">Retry</string>
@@ -32,16 +31,18 @@
<string name="theme_dark">Dark</string> <string name="theme_dark">Dark</string>
<string name="theme_system">Use System Theme</string> <string name="theme_system">Use System Theme</string>
<string name="language">Language</string> <string name="language">Language</string>
<string name="_default">Default</string> <string name="_default">Use System Language</string>
<string name="listening">Listening</string> <string name="listening">Listening</string>
<string name="whitelist">Whitelist</string>
<string name="whitelist_apps">Whitelist Apps</string> <string name="whitelist_apps">Whitelist Apps</string>
<string name="whitelist_desc">Choose which apps Lyrics Grabbr will listen to</string> <string name="whitelist_desc">Choose which apps Lyrics Grabbr will listen to</string>
<string name="search">Search</string> <string name="search">Search</string>
<string name="clear">Clear</string> <string name="clear">Clear</string>
<string name="power_management">Power Management</string>
<string name="keep_device_awake_title">Keep device awake</string>
<string name="keep_device_awake_desc">Keep device awake on lyrics page (Increases battery usage)</string>
<string name="screen_will_stay_on">Screen Will Stay On</string>
<!-- Lyrics --> <!-- Lyrics -->
<string name="lyrics">Lyrics</string>
<string name="instrumental">This song is an instrumental</string> <string name="instrumental">This song is an instrumental</string>
<!-- Notification --> <!-- Notification -->
+1
View File
@@ -2,4 +2,5 @@
<locale-config xmlns:android="http://schemas.android.com/apk/res/android"> <locale-config xmlns:android="http://schemas.android.com/apk/res/android">
<locale android:name="en" /> <locale android:name="en" />
<locale android:name="ar" /> <locale android:name="ar" />
<locale android:name="de" />
</locale-config> </locale-config>
@@ -0,0 +1,2 @@
## Veröffentlichung auf F-droid
Initiale Veröffentlichung auf F-droid
@@ -0,0 +1,2 @@
- App mit Kotlin und Jetpack Compose neu geschrieben
- Möglichkeit hinzugefügt, Spotify für Songtexte zu verwenden
@@ -0,0 +1,4 @@
- Eine Whitelist von Apps ist jetzt erforderlich, damit die App Benachrichtigungen von ihnen abrufen kann
- Spotify wurde aufgrund des nicht-FOSS-SDKs vollständig entfernt
- Spracheinstellungen (Hilfe bei Übersetzungen ist sehr willkommen)
- Einstellung hinzugefügt, um das Gerät wach zu halten, während Songtexte angezeigt werden
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 583 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

@@ -0,0 +1 @@
Lyrics Grabbr bietet Songtexte für das aktuell abgespielte Lied anhand von Benachrichtigungen an
@@ -0,0 +1 @@
Lyrics Grabbr
@@ -0,0 +1,4 @@
- A whitelist of apps is now required in order for the app to pick up on notifications from them
- Completely remove Spotify due to non-FOSS SDK
- Language settings (help with translations is much appreciated)
- Added a setting to keep the device awake when reading lyrics
Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 294 KiB