From d484ff7804420781c0f6015b37e76f3116f2fb00 Mon Sep 17 00:00:00 2001 From: SeniorZhai Date: Thu, 22 Jan 2026 13:21:32 +0800 Subject: [PATCH 1/3] Fix preview build --- .../java/one/mixin/android/compose/Dialogs.kt | 4 + .../compose/InputAmountUsageExample.kt | 0 .../one/mixin/android/compose/theme/Theme.kt | 142 ++++++++++-------- .../android/ui/home/web3/components/Review.kt | 25 ++- 4 files changed, 103 insertions(+), 68 deletions(-) delete mode 100644 app/src/main/java/one/mixin/android/compose/InputAmountUsageExample.kt diff --git a/app/src/main/java/one/mixin/android/compose/Dialogs.kt b/app/src/main/java/one/mixin/android/compose/Dialogs.kt index 4730dcac8d..ac4fd05dfb 100644 --- a/app/src/main/java/one/mixin/android/compose/Dialogs.kt +++ b/app/src/main/java/one/mixin/android/compose/Dialogs.kt @@ -11,6 +11,7 @@ import androidx.compose.runtime.SideEffect import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -25,6 +26,9 @@ fun IndeterminateProgressDialog( title: String = "", cancelable: Boolean? = null, ) { + if (LocalInspectionMode.current) { + return + } val context = LocalContext.current val activity = context.findFragmentActivityOrNull() diff --git a/app/src/main/java/one/mixin/android/compose/InputAmountUsageExample.kt b/app/src/main/java/one/mixin/android/compose/InputAmountUsageExample.kt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/app/src/main/java/one/mixin/android/compose/theme/Theme.kt b/app/src/main/java/one/mixin/android/compose/theme/Theme.kt index 5438cc4dbf..eb05de999d 100644 --- a/app/src/main/java/one/mixin/android/compose/theme/Theme.kt +++ b/app/src/main/java/one/mixin/android/compose/theme/Theme.kt @@ -10,19 +10,17 @@ import androidx.compose.material.RippleConfiguration import androidx.compose.material.RippleDefaults import androidx.compose.material.darkColors import androidx.compose.material.lightColors +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.compositionLocalOf +import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.colorspace.ColorSpaces import androidx.compose.ui.platform.LocalContext -import one.mixin.android.MixinApplication -import one.mixin.android.extension.isNightMode import one.mixin.android.extension.isScreenWideColorGamut import one.mixin.android.util.isCurrChinese -val isP3Supported = MixinApplication.appContext.isScreenWideColorGamut() - class AppColors( val primary: Color, val accent: Color, @@ -45,20 +43,8 @@ class AppColors( val walletRed: Color = Color(0xFFF67070), val walletGreen: Color = Color(0xFF50BD5C), val walletOrange: Color = Color(0xFFFFAA00), - val marketRed: Color = if (isP3Supported) Color( - colorSpace = ColorSpaces.DisplayP3, - red = 0.898f, - green = 0.471f, - blue = 0.455f, - alpha = 1f - ) else Color(0xFFE57874), - val marketGreen: Color = if (isP3Supported) Color( - colorSpace = ColorSpaces.DisplayP3, - red = 0.314f, - green = 0.741f, - blue = 0.361f, - alpha = 1f - ) else Color(0xFF50BD5C), + val marketRed: Color, + val marketGreen: Color, val shadow: Color = Color(0x33AAAAAA), val unchecked: Color, val tipWarning: Color, @@ -90,8 +76,73 @@ object MixinAppTheme { } -private val LightColorPalette = - AppColors( +private fun createMarketRedColor(isP3Supported: Boolean): Color { + if (isP3Supported) { + return Color( + colorSpace = ColorSpaces.DisplayP3, + red = 0.898f, + green = 0.471f, + blue = 0.455f, + alpha = 1f, + ) + } + return Color(0xFFE57874) +} + +private fun createMarketGreenColor(isP3Supported: Boolean): Color { + if (isP3Supported) { + return Color( + colorSpace = ColorSpaces.DisplayP3, + red = 0.314f, + green = 0.741f, + blue = 0.361f, + alpha = 1f, + ) + } + return Color(0xFF50BD5C) +} + +private fun createAppColors( + isDarkTheme: Boolean, + isP3Supported: Boolean, +): AppColors { + val marketRed: Color = createMarketRedColor(isP3Supported) + val marketGreen: Color = createMarketGreenColor(isP3Supported) + if (isDarkTheme) { + return AppColors( + primary = Color(0xFF2c3136), + accent = Color(0xFF3D75E3), + textPrimary = Color(0xFFFFFFFF), + textAssist = Color(0xFF7F878F), + textMinor = Color(0xFFD3D4D5), + textRemarks = Color(0xFF6E7073), + icon = Color(0xFFEAEAEB), + iconGray = Color(0xFF808691), + iconAction = Color(0xFFFFFFFF), + backgroundWindow = Color(0xFF23272B), + background = Color(0xFF2c3136), + backgroundDark = Color(0xFF121212), + backgroundGrayLight = Color(0xFF3B3F44), + backgroundGray = Color(0xFF3B3F44), + unchecked = Color(0xFFECECEC), + tipWarning = Color(0xFF3E373B), + tipWarningBorder = Color(0xFFE86B67), + borderPrimary = Color(0x33FFFFFF), + bgGradientStart = Color(0xFF2C3136), + bgGradientEnd = Color(0xFF1C2029), + borderColor = Color(0xFF6E7073), + walletBlue = Color(0xFF64B5F6), + walletYellow = Color(0xFFFFEE58), + walletPurple = Color(0xFFBA68C8), + badgeRed = Color(0xFFF67070), + warning = Color(0xFFF6A417), + bgClip = Color(0xFF3B3F44), + borderGray = Color(0xFFD6D6D6), + marketRed = marketRed, + marketGreen = marketGreen, + ) + } + return AppColors( primary = Color(0xFFFFFFFF), accent = Color(0xFF3D75E3), textPrimary = Color(0xFF000000), @@ -120,53 +171,22 @@ private val LightColorPalette = warning = Color(0xFFF6A417), bgClip = Color(0xFFF5F7FA), borderGray = Color(0xFFD6D6D6), + marketRed = marketRed, + marketGreen = marketGreen, ) +} -private val DarkColorPalette = - AppColors( - primary = Color(0xFF2c3136), - accent = Color(0xFF3D75E3), - textPrimary = Color(0xFFFFFFFF), - textAssist = Color(0xFF7F878F), - textMinor = Color(0xFFD3D4D5), - textRemarks = Color(0xFF6E7073), - icon = Color(0xFFEAEAEB), - iconGray = Color(0xFF808691), - iconAction = Color(0xFFFFFFFF), - backgroundWindow = Color(0xFF23272B), - background = Color(0xFF2c3136), - backgroundDark = Color(0xFF121212), - backgroundGrayLight = Color(0xFF3B3F44), - backgroundGray = Color(0xFF3B3F44), - unchecked = Color(0xFFECECEC), - tipWarning = Color(0xFF3E373B), - tipWarningBorder = Color(0xFFE86B67), - borderPrimary = Color(0x33FFFFFF), - bgGradientStart = Color(0xFF2C3136), - bgGradientEnd = Color(0xFF1C2029), - borderColor = Color(0xFF6E7073), - walletBlue = Color(0xFF64B5F6), - walletYellow = Color(0xFFFFEE58), - walletPurple = Color(0xFFBA68C8), - badgeRed = Color(0xFFF67070), - warning = Color(0xFFF6A417), - bgClip = Color(0xFF3B3F44), - borderGray = Color(0xFFD6D6D6), - ) - -private val LocalColors = compositionLocalOf { LightColorPalette } +private val LocalColors = compositionLocalOf { createAppColors(isDarkTheme = false, isP3Supported = false) } @Composable fun MixinAppTheme( - darkTheme: Boolean = MixinApplication.get().isNightMode(), + darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit, ) { - val colors = - if (darkTheme) { - DarkColorPalette - } else { - LightColorPalette - } + val context = LocalContext.current + val isInPreview: Boolean = LocalInspectionMode.current + val isP3Supported: Boolean = if (isInPreview) false else context.isScreenWideColorGamut() + val colors: AppColors = createAppColors(isDarkTheme = darkTheme, isP3Supported = isP3Supported) val textSelectionColors = TextSelectionColors( handleColor = Color(0xFF3D75E3), @@ -196,8 +216,6 @@ fun MixinAppTheme( @Composable @DrawableRes fun languageBasedImage(@DrawableRes defaultImage:Int, @DrawableRes zh:Int) : Int{ - val context = LocalContext.current - val drawableRes = when { isCurrChinese() -> zh else -> defaultImage diff --git a/app/src/main/java/one/mixin/android/ui/home/web3/components/Review.kt b/app/src/main/java/one/mixin/android/ui/home/web3/components/Review.kt index 7ea6cbed84..c961a93bdb 100644 --- a/app/src/main/java/one/mixin/android/ui/home/web3/components/Review.kt +++ b/app/src/main/java/one/mixin/android/ui/home/web3/components/Review.kt @@ -46,6 +46,7 @@ import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -481,9 +482,15 @@ private fun ApproveChangeItem( private fun SingleBalanceChangeItem( bc: BalanceChange ) { - val viewModel = hiltViewModel() - val priceUsd: String? by viewModel.getTokenPriceUsdFlow(bc.assetId) - .collectAsStateWithLifecycle(initialValue = null) + val isInPreview: Boolean = LocalInspectionMode.current + val priceUsd: String? = if (isInPreview) { + null + } else { + val viewModel: Web3ViewModel = hiltViewModel() + val collectedPriceUsd: String? by viewModel.getTokenPriceUsdFlow(bc.assetId) + .collectAsStateWithLifecycle(initialValue = null) + collectedPriceUsd + } val fiatPrice = bc.formatPrice(priceUsd) Row( @@ -528,9 +535,15 @@ private fun SingleBalanceChangeItem( private fun BalanceChangeItem( balanceChange: BalanceChange, ) { - val viewModel = hiltViewModel() - val priceUsd: String? by viewModel.getTokenPriceUsdFlow(balanceChange.assetId) - .collectAsStateWithLifecycle(initialValue = null) + val isInPreview: Boolean = LocalInspectionMode.current + val priceUsd: String? = if (isInPreview) { + null + } else { + val viewModel: Web3ViewModel = hiltViewModel() + val collectedPriceUsd: String? by viewModel.getTokenPriceUsdFlow(balanceChange.assetId) + .collectAsStateWithLifecycle(initialValue = null) + collectedPriceUsd + } val fiatPrice = balanceChange.formatPrice(priceUsd) Row( modifier = Modifier.fillMaxWidth(), From 39913677e1595b94da16b69995f6b320bb800323 Mon Sep 17 00:00:00 2001 From: SeniorZhai Date: Thu, 22 Jan 2026 14:03:07 +0800 Subject: [PATCH 2/3] Code clean --- .../mixin/android/extension/ViewExtension.kt | 121 ++++++++++-------- .../android/job/AttachmentDownloadJob.kt | 11 +- .../mixin/android/job/RefreshAddressJob.kt | 5 +- .../one/mixin/android/job/SendMessageJob.kt | 3 +- .../job/TranscriptAttachmentDownloadJob.kt | 7 +- .../java/one/mixin/android/net/Diagnosis.kt | 15 ++- .../java/one/mixin/android/pay/Lighting.kt | 5 +- .../ui/media/pager/MediaPagerActivity.kt | 2 + .../TranscriptMediaPagerActivity.kt | 16 ++- 9 files changed, 109 insertions(+), 76 deletions(-) diff --git a/app/src/main/java/one/mixin/android/extension/ViewExtension.kt b/app/src/main/java/one/mixin/android/extension/ViewExtension.kt index fa51328ba7..ae241e1d63 100644 --- a/app/src/main/java/one/mixin/android/extension/ViewExtension.kt +++ b/app/src/main/java/one/mixin/android/extension/ViewExtension.kt @@ -1,6 +1,15 @@ +@file:Suppress( + "unused", + "FunctionName", + "FoldableIfThen", + "IfThenToElvis", + "UNUSED_PARAMETER", +) + package one.mixin.android.extension import android.animation.Animator +import android.animation.AnimatorListenerAdapter import android.animation.ObjectAnimator import android.animation.ValueAnimator import android.app.Activity @@ -35,9 +44,11 @@ import androidx.appcompat.widget.PopupMenu import androidx.core.animation.doOnEnd import androidx.core.animation.doOnStart import androidx.core.graphics.ColorUtils -import androidx.core.view.ViewCompat -import androidx.core.view.ViewPropertyAnimatorListener import androidx.core.view.drawToBitmap +import androidx.core.view.forEach +import androidx.core.view.forEachIndexed +import androidx.core.view.isVisible +import androidx.core.view.marginBottom import androidx.core.view.updateLayoutParams import androidx.navigation.NavController import androidx.navigation.NavOptions @@ -57,13 +68,15 @@ const val ANIMATION_DURATION_SHORT = 260L const val ANIMATION_DURATION_SHORTEST = 120L fun View.hideKeyboard() { - val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + val inputMethodManager: InputMethodManager = + context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager inputMethodManager.hideSoftInputFromWindow(windowToken, 0) } fun View.showKeyboard() { if (requestFocus()) { - val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + val inputMethodManager: InputMethodManager = + context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager inputMethodManager.showSoftInput(this, SHOW_IMPLICIT) } } @@ -78,17 +91,7 @@ fun View.fadeIn( ) { this.visibility = VISIBLE this.alpha = 0f - ViewCompat.animate(this).alpha(maxAlpha).setDuration(duration).setListener( - object : ViewPropertyAnimatorListener { - override fun onAnimationStart(view: View) { - } - - override fun onAnimationEnd(view: View) { - } - - override fun onAnimationCancel(view: View) {} - }, - ).start() + animate().alpha(maxAlpha).setDuration(duration).start() } fun View.fadeOut(isGone: Boolean = false) { @@ -101,21 +104,15 @@ fun View.fadeOut( isGone: Boolean = false, ) { this.alpha = 1f - ViewCompat.animate(this).alpha(0f).setStartDelay(delay).setDuration(duration).setListener( - object : ViewPropertyAnimatorListener { - override fun onAnimationStart(view: View) { - view.isDrawingCacheEnabled = true - } - - override fun onAnimationEnd(view: View) { - view.visibility = if (isGone) GONE else INVISIBLE - view.alpha = 0f - view.isDrawingCacheEnabled = false - } - - override fun onAnimationCancel(view: View) {} - }, - ) + animate().alpha(0f).setStartDelay(delay).setDuration(duration) + .setListener( + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + visibility = if (isGone) GONE else INVISIBLE + alpha = 0f + } + }, + ) } fun View.translationX(value: Float) { @@ -126,7 +123,7 @@ fun View.translationX( value: Float, duration: Long, ) { - ViewCompat.animate(this).setDuration(duration).translationX(value).start() + animate().setDuration(duration).translationX(value).start() } fun View.translationY( @@ -141,18 +138,15 @@ fun View.translationY( duration: Long, endAction: (() -> Unit)? = null, ) { - ViewCompat.animate(this).setDuration(duration).translationY(value) + animate().setDuration(duration).translationY(value) .setListener( - object : ViewPropertyAnimatorListener { - override fun onAnimationEnd(view: View) { - endAction?.let { it() } + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + endAction?.invoke() } - - override fun onAnimationCancel(view: View) { - endAction?.let { it() } + override fun onAnimationCancel(animation: Animator) { + endAction?.invoke() } - - override fun onAnimationStart(view: View) {} }, ) .start() @@ -318,27 +312,32 @@ fun View.circularReveal() { circularReveal.start() } +@Suppress("unused") fun EditText.showCursor() { this.requestFocus() this.isCursorVisible = true } +@Suppress("unused") fun EditText.hideCursor() { this.clearFocus() this.isCursorVisible = false } +@Suppress("unused") fun ViewGroup.inflate( @LayoutRes layoutRes: Int, attachToRoot: Boolean = false, -) = LayoutInflater.from(context).inflate(layoutRes, this, attachToRoot)!! +): View { + return LayoutInflater.from(context).inflate(layoutRes, this, attachToRoot) +} fun View.navigateUp() { try { findNavController().navigateUp() - } catch (e: IllegalArgumentException) { + } catch (_: IllegalArgumentException) { // Workaround with https://issuetracker.google.com/issues/128881182 - } catch (e: IllegalStateException) { + } catch (_: IllegalStateException) { Timber.w("View $this does not have a NavController set") } } @@ -346,10 +345,10 @@ fun View.navigateUp() { fun NavController.safeNavigateUp(): Boolean { return try { navigateUp() - } catch (e: IllegalArgumentException) { + } catch (_: IllegalArgumentException) { // Workaround with https://issuetracker.google.com/issues/128881182 false - } catch (e: IllegalStateException) { + } catch (_: IllegalStateException) { false } } @@ -361,9 +360,9 @@ fun View.navigate( ) { try { findNavController().navigate(resId, bundle, navOptions) - } catch (e: IllegalArgumentException) { + } catch (_: IllegalArgumentException) { // Workaround with https://issuetracker.google.com/issues/128881182 - } catch (e: IllegalStateException) { + } catch (_: IllegalStateException) { Timber.w("View $this does not have a NavController set") } } @@ -400,10 +399,21 @@ fun View.bounce() { spring.endValue = 1.0 } +@Suppress("UnusedReceiverParameter", "FunctionName", "unused") +@Deprecated("Use intProperty", ReplaceWith("intProperty(name, getAction, setAction)")) fun View.IntProperty( name: String, getAction: (View) -> Int, setAction: (View, Int) -> Unit, +): Property { + return intProperty(name = name, getAction = getAction, setAction = setAction) +} + +@Suppress("UnusedReceiverParameter", "unused") +fun View.intProperty( + name: String, + getAction: (View) -> Int, + setAction: (View, Int) -> Unit, ): Property { return object : Property(Int::class.java, name) { override fun get(obj: View): Int { @@ -441,16 +451,17 @@ fun Int.withAlpha(alpha: Float): Int { } fun PopupMenu.showIcon() { - val menuHelper: Any - val argTypes: Array?> + val menuHelper: Any? try { val fMenuHelper: Field = PopupMenu::class.java.getDeclaredField("mPopup") fMenuHelper.isAccessible = true menuHelper = fMenuHelper.get(this) - argTypes = arrayOf(Boolean::class.javaPrimitiveType) - menuHelper.javaClass.getDeclaredMethod("setForceShowIcon", *argTypes) - .invoke(menuHelper, true) - } catch (e: Exception) { + val argTypes: Array?> = arrayOf(Boolean::class.javaPrimitiveType) + if (menuHelper != null) { + menuHelper.javaClass.getDeclaredMethod("setForceShowIcon", *argTypes) + .invoke(menuHelper, true) + } + } catch (_: Exception) { } } @@ -501,7 +512,9 @@ var View.backgroundColor: Int var View.backgroundDrawable: Drawable? inline get() = background - set(value) = setBackgroundDrawable(value) + set(value) { + background = value + } var View.backgroundResource: Int @Deprecated("Property does not have a getter") diff --git a/app/src/main/java/one/mixin/android/job/AttachmentDownloadJob.kt b/app/src/main/java/one/mixin/android/job/AttachmentDownloadJob.kt index f81faeaa10..82f775faea 100644 --- a/app/src/main/java/one/mixin/android/job/AttachmentDownloadJob.kt +++ b/app/src/main/java/one/mixin/android/job/AttachmentDownloadJob.kt @@ -101,13 +101,14 @@ class AttachmentDownloadJob( shareable = this.shareable }.attachmentId } catch (e: Exception) { - message.content!! + requireNotNull(message.content) }, ) val body = attachmentCall!!.execute().body() - if (body != null && (body.isSuccess || !isCancelled) && body.data != null) { - val attachmentResponse = body.data!! - attachmentResponse.view_url?.let { + if (body != null && body.isSuccess && !isCancelled && body.data != null) { + val attachmentResponse = requireNotNull(body.data) + val viewUrl: String? = attachmentResponse.view_url + viewUrl?.let { val result = decryptAttachment(it) if (result) { val attachmentExtra = GsonHelper.customGson.toJson(AttachmentExtra(attachmentResponse.attachment_id, message.messageId, attachmentResponse.created_at, shareable)) @@ -193,7 +194,7 @@ class AttachmentDownloadJob( return true } else if (response.isSuccessful && !isCancelled && response.body != null) { val sink = destination.sink().buffer() - sink.writeAll(response.body!!.source()) + sink.writeAll(requireNotNull(response.body).source()) sink.close() if (message.category.endsWith("_IMAGE")) { val attachmentCipherInputStream = diff --git a/app/src/main/java/one/mixin/android/job/RefreshAddressJob.kt b/app/src/main/java/one/mixin/android/job/RefreshAddressJob.kt index 3b6b06cd33..db5c5fee93 100644 --- a/app/src/main/java/one/mixin/android/job/RefreshAddressJob.kt +++ b/app/src/main/java/one/mixin/android/job/RefreshAddressJob.kt @@ -15,9 +15,8 @@ class RefreshAddressJob(private val chainId: String) : BaseJob( override fun onRun() = runBlocking { val response = tokenService.addresses(chainId) if (response != null && response.isSuccess && response.data != null) { - response.data?.let { - addressDao.insertList(it) - } + val addresses = requireNotNull(response.data) + addressDao.insertList(addresses) } } } diff --git a/app/src/main/java/one/mixin/android/job/SendMessageJob.kt b/app/src/main/java/one/mixin/android/job/SendMessageJob.kt index 5dbaafb16c..7650178967 100644 --- a/app/src/main/java/one/mixin/android/job/SendMessageJob.kt +++ b/app/src/main/java/one/mixin/android/job/SendMessageJob.kt @@ -271,11 +271,12 @@ open class SendMessageJob( } else { message.content!!.toByteArray() } + val participantPublicKey: String = participantSessionKey.publicKey ?: return val encryptContent = encryptedProtocol.encryptMessage( keyPair, plaintext, - participantSessionKey.publicKey!!.base64RawURLDecode(), + participantPublicKey.base64RawURLDecode(), participantSessionKey.sessionId, extensionSessionKey?.publicKey?.base64RawURLDecode(), extensionSessionKey?.sessionId, diff --git a/app/src/main/java/one/mixin/android/job/TranscriptAttachmentDownloadJob.kt b/app/src/main/java/one/mixin/android/job/TranscriptAttachmentDownloadJob.kt index dbb2f1dff5..f7dc1085eb 100644 --- a/app/src/main/java/one/mixin/android/job/TranscriptAttachmentDownloadJob.kt +++ b/app/src/main/java/one/mixin/android/job/TranscriptAttachmentDownloadJob.kt @@ -87,8 +87,9 @@ class TranscriptAttachmentDownloadJob( } attachmentCall = conversationApi.getAttachment(attachmentId) val body = attachmentCall!!.execute().body() - if (body != null && (body.isSuccess || !isCancelled) && body.data != null) { - val viewUrl = body.data?.view_url + if (body != null && body.isSuccess && !isCancelled && body.data != null) { + val attachmentResponse = body.data + val viewUrl = attachmentResponse?.view_url if (viewUrl != null) { if (decryptAttachment(viewUrl, transcriptMessage)) { processTranscript() @@ -162,7 +163,7 @@ class TranscriptAttachmentDownloadJob( return true } else if (response.isSuccessful && !isCancelled && response.body != null) { val sink = destination.sink().buffer() - sink.writeAll(response.body!!.source()) + sink.writeAll(requireNotNull(response.body).source()) sink.close() when { transcriptMessage.type.endsWith("_IMAGE") -> { diff --git a/app/src/main/java/one/mixin/android/net/Diagnosis.kt b/app/src/main/java/one/mixin/android/net/Diagnosis.kt index 7d07ab52db..49a58e5600 100644 --- a/app/src/main/java/one/mixin/android/net/Diagnosis.kt +++ b/app/src/main/java/one/mixin/android/net/Diagnosis.kt @@ -133,13 +133,16 @@ private fun getExportIp( val client = OkHttpClient() var ipRequest = Request.Builder().url(EXPORT_IP_PRIMARY).build() try { - var data = - client.newCall(ipRequest).execute().body?.string() - ?: throw IOException("EXPORT_IP_PRIMARY no data") + var data: String = client.newCall(ipRequest).execute().body.string() + if (data.isBlank()) { + throw IOException("EXPORT_IP_PRIMARY no data") + } val url = data.substringIgnoreError(data.indexOf("src=") + 4, data.lastIndexOf("frameborder")).replace("'".toRegex(), "").replace(" ".toRegex(), "") ipRequest = Request.Builder().url(url).build() - data = client.newCall(ipRequest).execute().body?.string() - ?: throw IOException("EXPORT_IP_PRIMARY no data") + data = client.newCall(ipRequest).execute().body.string() + if (data.isBlank()) { + throw IOException("EXPORT_IP_PRIMARY no data") + } val dataIp = data.substringIgnoreError(data.indexOf("您的IP地址信息") + 10) val dataAddress = dataIp.substringIgnoreError(0, dataIp.indexOf("
")) val ips = dataAddress.split(" ").toTypedArray() @@ -149,7 +152,7 @@ private fun getExportIp( Timber.i("Get export ip from $EXPORT_IP_PRIMARY meet ${e.localizedMessage}") try { ipRequest = Request.Builder().url(EXPORT_IP_SECONDARY).build() - val exportIp = client.newCall(ipRequest).execute().body?.string() + val exportIp: String = client.newCall(ipRequest).execute().body.string() result.append("${context.getString(R.string.export_ip)}: $exportIp") } catch (e: Exception) { Timber.i("Get export ip from $EXPORT_IP_SECONDARY meet ${e.localizedMessage}") diff --git a/app/src/main/java/one/mixin/android/pay/Lighting.kt b/app/src/main/java/one/mixin/android/pay/Lighting.kt index ca130846bd..370daaa348 100644 --- a/app/src/main/java/one/mixin/android/pay/Lighting.kt +++ b/app/src/main/java/one/mixin/android/pay/Lighting.kt @@ -17,8 +17,9 @@ internal suspend fun parseLightning( parseLighting: suspend (String) -> PaymentResponse? ): ExternalTransfer? { val r = parseLighting(url) ?: return null - val assetId = r.asset?.assetId ?:return null - val chainId = r.asset?.chainId ?:return null + val asset = r.asset ?: return null + val assetId = asset.assetId ?: return null + val chainId = asset.chainId ?: return null val destination = r.destination ?: return null val addressResponse = validateAddress(assetId, chainId, destination) ?: return null diff --git a/app/src/main/java/one/mixin/android/ui/media/pager/MediaPagerActivity.kt b/app/src/main/java/one/mixin/android/ui/media/pager/MediaPagerActivity.kt index 8d406cced3..fdd51e1c66 100644 --- a/app/src/main/java/one/mixin/android/ui/media/pager/MediaPagerActivity.kt +++ b/app/src/main/java/one/mixin/android/ui/media/pager/MediaPagerActivity.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package one.mixin.android.ui.media.pager import android.Manifest diff --git a/app/src/main/java/one/mixin/android/ui/media/pager/transcript/TranscriptMediaPagerActivity.kt b/app/src/main/java/one/mixin/android/ui/media/pager/transcript/TranscriptMediaPagerActivity.kt index e06a1bd597..87b1d27882 100644 --- a/app/src/main/java/one/mixin/android/ui/media/pager/transcript/TranscriptMediaPagerActivity.kt +++ b/app/src/main/java/one/mixin/android/ui/media/pager/transcript/TranscriptMediaPagerActivity.kt @@ -593,7 +593,7 @@ class TranscriptMediaPagerActivity : BaseActivity(), DismissFrameLayout.OnDismis private fun dismiss() { binding.viewPager.visibility = View.INVISIBLE - overridePendingTransition(0, 0) + setExitTransition(enterAnim = 0, exitAnim = 0) super.finish() } @@ -750,7 +750,19 @@ class TranscriptMediaPagerActivity : BaseActivity(), DismissFrameLayout.OnDismis override fun finish() { super.finish() - overridePendingTransition(0, R.anim.scale_out) + setExitTransition(enterAnim = 0, exitAnim = R.anim.scale_out) + } + + private fun setExitTransition( + enterAnim: Int, + exitAnim: Int, + ) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + overrideActivityTransition(Activity.OVERRIDE_TRANSITION_CLOSE, enterAnim, exitAnim) + return + } + @Suppress("DEPRECATION") + overridePendingTransition(enterAnim, exitAnim) } private val mediaPagerAdapterListener = From cf7a6707dd169091929598e8055561d2b96e38fc Mon Sep 17 00:00:00 2001 From: SeniorZhai Date: Thu, 12 Mar 2026 10:55:46 +0800 Subject: [PATCH 3/3] fix: resolve Compose @Preview rendering issues --- .../java/one/mixin/android/compose/AppBar.kt | 36 +++++---- .../compose/AuthBottomSheetDialogCompose.kt | 54 +++++++------ .../android/ui/auth/compose/PinKeyBoard.kt | 22 +++-- .../home/inscription/component/ShareCard.kt | 16 ++-- .../ui/home/web3/components/InputAction.kt | 5 +- .../android/ui/home/web3/components/Review.kt | 80 ++++++++++++------- .../ui/home/web3/components/SlippageInfo.kt | 9 ++- .../android/ui/home/web3/stake/StakePage.kt | 10 ++- .../ui/home/web3/stake/ValidatorsPage.kt | 10 ++- .../ui/home/web3/trade/SwapSlippagePage.kt | 32 ++++---- .../ui/home/web3/trade/SwapTokenPage.kt | 4 +- .../landing/components/CreateAccountPage.kt | 6 +- .../landing/components/MnemonicPhraseInput.kt | 29 +++---- .../setting/ui/page/MixinMemberUpgradePage.kt | 38 ++++++--- .../ui/tip/wc/sessionproposal/WCPinBoard.kt | 22 +++-- .../wc/sessionrequest/SessionRequestPage.kt | 18 +++-- .../ui/transfer/compose/SelectDatePage.kt | 4 +- .../wallet/components/AssetDashboardScreen.kt | 12 +-- 18 files changed, 250 insertions(+), 157 deletions(-) diff --git a/app/src/main/java/one/mixin/android/compose/AppBar.kt b/app/src/main/java/one/mixin/android/compose/AppBar.kt index c8b26934df..d8f8c36c48 100644 --- a/app/src/main/java/one/mixin/android/compose/AppBar.kt +++ b/app/src/main/java/one/mixin/android/compose/AppBar.kt @@ -110,21 +110,23 @@ fun MixinTopAppBar( @Preview @Composable fun PreviewMixinAppBar() { - MixinTopAppBar( - navigationIcon = { - MixinBackButton() - }, - title = { - Text(text = "Title") - }, - actions = { - IconButton(onClick = { }) { - Icon( - painter = painterResource(id = R.drawable.ic_more), - contentDescription = null, - tint = MixinAppTheme.colors.icon, - ) - } - }, - ) + MixinAppTheme { + MixinTopAppBar( + navigationIcon = { + MixinBackButton() + }, + title = { + Text(text = "Title") + }, + actions = { + IconButton(onClick = { }) { + Icon( + painter = painterResource(id = R.drawable.ic_more), + contentDescription = null, + tint = MixinAppTheme.colors.icon, + ) + } + }, + ) + } } diff --git a/app/src/main/java/one/mixin/android/ui/auth/compose/AuthBottomSheetDialogCompose.kt b/app/src/main/java/one/mixin/android/ui/auth/compose/AuthBottomSheetDialogCompose.kt index 2e5c326990..3cbc91cdeb 100644 --- a/app/src/main/java/one/mixin/android/ui/auth/compose/AuthBottomSheetDialogCompose.kt +++ b/app/src/main/java/one/mixin/android/ui/auth/compose/AuthBottomSheetDialogCompose.kt @@ -375,30 +375,32 @@ fun Modifier.verticalScrollbar( @Composable @Preview fun AuthBottomSheetDialogComposePreview() { - val context = LocalContext.current - AuthBottomSheetDialogCompose( - name = "Team Mixin", - iconUrl = "https://mixin-images.zeromesh.net/E2y0BnTopFK9qey0YI-8xV3M82kudNnTaGw0U5SU065864SsewNUo6fe9kDF1HIzVYhXqzws4lBZnLj1lPsjk-0=s256", - scopes = - listOf( - Scope.generateScopeFromString(context, "PROFILE:READ"), - Scope.generateScopeFromString(context, "PHONE:READ"), - Scope.generateScopeFromString(context, "MESSAGES:REPRESENT"), - Scope.generateScopeFromString(context, "CONTACTS:READ"), - Scope.generateScopeFromString(context, "ASSETS:READ"), - Scope.generateScopeFromString(context, "SNAPSHOTS:READ"), - Scope.generateScopeFromString(context, "APPS:READ"), - Scope.generateScopeFromString(context, "APPS:WRITE"), - Scope.generateScopeFromString(context, "CIRCLES:READ"), - Scope.generateScopeFromString(context, "CIRCLES:WRITE"), - Scope.generateScopeFromString(context, "COLLECTIBLES:READ"), - ), - {}, - AuthStep.INPUT, - "", - {}, - {}, - {}, - null, - ) + MixinAppTheme { + val context = LocalContext.current + AuthBottomSheetDialogCompose( + name = "Team Mixin", + iconUrl = "https://mixin-images.zeromesh.net/E2y0BnTopFK9qey0YI-8xV3M82kudNnTaGw0U5SU065864SsewNUo6fe9kDF1HIzVYhXqzws4lBZnLj1lPsjk-0=s256", + scopes = + listOf( + Scope.generateScopeFromString(context, "PROFILE:READ"), + Scope.generateScopeFromString(context, "PHONE:READ"), + Scope.generateScopeFromString(context, "MESSAGES:REPRESENT"), + Scope.generateScopeFromString(context, "CONTACTS:READ"), + Scope.generateScopeFromString(context, "ASSETS:READ"), + Scope.generateScopeFromString(context, "SNAPSHOTS:READ"), + Scope.generateScopeFromString(context, "APPS:READ"), + Scope.generateScopeFromString(context, "APPS:WRITE"), + Scope.generateScopeFromString(context, "CIRCLES:READ"), + Scope.generateScopeFromString(context, "CIRCLES:WRITE"), + Scope.generateScopeFromString(context, "COLLECTIBLES:READ"), + ), + {}, + AuthStep.INPUT, + "", + {}, + {}, + {}, + null, + ) + } } diff --git a/app/src/main/java/one/mixin/android/ui/auth/compose/PinKeyBoard.kt b/app/src/main/java/one/mixin/android/ui/auth/compose/PinKeyBoard.kt index 5fcb1364bc..535f96dae0 100644 --- a/app/src/main/java/one/mixin/android/ui/auth/compose/PinKeyBoard.kt +++ b/app/src/main/java/one/mixin/android/ui/auth/compose/PinKeyBoard.kt @@ -55,6 +55,7 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign @@ -83,14 +84,19 @@ fun PinKeyBoard( onVerifyRequest: ((String) -> Unit)?, ) { val context = LocalContext.current + val isInPreview = LocalInspectionMode.current // val open = context.defaultSharedPreferences.getBoolean(Constants.Account.PREF_BIOMETRICS, false) // val biometricEnable = !open && BiometricUtil.isSupport(context) - val showBiometric = BiometricUtil.shouldShowBiometric(context) - val randomKeyboardEnabled by LocalContext.current.defaultSharedPreferences - .booleanValueAsState( - key = Constants.Account.PREF_RANDOM, - defaultValue = false, - ) + val showBiometric = if (isInPreview) false else BiometricUtil.shouldShowBiometric(context) + val randomKeyboardEnabled by if (isInPreview) { + remember { mutableStateOf(false) } + } else { + LocalContext.current.defaultSharedPreferences + .booleanValueAsState( + key = Constants.Account.PREF_RANDOM, + defaultValue = false, + ) + } val list = if (randomKeyboardEnabled) { mutableListOf("1", "2", "3", "4", "5", "6", "7", "8", "9", "0").apply { @@ -426,5 +432,7 @@ fun PinKeyBoard( @Preview @Composable fun PinKeyBoardPreview() { - PinKeyBoard(AuthStep.INPUT, "", {}, null, null) + MixinAppTheme { + PinKeyBoard(AuthStep.INPUT, "", {}, null, null) + } } diff --git a/app/src/main/java/one/mixin/android/ui/home/inscription/component/ShareCard.kt b/app/src/main/java/one/mixin/android/ui/home/inscription/component/ShareCard.kt index a265a07ae3..cd2936b31f 100644 --- a/app/src/main/java/one/mixin/android/ui/home/inscription/component/ShareCard.kt +++ b/app/src/main/java/one/mixin/android/ui/home/inscription/component/ShareCard.kt @@ -143,12 +143,14 @@ fun ShareCard(modifier: Modifier, qrcode: Bitmap, inscriptionHash: String, value @Preview @Composable private fun DashedDividerPreview() { - DashedDivider( - thickness = 1.dp, - modifier = Modifier - .fillMaxWidth() - .padding(16.dp) - ) + MixinAppTheme { + DashedDivider( + thickness = 1.dp, + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + ) + } } @Composable @@ -174,4 +176,4 @@ fun DashedDivider( ) ) } -} \ No newline at end of file +} diff --git a/app/src/main/java/one/mixin/android/ui/home/web3/components/InputAction.kt b/app/src/main/java/one/mixin/android/ui/home/web3/components/InputAction.kt index 5069707816..3087a33cce 100644 --- a/app/src/main/java/one/mixin/android/ui/home/web3/components/InputAction.kt +++ b/app/src/main/java/one/mixin/android/ui/home/web3/components/InputAction.kt @@ -76,6 +76,7 @@ fun InputAction( @Preview @Composable fun PreviewInputActionMax() { - InputAction("MAX") {} + MixinAppTheme { + InputAction("MAX") {} + } } - diff --git a/app/src/main/java/one/mixin/android/ui/home/web3/components/Review.kt b/app/src/main/java/one/mixin/android/ui/home/web3/components/Review.kt index c961a93bdb..09e6ee1435 100644 --- a/app/src/main/java/one/mixin/android/ui/home/web3/components/Review.kt +++ b/app/src/main/java/one/mixin/android/ui/home/web3/components/Review.kt @@ -675,9 +675,10 @@ private fun Item( @Preview @Composable fun PreviewMessage() { - Box(modifier = Modifier.background(MixinAppTheme.colors.background)) { - MessagePreview( - content = """{ + MixinAppTheme { + Box(modifier = Modifier.background(MixinAppTheme.colors.background)) { + MessagePreview( + content = """{ "raw": [ "0x9df67f5a05fb594c4357d87221cbd69f1d5a6fbb", "{\"types\":{\"Alias\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"alias\",\"type\":\"address\"},{\"name\":\"timestamp\",\"type\":\"uint64\"}],\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"}]},\"domain\":{\"name\":\"snapshot\",\"version\":\"0.1.4\"},\"primaryType\":\"Alias\",\"message\":{\"from\":\"0x9df67f5a05fb594c4357d87221cbd69f1d5a6fbb\",\"alias\":\"0x8f14e8dbc7b3619e5210201022f637f271545c90\",\"timestamp\":\"1710766295\"}}" @@ -685,7 +686,8 @@ fun PreviewMessage() { "type": "TYPED_MESSAGE" } """, - ) { + ) { + } } } } @@ -693,27 +695,31 @@ fun PreviewMessage() { @Preview @Composable private fun TransactionPreview() { - TransactionPreview(balance = BigDecimal(0.134), chain = Chain.Ethereum, null) + MixinAppTheme { + TransactionPreview(balance = BigDecimal(0.134), chain = Chain.Ethereum, null) + } } @Preview @Composable private fun WarningPreview() { - Box( - modifier = - Modifier - .fillMaxWidth() - .height(300.dp), - ) { - ActionBottom( - modifier = Modifier.align(Alignment.BottomCenter), - cancelTitle = stringResource(id = R.string.Cancel), - confirmTitle = stringResource(id = R.string.Confirm), - cancelAction = { }, + MixinAppTheme { + Box( + modifier = + Modifier + .fillMaxWidth() + .height(300.dp), ) { - } + ActionBottom( + modifier = Modifier.align(Alignment.BottomCenter), + cancelTitle = stringResource(id = R.string.Cancel), + confirmTitle = stringResource(id = R.string.Confirm), + cancelAction = { }, + ) { + } - Warning(modifier = Modifier.align(Alignment.BottomCenter)) + Warning(modifier = Modifier.align(Alignment.BottomCenter)) + } } } @@ -788,9 +794,11 @@ fun ActionBottom( @Preview @Composable fun TransferBottomPreview() { - Column { - ActionBottom(modifier = Modifier, stringResource(id = R.string.Cancel), stringResource(id = R.string.Confirm), {}, {}) - ActionBottom(modifier = Modifier, stringResource(id = R.string.Discard), stringResource(id = R.string.Send), {}, {}) + MixinAppTheme { + Column { + ActionBottom(modifier = Modifier, stringResource(id = R.string.Cancel), stringResource(id = R.string.Confirm), {}, {}) + ActionBottom(modifier = Modifier, stringResource(id = R.string.Discard), stringResource(id = R.string.Send), {}, {}) + } } } @@ -804,7 +812,9 @@ fun BalanceChangePreview() { @Preview @Composable fun ItemPreview() { - Item(Item("Compute Unit Limit", "1400000 compute units")) + MixinAppTheme { + Item(Item("Compute Unit Limit", "1400000 compute units")) + } } @Preview @@ -822,13 +832,17 @@ fun SolanaParsedTxPreviewPreview() { @Preview @Composable fun InstructionPreview() { - Instruction(ParsedInstruction("", "", "", info = "cannot decode instruction for Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB")) + MixinAppTheme { + Instruction(ParsedInstruction("", "", "", info = "cannot decode instruction for Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB")) + } } @Preview @Composable fun SolanaParsedTxNullPreview() { - ParsedTxPreview(parsedTx = null, asset = null, solanaTxSource = SolanaTxSource.Web) + MixinAppTheme { + ParsedTxPreview(parsedTx = null, asset = null, solanaTxSource = SolanaTxSource.Web) + } } @Preview @@ -836,7 +850,9 @@ fun SolanaParsedTxNullPreview() { fun SolanaParsedTxInstructionNullPreview() { val data = """{"instructions":[]}""" val parsedTx = GsonHelper.customGson.fromJson(data, ParsedTx::class.java) - ParsedTxPreview(parsedTx = parsedTx, asset = null, solanaTxSource = SolanaTxSource.Web) + MixinAppTheme { + ParsedTxPreview(parsedTx = parsedTx, asset = null, solanaTxSource = SolanaTxSource.Web) + } } @Preview @@ -844,7 +860,9 @@ fun SolanaParsedTxInstructionNullPreview() { fun SolanaParsedTxBalanceChangeNullWebPreview() { val data = """{"instructions":[{"program_id":"ComputeBudget111111111111111111111111111111","program_name":"ComputeBudget","instruction_name":"SetComputeUnitLimit","items":[{"key":"Compute Unit Limit","value":"600000 compute units"}]},{"program_id":"ComputeBudget111111111111111111111111111111","program_name":"ComputeBudget","instruction_name":"SetComputeUnitPrice","items":[{"key":"Compute Unit Price","value":"0.1 lamports per compute unit"}]},{"program_id":"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL","program_name":"AssociatedTokenAccount","instruction_name":"Create"},{"program_id":"11111111111111111111111111111111","program_name":"System","instruction_name":"Transfer","items":[{"key":"Transfer Amount (SOL)","value":"0.01"}]},{"program_id":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA","program_name":"Token","instruction_name":"SyncNative"},{"program_id":"JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4","program_name":"Jupiter","instruction_name":"Route","items":[{"key":"Route Plan","value":""},{"key":"In Amount","value":"824635312696"},{"key":"Quoted Out Amount","value":"824635312704"},{"key":"Slippage Bps","value":"824635312712"},{"key":"Platform Fee Bps","value":"50"}],"token_changes":[{"address":"So11111111111111111111111111111111111111112","amount":10000000,"is_pay":true},{"address":"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v","amount":1323264,"is_pay":false}]},{"program_id":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA","program_name":"Token","instruction_name":"CloseAccount"}]}""" val parsedTx = GsonHelper.customGson.fromJson(data, ParsedTx::class.java) - ParsedTxPreview(parsedTx = parsedTx, asset = null, solanaTxSource = SolanaTxSource.Web) + MixinAppTheme { + ParsedTxPreview(parsedTx = parsedTx, asset = null, solanaTxSource = SolanaTxSource.Web) + } } @Preview @@ -852,7 +870,9 @@ fun SolanaParsedTxBalanceChangeNullWebPreview() { fun SolanaParsedTxBalanceChangeNullInnerPreview() { val data = """{"instructions":[{"program_id":"ComputeBudget111111111111111111111111111111","program_name":"ComputeBudget","instruction_name":"SetComputeUnitLimit","items":[{"key":"Compute Unit Limit","value":"600000 compute units"}]},{"program_id":"ComputeBudget111111111111111111111111111111","program_name":"ComputeBudget","instruction_name":"SetComputeUnitPrice","items":[{"key":"Compute Unit Price","value":"0.1 lamports per compute unit"}]},{"program_id":"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL","program_name":"AssociatedTokenAccount","instruction_name":"Create"},{"program_id":"11111111111111111111111111111111","program_name":"System","instruction_name":"Transfer","items":[{"key":"Transfer Amount (SOL)","value":"0.01"}]},{"program_id":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA","program_name":"Token","instruction_name":"SyncNative"},{"program_id":"JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4","program_name":"Jupiter","instruction_name":"Route","items":[{"key":"Route Plan","value":""},{"key":"In Amount","value":"824635312696"},{"key":"Quoted Out Amount","value":"824635312704"},{"key":"Slippage Bps","value":"824635312712"},{"key":"Platform Fee Bps","value":"50"}],"token_changes":[{"address":"So11111111111111111111111111111111111111112","amount":10000000,"is_pay":true},{"address":"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v","amount":1323264,"is_pay":false}]},{"program_id":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA","program_name":"Token","instruction_name":"CloseAccount"}]}""" val parsedTx = GsonHelper.customGson.fromJson(data, ParsedTx::class.java) - ParsedTxPreview(parsedTx = parsedTx, asset = null, solanaTxSource = SolanaTxSource.InnerSwap) + MixinAppTheme { + ParsedTxPreview(parsedTx = parsedTx, asset = null, solanaTxSource = SolanaTxSource.InnerSwap) + } } @Preview @@ -860,5 +880,7 @@ fun SolanaParsedTxBalanceChangeNullInnerPreview() { fun SolanaParsedTxTokenNullPreview() { val data = """{"balance_changes":[{"address":"So11111111111111111111111111111111111111112","amount":-10000000},{"address":"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v","amount":1323264}],"instructions":[{"program_id":"ComputeBudget111111111111111111111111111111","program_name":"ComputeBudget","instruction_name":"SetComputeUnitLimit","items":[{"key":"Compute Unit Limit","value":"600000 compute units"}]},{"program_id":"ComputeBudget111111111111111111111111111111","program_name":"ComputeBudget","instruction_name":"SetComputeUnitPrice","items":[{"key":"Compute Unit Price","value":"0.1 lamports per compute unit"}]},{"program_id":"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL","program_name":"AssociatedTokenAccount","instruction_name":"Create"},{"program_id":"11111111111111111111111111111111","program_name":"System","instruction_name":"Transfer","items":[{"key":"Transfer Amount (SOL)","value":"0.01"}]},{"program_id":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA","program_name":"Token","instruction_name":"SyncNative"},{"program_id":"JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4","program_name":"Jupiter","instruction_name":"Route","items":[{"key":"Route Plan","value":""},{"key":"In Amount","value":"824635312696"},{"key":"Quoted Out Amount","value":"824635312704"},{"key":"Slippage Bps","value":"824635312712"},{"key":"Platform Fee Bps","value":"50"}],"token_changes":[{"address":"So11111111111111111111111111111111111111112","amount":10000000,"is_pay":true},{"address":"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v","amount":1323264,"is_pay":false}]},{"program_id":"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA","program_name":"Token","instruction_name":"CloseAccount"}]}""" val parsedTx = GsonHelper.customGson.fromJson(data, ParsedTx::class.java) - ParsedTxPreview(parsedTx = parsedTx, asset = null, solanaTxSource = SolanaTxSource.InnerSwap) -} \ No newline at end of file + MixinAppTheme { + ParsedTxPreview(parsedTx = parsedTx, asset = null, solanaTxSource = SolanaTxSource.InnerSwap) + } +} diff --git a/app/src/main/java/one/mixin/android/ui/home/web3/components/SlippageInfo.kt b/app/src/main/java/one/mixin/android/ui/home/web3/components/SlippageInfo.kt index 5f91c2bfb8..4f6e6fa25c 100644 --- a/app/src/main/java/one/mixin/android/ui/home/web3/components/SlippageInfo.kt +++ b/app/src/main/java/one/mixin/android/ui/home/web3/components/SlippageInfo.kt @@ -112,12 +112,15 @@ private fun SlippageInfo( @Preview @Composable fun PreviewSlippageInfo() { - SlippageInfo(slippageBps = 50, true) {} + MixinAppTheme { + SlippageInfo(slippageBps = 50, true) {} + } } @Preview @Composable fun PreviewSlippageInfoWarning() { - SlippageInfo(slippageBps = 600, true) {} + MixinAppTheme { + SlippageInfo(slippageBps = 600, true) {} + } } - diff --git a/app/src/main/java/one/mixin/android/ui/home/web3/stake/StakePage.kt b/app/src/main/java/one/mixin/android/ui/home/web3/stake/StakePage.kt index 0bef8c3a78..cd3eb4731b 100644 --- a/app/src/main/java/one/mixin/android/ui/home/web3/stake/StakePage.kt +++ b/app/src/main/java/one/mixin/android/ui/home/web3/stake/StakePage.kt @@ -344,11 +344,15 @@ fun Item( @Preview @Composable private fun InputPreview() { - Input(text = "123") {} + MixinAppTheme { + Input(text = "123") {} + } } @Preview @Composable private fun ValidatorInfoPreview() { - ValidatorInfo(Validator("J2nUHEAgZFRyuJbFjdqPrAa9gyWDuc7hErtDQHPhsYRp", "Mixin Validator", "", "", "", "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png", "", 123123131231231, 9, 123124, 123123)) -} \ No newline at end of file + MixinAppTheme { + ValidatorInfo(Validator("J2nUHEAgZFRyuJbFjdqPrAa9gyWDuc7hErtDQHPhsYRp", "Mixin Validator", "", "", "", "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png", "", 123123131231231, 9, 123124, 123123)) + } +} diff --git a/app/src/main/java/one/mixin/android/ui/home/web3/stake/ValidatorsPage.kt b/app/src/main/java/one/mixin/android/ui/home/web3/stake/ValidatorsPage.kt index 02c47c432c..d926254b40 100644 --- a/app/src/main/java/one/mixin/android/ui/home/web3/stake/ValidatorsPage.kt +++ b/app/src/main/java/one/mixin/android/ui/home/web3/stake/ValidatorsPage.kt @@ -221,11 +221,15 @@ private fun SearchInput( @Composable fun PreviewValidatorItem() { val validator = Validator("J2nUHEAgZFRyuJbFjdqPrAa9gyWDuc7hErtDQHPhsYRp", "Mixin Validator", "", "", "", "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png", "", 123123131231231, 9, 123124, 123123) - ValidatorItem(validator) { } + MixinAppTheme { + ValidatorItem(validator) { } + } } @Preview @Composable fun PreviewSearchInput() { - SearchInput("") -} \ No newline at end of file + MixinAppTheme { + SearchInput("") + } +} diff --git a/app/src/main/java/one/mixin/android/ui/home/web3/trade/SwapSlippagePage.kt b/app/src/main/java/one/mixin/android/ui/home/web3/trade/SwapSlippagePage.kt index 21d6a65509..50ec7baade 100644 --- a/app/src/main/java/one/mixin/android/ui/home/web3/trade/SwapSlippagePage.kt +++ b/app/src/main/java/one/mixin/android/ui/home/web3/trade/SwapSlippagePage.kt @@ -282,23 +282,27 @@ private fun String.isSlippageValid(): Boolean { @Preview @Composable fun PreviewAuto() { - Auto( - auto = - remember { - mutableStateOf(true) - }, - originAuto = true, - originBps = 80, - ) + MixinAppTheme { + Auto( + auto = + remember { + mutableStateOf(true) + }, + originAuto = true, + originBps = 80, + ) + } } @Preview @Composable fun PreviewCustom() { - Custom( - bps = - remember { - mutableStateOf("50") - }, - ) + MixinAppTheme { + Custom( + bps = + remember { + mutableStateOf("50") + }, + ) + } } diff --git a/app/src/main/java/one/mixin/android/ui/home/web3/trade/SwapTokenPage.kt b/app/src/main/java/one/mixin/android/ui/home/web3/trade/SwapTokenPage.kt index cd17c5ffec..b888c68c0d 100644 --- a/app/src/main/java/one/mixin/android/ui/home/web3/trade/SwapTokenPage.kt +++ b/app/src/main/java/one/mixin/android/ui/home/web3/trade/SwapTokenPage.kt @@ -133,6 +133,8 @@ fun SwapTokenPage( @Preview(widthDp = 300) @Composable fun SwapTokenPagePreView() { - SwapTokenPage(token = SwapToken("","1111111111111111111111111", "", 9, "Solana", "SOL", "", SwapChain("", "Solana", "SOL", "", ""))) { + MixinAppTheme { + SwapTokenPage(token = SwapToken("", "1111111111111111111111111", "", 9, "Solana", "SOL", "", SwapChain("", "Solana", "SOL", "", ""))) { + } } } diff --git a/app/src/main/java/one/mixin/android/ui/landing/components/CreateAccountPage.kt b/app/src/main/java/one/mixin/android/ui/landing/components/CreateAccountPage.kt index 338aaef73b..1158d763eb 100644 --- a/app/src/main/java/one/mixin/android/ui/landing/components/CreateAccountPage.kt +++ b/app/src/main/java/one/mixin/android/ui/landing/components/CreateAccountPage.kt @@ -126,5 +126,7 @@ fun CreateItem(@DrawableRes iconId: Int, @StringRes titleId: Int, @StringRes sub @Preview @Composable fun CreateAccountPagePreview() { - CreateAccountPage({},{}, {}, {}, {}, {}) -} \ No newline at end of file + MixinAppTheme { + CreateAccountPage({}, {}, {}, {}, {}, {}) + } +} diff --git a/app/src/main/java/one/mixin/android/ui/landing/components/MnemonicPhraseInput.kt b/app/src/main/java/one/mixin/android/ui/landing/components/MnemonicPhraseInput.kt index daa5e65ced..989cead5b3 100644 --- a/app/src/main/java/one/mixin/android/ui/landing/components/MnemonicPhraseInput.kt +++ b/app/src/main/java/one/mixin/android/ui/landing/components/MnemonicPhraseInput.kt @@ -18,11 +18,9 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions @@ -52,6 +50,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -67,7 +66,6 @@ import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import com.checkout.threedsobfuscation.le import kotlinx.coroutines.launch import one.mixin.android.Constants import one.mixin.android.MixinApp @@ -128,11 +126,12 @@ fun MnemonicPhraseInput( } } + val isInPreview = LocalInspectionMode.current var loading by remember { mutableStateOf(false) } var errorInfo by remember { mutableStateOf("") } val context = LocalContext.current val keyboardController = LocalSoftwareKeyboardController.current - val walletViewModel = hiltViewModel() + val walletViewModel = if (isInPreview) null else hiltViewModel() val coroutineScope = rememberCoroutineScope() val focusManager = LocalFocusManager.current var currentText by remember { mutableStateOf("") } @@ -491,11 +490,11 @@ fun MnemonicPhraseInput( val selfId = Session.getAccountId()!! val seed = tip?.getOrRecoverTipPriv(context, pin!!)?.getOrThrow() val edKey = tip?.getMnemonicEdKey(context, pin!!, seed!!) - val r = walletViewModel.saltExport( + val r = requireNotNull(walletViewModel).saltExport( ExportRequest( publicKey = edKey!!.publicKey.toHex(), signature = initFromSeedAndSign(edKey.privateKey, selfId.toByteArray()).toHex(), - pinBase64 = walletViewModel.getEncryptedTipBody(selfId, pin!!), + pinBase64 = requireNotNull(walletViewModel).getEncryptedTipBody(selfId, pin!!), ) ) r.data?.let { @@ -740,11 +739,11 @@ fun MnemonicPhraseInput( val selfId = Session.getAccountId()!! val seed = tip?.getOrRecoverTipPriv(context, pin!!)?.getOrThrow() val edKey = tip?.getMnemonicEdKey(context, pin!!, seed!!) - val r = walletViewModel.saltExport( + val r = requireNotNull(walletViewModel).saltExport( ExportRequest( publicKey = edKey!!.publicKey.toHex(), signature = initFromSeedAndSign(edKey.privateKey, selfId.toByteArray()).toHex(), - pinBase64 = walletViewModel.getEncryptedTipBody(selfId, pin!!), + pinBase64 = requireNotNull(walletViewModel).getEncryptedTipBody(selfId, pin!!), ) ) r.data?.let { @@ -951,11 +950,13 @@ fun InputBar(string: String, callback: (String) -> Unit) { @Preview(backgroundColor = 0xFFFFFFFF, showSystemUi = true) @Composable fun MnemonicPhraseInputPreview() { - MnemonicPhraseInput( - state = MnemonicState.Input, - onScan = {}, - onComplete = { mnemonicList -> /* Handle mnemonic change */ }, - ) + MixinAppTheme { + MnemonicPhraseInput( + state = MnemonicState.Input, + onScan = {}, + onComplete = { }, + ) + } } @Composable @@ -993,4 +994,4 @@ fun BulletPointText( modifier = Modifier.weight(1f) ) } -} \ No newline at end of file +} diff --git a/app/src/main/java/one/mixin/android/ui/setting/ui/page/MixinMemberUpgradePage.kt b/app/src/main/java/one/mixin/android/ui/setting/ui/page/MixinMemberUpgradePage.kt index 68c7d76c37..abe0a56dfb 100644 --- a/app/src/main/java/one/mixin/android/ui/setting/ui/page/MixinMemberUpgradePage.kt +++ b/app/src/main/java/one/mixin/android/ui/setting/ui/page/MixinMemberUpgradePage.kt @@ -12,6 +12,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -58,7 +59,8 @@ fun MixinMemberUpgradePage( onContactTeamMixin: () -> Unit = {}, onViewInvoice: (MembershipOrder) -> Unit = {} ) { - val viewModel: MemberViewModel = hiltViewModel() + val isInPreview = LocalInspectionMode.current + val viewModel: MemberViewModel? = if (isInPreview) null else hiltViewModel() var purchaseState by remember { mutableStateOf(PlanPurchaseState()) } var savedOrderId by remember { mutableStateOf(null) } @@ -76,12 +78,28 @@ fun MixinMemberUpgradePage( ) } - val pendingOrderState by viewModel.pendingOrder.collectAsState() - val subscriptionPlans by viewModel.subscriptionPlans.collectAsState() + val pendingOrderState = if (isInPreview) { + null + } else { + viewModel?.pendingOrder?.collectAsState()?.value + } + val subscriptionPlans = if (isInPreview) { + emptyList() + } else { + viewModel?.subscriptionPlans?.collectAsState()?.value.orEmpty() + } LaunchedEffect(Unit) { + if (isInPreview) { + purchaseState = purchaseState.copy( + availablePlans = emptyList(), + availablePlayStorePlans = emptySet(), + loading = false, + ) + return@LaunchedEffect + } try { - val response = viewModel.getPlans() + val response = requireNotNull(viewModel).getPlans() if (response.isSuccess && response.data != null) { val availablePlayStorePlans = if (BuildConfig.IS_GOOGLE_PLAY) { val billingPlanIds = subscriptionPlans.map { it.planId }.toSet() @@ -117,9 +135,10 @@ fun MixinMemberUpgradePage( } LaunchedEffect(pendingOrderState?.orderId ?: "") { + if (isInPreview) return@LaunchedEffect try { while (pendingOrderState?.orderId.isNullOrEmpty().not()) { - val orderResponse = viewModel.getOrder(pendingOrderState!!.orderId) + val orderResponse = requireNotNull(viewModel).getOrder(pendingOrderState!!.orderId) if (orderResponse?.isSuccess == true && orderResponse.data != null) { val order = orderResponse.data!! val status = MemberOrderStatus.fromString(order.status) @@ -127,14 +146,14 @@ fun MixinMemberUpgradePage( when (status) { MemberOrderStatus.PAID, MemberOrderStatus.COMPLETED -> { Timber.d("Order completed: ${order.orderId}") - viewModel.insertOrders(order) + requireNotNull(viewModel).insertOrders(order) onClose() break } MemberOrderStatus.FAILED, MemberOrderStatus.EXPIRED, MemberOrderStatus.CANCEL -> { Timber.d("Order failed: ${order.orderId}") - viewModel.insertOrders(order) + requireNotNull(viewModel).insertOrders(order) onClose() break } @@ -188,7 +207,8 @@ fun MixinMemberUpgradePage( val plan = mapLocalPlanToMemberOrderPlan(selectedPlan, purchaseState.availablePlans) ?: return@MemberUpgradePaymentButton - viewModel.viewModelScope.launch(CoroutineExceptionHandler { _, error -> + val memberViewModel = viewModel ?: return@MemberUpgradePaymentButton + memberViewModel.viewModelScope.launch(CoroutineExceptionHandler { _, error -> purchaseState = purchaseState.copy(loading = false) purchaseState = purchaseState.copy( error = ErrorHandler.getErrorMessage(error) @@ -200,7 +220,7 @@ fun MixinMemberUpgradePage( } else { MemberOrderRequest(plan = plan.plan) } - val orderResponse = viewModel.createMemberOrder(orderRequest) + val orderResponse = memberViewModel.createMemberOrder(orderRequest) if (orderResponse.isSuccess && orderResponse.data != null) { orderResponse.data?.orderId?.let { orderId -> diff --git a/app/src/main/java/one/mixin/android/ui/tip/wc/sessionproposal/WCPinBoard.kt b/app/src/main/java/one/mixin/android/ui/tip/wc/sessionproposal/WCPinBoard.kt index 5c40a27324..02fe22b183 100644 --- a/app/src/main/java/one/mixin/android/ui/tip/wc/sessionproposal/WCPinBoard.kt +++ b/app/src/main/java/one/mixin/android/ui/tip/wc/sessionproposal/WCPinBoard.kt @@ -56,6 +56,7 @@ import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.ClipboardManager import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString @@ -92,13 +93,18 @@ fun WCPinBoard( onPinComplete: ((String) -> Unit)?, ) { val context = LocalContext.current + val isInPreview = LocalInspectionMode.current val clipboardManager: ClipboardManager = LocalClipboardManager.current - val showBiometric = allowBiometric && BiometricUtil.shouldShowBiometric(context) - val randomKeyboardEnabled by LocalContext.current.defaultSharedPreferences - .booleanValueAsState( - key = Constants.Account.PREF_RANDOM, - defaultValue = false, - ) + val showBiometric = allowBiometric && !isInPreview && BiometricUtil.shouldShowBiometric(context) + val randomKeyboardEnabled by if (isInPreview) { + remember { mutableStateOf(false) } + } else { + LocalContext.current.defaultSharedPreferences + .booleanValueAsState( + key = Constants.Account.PREF_RANDOM, + defaultValue = false, + ) + } val list = if (randomKeyboardEnabled) { mutableListOf("1", "2", "3", "4", "5", "6", "7", "8", "9", "0").apply { @@ -468,5 +474,7 @@ fun WCPinBoard( @Preview @Composable fun WCPinBoardPreview() { - WCPinBoard(Step.Input, null, allowBiometric = false, true, {}, {}, {}, null, null) + MixinAppTheme { + WCPinBoard(Step.Input, null, allowBiometric = false, true, {}, {}, {}, null, null) + } } diff --git a/app/src/main/java/one/mixin/android/ui/tip/wc/sessionrequest/SessionRequestPage.kt b/app/src/main/java/one/mixin/android/ui/tip/wc/sessionrequest/SessionRequestPage.kt index 26629b37c3..63780c43e0 100644 --- a/app/src/main/java/one/mixin/android/ui/tip/wc/sessionrequest/SessionRequestPage.kt +++ b/app/src/main/java/one/mixin/android/ui/tip/wc/sessionrequest/SessionRequestPage.kt @@ -586,17 +586,21 @@ fun FeeInfo( @Preview @Composable private fun NetworkInfoPreview() { - FeeInfo("0.0169028 ETH", BigDecimal("7.57")) + MixinAppTheme { + FeeInfo("0.0169028 ETH", BigDecimal("7.57")) + } } @Preview @Composable private fun HintPreview() { - Column(modifier = Modifier.padding(8.dp)) { - Hint(Hint.NoPreview) - Box(modifier = Modifier.height(8.dp)) - Hint(Hint.Cancel) - Box(modifier = Modifier.height(8.dp)) - Hint(Hint.SpeedUp) + MixinAppTheme { + Column(modifier = Modifier.padding(8.dp)) { + Hint(Hint.NoPreview) + Box(modifier = Modifier.height(8.dp)) + Hint(Hint.Cancel) + Box(modifier = Modifier.height(8.dp)) + Hint(Hint.SpeedUp) + } } } diff --git a/app/src/main/java/one/mixin/android/ui/transfer/compose/SelectDatePage.kt b/app/src/main/java/one/mixin/android/ui/transfer/compose/SelectDatePage.kt index cf2ff89c54..23a9bfcf8a 100644 --- a/app/src/main/java/one/mixin/android/ui/transfer/compose/SelectDatePage.kt +++ b/app/src/main/java/one/mixin/android/ui/transfer/compose/SelectDatePage.kt @@ -315,5 +315,7 @@ fun SegmentedControl( @Composable @Preview fun SelectDatePagePreview() { - SelectDatePage(onExit = {}, onResult = {}) + MixinAppTheme { + SelectDatePage(onExit = {}, onResult = {}) + } } diff --git a/app/src/main/java/one/mixin/android/ui/wallet/components/AssetDashboardScreen.kt b/app/src/main/java/one/mixin/android/ui/wallet/components/AssetDashboardScreen.kt index 876ad33672..ae71a2e69a 100644 --- a/app/src/main/java/one/mixin/android/ui/wallet/components/AssetDashboardScreen.kt +++ b/app/src/main/java/one/mixin/android/ui/wallet/components/AssetDashboardScreen.kt @@ -768,9 +768,11 @@ fun CreateSafeCard( @Preview @Composable fun CardPreview() { - Column { - CreateSafeCard {} - Spacer(modifier = Modifier.height(8.dp)) - UpgradeSafeCard({}, {}) + MixinAppTheme { + Column { + CreateSafeCard {} + Spacer(modifier = Modifier.height(8.dp)) + UpgradeSafeCard({}, {}) + } } -} \ No newline at end of file +}