Automatic Lint

This commit is contained in:
Syer10
2024-03-30 20:30:56 +00:00
parent 423267e4e6
commit 37f9bdaf8d
14 changed files with 269 additions and 245 deletions

View File

@@ -71,9 +71,10 @@ internal class StandardPreference<T>(
/** /**
* Returns a cold [Flow] of this preference to receive updates when its value changes. * Returns a cold [Flow] of this preference to receive updates when its value changes.
*/ */
override fun changes(): Flow<T> = listener override fun changes(): Flow<T> =
.filter { it == key } listener
.map { get() } .filter { it == key }
.map { get() }
/** /**
* Returns a hot [StateFlow] of this preference bound to the given [scope], allowing to read the * Returns a hot [StateFlow] of this preference bound to the given [scope], allowing to read the

View File

@@ -51,7 +51,7 @@ interface DataComponent {
.serverUrl( .serverUrl(
URLBuilder(serverPreferences.serverUrl().get()) URLBuilder(serverPreferences.serverUrl().get())
.appendPathSegments("api", "graphql") .appendPathSegments("api", "graphql")
.buildString() .buildString(),
) )
.ktorClient(http) .ktorClient(http)
.build() .build()
@@ -90,6 +90,5 @@ interface DataComponent {
fun updatesRepository(ktorfit: Ktorfit) = ktorfit.create<UpdatesRepository>() fun updatesRepository(ktorfit: Ktorfit) = ktorfit.create<UpdatesRepository>()
@Provides @Provides
fun settingsRepository(apolloClient: ApolloClient): SettingsRepository = fun settingsRepository(apolloClient: ApolloClient): SettingsRepository = SettingsRepositoryImpl(apolloClient)
SettingsRepositoryImpl(apolloClient)
} }

View File

@@ -26,154 +26,160 @@ import ca.gosyer.jui.domain.settings.model.WebUIChannel as DomainWebUIChannel
import ca.gosyer.jui.domain.settings.model.WebUIFlavor as DomainWebUIFlavor import ca.gosyer.jui.domain.settings.model.WebUIFlavor as DomainWebUIFlavor
import ca.gosyer.jui.domain.settings.model.WebUIInterface as DomainWebUIInterface import ca.gosyer.jui.domain.settings.model.WebUIInterface as DomainWebUIInterface
class SettingsRepositoryImpl(private val apolloClient: ApolloClient) : SettingsRepository { class SettingsRepositoryImpl(
private val apolloClient: ApolloClient,
) : SettingsRepository {
private fun SettingsTypeFragment.toSettings() =
Settings(
autoDownloadNewChapters = autoDownloadNewChapters,
autoDownloadNewChaptersLimit = autoDownloadNewChaptersLimit,
backupInterval = backupInterval,
backupPath = backupPath,
backupTTL = backupTTL,
backupTime = backupTime,
basicAuthEnabled = basicAuthEnabled,
basicAuthPassword = basicAuthPassword,
basicAuthUsername = basicAuthUsername,
debugLogsEnabled = debugLogsEnabled,
downloadAsCbz = downloadAsCbz,
downloadsPath = downloadsPath,
electronPath = electronPath,
excludeCompleted = excludeCompleted,
excludeEntryWithUnreadChapters = excludeEntryWithUnreadChapters,
excludeNotStarted = excludeNotStarted,
excludeUnreadChapters = excludeUnreadChapters,
extensionRepos = extensionRepos,
flareSolverrEnabled = flareSolverrEnabled,
flareSolverrSessionName = flareSolverrSessionName,
flareSolverrSessionTtl = flareSolverrSessionTtl,
flareSolverrTimeout = flareSolverrTimeout,
flareSolverrUrl = flareSolverrUrl,
globalUpdateInterval = globalUpdateInterval,
gqlDebugLogsEnabled = gqlDebugLogsEnabled,
initialOpenInBrowserEnabled = initialOpenInBrowserEnabled,
ip = ip,
localSourcePath = localSourcePath,
maxSourcesInParallel = maxSourcesInParallel,
port = port,
socksProxyEnabled = socksProxyEnabled,
socksProxyHost = socksProxyHost,
socksProxyPassword = socksProxyPassword,
socksProxyPort = socksProxyPort,
socksProxyUsername = socksProxyUsername,
socksProxyVersion = socksProxyVersion,
systemTrayEnabled = systemTrayEnabled,
updateMangas = updateMangas,
webUIChannel = webUIChannel.toDomain(),
webUIFlavor = webUIFlavor.toDomain(),
webUIInterface = webUIInterface.toDomain(),
webUIUpdateCheckInterval = webUIUpdateCheckInterval,
)
private fun SettingsTypeFragment.toSettings() = Settings( private fun WebUIChannel.toDomain() =
autoDownloadNewChapters = autoDownloadNewChapters, when (this) {
autoDownloadNewChaptersLimit = autoDownloadNewChaptersLimit, WebUIChannel.BUNDLED -> DomainWebUIChannel.BUNDLED
backupInterval = backupInterval, WebUIChannel.STABLE -> DomainWebUIChannel.STABLE
backupPath = backupPath, WebUIChannel.PREVIEW -> DomainWebUIChannel.PREVIEW
backupTTL = backupTTL, WebUIChannel.UNKNOWN__ -> DomainWebUIChannel.UNKNOWN__
backupTime = backupTime, }
basicAuthEnabled = basicAuthEnabled,
basicAuthPassword = basicAuthPassword,
basicAuthUsername = basicAuthUsername,
debugLogsEnabled = debugLogsEnabled,
downloadAsCbz = downloadAsCbz,
downloadsPath = downloadsPath,
electronPath = electronPath,
excludeCompleted = excludeCompleted,
excludeEntryWithUnreadChapters = excludeEntryWithUnreadChapters,
excludeNotStarted = excludeNotStarted,
excludeUnreadChapters = excludeUnreadChapters,
extensionRepos = extensionRepos,
flareSolverrEnabled = flareSolverrEnabled,
flareSolverrSessionName = flareSolverrSessionName,
flareSolverrSessionTtl = flareSolverrSessionTtl,
flareSolverrTimeout = flareSolverrTimeout,
flareSolverrUrl = flareSolverrUrl,
globalUpdateInterval = globalUpdateInterval,
gqlDebugLogsEnabled = gqlDebugLogsEnabled,
initialOpenInBrowserEnabled = initialOpenInBrowserEnabled,
ip = ip,
localSourcePath = localSourcePath,
maxSourcesInParallel = maxSourcesInParallel,
port = port,
socksProxyEnabled = socksProxyEnabled,
socksProxyHost = socksProxyHost,
socksProxyPassword = socksProxyPassword,
socksProxyPort = socksProxyPort,
socksProxyUsername = socksProxyUsername,
socksProxyVersion = socksProxyVersion,
systemTrayEnabled = systemTrayEnabled,
updateMangas = updateMangas,
webUIChannel = webUIChannel.toDomain(),
webUIFlavor = webUIFlavor.toDomain(),
webUIInterface = webUIInterface.toDomain(),
webUIUpdateCheckInterval = webUIUpdateCheckInterval
)
private fun WebUIChannel.toDomain() = when (this) { private fun WebUIFlavor.toDomain() =
WebUIChannel.BUNDLED -> DomainWebUIChannel.BUNDLED when (this) {
WebUIChannel.STABLE -> DomainWebUIChannel.STABLE WebUIFlavor.WEBUI -> DomainWebUIFlavor.WEBUI
WebUIChannel.PREVIEW -> DomainWebUIChannel.PREVIEW WebUIFlavor.VUI -> DomainWebUIFlavor.VUI
WebUIChannel.UNKNOWN__ -> DomainWebUIChannel.UNKNOWN__ WebUIFlavor.CUSTOM -> DomainWebUIFlavor.CUSTOM
} WebUIFlavor.UNKNOWN__ -> DomainWebUIFlavor.UNKNOWN__
}
private fun WebUIFlavor.toDomain() = when (this) { private fun WebUIInterface.toDomain() =
WebUIFlavor.WEBUI -> DomainWebUIFlavor.WEBUI when (this) {
WebUIFlavor.VUI -> DomainWebUIFlavor.VUI WebUIInterface.BROWSER -> DomainWebUIInterface.BROWSER
WebUIFlavor.CUSTOM -> DomainWebUIFlavor.CUSTOM WebUIInterface.ELECTRON -> DomainWebUIInterface.ELECTRON
WebUIFlavor.UNKNOWN__ -> DomainWebUIFlavor.UNKNOWN__ WebUIInterface.UNKNOWN__ -> DomainWebUIInterface.UNKNOWN__
} }
private fun WebUIInterface.toDomain() = when (this) { private fun DomainWebUIChannel.toGraphQL() =
WebUIInterface.BROWSER -> DomainWebUIInterface.BROWSER when (this) {
WebUIInterface.ELECTRON -> DomainWebUIInterface.ELECTRON DomainWebUIChannel.BUNDLED -> WebUIChannel.BUNDLED
WebUIInterface.UNKNOWN__ -> DomainWebUIInterface.UNKNOWN__ DomainWebUIChannel.STABLE -> WebUIChannel.STABLE
} DomainWebUIChannel.PREVIEW -> WebUIChannel.PREVIEW
DomainWebUIChannel.UNKNOWN__ -> WebUIChannel.UNKNOWN__
}
private fun DomainWebUIChannel.toGraphQL() = when (this) { private fun DomainWebUIFlavor.toGraphQL() =
DomainWebUIChannel.BUNDLED -> WebUIChannel.BUNDLED when (this) {
DomainWebUIChannel.STABLE -> WebUIChannel.STABLE DomainWebUIFlavor.WEBUI -> WebUIFlavor.WEBUI
DomainWebUIChannel.PREVIEW -> WebUIChannel.PREVIEW DomainWebUIFlavor.VUI -> WebUIFlavor.VUI
DomainWebUIChannel.UNKNOWN__ -> WebUIChannel.UNKNOWN__ DomainWebUIFlavor.CUSTOM -> WebUIFlavor.CUSTOM
} DomainWebUIFlavor.UNKNOWN__ -> WebUIFlavor.UNKNOWN__
}
private fun DomainWebUIFlavor.toGraphQL() = when (this) { private fun DomainWebUIInterface.toGraphQL() =
DomainWebUIFlavor.WEBUI -> WebUIFlavor.WEBUI when (this) {
DomainWebUIFlavor.VUI -> WebUIFlavor.VUI DomainWebUIInterface.BROWSER -> WebUIInterface.BROWSER
DomainWebUIFlavor.CUSTOM -> WebUIFlavor.CUSTOM DomainWebUIInterface.ELECTRON -> WebUIInterface.ELECTRON
DomainWebUIFlavor.UNKNOWN__ -> WebUIFlavor.UNKNOWN__ DomainWebUIInterface.UNKNOWN__ -> WebUIInterface.UNKNOWN__
} }
private fun DomainWebUIInterface.toGraphQL() = when (this) { override fun getSettings(): Flow<Settings> =
DomainWebUIInterface.BROWSER -> WebUIInterface.BROWSER apolloClient.query(AllSettingsQuery()).toFlow()
DomainWebUIInterface.ELECTRON -> WebUIInterface.ELECTRON
DomainWebUIInterface.UNKNOWN__ -> WebUIInterface.UNKNOWN__
}
override fun getSettings(): Flow<Settings> {
return apolloClient.query(AllSettingsQuery()).toFlow()
.map { .map {
it.dataOrThrow().settings.settingsTypeFragment.toSettings() it.dataOrThrow().settings.settingsTypeFragment.toSettings()
} }
.flowOn(Dispatchers.IO) .flowOn(Dispatchers.IO)
}
private fun SetSettingsInput.toMutation() =
SetSettingsMutation(
autoDownloadNewChapters = autoDownloadNewChapters.toOptional(),
autoDownloadNewChaptersLimit = autoDownloadNewChaptersLimit.toOptional(),
backupInterval = backupInterval.toOptional(),
backupPath = backupPath.toOptional(),
backupTTL = backupTTL.toOptional(),
backupTime = backupTime.toOptional(),
basicAuthEnabled = basicAuthEnabled.toOptional(),
basicAuthPassword = basicAuthPassword.toOptional(),
basicAuthUsername = basicAuthUsername.toOptional(),
debugLogsEnabled = debugLogsEnabled.toOptional(),
downloadAsCbz = downloadAsCbz.toOptional(),
downloadsPath = downloadsPath.toOptional(),
electronPath = electronPath.toOptional(),
excludeCompleted = excludeCompleted.toOptional(),
excludeEntryWithUnreadChapters = excludeEntryWithUnreadChapters.toOptional(),
excludeNotStarted = excludeNotStarted.toOptional(),
excludeUnreadChapters = excludeUnreadChapters.toOptional(),
extensionRepos = extensionRepos.toOptional(),
flareSolverrEnabled = flareSolverrEnabled.toOptional(),
flareSolverrSessionName = flareSolverrSessionName.toOptional(),
flareSolverrSessionTtl = flareSolverrSessionTtl.toOptional(),
flareSolverrTimeout = flareSolverrTimeout.toOptional(),
flareSolverrUrl = flareSolverrUrl.toOptional(),
globalUpdateInterval = globalUpdateInterval.toOptional(),
gqlDebugLogsEnabled = gqlDebugLogsEnabled.toOptional(),
initialOpenInBrowserEnabled = initialOpenInBrowserEnabled.toOptional(),
ip = ip.toOptional(),
localSourcePath = localSourcePath.toOptional(),
maxSourcesInParallel = maxSourcesInParallel.toOptional(),
port = port.toOptional(),
socksProxyEnabled = socksProxyEnabled.toOptional(),
socksProxyHost = socksProxyHost.toOptional(),
socksProxyPassword = socksProxyPassword.toOptional(),
socksProxyPort = socksProxyPort.toOptional(),
socksProxyUsername = socksProxyUsername.toOptional(),
socksProxyVersion = socksProxyVersion.toOptional(),
systemTrayEnabled = systemTrayEnabled.toOptional(),
updateMangas = updateMangas.toOptional(),
webUIChannel = webUIChannel?.toGraphQL().toOptional(),
webUIFlavor = webUIFlavor?.toGraphQL().toOptional(),
webUIInterface = webUIInterface?.toGraphQL().toOptional(),
webUIUpdateCheckInterval = webUIUpdateCheckInterval.toOptional(),
)
private fun SetSettingsInput.toMutation() = SetSettingsMutation( override fun setSettings(input: SetSettingsInput): Flow<Unit> =
autoDownloadNewChapters = autoDownloadNewChapters.toOptional(), apolloClient.mutation(input.toMutation())
autoDownloadNewChaptersLimit = autoDownloadNewChaptersLimit.toOptional(),
backupInterval = backupInterval.toOptional(),
backupPath = backupPath.toOptional(),
backupTTL = backupTTL.toOptional(),
backupTime = backupTime.toOptional(),
basicAuthEnabled = basicAuthEnabled.toOptional(),
basicAuthPassword = basicAuthPassword.toOptional(),
basicAuthUsername = basicAuthUsername.toOptional(),
debugLogsEnabled = debugLogsEnabled.toOptional(),
downloadAsCbz = downloadAsCbz.toOptional(),
downloadsPath = downloadsPath.toOptional(),
electronPath = electronPath.toOptional(),
excludeCompleted = excludeCompleted.toOptional(),
excludeEntryWithUnreadChapters = excludeEntryWithUnreadChapters.toOptional(),
excludeNotStarted = excludeNotStarted.toOptional(),
excludeUnreadChapters = excludeUnreadChapters.toOptional(),
extensionRepos = extensionRepos.toOptional(),
flareSolverrEnabled = flareSolverrEnabled.toOptional(),
flareSolverrSessionName = flareSolverrSessionName.toOptional(),
flareSolverrSessionTtl = flareSolverrSessionTtl.toOptional(),
flareSolverrTimeout = flareSolverrTimeout.toOptional(),
flareSolverrUrl = flareSolverrUrl.toOptional(),
globalUpdateInterval = globalUpdateInterval.toOptional(),
gqlDebugLogsEnabled = gqlDebugLogsEnabled.toOptional(),
initialOpenInBrowserEnabled = initialOpenInBrowserEnabled.toOptional(),
ip = ip.toOptional(),
localSourcePath = localSourcePath.toOptional(),
maxSourcesInParallel = maxSourcesInParallel.toOptional(),
port = port.toOptional(),
socksProxyEnabled = socksProxyEnabled.toOptional(),
socksProxyHost = socksProxyHost.toOptional(),
socksProxyPassword = socksProxyPassword.toOptional(),
socksProxyPort = socksProxyPort.toOptional(),
socksProxyUsername = socksProxyUsername.toOptional(),
socksProxyVersion = socksProxyVersion.toOptional(),
systemTrayEnabled = systemTrayEnabled.toOptional(),
updateMangas = updateMangas.toOptional(),
webUIChannel = webUIChannel?.toGraphQL().toOptional(),
webUIFlavor = webUIFlavor?.toGraphQL().toOptional(),
webUIInterface = webUIInterface?.toGraphQL().toOptional(),
webUIUpdateCheckInterval = webUIUpdateCheckInterval.toOptional(),
)
override fun setSettings(input: SetSettingsInput): Flow<Unit> {
return apolloClient.mutation(input.toMutation())
.toFlow() .toFlow()
.map { .map {
it.dataOrThrow() it.dataOrThrow()
Unit Unit
} }
.flowOn(Dispatchers.IO) .flowOn(Dispatchers.IO)
}
} }

View File

@@ -16,14 +16,22 @@ import kotlinx.coroutines.flow.StateFlow
actual class ServerHostPreferences actual constructor( actual class ServerHostPreferences actual constructor(
@Suppress("unused") private val preferenceStore: PreferenceStore, @Suppress("unused") private val preferenceStore: PreferenceStore,
) { ) {
actual fun host(): Preference<Boolean> = object : Preference<Boolean> { actual fun host(): Preference<Boolean> =
override fun key(): String = "host" object : Preference<Boolean> {
override fun get(): Boolean = false override fun key(): String = "host"
override fun isSet(): Boolean = false
override fun delete() {} override fun get(): Boolean = false
override fun defaultValue(): Boolean = false
override fun changes(): Flow<Boolean> = MutableStateFlow(false) override fun isSet(): Boolean = false
override fun stateIn(scope: CoroutineScope): StateFlow<Boolean> = MutableStateFlow(false)
override fun set(value: Boolean) {} override fun delete() {}
}
override fun defaultValue(): Boolean = false
override fun changes(): Flow<Boolean> = MutableStateFlow(false)
override fun stateIn(scope: CoroutineScope): StateFlow<Boolean> = MutableStateFlow(false)
override fun set(value: Boolean) {}
}
} }

View File

@@ -18,13 +18,15 @@ class SetSettings
constructor( constructor(
private val settingsRepository: SettingsRepository, private val settingsRepository: SettingsRepository,
) { ) {
suspend fun await(input: SetSettingsInput, onError: suspend (Throwable) -> Unit = {}) = suspend fun await(
asFlow(input) input: SetSettingsInput,
.catch { onError: suspend (Throwable) -> Unit = {},
onError(it) ) = asFlow(input)
log.warn(it) { "Failed to check for server updates" } .catch {
} onError(it)
.singleOrNull() log.warn(it) { "Failed to check for server updates" }
}
.singleOrNull()
fun asFlow(input: SetSettingsInput) = settingsRepository.setSettings(input) fun asFlow(input: SetSettingsInput) = settingsRepository.setSettings(input)

View File

@@ -10,5 +10,5 @@ enum class WebUIChannel {
BUNDLED, BUNDLED,
STABLE, STABLE,
PREVIEW, PREVIEW,
UNKNOWN__; UNKNOWN__,
} }

View File

@@ -10,5 +10,5 @@ enum class WebUIFlavor {
WEBUI, WEBUI,
VUI, VUI,
CUSTOM, CUSTOM,
UNKNOWN__; UNKNOWN__,
} }

View File

@@ -9,5 +9,5 @@ package ca.gosyer.jui.domain.settings.model
enum class WebUIInterface { enum class WebUIInterface {
BROWSER, BROWSER,
ELECTRON, ELECTRON,
UNKNOWN__; UNKNOWN__,
} }

View File

@@ -11,7 +11,6 @@ import ca.gosyer.jui.domain.settings.model.Settings
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
interface SettingsRepository { interface SettingsRepository {
fun getSettings(): Flow<Settings> fun getSettings(): Flow<Settings>
fun setSettings(input: SetSettingsInput): Flow<Unit> fun setSettings(input: SetSettingsInput): Flow<Unit>

View File

@@ -64,6 +64,6 @@ actual class ServerHostPreferences actual constructor(
).mapNotNull { ).mapNotNull {
it.getProperty() it.getProperty()
}.plus( }.plus(
"-Dsuwayomi.tachidesk.config.server.initialOpenInBrowserEnabled=false" "-Dsuwayomi.tachidesk.config.server.initialOpenInBrowserEnabled=false",
).toTypedArray() ).toTypedArray()
} }

View File

@@ -92,19 +92,19 @@ sealed class ServerHostPreference<T : Any> {
class BackupPath( class BackupPath(
preferenceStore: PreferenceStore, preferenceStore: PreferenceStore,
) : StringServerHostPreference( ) : StringServerHostPreference(
preferenceStore, preferenceStore,
"backupPath", "backupPath",
"", "",
) )
// LocalSource // LocalSource
class LocalSourcePath( class LocalSourcePath(
preferenceStore: PreferenceStore, preferenceStore: PreferenceStore,
) : StringServerHostPreference( ) : StringServerHostPreference(
preferenceStore, preferenceStore,
"localSourcePath", "localSourcePath",
"", "",
) )
// Authentication // Authentication
class BasicAuthEnabled( class BasicAuthEnabled(

View File

@@ -16,14 +16,22 @@ import kotlinx.coroutines.flow.StateFlow
actual class ServerHostPreferences actual constructor( actual class ServerHostPreferences actual constructor(
@Suppress("unused") private val preferenceStore: PreferenceStore, @Suppress("unused") private val preferenceStore: PreferenceStore,
) { ) {
actual fun host(): Preference<Boolean> = object : Preference<Boolean> { actual fun host(): Preference<Boolean> =
override fun key(): String = "host" object : Preference<Boolean> {
override fun get(): Boolean = false override fun key(): String = "host"
override fun isSet(): Boolean = false
override fun delete() {} override fun get(): Boolean = false
override fun defaultValue(): Boolean = false
override fun changes(): Flow<Boolean> = MutableStateFlow(false) override fun isSet(): Boolean = false
override fun stateIn(scope: CoroutineScope): StateFlow<Boolean> = MutableStateFlow(false)
override fun set(value: Boolean) {} override fun delete() {}
}
override fun defaultValue(): Boolean = false
override fun changes(): Flow<Boolean> = MutableStateFlow(false)
override fun stateIn(scope: CoroutineScope): StateFlow<Boolean> = MutableStateFlow(false)
override fun set(value: Boolean) {}
}
} }

View File

@@ -144,7 +144,6 @@ private class ServerSettingMutableStateFlow<T>(
scope: CoroutineScope, scope: CoroutineScope,
private val state: MutableStateFlow<T> = MutableStateFlow(getSetting(parent.value)), private val state: MutableStateFlow<T> = MutableStateFlow(getSetting(parent.value)),
) : MutableStateFlow<T> by state { ) : MutableStateFlow<T> by state {
init { init {
parent parent
.onEach { state.value = getSetting(it) } .onEach { state.value = getSetting(it) }
@@ -164,184 +163,184 @@ class ServerSettings(
private val setSettings: SetSettings, private val setSettings: SetSettings,
private val scope: CoroutineScope, private val scope: CoroutineScope,
initial: Settings, initial: Settings,
private val onError: (String) -> Unit private val onError: (String) -> Unit,
) { ) {
val settings = MutableStateFlow(initial) val settings = MutableStateFlow(initial)
val autoDownloadNewChapters = getServerFlow( val autoDownloadNewChapters = getServerFlow(
getSetting = { it.autoDownloadNewChapters }, getSetting = { it.autoDownloadNewChapters },
getInput = { SetSettingsInput(autoDownloadNewChapters = it) } getInput = { SetSettingsInput(autoDownloadNewChapters = it) },
) )
val autoDownloadNewChaptersLimit = getServerFlow( val autoDownloadNewChaptersLimit = getServerFlow(
getSetting = { it.autoDownloadNewChaptersLimit.toString() }, getSetting = { it.autoDownloadNewChaptersLimit.toString() },
getInput = { SetSettingsInput(autoDownloadNewChaptersLimit = it.toIntOrNull()) } getInput = { SetSettingsInput(autoDownloadNewChaptersLimit = it.toIntOrNull()) },
) )
val backupInterval = getServerFlow( val backupInterval = getServerFlow(
getSetting = { it.backupInterval.toString() }, getSetting = { it.backupInterval.toString() },
getInput = { SetSettingsInput(backupInterval = it.toIntOrNull()) } getInput = { SetSettingsInput(backupInterval = it.toIntOrNull()) },
) )
val backupPath = getServerFlow( val backupPath = getServerFlow(
getSetting = { it.backupPath }, getSetting = { it.backupPath },
getInput = { SetSettingsInput(backupPath = it) } getInput = { SetSettingsInput(backupPath = it) },
) )
val backupTTL = getServerFlow( val backupTTL = getServerFlow(
getSetting = { it.backupTTL.toString() }, getSetting = { it.backupTTL.toString() },
getInput = { SetSettingsInput(backupTTL = it.toIntOrNull()) } getInput = { SetSettingsInput(backupTTL = it.toIntOrNull()) },
) )
val backupTime = getServerFlow( val backupTime = getServerFlow(
getSetting = { it.backupTime }, getSetting = { it.backupTime },
getInput = { SetSettingsInput(backupTime = it) } getInput = { SetSettingsInput(backupTime = it) },
) )
val basicAuthEnabled = getServerFlow( val basicAuthEnabled = getServerFlow(
getSetting = { it.basicAuthEnabled }, getSetting = { it.basicAuthEnabled },
getInput = { SetSettingsInput(basicAuthEnabled = it) } getInput = { SetSettingsInput(basicAuthEnabled = it) },
) )
val basicAuthPassword = getServerFlow( val basicAuthPassword = getServerFlow(
getSetting = { it.basicAuthPassword }, getSetting = { it.basicAuthPassword },
getInput = { SetSettingsInput(basicAuthPassword = it) } getInput = { SetSettingsInput(basicAuthPassword = it) },
) )
val basicAuthUsername = getServerFlow( val basicAuthUsername = getServerFlow(
getSetting = { it.basicAuthUsername }, getSetting = { it.basicAuthUsername },
getInput = { SetSettingsInput(basicAuthUsername = it) } getInput = { SetSettingsInput(basicAuthUsername = it) },
) )
val debugLogsEnabled = getServerFlow( val debugLogsEnabled = getServerFlow(
getSetting = { it.debugLogsEnabled }, getSetting = { it.debugLogsEnabled },
getInput = { SetSettingsInput(debugLogsEnabled = it) } getInput = { SetSettingsInput(debugLogsEnabled = it) },
) )
val downloadAsCbz = getServerFlow( val downloadAsCbz = getServerFlow(
getSetting = { it.downloadAsCbz }, getSetting = { it.downloadAsCbz },
getInput = { SetSettingsInput(downloadAsCbz = it) } getInput = { SetSettingsInput(downloadAsCbz = it) },
) )
val downloadsPath = getServerFlow( val downloadsPath = getServerFlow(
getSetting = { it.downloadsPath }, getSetting = { it.downloadsPath },
getInput = { SetSettingsInput(downloadsPath = it) } getInput = { SetSettingsInput(downloadsPath = it) },
) )
val electronPath = getServerFlow( val electronPath = getServerFlow(
getSetting = { it.electronPath }, getSetting = { it.electronPath },
getInput = { SetSettingsInput(electronPath = it) } getInput = { SetSettingsInput(electronPath = it) },
) )
val excludeCompleted = getServerFlow( val excludeCompleted = getServerFlow(
getSetting = { it.excludeCompleted }, getSetting = { it.excludeCompleted },
getInput = { SetSettingsInput(excludeCompleted = it) } getInput = { SetSettingsInput(excludeCompleted = it) },
) )
val excludeEntryWithUnreadChapters = getServerFlow( val excludeEntryWithUnreadChapters = getServerFlow(
getSetting = { it.excludeEntryWithUnreadChapters }, getSetting = { it.excludeEntryWithUnreadChapters },
getInput = { SetSettingsInput(excludeEntryWithUnreadChapters = it) } getInput = { SetSettingsInput(excludeEntryWithUnreadChapters = it) },
) )
val excludeNotStarted = getServerFlow( val excludeNotStarted = getServerFlow(
getSetting = { it.excludeNotStarted }, getSetting = { it.excludeNotStarted },
getInput = { SetSettingsInput(excludeNotStarted = it) } getInput = { SetSettingsInput(excludeNotStarted = it) },
) )
val excludeUnreadChapters = getServerFlow( val excludeUnreadChapters = getServerFlow(
getSetting = { it.excludeUnreadChapters }, getSetting = { it.excludeUnreadChapters },
getInput = { SetSettingsInput(excludeUnreadChapters = it) } getInput = { SetSettingsInput(excludeUnreadChapters = it) },
) )
val extensionRepos = getServerFlow( val extensionRepos = getServerFlow(
getSetting = { it.extensionRepos }, getSetting = { it.extensionRepos },
getInput = { SetSettingsInput(extensionRepos = it) } getInput = { SetSettingsInput(extensionRepos = it) },
) )
val flareSolverrEnabled = getServerFlow( val flareSolverrEnabled = getServerFlow(
getSetting = { it.flareSolverrEnabled }, getSetting = { it.flareSolverrEnabled },
getInput = { SetSettingsInput(flareSolverrEnabled = it) } getInput = { SetSettingsInput(flareSolverrEnabled = it) },
) )
val flareSolverrSessionName = getServerFlow( val flareSolverrSessionName = getServerFlow(
getSetting = { it.flareSolverrSessionName }, getSetting = { it.flareSolverrSessionName },
getInput = { SetSettingsInput(flareSolverrSessionName = it) } getInput = { SetSettingsInput(flareSolverrSessionName = it) },
) )
val flareSolverrSessionTtl = getServerFlow( val flareSolverrSessionTtl = getServerFlow(
getSetting = { it.flareSolverrSessionTtl.toString() }, getSetting = { it.flareSolverrSessionTtl.toString() },
getInput = { SetSettingsInput(flareSolverrSessionTtl = it.toIntOrNull()) } getInput = { SetSettingsInput(flareSolverrSessionTtl = it.toIntOrNull()) },
) )
val flareSolverrTimeout = getServerFlow( val flareSolverrTimeout = getServerFlow(
getSetting = { it.flareSolverrTimeout.toString() }, getSetting = { it.flareSolverrTimeout.toString() },
getInput = { SetSettingsInput(flareSolverrTimeout = it.toIntOrNull()) } getInput = { SetSettingsInput(flareSolverrTimeout = it.toIntOrNull()) },
) )
val flareSolverrUrl = getServerFlow( val flareSolverrUrl = getServerFlow(
getSetting = { it.flareSolverrUrl }, getSetting = { it.flareSolverrUrl },
getInput = { SetSettingsInput(flareSolverrUrl = it) } getInput = { SetSettingsInput(flareSolverrUrl = it) },
) )
val globalUpdateInterval = getServerFlow( val globalUpdateInterval = getServerFlow(
getSetting = { it.globalUpdateInterval.toString() }, getSetting = { it.globalUpdateInterval.toString() },
getInput = { SetSettingsInput(globalUpdateInterval = it.toDoubleOrNull()?.takeIf { it !in 0.01..5.99 }) } getInput = { SetSettingsInput(globalUpdateInterval = it.toDoubleOrNull()?.takeIf { it !in 0.01..5.99 }) },
) )
val gqlDebugLogsEnabled = getServerFlow( val gqlDebugLogsEnabled = getServerFlow(
getSetting = { it.gqlDebugLogsEnabled }, getSetting = { it.gqlDebugLogsEnabled },
getInput = { SetSettingsInput(gqlDebugLogsEnabled = it) } getInput = { SetSettingsInput(gqlDebugLogsEnabled = it) },
) )
val initialOpenInBrowserEnabled = getServerFlow( val initialOpenInBrowserEnabled = getServerFlow(
getSetting = { it.initialOpenInBrowserEnabled }, getSetting = { it.initialOpenInBrowserEnabled },
getInput = { SetSettingsInput(initialOpenInBrowserEnabled = it) } getInput = { SetSettingsInput(initialOpenInBrowserEnabled = it) },
) )
val ip = getServerFlow( val ip = getServerFlow(
getSetting = { it.ip }, getSetting = { it.ip },
getInput = { SetSettingsInput(ip = it) } getInput = { SetSettingsInput(ip = it) },
) )
val localSourcePath = getServerFlow( val localSourcePath = getServerFlow(
getSetting = { it.localSourcePath }, getSetting = { it.localSourcePath },
getInput = { SetSettingsInput(localSourcePath = it) } getInput = { SetSettingsInput(localSourcePath = it) },
) )
val maxSourcesInParallel = getServerFlow( val maxSourcesInParallel = getServerFlow(
getSetting = { it.maxSourcesInParallel.toString() }, getSetting = { it.maxSourcesInParallel.toString() },
getInput = { SetSettingsInput(maxSourcesInParallel = it.toIntOrNull()) } getInput = { SetSettingsInput(maxSourcesInParallel = it.toIntOrNull()) },
) )
val port = getServerFlow( val port = getServerFlow(
getSetting = { it.port.toString() }, getSetting = { it.port.toString() },
getInput = { SetSettingsInput(port = it.toIntOrNull()) } getInput = { SetSettingsInput(port = it.toIntOrNull()) },
) )
val socksProxyEnabled = getServerFlow( val socksProxyEnabled = getServerFlow(
getSetting = { it.socksProxyEnabled }, getSetting = { it.socksProxyEnabled },
getInput = { SetSettingsInput(socksProxyEnabled = it) } getInput = { SetSettingsInput(socksProxyEnabled = it) },
) )
val socksProxyHost = getServerFlow( val socksProxyHost = getServerFlow(
getSetting = { it.socksProxyHost }, getSetting = { it.socksProxyHost },
getInput = { SetSettingsInput(socksProxyHost = it) } getInput = { SetSettingsInput(socksProxyHost = it) },
) )
val socksProxyPassword = getServerFlow( val socksProxyPassword = getServerFlow(
getSetting = { it.socksProxyPassword }, getSetting = { it.socksProxyPassword },
getInput = { SetSettingsInput(socksProxyPassword = it) } getInput = { SetSettingsInput(socksProxyPassword = it) },
) )
val socksProxyPort = getServerFlow( val socksProxyPort = getServerFlow(
getSetting = { it.socksProxyPort }, getSetting = { it.socksProxyPort },
getInput = { SetSettingsInput(socksProxyPort = it) } getInput = { SetSettingsInput(socksProxyPort = it) },
) )
val socksProxyUsername = getServerFlow( val socksProxyUsername = getServerFlow(
getSetting = { it.socksProxyUsername }, getSetting = { it.socksProxyUsername },
getInput = { SetSettingsInput(socksProxyUsername = it) } getInput = { SetSettingsInput(socksProxyUsername = it) },
) )
val socksProxyVersion = getServerFlow( val socksProxyVersion = getServerFlow(
getSetting = { it.socksProxyVersion }, getSetting = { it.socksProxyVersion },
getInput = { SetSettingsInput(socksProxyVersion = it) } getInput = { SetSettingsInput(socksProxyVersion = it) },
) )
val systemTrayEnabled = getServerFlow( val systemTrayEnabled = getServerFlow(
getSetting = { it.systemTrayEnabled }, getSetting = { it.systemTrayEnabled },
getInput = { SetSettingsInput(systemTrayEnabled = it) } getInput = { SetSettingsInput(systemTrayEnabled = it) },
) )
val updateMangas = getServerFlow( val updateMangas = getServerFlow(
getSetting = { it.updateMangas }, getSetting = { it.updateMangas },
getInput = { SetSettingsInput(updateMangas = it) } getInput = { SetSettingsInput(updateMangas = it) },
) )
val webUIChannel = getServerFlow( val webUIChannel = getServerFlow(
getSetting = { it.webUIChannel }, getSetting = { it.webUIChannel },
getInput = { SetSettingsInput(webUIChannel = it) } getInput = { SetSettingsInput(webUIChannel = it) },
) )
val webUIFlavor = getServerFlow( val webUIFlavor = getServerFlow(
getSetting = { it.webUIFlavor }, getSetting = { it.webUIFlavor },
getInput = { SetSettingsInput(webUIFlavor = it) } getInput = { SetSettingsInput(webUIFlavor = it) },
) )
val webUIInterface = getServerFlow( val webUIInterface = getServerFlow(
getSetting = { it.webUIInterface }, getSetting = { it.webUIInterface },
getInput = { SetSettingsInput(webUIInterface = it) } getInput = { SetSettingsInput(webUIInterface = it) },
) )
val webUIUpdateCheckInterval = getServerFlow( val webUIUpdateCheckInterval = getServerFlow(
getSetting = { it.webUIUpdateCheckInterval }, getSetting = { it.webUIUpdateCheckInterval },
getInput = { SetSettingsInput(webUIUpdateCheckInterval = it) } getInput = { SetSettingsInput(webUIUpdateCheckInterval = it) },
) )
private fun <T> getServerFlow( private fun <T> getServerFlow(
getSetting: (Settings) -> T, getSetting: (Settings) -> T,
getInput: (T) -> SetSettingsInput, getInput: (T) -> SetSettingsInput,
): MutableStateFlow<T> { ): MutableStateFlow<T> =
return ServerSettingMutableStateFlow( ServerSettingMutableStateFlow(
parent = settings, parent = settings,
getSetting = getSetting, getSetting = getSetting,
setSetting = { setSetting = {
@@ -349,7 +348,7 @@ class ServerSettings(
val input = getInput(it) val input = getInput(it)
setSettings.await( setSettings.await(
input, input,
onError = { onError(it.message.orEmpty()) } onError = { onError(it.message.orEmpty()) },
) )
val response = getSettings.await(onError = { onError(it.message.orEmpty()) }) val response = getSettings.await(onError = { onError(it.message.orEmpty()) })
if (response != null) { if (response != null) {
@@ -359,7 +358,6 @@ class ServerSettings(
}, },
scope = scope, scope = scope,
) )
}
} }
class SettingsServerViewModel class SettingsServerViewModel
@@ -598,7 +596,7 @@ fun LazyListScope.ServerSettingsItems(
preference = serverSettings.ip, preference = serverSettings.ip,
title = stringResource(MR.strings.host_ip), title = stringResource(MR.strings.host_ip),
subtitle = stringResource(MR.strings.host_ip_sub, ipValue), subtitle = stringResource(MR.strings.host_ip_sub, ipValue),
enabled = !hosted enabled = !hosted,
) )
} }
item { item {
@@ -607,7 +605,7 @@ fun LazyListScope.ServerSettingsItems(
preference = serverSettings.port, preference = serverSettings.port,
title = stringResource(MR.strings.host_port), title = stringResource(MR.strings.host_port),
subtitle = stringResource(MR.strings.host_port_sub, portValue), subtitle = stringResource(MR.strings.host_port_sub, portValue),
enabled = !hosted enabled = !hosted,
) )
} }
item { item {
@@ -615,7 +613,7 @@ fun LazyListScope.ServerSettingsItems(
PreferenceRow( PreferenceRow(
stringResource(MR.strings.extension_repos), stringResource(MR.strings.extension_repos),
subtitle = stringResource(MR.strings.extension_repos_sub), subtitle = stringResource(MR.strings.extension_repos_sub),
onClick = dialog::show onClick = dialog::show,
) )
val repos by serverSettings.extensionRepos.collectAsState() val repos by serverSettings.extensionRepos.collectAsState()
ExtensionReposDialog( ExtensionReposDialog(
@@ -623,7 +621,7 @@ fun LazyListScope.ServerSettingsItems(
repos, repos,
onSetRepos = { onSetRepos = {
serverSettings.extensionRepos.value = it serverSettings.extensionRepos.value = it
} },
) )
} }
item { item {
@@ -675,7 +673,7 @@ fun LazyListScope.ServerSettingsItems(
preference = serverSettings.socksProxyVersion, preference = serverSettings.socksProxyVersion,
choices = mapOf( choices = mapOf(
4 to "SOCKS4", 4 to "SOCKS4",
5 to "SOCKS5" 5 to "SOCKS5",
).toImmutableMap(), ).toImmutableMap(),
title = stringResource(MR.strings.host_socks_version), title = stringResource(MR.strings.host_socks_version),
enabled = socksProxyEnabled, enabled = socksProxyEnabled,
@@ -685,7 +683,7 @@ fun LazyListScope.ServerSettingsItems(
EditTextPreference( EditTextPreference(
preference = serverSettings.globalUpdateInterval, preference = serverSettings.globalUpdateInterval,
title = stringResource(MR.strings.global_update_interval), title = stringResource(MR.strings.global_update_interval),
subtitle = stringResource(MR.strings.global_update_interval_sub) subtitle = stringResource(MR.strings.global_update_interval_sub),
) )
} }
item { item {
@@ -720,7 +718,7 @@ fun LazyListScope.ServerSettingsItems(
EditTextPreference( EditTextPreference(
preference = serverSettings.maxSourcesInParallel, preference = serverSettings.maxSourcesInParallel,
title = stringResource(MR.strings.max_sources_parallel), title = stringResource(MR.strings.max_sources_parallel),
subtitle = stringResource(MR.strings.max_sources_parallel_sub) subtitle = stringResource(MR.strings.max_sources_parallel_sub),
) )
} }
@@ -778,7 +776,7 @@ fun LazyListScope.ServerSettingsItems(
preference = serverSettings.initialOpenInBrowserEnabled, preference = serverSettings.initialOpenInBrowserEnabled,
title = stringResource(MR.strings.host_open_in_browser), title = stringResource(MR.strings.host_open_in_browser),
subtitle = stringResource(MR.strings.host_open_in_browser_sub), subtitle = stringResource(MR.strings.host_open_in_browser_sub),
enabled = !hosted, //webUIEnabledValue, enabled = !hosted, // webUIEnabledValue,
) )
} }
@@ -802,14 +800,14 @@ fun LazyListScope.ServerSettingsItems(
PreferenceRow( PreferenceRow(
title = stringResource(MR.strings.backup_time), title = stringResource(MR.strings.backup_time),
subtitle = stringResource(MR.strings.backup_time_sub), subtitle = stringResource(MR.strings.backup_time_sub),
onClick = dialog::show onClick = dialog::show,
) )
BackupTimeDialog( BackupTimeDialog(
dialog, dialog,
backupTime, backupTime,
onSetTime = { onSetTime = {
serverSettings.backupTime.value = it serverSettings.backupTime.value = it
} },
) )
} }
@@ -818,7 +816,7 @@ fun LazyListScope.ServerSettingsItems(
preference = serverSettings.basicAuthEnabled, preference = serverSettings.basicAuthEnabled,
title = stringResource(MR.strings.basic_auth), title = stringResource(MR.strings.basic_auth),
subtitle = stringResource(MR.strings.host_basic_auth_sub), subtitle = stringResource(MR.strings.host_basic_auth_sub),
enabled = !hosted enabled = !hosted,
) )
} }
@@ -888,13 +886,13 @@ private val repoRegex =
( (
"https:\\/\\/(?>www\\.|raw\\.)?(github|githubusercontent)\\.com" + "https:\\/\\/(?>www\\.|raw\\.)?(github|githubusercontent)\\.com" +
"\\/([^\\/]+)\\/([^\\/]+)(?>(?>\\/tree|\\/blob)?\\/([^\\/\\n]*))?(?>\\/([^\\/\\n]*\\.json)?)?" "\\/([^\\/]+)\\/([^\\/]+)(?>(?>\\/tree|\\/blob)?\\/([^\\/\\n]*))?(?>\\/([^\\/\\n]*\\.json)?)?"
).toRegex() ).toRegex()
@Composable @Composable
fun ExtensionReposDialog( fun ExtensionReposDialog(
state: MaterialDialogState, state: MaterialDialogState,
extensionRepos: List<String>, extensionRepos: List<String>,
onSetRepos: (List<String>) -> Unit onSetRepos: (List<String>) -> Unit,
) { ) {
val repos = remember(state.showing) { val repos = remember(state.showing) {
extensionRepos.toMutableStateList() extensionRepos.toMutableStateList()
@@ -928,7 +926,7 @@ fun ExtensionReposDialog(
repos.add(newRepo) repos.add(newRepo)
newRepo = "" newRepo = ""
} }
} },
), ),
isError = newRepo.isNotBlank() && !repoMatches, isError = newRepo.isNotBlank() && !repoMatches,
) )
@@ -938,11 +936,11 @@ fun ExtensionReposDialog(
newRepo = "" newRepo = ""
}, },
enabled = repoMatches, enabled = repoMatches,
modifier = Modifier.weight(1f, fill = false) modifier = Modifier.weight(1f, fill = false),
) { ) {
Icon( Icon(
Icons.Rounded.Add, Icons.Rounded.Add,
contentDescription = stringResource(MR.strings.action_add) contentDescription = stringResource(MR.strings.action_add),
) )
} }
} }
@@ -963,15 +961,15 @@ fun ExtensionReposDialog(
style = MaterialTheme.typography.body1, style = MaterialTheme.typography.body1,
modifier = Modifier modifier = Modifier
.weight(4f) .weight(4f)
.wrapContentWidth(Alignment.Start) .wrapContentWidth(Alignment.Start),
) )
IconButton( IconButton(
onClick = { repos.remove(item) }, onClick = { repos.remove(item) },
modifier = Modifier.weight(1f, fill = false) modifier = Modifier.weight(1f, fill = false),
) { ) {
Icon( Icon(
Icons.Rounded.Delete, Icons.Rounded.Delete,
contentDescription = stringResource(MR.strings.action_delete) contentDescription = stringResource(MR.strings.action_delete),
) )
} }
} }
@@ -984,11 +982,12 @@ val formatter = LocalTime.Format {
char(':') char(':')
minute() minute()
} }
@Composable @Composable
fun BackupTimeDialog( fun BackupTimeDialog(
state: MaterialDialogState, state: MaterialDialogState,
backupTime: String, backupTime: String,
onSetTime: (String) -> Unit onSetTime: (String) -> Unit,
) { ) {
val time = remember(state.showing) { val time = remember(state.showing) {
LocalTime.parse(backupTime, formatter) LocalTime.parse(backupTime, formatter)

View File

@@ -79,8 +79,10 @@ actual class SettingsServerHostViewModel
// Downloader // Downloader
val downloadPath = serverHostPreferences.downloadPath().asStateIn(scope) val downloadPath = serverHostPreferences.downloadPath().asStateIn(scope)
// Backup // Backup
val backupPath = serverHostPreferences.backupPath().asStateIn(scope) val backupPath = serverHostPreferences.backupPath().asStateIn(scope)
// LocalSource // LocalSource
val localSourcePath = serverHostPreferences.localSourcePath().asStateIn(scope) val localSourcePath = serverHostPreferences.localSourcePath().asStateIn(scope)