[优化] 一些界面问题
This commit is contained in:
@@ -16,6 +16,7 @@ import io.legado.app.constant.NotificationId
|
|||||||
import io.legado.app.constant.PreferKey
|
import io.legado.app.constant.PreferKey
|
||||||
import io.legado.app.receiver.NetworkChangedListener
|
import io.legado.app.receiver.NetworkChangedListener
|
||||||
import io.legado.app.utils.NetworkUtils
|
import io.legado.app.utils.NetworkUtils
|
||||||
|
import io.legado.app.utils.eventBus.FlowEventBus
|
||||||
import io.legado.app.utils.getPrefBoolean
|
import io.legado.app.utils.getPrefBoolean
|
||||||
import io.legado.app.utils.getPrefInt
|
import io.legado.app.utils.getPrefInt
|
||||||
import io.legado.app.utils.postEvent
|
import io.legado.app.utils.postEvent
|
||||||
@@ -108,6 +109,7 @@ class WebService : BaseService() {
|
|||||||
}
|
}
|
||||||
startForegroundNotification()
|
startForegroundNotification()
|
||||||
postEvent(EventBus.WEB_SERVICE, hostAddress)
|
postEvent(EventBus.WEB_SERVICE, hostAddress)
|
||||||
|
FlowEventBus.post(EventBus.WEB_SERVICE, hostAddress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,6 +143,7 @@ class WebService : BaseService() {
|
|||||||
webSocketServer?.stop()
|
webSocketServer?.stop()
|
||||||
}
|
}
|
||||||
postEvent(EventBus.WEB_SERVICE, "")
|
postEvent(EventBus.WEB_SERVICE, "")
|
||||||
|
FlowEventBus.post(EventBus.WEB_SERVICE, "")
|
||||||
upTile(false)
|
upTile(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,6 +173,7 @@ class WebService : BaseService() {
|
|||||||
hostAddress = notificationList.first()
|
hostAddress = notificationList.first()
|
||||||
isRun = true
|
isRun = true
|
||||||
postEvent(EventBus.WEB_SERVICE, hostAddress)
|
postEvent(EventBus.WEB_SERVICE, hostAddress)
|
||||||
|
FlowEventBus.post(EventBus.WEB_SERVICE, hostAddress)
|
||||||
startForegroundNotification()
|
startForegroundNotification()
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
toastOnUi(e.localizedMessage ?: "")
|
toastOnUi(e.localizedMessage ?: "")
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import androidx.compose.material.icons.filled.Settings
|
|||||||
import androidx.compose.material.icons.filled.Source
|
import androidx.compose.material.icons.filled.Source
|
||||||
import androidx.compose.material.icons.filled.Translate
|
import androidx.compose.material.icons.filled.Translate
|
||||||
import androidx.compose.material.icons.filled.Web
|
import androidx.compose.material.icons.filled.Web
|
||||||
import androidx.compose.material3.DropdownMenu
|
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
@@ -37,9 +36,6 @@ import androidx.compose.material3.TopAppBarDefaults
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@@ -67,7 +63,6 @@ fun MyScreen(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
val uiState by viewModel.uiState.collectAsState()
|
val uiState by viewModel.uiState.collectAsState()
|
||||||
var showMenu by remember { mutableStateOf(false) }
|
|
||||||
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
@@ -126,35 +121,26 @@ fun MyScreen(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onClick = {
|
dropdownMenu = if (uiState.isWebServiceRun) {
|
||||||
viewModel.onEvent(PrefClickEvent.ToggleWebService)
|
{ onDismiss ->
|
||||||
},
|
|
||||||
onLongClick = {
|
|
||||||
if (uiState.isWebServiceRun) {
|
|
||||||
showMenu = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
DropdownMenu(
|
|
||||||
expanded = showMenu,
|
|
||||||
onDismissRequest = { showMenu = false }
|
|
||||||
) {
|
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text("复制地址") },
|
text = { Text("复制地址") },
|
||||||
onClick = {
|
onClick = {
|
||||||
onNavigate(PrefClickEvent.CopyUrl(uiState.webServiceAddress))
|
onNavigate(PrefClickEvent.CopyUrl(uiState.webServiceAddress))
|
||||||
showMenu = false
|
onDismiss()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text("浏览器打开") },
|
text = { Text("浏览器打开") },
|
||||||
onClick = {
|
onClick = {
|
||||||
onNavigate(PrefClickEvent.OpenUrl(uiState.webServiceAddress))
|
onNavigate(PrefClickEvent.OpenUrl(uiState.webServiceAddress))
|
||||||
showMenu = false
|
onDismiss()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
} else null,
|
||||||
|
onClick = { }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
SplicedColumnGroup(
|
SplicedColumnGroup(
|
||||||
|
|||||||
@@ -2,10 +2,15 @@ package io.legado.app.ui.main.my
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import io.legado.app.constant.EventBus
|
||||||
import io.legado.app.service.WebService
|
import io.legado.app.service.WebService
|
||||||
|
import io.legado.app.utils.eventBus.FlowEventBus
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
data class MyUiState(
|
data class MyUiState(
|
||||||
val isWebServiceRun: Boolean = false,
|
val isWebServiceRun: Boolean = false,
|
||||||
@@ -17,7 +22,6 @@ sealed class PrefClickEvent {
|
|||||||
data class CopyUrl(val url: String) : PrefClickEvent()
|
data class CopyUrl(val url: String) : PrefClickEvent()
|
||||||
data class ShowMd(val title: String, val path: String) : PrefClickEvent()
|
data class ShowMd(val title: String, val path: String) : PrefClickEvent()
|
||||||
data class StartActivity(val destination: Class<*>, val configTag: String? = null) : PrefClickEvent()
|
data class StartActivity(val destination: Class<*>, val configTag: String? = null) : PrefClickEvent()
|
||||||
object ShowWebServiceMenu : PrefClickEvent()
|
|
||||||
object ToggleWebService : PrefClickEvent()
|
object ToggleWebService : PrefClickEvent()
|
||||||
object ExitApp : PrefClickEvent()
|
object ExitApp : PrefClickEvent()
|
||||||
}
|
}
|
||||||
@@ -29,40 +33,40 @@ class MyViewModel(
|
|||||||
private val _uiState = MutableStateFlow(
|
private val _uiState = MutableStateFlow(
|
||||||
MyUiState(
|
MyUiState(
|
||||||
isWebServiceRun = WebService.isRun,
|
isWebServiceRun = WebService.isRun,
|
||||||
webServiceAddress = if (WebService.isRun) {
|
webServiceAddress = WebService.hostAddress
|
||||||
WebService.hostAddress
|
|
||||||
} else ""
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val uiState: StateFlow<MyUiState> = _uiState.asStateFlow()
|
val uiState: StateFlow<MyUiState> = _uiState.asStateFlow()
|
||||||
|
|
||||||
|
init {
|
||||||
|
viewModelScope.launch {
|
||||||
|
FlowEventBus.with<String>(EventBus.WEB_SERVICE)
|
||||||
|
.collect { address ->
|
||||||
|
_uiState.update { state ->
|
||||||
|
state.copy(
|
||||||
|
isWebServiceRun = address.isNotEmpty(),
|
||||||
|
webServiceAddress = address
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun onEvent(event: PrefClickEvent) {
|
fun onEvent(event: PrefClickEvent) {
|
||||||
when (event) {
|
when (event) {
|
||||||
|
|
||||||
PrefClickEvent.ToggleWebService -> {
|
PrefClickEvent.ToggleWebService -> {
|
||||||
val newRun = !_uiState.value.isWebServiceRun
|
val currentIsRun = _uiState.value.isWebServiceRun
|
||||||
if (newRun) {
|
|
||||||
|
if (!currentIsRun) {
|
||||||
WebService.start(getApplication())
|
WebService.start(getApplication())
|
||||||
} else {
|
} else {
|
||||||
WebService.stop(getApplication())
|
WebService.stop(getApplication())
|
||||||
}
|
_uiState.update { it.copy(isWebServiceRun = false, webServiceAddress = "") }
|
||||||
updateWebServiceState()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PrefClickEvent.ShowWebServiceMenu -> {
|
|
||||||
// UI 自己处理 showMenu
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateWebServiceState() {
|
|
||||||
_uiState.value = MyUiState(
|
|
||||||
isWebServiceRun = WebService.isRun,
|
|
||||||
webServiceAddress = if (WebService.isRun) {
|
|
||||||
WebService.hostAddress
|
|
||||||
} else ""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ import io.legado.app.data.repository.UploadRepository
|
|||||||
import io.legado.app.ui.replace.edit.ReplaceEditActivity
|
import io.legado.app.ui.replace.edit.ReplaceEditActivity
|
||||||
import io.legado.app.ui.widget.components.ActionItem
|
import io.legado.app.ui.widget.components.ActionItem
|
||||||
import io.legado.app.ui.widget.components.AnimatedText
|
import io.legado.app.ui.widget.components.AnimatedText
|
||||||
|
import io.legado.app.ui.widget.components.EmptyMessageView
|
||||||
import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn
|
import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn
|
||||||
import io.legado.app.ui.widget.components.SearchBarSection
|
import io.legado.app.ui.widget.components.SearchBarSection
|
||||||
import io.legado.app.ui.widget.components.SelectionBottomBar
|
import io.legado.app.ui.widget.components.SelectionBottomBar
|
||||||
@@ -494,6 +495,12 @@ fun ReplaceRuleScreen(
|
|||||||
.padding(padding)
|
.padding(padding)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
|
if (rules.isEmpty()) {
|
||||||
|
EmptyMessageView(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
message = "没有替换规则!"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
FastScrollLazyColumn(
|
FastScrollLazyColumn(
|
||||||
state = listState,
|
state = listState,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -630,6 +637,7 @@ fun ReplaceRuleScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@@ -1,34 +1,30 @@
|
|||||||
package io.legado.app.ui.widget.components
|
package io.legado.app.ui.widget.components
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.combinedClickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
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.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.heightIn
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ChevronRight
|
import androidx.compose.material.icons.filled.ChevronRight
|
||||||
import androidx.compose.material.icons.filled.Info
|
import androidx.compose.material.icons.filled.Info
|
||||||
|
import androidx.compose.material3.DropdownMenu
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.ListItem
|
import androidx.compose.material3.ListItem
|
||||||
import androidx.compose.material3.ListItemDefaults
|
import androidx.compose.material3.ListItemDefaults
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.MaterialTheme.colorScheme
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.painter.Painter
|
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.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
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.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@@ -101,34 +97,38 @@ fun SettingItem(
|
|||||||
description: String? = null,
|
description: String? = null,
|
||||||
option: String? = null,
|
option: String? = null,
|
||||||
trailingContent: @Composable (() -> Unit)? = null,
|
trailingContent: @Composable (() -> Unit)? = null,
|
||||||
|
dropdownMenu: (@Composable (onDismiss: () -> Unit) -> Unit)? = null,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
onLongClick: (() -> Unit)? = null,
|
onLongClick: (() -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
|
var showMenu by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
Box ( modifier = Modifier.fillMaxWidth() ){
|
||||||
ListItem(
|
ListItem(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.clip(RoundedCornerShape(4.dp))
|
.clip(RoundedCornerShape(4.dp))
|
||||||
.combinedClickable(
|
.combinedClickable(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
onLongClick = onLongClick
|
onLongClick = {
|
||||||
|
if (dropdownMenu != null) {
|
||||||
|
showMenu = true
|
||||||
|
onLongClick?.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
),
|
),
|
||||||
leadingContent = {
|
leadingContent = {
|
||||||
when {
|
when {
|
||||||
painter != null -> {
|
painter != null -> Icon(
|
||||||
Icon(
|
|
||||||
painter = painter,
|
painter = painter,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = MaterialTheme.colorScheme.onSurfaceVariant
|
tint = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
)
|
)
|
||||||
}
|
imageVector != null -> Icon(
|
||||||
|
|
||||||
imageVector != null -> {
|
|
||||||
Icon(
|
|
||||||
imageVector = imageVector,
|
imageVector = imageVector,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = MaterialTheme.colorScheme.onSurfaceVariant
|
tint = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
headlineContent = {
|
headlineContent = {
|
||||||
Text(
|
Text(
|
||||||
@@ -137,7 +137,9 @@ fun SettingItem(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
supportingContent = {
|
supportingContent = {
|
||||||
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
|
Column(
|
||||||
|
verticalArrangement = Arrangement.spacedBy(2.dp)
|
||||||
|
) {
|
||||||
description?.let {
|
description?.let {
|
||||||
Text(
|
Text(
|
||||||
text = it,
|
text = it,
|
||||||
@@ -145,9 +147,8 @@ fun SettingItem(
|
|||||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
option?.let {
|
option?.let {
|
||||||
AnimatedTextLine(
|
Text(
|
||||||
text = it,
|
text = it,
|
||||||
style = MaterialTheme.typography.labelMedium,
|
style = MaterialTheme.typography.labelMedium,
|
||||||
color = MaterialTheme.colorScheme.primary,
|
color = MaterialTheme.colorScheme.primary,
|
||||||
@@ -162,4 +163,16 @@ fun SettingItem(
|
|||||||
containerColor = MaterialTheme.colorScheme.surfaceContainerLow
|
containerColor = MaterialTheme.colorScheme.surfaceContainerLow
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (dropdownMenu != null) {
|
||||||
|
DropdownMenu(
|
||||||
|
expanded = showMenu,
|
||||||
|
onDismissRequest = { showMenu = false }
|
||||||
|
) {
|
||||||
|
dropdownMenu {
|
||||||
|
showMenu = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package io.legado.app.utils.eventBus
|
||||||
|
|
||||||
|
import kotlinx.coroutines.MainScope
|
||||||
|
import kotlinx.coroutines.channels.BufferOverflow
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
object FlowEventBus {
|
||||||
|
// 核心存储结构:Tag -> SharedFlow
|
||||||
|
private val events = ConcurrentHashMap<String, MutableSharedFlow<Any>>()
|
||||||
|
|
||||||
|
// 获取或创建对应 Tag 的 Flow
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun <T> with(tag: String): MutableSharedFlow<T> {
|
||||||
|
return events.getOrPut(tag) {
|
||||||
|
MutableSharedFlow<Any>(
|
||||||
|
replay = 1, // 相当于 LiveData 的粘性,确保新订阅者能收到最后一次通知
|
||||||
|
extraBufferCapacity = 64,
|
||||||
|
onBufferOverflow = BufferOverflow.DROP_OLDEST
|
||||||
|
)
|
||||||
|
} as MutableSharedFlow<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
// 快捷发送
|
||||||
|
fun post(tag: String, value: Any) {
|
||||||
|
MainScope().launch {
|
||||||
|
with<Any>(tag).emit(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package io.legado.app.utils.eventBus
|
||||||
|
|
||||||
|
import io.legado.app.utils.eventBus.FlowEventBus.with
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class FlowEventBusExt {
|
||||||
|
|
||||||
|
// 在协程中直接调用
|
||||||
|
suspend fun <T> post(tag: String, value: T) {
|
||||||
|
with<T>(tag).emit(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在非协程环境调用
|
||||||
|
fun <T> postSync(tag: String, value: T) {
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
with<T>(tag).emit(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user