mirror of
https://github.com/Suwayomi/TachideskJUI.git
synced 2025-12-10 06:42:05 +01:00
More formatting fixes
This commit is contained in:
@@ -49,7 +49,6 @@ import kotlinx.coroutines.flow.map
|
|||||||
import kotlinx.coroutines.flow.mapLatest
|
import kotlinx.coroutines.flow.mapLatest
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
import kotlinx.coroutines.job
|
import kotlinx.coroutines.job
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import org.lighthousegames.logging.logging
|
import org.lighthousegames.logging.logging
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
|||||||
@@ -67,7 +67,13 @@ subprojects {
|
|||||||
}
|
}
|
||||||
tasks.withType<org.jmailen.gradle.kotlinter.tasks.FormatTask> {
|
tasks.withType<org.jmailen.gradle.kotlinter.tasks.FormatTask> {
|
||||||
source(files("src"))
|
source(files("src"))
|
||||||
exclude("ca/gosyer/jui/*/build", "ca/gosyer/jui/*/build")
|
exclude(
|
||||||
|
"ca/gosyer/jui/*/build",
|
||||||
|
"ca/gosyer/jui/*/build",
|
||||||
|
"**/generated/**",
|
||||||
|
"ca/gosyer/jui/data/graphql",
|
||||||
|
"ca/gosyer/jui/uicore/icons/juiassets",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
plugins.withType<com.android.build.gradle.BasePlugin> {
|
plugins.withType<com.android.build.gradle.BasePlugin> {
|
||||||
configure<com.android.build.gradle.BaseExtension> {
|
configure<com.android.build.gradle.BaseExtension> {
|
||||||
|
|||||||
@@ -10,8 +10,10 @@ import com.russhwolf.settings.PreferencesSettings
|
|||||||
import me.tatarka.inject.annotations.Inject
|
import me.tatarka.inject.annotations.Inject
|
||||||
import java.util.prefs.Preferences
|
import java.util.prefs.Preferences
|
||||||
|
|
||||||
@Inject
|
actual class PreferenceStoreFactory {
|
||||||
actual class PreferenceStoreFactory() {
|
@Inject
|
||||||
|
constructor()
|
||||||
|
|
||||||
private val rootNode: Preferences = Preferences.userRoot()
|
private val rootNode: Preferences = Preferences.userRoot()
|
||||||
.node("ca/gosyer/tachideskjui")
|
.node("ca/gosyer/tachideskjui")
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,10 @@ import com.russhwolf.settings.NSUserDefaultsSettings
|
|||||||
import me.tatarka.inject.annotations.Inject
|
import me.tatarka.inject.annotations.Inject
|
||||||
import platform.Foundation.NSUserDefaults
|
import platform.Foundation.NSUserDefaults
|
||||||
|
|
||||||
@Inject
|
actual class PreferenceStoreFactory {
|
||||||
actual class PreferenceStoreFactory() {
|
@Inject
|
||||||
|
constructor()
|
||||||
|
|
||||||
actual fun create(vararg names: String): PreferenceStore =
|
actual fun create(vararg names: String): PreferenceStore =
|
||||||
StandardPreferenceStore(
|
StandardPreferenceStore(
|
||||||
NSUserDefaultsSettings(
|
NSUserDefaultsSettings(
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ import ca.gosyer.jui.core.lang.toPlatform
|
|||||||
import kotlinx.datetime.Instant
|
import kotlinx.datetime.Instant
|
||||||
import me.tatarka.inject.annotations.Inject
|
import me.tatarka.inject.annotations.Inject
|
||||||
|
|
||||||
@Inject
|
actual class DateHandler {
|
||||||
actual class DateHandler() {
|
@Inject
|
||||||
|
constructor()
|
||||||
|
|
||||||
actual val formatOptions by lazy {
|
actual val formatOptions by lazy {
|
||||||
listOf(
|
listOf(
|
||||||
"",
|
"",
|
||||||
|
|||||||
@@ -9,8 +9,10 @@ import java.time.ZoneId
|
|||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
import java.time.format.FormatStyle
|
import java.time.format.FormatStyle
|
||||||
|
|
||||||
@Inject
|
actual class DateHandler {
|
||||||
actual class DateHandler() {
|
@Inject
|
||||||
|
constructor()
|
||||||
|
|
||||||
actual val formatOptions by lazy {
|
actual val formatOptions by lazy {
|
||||||
listOf(
|
listOf(
|
||||||
"",
|
"",
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ abstract class WebsocketService(
|
|||||||
protected val json = Json {
|
protected val json = Json {
|
||||||
ignoreUnknownKeys = true
|
ignoreUnknownKeys = true
|
||||||
}
|
}
|
||||||
protected abstract val _status: MutableStateFlow<Status>
|
protected abstract val status: MutableStateFlow<Status>
|
||||||
|
|
||||||
protected val serverUrl = serverPreferences.serverUrl().stateIn(GlobalScope)
|
protected val serverUrl = serverPreferences.serverUrl().stateIn(GlobalScope)
|
||||||
|
|
||||||
@@ -47,10 +47,10 @@ abstract class WebsocketService(
|
|||||||
job?.cancel()
|
job?.cancel()
|
||||||
job = serverUrl
|
job = serverUrl
|
||||||
.mapLatest { serverUrl ->
|
.mapLatest { serverUrl ->
|
||||||
_status.value = Status.STARTING
|
status.value = Status.STARTING
|
||||||
while (true) {
|
while (true) {
|
||||||
if (errorConnectionCount > 3) {
|
if (errorConnectionCount > 3) {
|
||||||
_status.value = Status.STOPPED
|
status.value = Status.STOPPED
|
||||||
throw CancellationException("Finish")
|
throw CancellationException("Finish")
|
||||||
}
|
}
|
||||||
runCatching {
|
runCatching {
|
||||||
@@ -65,7 +65,7 @@ abstract class WebsocketService(
|
|||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
errorConnectionCount = 0
|
errorConnectionCount = 0
|
||||||
_status.value = Status.RUNNING
|
status.value = Status.RUNNING
|
||||||
send(Frame.Text("STATUS"))
|
send(Frame.Text("STATUS"))
|
||||||
|
|
||||||
incoming.receiveAsFlow()
|
incoming.receiveAsFlow()
|
||||||
@@ -77,13 +77,13 @@ abstract class WebsocketService(
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}.throwIfCancellation().isFailure.let {
|
}.throwIfCancellation().isFailure.let {
|
||||||
_status.value = Status.STARTING
|
status.value = Status.STARTING
|
||||||
if (it) errorConnectionCount++
|
if (it) errorConnectionCount++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.catch {
|
.catch {
|
||||||
_status.value = Status.STOPPED
|
status.value = Status.STOPPED
|
||||||
log.warn(it) { "Error while running websocket service" }
|
log.warn(it) { "Error while running websocket service" }
|
||||||
}
|
}
|
||||||
.launchIn(GlobalScope)
|
.launchIn(GlobalScope)
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ class DownloadService(
|
|||||||
serverPreferences: ServerPreferences,
|
serverPreferences: ServerPreferences,
|
||||||
client: Http,
|
client: Http,
|
||||||
) : WebsocketService(serverPreferences, client) {
|
) : WebsocketService(serverPreferences, client) {
|
||||||
override val _status: MutableStateFlow<Status>
|
override val status: MutableStateFlow<Status>
|
||||||
get() = status
|
get() = DownloadService.status
|
||||||
|
|
||||||
override val query: String
|
override val query: String
|
||||||
get() = "/api/v1/downloads"
|
get() = "/api/v1/downloads"
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ class LibraryUpdateService(
|
|||||||
serverPreferences: ServerPreferences,
|
serverPreferences: ServerPreferences,
|
||||||
client: Http,
|
client: Http,
|
||||||
) : WebsocketService(serverPreferences, client) {
|
) : WebsocketService(serverPreferences, client) {
|
||||||
override val _status: MutableStateFlow<Status>
|
override val status: MutableStateFlow<Status>
|
||||||
get() = status
|
get() = LibraryUpdateService.status
|
||||||
|
|
||||||
override val query: String
|
override val query: String
|
||||||
get() = "/api/v1/update"
|
get() = "/api/v1/update"
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ class SourcePager(
|
|||||||
) : CoroutineScope by CoroutineScope(Dispatchers.Default + SupervisorJob()) {
|
) : CoroutineScope by CoroutineScope(Dispatchers.Default + SupervisorJob()) {
|
||||||
private val sourceMutex = Mutex()
|
private val sourceMutex = Mutex()
|
||||||
|
|
||||||
private val _sourceManga = MutableStateFlow<List<Manga>>(emptyList())
|
private val sourceManga = MutableStateFlow<List<Manga>>(emptyList())
|
||||||
|
|
||||||
private val mangaIds = _sourceManga.map { mangas -> mangas.map { it.id } }
|
private val mangaIds = sourceManga.map { mangas -> mangas.map { it.id } }
|
||||||
.stateIn(this, SharingStarted.Eagerly, emptyList())
|
.stateIn(this, SharingStarted.Eagerly, emptyList())
|
||||||
|
|
||||||
private val changedManga =
|
private val changedManga =
|
||||||
@@ -57,7 +57,7 @@ class SourcePager(
|
|||||||
}
|
}
|
||||||
}.stateIn(this, SharingStarted.Eagerly, emptyMap())
|
}.stateIn(this, SharingStarted.Eagerly, emptyMap())
|
||||||
|
|
||||||
val mangas = combine(_sourceManga, changedManga) { sourceManga, changedManga ->
|
val mangas = combine(sourceManga, changedManga) { sourceManga, changedManga ->
|
||||||
sourceManga.map { changedManga[it.id] ?: it }
|
sourceManga.map { changedManga[it.id] ?: it }
|
||||||
}.stateIn(this, SharingStarted.Eagerly, emptyList())
|
}.stateIn(this, SharingStarted.Eagerly, emptyList())
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ class SourcePager(
|
|||||||
_pageNum.value++
|
_pageNum.value++
|
||||||
val page = fetcher.get(_pageNum.value)
|
val page = fetcher.get(_pageNum.value)
|
||||||
if (page != null) {
|
if (page != null) {
|
||||||
_sourceManga.value = _sourceManga.value + page.mangaList
|
sourceManga.value += page.mangaList
|
||||||
_hasNextPage.value = page.hasNextPage
|
_hasNextPage.value = page.hasNextPage
|
||||||
} else {
|
} else {
|
||||||
_pageNum.value--
|
_pageNum.value--
|
||||||
|
|||||||
@@ -8,6 +8,4 @@ package ca.gosyer.jui.ios
|
|||||||
|
|
||||||
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||||
|
|
||||||
actual fun create(context: ContextWrapper): AppComponent {
|
actual fun create(context: ContextWrapper): AppComponent = AppComponent.create(context)
|
||||||
return AppComponent.create(context)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,6 +8,4 @@ package ca.gosyer.jui.ios
|
|||||||
|
|
||||||
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||||
|
|
||||||
actual fun create(context: ContextWrapper): AppComponent {
|
actual fun create(context: ContextWrapper): AppComponent = AppComponent.create(context)
|
||||||
return AppComponent.create(context)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,6 +8,4 @@ package ca.gosyer.jui.ios
|
|||||||
|
|
||||||
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||||
|
|
||||||
actual fun create(context: ContextWrapper): AppComponent {
|
actual fun create(context: ContextWrapper): AppComponent = AppComponent.create(context)
|
||||||
return AppComponent.create(context)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ class ReaderMenuViewModel(
|
|||||||
cur.orEmpty() +
|
cur.orEmpty() +
|
||||||
ReaderPageSeparator(viewerChapters.currChapter, viewerChapters.nextChapter) +
|
ReaderPageSeparator(viewerChapters.currChapter, viewerChapters.nextChapter) +
|
||||||
next.orEmpty()
|
next.orEmpty()
|
||||||
).toImmutableList()
|
).toImmutableList()
|
||||||
}
|
}
|
||||||
}.stateIn(scope, SharingStarted.Eagerly, persistentListOf())
|
}.stateIn(scope, SharingStarted.Eagerly, persistentListOf())
|
||||||
|
|
||||||
|
|||||||
@@ -185,16 +185,17 @@ class SettingsBackupViewModel(
|
|||||||
.launchIn(scope)
|
.launchIn(scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun RestoreStatus.toStatus() = when (state) {
|
private fun RestoreStatus.toStatus() =
|
||||||
RestoreState.IDLE -> Status.Success
|
when (state) {
|
||||||
RestoreState.SUCCESS -> Status.Success
|
RestoreState.IDLE -> Status.Success
|
||||||
RestoreState.FAILURE -> Status.Error
|
RestoreState.SUCCESS -> Status.Success
|
||||||
RestoreState.RESTORING_CATEGORIES -> Status.InProgress(0.01f)
|
RestoreState.FAILURE -> Status.Error
|
||||||
RestoreState.RESTORING_SETTINGS -> Status.InProgress(0.02f)
|
RestoreState.RESTORING_CATEGORIES -> Status.InProgress(0.01f)
|
||||||
RestoreState.RESTORING_MANGA -> Status.InProgress((completed.toFloat() / total).coerceIn(0f, 0.99f))
|
RestoreState.RESTORING_SETTINGS -> Status.InProgress(0.02f)
|
||||||
RestoreState.RESTORING_META -> Status.InProgress(1f)
|
RestoreState.RESTORING_MANGA -> Status.InProgress((completed.toFloat() / total).coerceIn(0f, 0.99f))
|
||||||
RestoreState.UNKNOWN -> Status.Error
|
RestoreState.RESTORING_META -> Status.InProgress(1f)
|
||||||
}
|
RestoreState.UNKNOWN -> Status.Error
|
||||||
|
}
|
||||||
|
|
||||||
fun stopRestore() {
|
fun stopRestore() {
|
||||||
_restoreStatus.value = Status.Error
|
_restoreStatus.value = Status.Error
|
||||||
@@ -206,7 +207,8 @@ class SettingsBackupViewModel(
|
|||||||
fun exportBackup() {
|
fun exportBackup() {
|
||||||
exportBackupFile
|
exportBackupFile
|
||||||
.asFlow(
|
.asFlow(
|
||||||
true, true, // todo
|
true,
|
||||||
|
true, // todo
|
||||||
) {
|
) {
|
||||||
onDownload { bytesSentTotal, contentLength ->
|
onDownload { bytesSentTotal, contentLength ->
|
||||||
_creatingStatus.value = Status.InProgress(
|
_creatingStatus.value = Status.InProgress(
|
||||||
|
|||||||
@@ -887,7 +887,7 @@ 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(
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ import kotlinx.coroutines.flow.collect
|
|||||||
import kotlinx.coroutines.flow.mapLatest
|
import kotlinx.coroutines.flow.mapLatest
|
||||||
import kotlinx.coroutines.flow.merge
|
import kotlinx.coroutines.flow.merge
|
||||||
|
|
||||||
private fun SourceFiltersView<*, *>.toSourceFilter(): SourceFilter {
|
private fun SourceFiltersView<*, *>.toSourceFilter(): SourceFilter =
|
||||||
return when (this) {
|
when (this) {
|
||||||
is SourceFiltersView.CheckBox -> filter.copy(value = state.value)
|
is SourceFiltersView.CheckBox -> filter.copy(value = state.value)
|
||||||
is SourceFiltersView.Group -> filter.copy(value = state.value.map { it.toSourceFilter() })
|
is SourceFiltersView.Group -> filter.copy(value = state.value.map { it.toSourceFilter() })
|
||||||
is SourceFiltersView.Header -> filter
|
is SourceFiltersView.Header -> filter
|
||||||
@@ -37,7 +37,6 @@ private fun SourceFiltersView<*, *>.toSourceFilter(): SourceFilter {
|
|||||||
is SourceFiltersView.Text -> filter.copy(value = state.value)
|
is SourceFiltersView.Text -> filter.copy(value = state.value)
|
||||||
is SourceFiltersView.TriState -> filter.copy(value = state.value)
|
is SourceFiltersView.TriState -> filter.copy(value = state.value)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
class SourceScreen(
|
class SourceScreen(
|
||||||
val source: Source,
|
val source: Source,
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ sealed class SourceSettingsView<T : SourcePreference, R : Any?> {
|
|||||||
override val title: String?,
|
override val title: String?,
|
||||||
override val subtitle: String?,
|
override val subtitle: String?,
|
||||||
override val props: CheckBoxSourcePreference,
|
override val props: CheckBoxSourcePreference,
|
||||||
) : SourceSettingsView<CheckBoxSourcePreference, Boolean>(){
|
) : SourceSettingsView<CheckBoxSourcePreference, Boolean>() {
|
||||||
private val _state = MutableStateFlow(
|
private val _state = MutableStateFlow(
|
||||||
props.currentValue ?: props.default,
|
props.currentValue ?: props.default,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -19,8 +19,7 @@ import me.tatarka.inject.annotations.Inject
|
|||||||
import org.lighthousegames.logging.logging
|
import org.lighthousegames.logging.logging
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
class TrayViewModel
|
class TrayViewModel(
|
||||||
constructor(
|
|
||||||
updateChecker: UpdateChecker,
|
updateChecker: UpdateChecker,
|
||||||
contextWrapper: ContextWrapper,
|
contextWrapper: ContextWrapper,
|
||||||
) : ViewModel(contextWrapper) {
|
) : ViewModel(contextWrapper) {
|
||||||
|
|||||||
@@ -67,8 +67,7 @@ actual fun getServerHostItems(viewModel: @Composable () -> SettingsServerHostVie
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
actual class SettingsServerHostViewModel
|
actual class SettingsServerHostViewModel(
|
||||||
constructor(
|
|
||||||
serverPreferences: ServerPreferences,
|
serverPreferences: ServerPreferences,
|
||||||
serverHostPreferences: ServerHostPreferences,
|
serverHostPreferences: ServerHostPreferences,
|
||||||
private val serverService: ServerService,
|
private val serverService: ServerService,
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
|||||||
import me.tatarka.inject.annotations.Inject
|
import me.tatarka.inject.annotations.Inject
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
actual class DebugOverlayViewModel
|
actual class DebugOverlayViewModel(
|
||||||
constructor(
|
|
||||||
contextWrapper: ContextWrapper,
|
contextWrapper: ContextWrapper,
|
||||||
) : ViewModel(contextWrapper) {
|
) : ViewModel(contextWrapper) {
|
||||||
actual val maxMemory: String
|
actual val maxMemory: String
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import me.tatarka.inject.annotations.Inject
|
|||||||
actual fun getServerHostItems(viewModel: @Composable () -> SettingsServerHostViewModel): LazyListScope.() -> Unit = {}
|
actual fun getServerHostItems(viewModel: @Composable () -> SettingsServerHostViewModel): LazyListScope.() -> Unit = {}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
actual class SettingsServerHostViewModel
|
actual class SettingsServerHostViewModel(
|
||||||
constructor(
|
|
||||||
contextWrapper: ContextWrapper,
|
contextWrapper: ContextWrapper,
|
||||||
) : ViewModel(contextWrapper)
|
) : ViewModel(contextWrapper)
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ import androidx.compose.ui.text.intl.Locale
|
|||||||
import platform.Foundation.NSString
|
import platform.Foundation.NSString
|
||||||
import platform.Foundation.localizedCaseInsensitiveCompare
|
import platform.Foundation.localizedCaseInsensitiveCompare
|
||||||
|
|
||||||
actual class CollatorComparator() : Comparator<String> {
|
actual class CollatorComparator : Comparator<String> {
|
||||||
|
constructor()
|
||||||
actual constructor(locale: Locale) : this()
|
actual constructor(locale: Locale) : this()
|
||||||
|
|
||||||
actual override fun compare(
|
actual override fun compare(
|
||||||
|
|||||||
@@ -17,8 +17,7 @@ import me.tatarka.inject.annotations.Inject
|
|||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
actual class DebugOverlayViewModel
|
actual class DebugOverlayViewModel(
|
||||||
constructor(
|
|
||||||
contextWrapper: ContextWrapper,
|
contextWrapper: ContextWrapper,
|
||||||
) : ViewModel(contextWrapper) {
|
) : ViewModel(contextWrapper) {
|
||||||
override val scope = MainScope()
|
override val scope = MainScope()
|
||||||
|
|||||||
@@ -15,8 +15,10 @@ import kotlinx.coroutines.flow.MutableSharedFlow
|
|||||||
import kotlinx.coroutines.flow.asSharedFlow
|
import kotlinx.coroutines.flow.asSharedFlow
|
||||||
import me.tatarka.inject.annotations.Inject
|
import me.tatarka.inject.annotations.Inject
|
||||||
|
|
||||||
@Inject
|
actual class ContextWrapper {
|
||||||
actual class ContextWrapper() {
|
@Inject
|
||||||
|
constructor()
|
||||||
|
|
||||||
private val _toasts = MutableSharedFlow<Pair<String, Length>>()
|
private val _toasts = MutableSharedFlow<Pair<String, Length>>()
|
||||||
val toasts = _toasts.asSharedFlow()
|
val toasts = _toasts.asSharedFlow()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user