diff --git a/app/src/main/java/com/huanchengfly/tieba/post/Extensions.kt b/app/src/main/java/com/huanchengfly/tieba/post/Extensions.kt index a1f7c22a..c4fe729a 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/Extensions.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/Extensions.kt @@ -20,6 +20,7 @@ import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.huanchengfly.tieba.post.utils.GsonUtil import com.huanchengfly.tieba.post.utils.MD5Util +import java.io.File import kotlin.math.roundToInt @@ -51,6 +52,11 @@ inline fun String.fromJson(): Data { return GsonUtil.getGson().fromJson(this, type) } +inline fun File.fromJson(): Data { + val type = object : TypeToken() {}.type + return GsonUtil.getGson().fromJson(reader(), type) +} + fun Any.toJson(): String = Gson().toJson(this) fun String.toMD5(): String = MD5Util.toMd5(this) diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/forum/ForumPage.kt b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/forum/ForumPage.kt index 96d0a99a..ebcdb0ab 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/forum/ForumPage.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/forum/ForumPage.kt @@ -468,7 +468,6 @@ fun ForumPage( if (account != null && forum != null) { ConfirmDialog( dialogState = unlikeDialogState, - modifier = Modifier, onConfirm = { viewModel.send( ForumUiIntent.Unlike(forum.id, forumName, tbs ?: account.tbs) diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/home/HomePage.kt b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/home/HomePage.kt index 7e8923fb..5965a7ea 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/home/HomePage.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/home/HomePage.kt @@ -231,12 +231,19 @@ private fun ForumItem( ConfirmDialog( dialogState = dialogState, - modifier = Modifier, onConfirm = { viewModel.send(HomeUiIntent.Unfollow(item.forumId, item.forumName)) }, + modifier = Modifier, onCancel = { willUnfollow = false }, - title = { Text(text = stringResource(id = R.string.title_dialog_unfollow_forum, item.forumName)) } + title = { + Text( + text = stringResource( + id = R.string.title_dialog_unfollow_forum, + item.forumName + ) + ) + } ) LaunchedEffect(key1 = "launchUnfollowDialog") { diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/widgets/compose/Dialogs.kt b/app/src/main/java/com/huanchengfly/tieba/post/ui/widgets/compose/Dialogs.kt index 2069ad55..aedf733b 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/ui/widgets/compose/Dialogs.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/widgets/compose/Dialogs.kt @@ -20,6 +20,7 @@ import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -41,8 +42,7 @@ fun DialogScope.DialogPositiveButton( dismiss() }, modifier = Modifier - .fillMaxWidth() - .padding(vertical = 4.dp), + .fillMaxWidth(), shape = RoundedCornerShape(100), colors = ButtonDefaults.textButtonColors( backgroundColor = MaterialTheme.colors.secondary, @@ -100,6 +100,7 @@ fun TimePickerDialog( ) { var timeVal by remember { mutableStateOf(currentTime) } Dialog( + modifier = modifier, dialogState = dialogState, onDismiss = onCancel, title = title, @@ -107,7 +108,6 @@ fun TimePickerDialog( DialogPositiveButton(text = confirmText, onClick = { onConfirm.invoke(timeVal) }) DialogNegativeButton(text = cancelText, onClick = onCancel) }, - modifier = modifier, ) { Column(modifier = Modifier.padding(horizontal = 24.dp)) { ProvideTextStyle(value = MaterialTheme.typography.body1) { @@ -130,17 +130,72 @@ fun TimePickerDialog( } @Composable -fun ConfirmDialog( - dialogState: DialogState = rememberDialogState(), +fun AlertDialog( + dialogState: DialogState, modifier: Modifier = Modifier, - onConfirm: () -> Unit, - onCancel: (() -> Unit)? = null, - confirmText: String = stringResource(id = R.string.button_sure_default), - cancelText: String = stringResource(id = R.string.button_cancel), - title: @Composable (DialogScope.() -> Unit), + onDismiss: (() -> Unit)? = null, + confirmText: String = stringResource(id = R.string.button_ok), + title: @Composable (DialogScope.() -> Unit) = {}, content: @Composable (DialogScope.() -> Unit) = {}, ) { Dialog( + modifier = modifier, + dialogState = dialogState, + onDismiss = onDismiss, + title = title, + buttons = { + DialogPositiveButton(text = confirmText) + }, + ) { + Column(modifier = Modifier.padding(horizontal = 24.dp)) { + ProvideTextStyle(value = MaterialTheme.typography.body1) { + ProvideContentColor(color = ExtendedTheme.colors.text) { + content() + } + } + } + } +} + +@Composable +fun AlertDialog( + dialogState: DialogState, + modifier: Modifier = Modifier, + onDismiss: (() -> Unit)? = null, + title: @Composable (DialogScope.() -> Unit) = {}, + content: @Composable (DialogScope.() -> Unit) = {}, + buttons: @Composable (DialogScope.() -> Unit) = {}, +) { + Dialog( + modifier = modifier, + dialogState = dialogState, + onDismiss = onDismiss, + title = title, + buttons = buttons, + ) { + Column(modifier = Modifier.padding(horizontal = 24.dp)) { + ProvideTextStyle(value = MaterialTheme.typography.body1) { + ProvideContentColor(color = ExtendedTheme.colors.text) { + content() + } + } + } + } +} + +@Composable +fun ConfirmDialog( + dialogState: DialogState, + onConfirm: () -> Unit, + modifier: Modifier = Modifier, + onCancel: (() -> Unit)? = null, + confirmText: String = stringResource(id = R.string.button_sure_default), + cancelText: String = stringResource(id = R.string.button_cancel), + title: @Composable (DialogScope.() -> Unit) = {}, + content: @Composable (DialogScope.() -> Unit) = {}, +) { + Dialog( + modifier = modifier, dialogState = dialogState, onDismiss = onCancel, title = title, @@ -148,7 +203,6 @@ fun ConfirmDialog( DialogPositiveButton(text = confirmText, onClick = onConfirm) DialogNegativeButton(text = cancelText, onClick = onCancel) }, - modifier = modifier, ) { Column(modifier = Modifier.padding(horizontal = 12.dp)) { ProvideTextStyle(value = MaterialTheme.typography.body1) { @@ -180,6 +234,7 @@ fun PromptDialog( textVal = value } Dialog( + modifier = modifier, dialogState = dialogState, onDismiss = onCancel, title = title, @@ -187,7 +242,6 @@ fun PromptDialog( DialogPositiveButton(text = confirmText, onClick = { onConfirm.invoke(textVal) }) DialogNegativeButton(text = cancelText, onClick = onCancel) }, - modifier = modifier, ) { val focusRequester = FocusRequester.Default val softwareKeyboardController = LocalSoftwareKeyboardController.current @@ -236,14 +290,14 @@ fun PromptDialog( @OptIn(ExperimentalComposeUiApi::class) @Composable fun Dialog( + modifier: Modifier = Modifier, dialogState: DialogState = rememberDialogState(), onDismiss: (() -> Unit)? = null, + title: @Composable (DialogScope.() -> Unit) = {}, cancelable: Boolean = true, cancelableOnTouchOutside: Boolean = true, - title: @Composable DialogScope.() -> Unit, - buttons: @Composable DialogScope.() -> Unit = {}, - modifier: Modifier = Modifier, - content: @Composable DialogScope.() -> Unit, + buttons: @Composable (DialogScope.() -> Unit) = {}, + content: @Composable (DialogScope.() -> Unit), ) { if (dialogState.show) { val dialogScope = DialogScope( @@ -268,19 +322,22 @@ fun Dialog( dialogScope.dismiss() } ) { - Column(modifier = modifier - .align(Alignment.BottomCenter) - .fillMaxWidth() - .padding(16.dp) - .background( - color = ExtendedTheme.colors.background, - shape = RoundedCornerShape(24.dp) - ) - .padding(vertical = 24.dp) - .clickable( - interactionSource = remember { MutableInteractionSource() }, - indication = null - ) {} + Column( + modifier = modifier + .align(Alignment.BottomCenter) + .fillMaxWidth() + .padding(16.dp) + .background( + color = ExtendedTheme.colors.background, + shape = RoundedCornerShape(24.dp) + ) + .padding(vertical = 24.dp) + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + onClick = {} + ), + verticalArrangement = Arrangement.spacedBy(16.dp) ) { ProvideContentColor(color = ExtendedTheme.colors.text) { Box( @@ -288,11 +345,10 @@ fun Dialog( .padding(horizontal = 24.dp) .align(Alignment.CenterHorizontally) ) { - ProvideTextStyle(value = MaterialTheme.typography.h6) { + ProvideTextStyle(value = MaterialTheme.typography.h6.copy(fontWeight = FontWeight.Bold)) { dialogScope.title() } } - Spacer(modifier = Modifier.height(16.dp)) Box(modifier = Modifier.align(Alignment.CenterHorizontally)) { dialogScope.content() } diff --git a/app/src/main/java/com/huanchengfly/tieba/post/utils/EmoticonManager.kt b/app/src/main/java/com/huanchengfly/tieba/post/utils/EmoticonManager.kt index 5763c6f8..7c8f641e 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/utils/EmoticonManager.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/utils/EmoticonManager.kt @@ -1,5 +1,6 @@ package com.huanchengfly.tieba.post.utils +import android.annotation.SuppressLint import android.content.Context import android.graphics.Bitmap import android.graphics.drawable.BitmapDrawable @@ -25,6 +26,7 @@ import com.github.panpf.sketch.request.LoadResult import com.google.accompanist.drawablepainter.rememberDrawablePainter import com.huanchengfly.tieba.post.App import com.huanchengfly.tieba.post.R +import com.huanchengfly.tieba.post.fromJson import com.huanchengfly.tieba.post.models.EmoticonCache import com.huanchengfly.tieba.post.pxToDp import com.huanchengfly.tieba.post.pxToSp @@ -188,16 +190,14 @@ object EmoticonManager { return contextRef.get() ?: App.INSTANCE } - fun getEmoticonDataCache(): EmoticonCache { - val emoticonDataCacheFile = File(getEmoticonCacheDir(), "emoticon_data_cache") - if (emoticonDataCacheFile.exists()) { - return GsonUtil.getGson() - .fromJson(emoticonDataCacheFile.reader(), EmoticonCache::class.java) - } - return EmoticonCache() + private fun getEmoticonDataCache(): EmoticonCache { + return runCatching { + File(getEmoticonCacheDir(), "emoticon_data_cache").takeIf { it.exists() } + ?.fromJson() + }.getOrNull() ?: EmoticonCache() } - fun getEmoticonCacheDir(): File { + private fun getEmoticonCacheDir(): File { return File(getContext().externalCacheDir ?: getContext().cacheDir, "emoticon").apply { if (exists() && isFile) { delete() @@ -208,7 +208,7 @@ object EmoticonManager { } } - fun getEmoticonFile(id: String): File { + private fun getEmoticonFile(id: String): File { return File(getEmoticonCacheDir(), "$id.png") } @@ -216,7 +216,7 @@ object EmoticonManager { return emoticonMapping[name] } - fun getEmoticonNameById(id: String): String? { + private fun getEmoticonNameById(id: String): String? { return emoticonMapping.firstNotNullOfOrNull { (name, emoticonId) -> if (emoticonId == id) { name @@ -226,7 +226,8 @@ object EmoticonManager { } } - fun getEmoticonResId(context: Context, id: String): Int { + @SuppressLint("DiscouragedApi") + private fun getEmoticonResId(context: Context, id: String): Int { return context.resources.getIdentifier(id, "drawable", context.packageName) }