mirror of
https://github.com/revanced/revanced-manager
synced 2024-05-14 13:56:57 +02:00
refactor: use correct coroutine scopes
This commit is contained in:
parent
18cbe51e6b
commit
81f485da6b
@ -19,13 +19,14 @@ import app.revanced.manager.domain.sources.RemoteSource
|
|||||||
import app.revanced.manager.domain.sources.Source
|
import app.revanced.manager.domain.sources.Source
|
||||||
import app.revanced.manager.ui.viewmodel.SourcesViewModel
|
import app.revanced.manager.ui.viewmodel.SourcesViewModel
|
||||||
import app.revanced.manager.util.uiSafe
|
import app.revanced.manager.util.uiSafe
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun SourceItem(source: Source, onDelete: () -> Unit) {
|
fun SourceItem(source: Source, onDelete: () -> Unit, coroutineScope: CoroutineScope) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val composableScope = rememberCoroutineScope()
|
||||||
var sheetActive by rememberSaveable { mutableStateOf(false) }
|
var sheetActive by rememberSaveable { mutableStateOf(false) }
|
||||||
|
|
||||||
val bundle by source.bundle.collectAsStateWithLifecycle()
|
val bundle by source.bundle.collectAsStateWithLifecycle()
|
||||||
@ -53,14 +54,15 @@ fun SourceItem(source: Source, onDelete: () -> Unit) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
when (source) {
|
when (source) {
|
||||||
is RemoteSource -> RemoteSourceItem(source)
|
is RemoteSource -> RemoteSourceItem(source, coroutineScope)
|
||||||
is LocalSource -> LocalSourceItem(source)
|
is LocalSource -> LocalSourceItem(source, coroutineScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
coroutineScope.launch {
|
composableScope.launch {
|
||||||
modalSheetState.hide()
|
modalSheetState.hide()
|
||||||
|
sheetActive = false
|
||||||
onDelete()
|
onDelete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,8 +103,7 @@ fun SourceItem(source: Source, onDelete: () -> Unit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun RemoteSourceItem(source: RemoteSource) {
|
private fun RemoteSourceItem(source: RemoteSource, coroutineScope: CoroutineScope) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
|
||||||
val androidContext = LocalContext.current
|
val androidContext = LocalContext.current
|
||||||
Text(text = "(api url here)")
|
Text(text = "(api url here)")
|
||||||
|
|
||||||
@ -118,12 +119,16 @@ private fun RemoteSourceItem(source: RemoteSource) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun LocalSourceItem(source: LocalSource) {
|
private fun LocalSourceItem(source: LocalSource, coroutineScope: CoroutineScope) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
|
||||||
val androidContext = LocalContext.current
|
val androidContext = LocalContext.current
|
||||||
val resolver = remember { androidContext.contentResolver!! }
|
val resolver = remember { androidContext.contentResolver!! }
|
||||||
|
|
||||||
fun loadAndReplace(uri: Uri, @StringRes toastMsg: Int, errorLogMsg: String, callback: suspend (InputStream) -> Unit) = coroutineScope.launch {
|
fun loadAndReplace(
|
||||||
|
uri: Uri,
|
||||||
|
@StringRes toastMsg: Int,
|
||||||
|
errorLogMsg: String,
|
||||||
|
callback: suspend (InputStream) -> Unit
|
||||||
|
) = coroutineScope.launch {
|
||||||
uiSafe(androidContext, toastMsg, errorLogMsg) {
|
uiSafe(androidContext, toastMsg, errorLogMsg) {
|
||||||
resolver.openInputStream(uri)!!.use {
|
resolver.openInputStream(uri)!!.use {
|
||||||
callback(it)
|
callback(it)
|
||||||
@ -138,7 +143,11 @@ private fun LocalSourceItem(source: LocalSource) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onIntegrationsSelection = { uri ->
|
onIntegrationsSelection = { uri ->
|
||||||
loadAndReplace(uri, R.string.source_replace_integrations_fail, "Failed to replace integrations") {
|
loadAndReplace(
|
||||||
|
uri,
|
||||||
|
R.string.source_replace_integrations_fail,
|
||||||
|
"Failed to replace integrations"
|
||||||
|
) {
|
||||||
source.replace(null, it)
|
source.replace(null, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ fun DashboardScreen(
|
|||||||
val pages: Array<DashboardPage> = DashboardPage.values()
|
val pages: Array<DashboardPage> = DashboardPage.values()
|
||||||
|
|
||||||
val pagerState = rememberPagerState()
|
val pagerState = rememberPagerState()
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val composableScope = rememberCoroutineScope()
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
@ -74,7 +74,7 @@ fun DashboardScreen(
|
|||||||
pages.forEachIndexed { index, page ->
|
pages.forEachIndexed { index, page ->
|
||||||
Tab(
|
Tab(
|
||||||
selected = pagerState.currentPage == index,
|
selected = pagerState.currentPage == index,
|
||||||
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(index) } },
|
onClick = { composableScope.launch { pagerState.animateScrollToPage(index) } },
|
||||||
text = { Text(stringResource(page.titleResId)) },
|
text = { Text(stringResource(page.titleResId)) },
|
||||||
icon = { Icon(page.icon, null) },
|
icon = { Icon(page.icon, null) },
|
||||||
selectedContentColor = MaterialTheme.colorScheme.primary,
|
selectedContentColor = MaterialTheme.colorScheme.primary,
|
||||||
|
@ -59,7 +59,7 @@ fun PatchesSelectorScreen(
|
|||||||
vm: PatchesSelectorViewModel
|
vm: PatchesSelectorViewModel
|
||||||
) {
|
) {
|
||||||
val pagerState = rememberPagerState()
|
val pagerState = rememberPagerState()
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val composableScope = rememberCoroutineScope()
|
||||||
|
|
||||||
val bundles by vm.bundlesFlow.collectAsStateWithLifecycle(initialValue = emptyArray())
|
val bundles by vm.bundlesFlow.collectAsStateWithLifecycle(initialValue = emptyArray())
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ fun PatchesSelectorScreen(
|
|||||||
text = { Text(stringResource(R.string.patch)) },
|
text = { Text(stringResource(R.string.patch)) },
|
||||||
icon = { Icon(Icons.Default.Build, null) },
|
icon = { Icon(Icons.Default.Build, null) },
|
||||||
onClick = {
|
onClick = {
|
||||||
coroutineScope.launch {
|
composableScope.launch {
|
||||||
onPatchClick(vm.getAndSaveSelection())
|
onPatchClick(vm.getAndSaveSelection())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,7 +112,7 @@ fun PatchesSelectorScreen(
|
|||||||
bundles.forEachIndexed { index, bundle ->
|
bundles.forEachIndexed { index, bundle ->
|
||||||
Tab(
|
Tab(
|
||||||
selected = pagerState.currentPage == index,
|
selected = pagerState.currentPage == index,
|
||||||
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(index) } },
|
onClick = { composableScope.launch { pagerState.animateScrollToPage(index) } },
|
||||||
text = { Text(bundle.name) },
|
text = { Text(bundle.name) },
|
||||||
selectedContentColor = MaterialTheme.colorScheme.primary,
|
selectedContentColor = MaterialTheme.colorScheme.primary,
|
||||||
unselectedContentColor = MaterialTheme.colorScheme.onSurfaceVariant
|
unselectedContentColor = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
@ -7,33 +7,27 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
import app.revanced.manager.R
|
import app.revanced.manager.R
|
||||||
import app.revanced.manager.ui.component.sources.NewSourceDialog
|
import app.revanced.manager.ui.component.sources.NewSourceDialog
|
||||||
import app.revanced.manager.ui.component.sources.SourceItem
|
import app.revanced.manager.ui.component.sources.SourceItem
|
||||||
import app.revanced.manager.ui.viewmodel.SourcesViewModel
|
import app.revanced.manager.ui.viewmodel.SourcesViewModel
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.koin.androidx.compose.getViewModel
|
import org.koin.androidx.compose.getViewModel
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SourcesScreen(vm: SourcesViewModel = getViewModel()) {
|
fun SourcesScreen(vm: SourcesViewModel = getViewModel()) {
|
||||||
var showNewSourceDialog by rememberSaveable { mutableStateOf(false) }
|
var showNewSourceDialog by rememberSaveable { mutableStateOf(false) }
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
|
|
||||||
val sources by vm.sources.collectAsStateWithLifecycle(initialValue = emptyList())
|
val sources by vm.sources.collectAsStateWithLifecycle(initialValue = emptyList())
|
||||||
|
|
||||||
if (showNewSourceDialog) NewSourceDialog(
|
if (showNewSourceDialog) NewSourceDialog(
|
||||||
onDismissRequest = { showNewSourceDialog = false },
|
onDismissRequest = { showNewSourceDialog = false },
|
||||||
onLocalSubmit = { name, patches, integrations ->
|
onLocalSubmit = { name, patches, integrations ->
|
||||||
showNewSourceDialog = false
|
showNewSourceDialog = false
|
||||||
scope.launch {
|
vm.addLocal(name, patches, integrations)
|
||||||
vm.addLocal(name, patches, integrations)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
onRemoteSubmit = { name, url ->
|
onRemoteSubmit = { name, url ->
|
||||||
showNewSourceDialog = false
|
showNewSourceDialog = false
|
||||||
scope.launch {
|
vm.addRemote(name, url)
|
||||||
vm.addRemote(name, url)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -46,7 +40,8 @@ fun SourcesScreen(vm: SourcesViewModel = getViewModel()) {
|
|||||||
source = it,
|
source = it,
|
||||||
onDelete = {
|
onDelete = {
|
||||||
vm.delete(it)
|
vm.delete(it)
|
||||||
}
|
},
|
||||||
|
coroutineScope = vm.viewModelScope
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,9 +80,11 @@ class PatchesSelectorViewModel(
|
|||||||
if (patches.contains(name)) patches.remove(name) else patches.add(name)
|
if (patches.contains(name)) patches.remove(name) else patches.add(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getAndSaveSelection(): PatchesSelection = withContext(Dispatchers.Default) {
|
suspend fun getAndSaveSelection(): PatchesSelection =
|
||||||
selectedPatches.also {
|
selectedPatches.also {
|
||||||
selectionRepository.updateSelection(appInfo.packageName, it)
|
withContext(Dispatchers.Default) {
|
||||||
|
selectionRepository.updateSelection(appInfo.packageName, it)
|
||||||
|
}
|
||||||
}.mapValues { it.value.toMutableList() }.apply {
|
}.mapValues { it.value.toMutableList() }.apply {
|
||||||
if (allowExperimental) {
|
if (allowExperimental) {
|
||||||
return@apply
|
return@apply
|
||||||
@ -93,7 +95,6 @@ class PatchesSelectorViewModel(
|
|||||||
this[it.uid]?.removeAll(it.unsupported.map { patch -> patch.name })
|
this[it.uid]?.removeAll(it.unsupported.map { patch -> patch.name })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch(Dispatchers.Default) {
|
viewModelScope.launch(Dispatchers.Default) {
|
||||||
|
@ -12,7 +12,10 @@ import app.revanced.manager.util.uiSafe
|
|||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class SourcesViewModel(private val app: Application, private val sourceRepository: SourceRepository) : ViewModel() {
|
class SourcesViewModel(
|
||||||
|
private val app: Application,
|
||||||
|
private val sourceRepository: SourceRepository
|
||||||
|
) : ViewModel() {
|
||||||
val sources = sourceRepository.sources
|
val sources = sourceRepository.sources
|
||||||
private val contentResolver: ContentResolver = app.contentResolver
|
private val contentResolver: ContentResolver = app.contentResolver
|
||||||
|
|
||||||
@ -26,7 +29,7 @@ class SourcesViewModel(private val app: Application, private val sourceRepositor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun addLocal(name: String, patchBundle: Uri, integrations: Uri?) {
|
fun addLocal(name: String, patchBundle: Uri, integrations: Uri?) = viewModelScope.launch {
|
||||||
contentResolver.openInputStream(patchBundle)!!.use { patchesStream ->
|
contentResolver.openInputStream(patchBundle)!!.use { patchesStream ->
|
||||||
val integrationsStream = integrations?.let { contentResolver.openInputStream(it) }
|
val integrationsStream = integrations?.let { contentResolver.openInputStream(it) }
|
||||||
try {
|
try {
|
||||||
@ -37,7 +40,8 @@ class SourcesViewModel(private val app: Application, private val sourceRepositor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun addRemote(name: String, apiUrl: Url) = sourceRepository.createRemoteSource(name, apiUrl)
|
fun addRemote(name: String, apiUrl: Url) =
|
||||||
|
viewModelScope.launch { sourceRepository.createRemoteSource(name, apiUrl) }
|
||||||
|
|
||||||
fun delete(source: Source) = viewModelScope.launch { sourceRepository.remove(source) }
|
fun delete(source: Source) = viewModelScope.launch { sourceRepository.remove(source) }
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user