mirror of
https://github.com/IllusionMan1212/lyrics-grabbr.git
synced 2026-10-24 02:12:27 +00:00
feat: added setting to configure custom API endpoint
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
<application
|
||||
android:name=".LGApp"
|
||||
android:allowBackup="true"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:localeConfig="@xml/locales_config"
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.illusionman1212.lyricsgrabbr.data
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import com.illusionman1212.lyricsgrabbr.R
|
||||
import com.illusionman1212.lyricsgrabbr.data.network.GET
|
||||
@@ -32,11 +33,9 @@ class HomeRepository(private val context: Context) {
|
||||
return pkgs.contains(packageName)
|
||||
}
|
||||
|
||||
suspend fun makeSearchRequest(lContext: Context, song: String, artist: String): Pair<String?, Boolean> {
|
||||
val builder = Uri.Builder()
|
||||
val url = builder.scheme("https")
|
||||
.authority("api.illusionman1212.com")
|
||||
.appendPath("lyrics")
|
||||
suspend fun makeSearchRequest(lContext: Context, baseUrl: String, song: String, artist: String): Pair<String?, Boolean> {
|
||||
val url = Uri.parse(baseUrl)
|
||||
.buildUpon()
|
||||
.appendPath("search")
|
||||
.appendQueryParameter("q", "$song $artist")
|
||||
.appendQueryParameter("disableFuzzy", "true")
|
||||
@@ -76,7 +75,7 @@ class HomeRepository(private val context: Context) {
|
||||
return Pair(lContext.resources.getString(R.string.timeout), false)
|
||||
}
|
||||
|
||||
return Pair(lContext.resources.getString(R.string.generic_error), false)
|
||||
return Pair(e.message, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -5,6 +5,7 @@ import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.intPreferencesKey
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.core.stringSetPreferencesKey
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
@@ -19,6 +20,7 @@ data class SettingsPreferences(
|
||||
val whitelist: Set<String> = emptySet(),
|
||||
val keepScreenOn: Boolean = false,
|
||||
val whitelistPromptSeen: Boolean = false,
|
||||
val geniURLbaseURL: String = "https://api.illusionman1212.com/lyrics",
|
||||
)
|
||||
|
||||
class SettingsPreferencesRepository(
|
||||
@@ -29,6 +31,7 @@ class SettingsPreferencesRepository(
|
||||
private val WHITELIST = stringSetPreferencesKey("apps_whitelist")
|
||||
private val KEEP_SCREEN_ON = booleanPreferencesKey("keep_screen_on")
|
||||
private val WHITELIST_PROMPT_SEEN = booleanPreferencesKey("whitelist_prompt_seen")
|
||||
private val GENIURL_BASE_URL = stringPreferencesKey("geniurl_base_url")
|
||||
}
|
||||
|
||||
val preferences = dataStore.data.map { mapSettingsPreferences(it) }
|
||||
@@ -63,12 +66,19 @@ class SettingsPreferencesRepository(
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun setGeniURLBaseURL(url: String) {
|
||||
dataStore.edit { prefs ->
|
||||
prefs[GENIURL_BASE_URL] = url
|
||||
}
|
||||
}
|
||||
|
||||
private fun mapSettingsPreferences(prefs: Preferences): SettingsPreferences {
|
||||
return SettingsPreferences(
|
||||
prefs[APP_THEME] ?: Theme.SYSTEM.ordinal,
|
||||
prefs[WHITELIST] ?: emptySet(),
|
||||
prefs[KEEP_SCREEN_ON] ?: false,
|
||||
prefs[WHITELIST_PROMPT_SEEN] ?: false,
|
||||
prefs[GENIURL_BASE_URL] ?: "https://api.illusionman1212.com/lyrics",
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.illusionman1212.lyricsgrabbr.ui.screens
|
||||
|
||||
import android.util.Patterns
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@@ -19,6 +20,7 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Apps
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material.icons.filled.ScreenLockPortrait
|
||||
import androidx.compose.material.icons.outlined.Cloud
|
||||
import androidx.compose.material.icons.outlined.Palette
|
||||
import androidx.compose.material.icons.outlined.Translate
|
||||
import androidx.compose.material3.Icon
|
||||
@@ -27,6 +29,7 @@ import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -96,6 +99,7 @@ fun SettingsPage(
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
Appearance(viewModel, uiState)
|
||||
geniURL(viewModel, uiState)
|
||||
Listening(navigateToWhitelist)
|
||||
PowerManagement(viewModel, uiState)
|
||||
}
|
||||
@@ -185,6 +189,63 @@ private fun PowerManagement(viewModel: SettingsViewModel, uiState: SettingsState
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun geniURL(viewModel: SettingsViewModel, uiState: SettingsState) {
|
||||
var dialogOpen by remember { mutableStateOf(false) }
|
||||
|
||||
SettingGroup(title = "geniURL") {
|
||||
DialogSetting(
|
||||
title = stringResource(id = R.string.api_base_url),
|
||||
value = uiState.geniURLbaseURL,
|
||||
icon = Icons.Outlined.Cloud,
|
||||
onClick = { dialogOpen = true }
|
||||
)
|
||||
}
|
||||
|
||||
if (dialogOpen) {
|
||||
BaseURLDialog(
|
||||
uiState = uiState,
|
||||
viewModel = viewModel,
|
||||
onDismiss = { dialogOpen = false },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BaseURLDialog(uiState: SettingsState, viewModel: SettingsViewModel, onDismiss: () -> Unit) {
|
||||
var value by remember { mutableStateOf(uiState.geniURLbaseURL) }
|
||||
var isValidUrl by remember { mutableStateOf(true) }
|
||||
|
||||
LGAlertDialog(
|
||||
onDismiss = onDismiss,
|
||||
title = stringResource(id = R.string.base_url),
|
||||
buttons = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
viewModel.setGeniURLBaseURL(value)
|
||||
onDismiss()
|
||||
},
|
||||
enabled = isValidUrl
|
||||
) {
|
||||
Text(stringResource(id = R.string.confirm))
|
||||
}
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text(stringResource(id = R.string.cancel))
|
||||
}
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
TextField(
|
||||
value = value,
|
||||
isError = !isValidUrl,
|
||||
onValueChange = { newValue ->
|
||||
isValidUrl = Patterns.WEB_URL.matcher(newValue.lowercase()).matches() && newValue.startsWith("http", true)
|
||||
value = newValue
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ThemeDialog(
|
||||
uiState: SettingsState,
|
||||
|
||||
@@ -11,9 +11,11 @@ import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import com.illusionman1212.lyricsgrabbr.LGApp
|
||||
import com.illusionman1212.lyricsgrabbr.NotificationEvent
|
||||
import com.illusionman1212.lyricsgrabbr.data.HomeRepository
|
||||
import com.illusionman1212.lyricsgrabbr.data.SettingsPreferencesRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -85,7 +87,7 @@ data class HomeState(
|
||||
val error: String? = null,
|
||||
)
|
||||
|
||||
class HomeViewModel(private val homeRepository: HomeRepository): ViewModel() {
|
||||
class HomeViewModel(private val homeRepository: HomeRepository, private val settingsRepository: SettingsPreferencesRepository): ViewModel() {
|
||||
private val _uiState = MutableStateFlow(HomeState())
|
||||
val uiState = _uiState.asStateFlow()
|
||||
private val json = Json {
|
||||
@@ -107,7 +109,8 @@ class HomeViewModel(private val homeRepository: HomeRepository): ViewModel() {
|
||||
_uiState.update { HomeState(true, uiState.value.results, uiState.value.notification, null) }
|
||||
|
||||
withContext(Dispatchers.IO) {
|
||||
val (res, isSuccess) = homeRepository.makeSearchRequest(context, song, artist)
|
||||
val baseUrl = settingsRepository.preferences.first().geniURLbaseURL
|
||||
val (res, isSuccess) = homeRepository.makeSearchRequest(context, baseUrl, song, artist)
|
||||
if (isSuccess) {
|
||||
val results = json.decodeFromString(SearchResultsResponse.serializer(), res!!).all.map {
|
||||
SearchResult(
|
||||
@@ -136,7 +139,7 @@ class HomeViewModel(private val homeRepository: HomeRepository): ViewModel() {
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
val application = (this[APPLICATION_KEY] as LGApp)
|
||||
HomeViewModel(application.homeRepository)
|
||||
HomeViewModel(application.homeRepository, application.settingsPreferencesRepository)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ data class SettingsState(
|
||||
val applications: Map<String, AppInfo> = emptyMap(),
|
||||
val whitelistSearchQuery: String = "",
|
||||
val keepScreenOn: Boolean = false,
|
||||
val geniURLbaseURL: String = "",
|
||||
val whitelistPromptSeen: Boolean = true,
|
||||
)
|
||||
|
||||
@@ -55,6 +56,15 @@ class SettingsViewModel(private val settingsPrefsRepo: SettingsPreferencesReposi
|
||||
}
|
||||
}
|
||||
|
||||
fun setGeniURLBaseURL(baseUrl: String) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
settingsPrefsRepo.setGeniURLBaseURL(baseUrl)
|
||||
_uiState.update { state ->
|
||||
state.copy(geniURLbaseURL = baseUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleKeepScreenOn() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
settingsPrefsRepo.toggleKeepScreenOn()
|
||||
@@ -165,6 +175,7 @@ class SettingsViewModel(private val settingsPrefsRepo: SettingsPreferencesReposi
|
||||
appTheme = it.appTheme,
|
||||
keepScreenOn = it.keepScreenOn,
|
||||
whitelistPromptSeen = it.whitelistPromptSeen,
|
||||
geniURLbaseURL = it.geniURLbaseURL,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<!-- General -->
|
||||
<string name="go_back">رجوع</string>
|
||||
<string name="cancel">إلغاء</string>
|
||||
<string name="confirm">تأكيد</string>
|
||||
<string name="timeout">لقد انتهت مهلة الطلب، حاول مرة أخرى لاحقًا</string>
|
||||
<string name="generic_error">لقد حدث خطأ، حاول مرة أخرى لاحقاً</string>
|
||||
<string name="internal_server_error">تأكد من تشغيل خادم geniURL الخاص بك إذا كنت تستضيف ذاتيًا أو اتصل بمضيفك.</string>
|
||||
@@ -47,6 +48,8 @@
|
||||
<string name="keep_device_awake_title">أبق الجهاز مستيقظا</string>
|
||||
<string name="keep_device_awake_desc">أبق الجهاز مستيقظا على صفحة كلمات الأغاني (يزيد من استخدام البطارية)</string>
|
||||
<string name="screen_will_stay_on">ستبقى الشاشة على قيد التشغيل</string>
|
||||
<string name="api_base_url">عنوان URL الأساسي لواجهة برمجة التطبيقات (API)</string>
|
||||
<string name="base_url">عنوان URL الأساسي</string>
|
||||
|
||||
<!-- Lyrics -->
|
||||
<string name="instrumental">هذه الأغنية موسيقية</string>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<!-- General -->
|
||||
<string name="go_back">Go Back</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="confirm">Confirm</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="internal_server_error">Internal server error. Make sure your geniURL server is running if self-hosting or contact your hoster.</string>
|
||||
@@ -46,6 +47,8 @@
|
||||
<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>
|
||||
<string name="api_base_url">API Base URL</string>
|
||||
<string name="base_url">Base URL</string>
|
||||
|
||||
<!-- Lyrics -->
|
||||
<string name="instrumental">This song is an instrumental</string>
|
||||
|
||||
Reference in New Issue
Block a user