1、项目toast替换
2、添加注销账号功能
3、部分代码优化
This commit is contained in:
shenzuqiang 2026-03-10 15:38:29 +08:00
parent 5278050b1c
commit 85d03e0390
31 changed files with 682 additions and 147 deletions

View File

@ -4,10 +4,10 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2026-03-09T06:18:00.411600700Z"> <DropdownSelection timestamp="2026-03-10T06:53:45.140671700Z">
<Target type="DEFAULT_BOOT"> <Target type="DEFAULT_BOOT">
<handle> <handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=JRBI89BIE6AI5TG6" /> <DeviceId pluginId="PhysicalDevice" identifier="serial=d927cac5" />
</handle> </handle>
</Target> </Target>
</DropdownSelection> </DropdownSelection>

View File

@ -129,7 +129,7 @@ dependencies {
implementation(libs.androidx.activity) implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout) implementation(libs.androidx.constraintlayout)
implementation(libs.androidx.core.splashscreen) implementation(libs.androidx.core.splashscreen)
implementation(libs.multidex) // implementation(libs.multidex)
// Compose 依赖 // Compose 依赖
implementation(platform(libs.androidx.compose.bom)) implementation(platform(libs.androidx.compose.bom))

View File

@ -1,18 +1,7 @@
package com.img.rabbit package com.img.rabbit
import android.app.Activity
import android.app.ActivityManager
import android.app.Application import android.app.Application
import android.content.Intent
import android.graphics.BitmapFactory
import android.os.Build
import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.KeyEvent
import android.webkit.WebView
import androidx.activity.ComponentActivity
import androidx.activity.OnBackPressedCallback
import androidx.multidex.MultiDex
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.img.rabbit.utils.NetworkMonitor import com.img.rabbit.utils.NetworkMonitor
import com.g.gysdk.GYManager import com.g.gysdk.GYManager
@ -61,7 +50,7 @@ class BaseApplication : Application() {
} }
override fun attachBaseContext(base: android.content.Context?) { override fun attachBaseContext(base: android.content.Context?) {
MultiDex.install(base) // MultiDex.install(base)
super.attachBaseContext(base) super.attachBaseContext(base)
} }

View File

@ -196,13 +196,7 @@ class MainActivity : ComponentActivity(), LoadingCallback {
showSplash = true showSplash = true
} }
if(showSplash){ //|| globalLogout.value == true){ if(showSplash){
// 全局注销,重新登录
// if(globalLogout.value == true){
// loginViewModel = viewModel()
// loginViewModel.requestUserConfig()
// }
val token = PreferenceUtil.getAccessToken() val token = PreferenceUtil.getAccessToken()
// 未登录,显示登录页 // 未登录,显示登录页
if (token.isNullOrEmpty() && loginViewModel.userConfigResult.value == null) { if (token.isNullOrEmpty() && loginViewModel.userConfigResult.value == null) {
@ -368,7 +362,7 @@ class MainActivity : ComponentActivity(), LoadingCallback {
} }
} }
// 模拟加载过程,2秒后关闭启动页 // 模拟加载过程,500毫秒后关闭启动页
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
delay(500L) delay(500L)
splashViewModel.setLoading(false) splashViewModel.setLoading(false)

View File

@ -1,3 +1,4 @@
package com.img.rabbit.bean.local package com.img.rabbit.bean.local
data class NotifyBean(var code: String,var message: String)
data class ErrorBean(var code: String,var message: String) data class ErrorBean(var code: String,var message: String)

View File

@ -23,6 +23,7 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
@ -71,6 +72,7 @@ import com.g.gysdk.EloginActivityParam
import com.g.gysdk.GYManager import com.g.gysdk.GYManager
import com.g.gysdk.GYResponse import com.g.gysdk.GYResponse
import com.g.gysdk.GyCallBack import com.g.gysdk.GyCallBack
import com.img.rabbit.components.CenterToast
import com.img.rabbit.config.Constants.agreementUrl import com.img.rabbit.config.Constants.agreementUrl
import com.img.rabbit.config.Constants.privacyUrl import com.img.rabbit.config.Constants.privacyUrl
import com.img.rabbit.pages.toolbar.TitleBar import com.img.rabbit.pages.toolbar.TitleBar
@ -87,18 +89,6 @@ import org.json.JSONObject
@Composable @Composable
fun LoginScreen(navController: NavHostController? = null, generalViewModel: GeneralViewModel, loginViewModel: LoginViewModel, isVisibilityBreak: Boolean) { fun LoginScreen(navController: NavHostController? = null, generalViewModel: GeneralViewModel, loginViewModel: LoginViewModel, isVisibilityBreak: Boolean) {
val context = LocalContext.current val context = LocalContext.current
// val networkStatus by generalViewModel.networkStatus.observeAsState(initial = true)
// var showNetworkDisconnected by remember { mutableStateOf(false) }
//
// // 网络状态监听
// LaunchedEffect(networkStatus) {
// if (!networkStatus) {
// // 网络断开时的处理
// Log.w("NetworkStatus","网络断开")
// }else{
// Log.w("NetworkStatus","网络已连接")
// }
// }
//关于登录的事件监听 //关于登录的事件监听
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
@ -120,20 +110,20 @@ fun LoginScreen(navController: NavHostController? = null, generalViewModel: Gene
if (loginViewModel.loginResult.value?.data?.token?.isNotEmpty() == true) { if (loginViewModel.loginResult.value?.data?.token?.isNotEmpty() == true) {
val loginInfo = loginViewModel.loginResult.value?.data val loginInfo = loginViewModel.loginResult.value?.data
AppEventBus.post( LoginBindEvent.Login(userId = loginInfo?.user_id?:"", loginType = PreferenceUtil.getLoginType(), isLogin = true, data = loginInfo) ) AppEventBus.post( LoginBindEvent.Login(userId = loginInfo?.user_id?:"", loginType = PreferenceUtil.getLoginType(), isLogin = true, data = loginInfo) )
Toast.makeText(context, "登录成功", Toast.LENGTH_SHORT).show() //提示登录成功 CenterToast.show("登录成功")
if(isVisibilityBreak){ if(isVisibilityBreak){
navController?.popBackStack() // 当允许返回上一页时,登录成功后,返回上一页 navController?.popBackStack() // 当允许返回上一页时,登录成功后,返回上一页
} }
loginViewModel.loginResult.value = null //清理loginState loginViewModel.loginResult.value = null //清理loginState
}else if(loginViewModel.loginResult.value != null && loginViewModel.loginResult.value?.data?.token == null){ }else if(loginViewModel.loginResult.value != null && loginViewModel.loginResult.value?.data?.token == null){
Log.w("LoginScreen","登录失败,无有效的Token") Log.w("LoginScreen","登录失败,无有效的Token")
Toast.makeText(context, "登录失败,请重新登录", Toast.LENGTH_SHORT).show()//提示登录成功 CenterToast.show("登录失败,请重新登录")
} }
} }
Scaffold{ Scaffold{
Box( Box(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize().navigationBarsPadding()
) { ) {
Image( Image(
painter = painterResource(id = R.mipmap.ic_main_previous_mask), painter = painterResource(id = R.mipmap.ic_main_previous_mask),
@ -758,11 +748,7 @@ private fun WxLoginScreen(
//打开微信登录 //打开微信登录
viewModel.authorWechat(context, generalViewModel.api) viewModel.authorWechat(context, generalViewModel.api)
} else { } else {
Toast.makeText( CenterToast.show("请先同意用户协议和隐私政策")
context,
"请先同意用户协议和隐私政策",
Toast.LENGTH_SHORT
).show()
} }
} }
) { ) {
@ -934,11 +920,7 @@ private fun AliPayLoginScreen(
// 打开支付宝登录 // 打开支付宝登录
viewModel.requestAliPayAuthParam(context) viewModel.requestAliPayAuthParam(context)
} else { } else {
Toast.makeText( CenterToast.show("请先同意用户协议和隐私政策")
context,
"请先同意用户协议和隐私政策",
Toast.LENGTH_SHORT
).show()
} }
} }
) { ) {
@ -1164,7 +1146,7 @@ private fun OtherLoginBar(viewModel: LoginViewModel) {
*/ */
private fun validatePhoneEmpty(context: Context, viewModel: LoginViewModel, showToast: Boolean = false): Boolean { private fun validatePhoneEmpty(context: Context, viewModel: LoginViewModel, showToast: Boolean = false): Boolean {
if (showToast && viewModel.userName.value.isEmpty()) { if (showToast && viewModel.userName.value.isEmpty()) {
Toast.makeText(context, "请输入手机号", Toast.LENGTH_SHORT).show() CenterToast.show("请输入手机号")
} }
return viewModel.userName.value.isNotEmpty() return viewModel.userName.value.isNotEmpty()
} }
@ -1175,11 +1157,11 @@ private fun validatePhoneEmpty(context: Context, viewModel: LoginViewModel, show
private fun validateCaptchaLoginEmpty(context: Context, viewModel: LoginViewModel, showToast: Boolean = false): Boolean { private fun validateCaptchaLoginEmpty(context: Context, viewModel: LoginViewModel, showToast: Boolean = false): Boolean {
if (showToast) { if (showToast) {
if(viewModel.userName.value.isEmpty()){ if(viewModel.userName.value.isEmpty()){
Toast.makeText(context, "请输入手机号", Toast.LENGTH_SHORT).show() CenterToast.show("请输入手机号")
}else if(viewModel.captcha.value.isEmpty()){ }else if(viewModel.captcha.value.isEmpty()){
Toast.makeText(context, "请输入验证码", Toast.LENGTH_SHORT).show() CenterToast.show("请输入验证码")
}else if(!viewModel.isPolicyAgreement.value){ }else if(!viewModel.isPolicyAgreement.value){
Toast.makeText(context, "请同意用户协议和隐私政策", Toast.LENGTH_SHORT).show() CenterToast.show("请同意用户协议和隐私政策")
} }
} }
return viewModel.userName.value.isNotEmpty() && viewModel.captcha.value.isNotEmpty() && viewModel.isPolicyAgreement.value return viewModel.userName.value.isNotEmpty() && viewModel.captcha.value.isNotEmpty() && viewModel.isPolicyAgreement.value

View File

@ -2,9 +2,9 @@ package com.img.rabbit.pages
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.util.Log import android.util.Log
import android.view.Gravity
import android.widget.Toast
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
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.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
@ -50,6 +50,7 @@ import com.img.rabbit.pages.screen.mine.setting.AboutScreen
import com.img.rabbit.pages.screen.mine.setting.AccountBindScreen import com.img.rabbit.pages.screen.mine.setting.AccountBindScreen
import com.img.rabbit.pages.screen.mine.setting.AccountManagerScreen import com.img.rabbit.pages.screen.mine.setting.AccountManagerScreen
import com.img.rabbit.pages.screen.mine.setting.BindScreen import com.img.rabbit.pages.screen.mine.setting.BindScreen
import com.img.rabbit.pages.screen.mine.setting.DeleteAccountScreen
import com.img.rabbit.pages.screen.other.CameraGuideScreen import com.img.rabbit.pages.screen.other.CameraGuideScreen
import com.img.rabbit.route.ScreenRoute import com.img.rabbit.route.ScreenRoute
import com.img.rabbit.viewmodel.BindViewModel import com.img.rabbit.viewmodel.BindViewModel
@ -133,14 +134,23 @@ fun MainScreen(generalViewModel: GeneralViewModel, loginViewModel: LoginViewMode
Icon( Icon(
painter = painterResource(id = iconRes), painter = painterResource(id = iconRes),
contentDescription = item.title, contentDescription = item.title,
tint = Color.Unspecified tint = Color.Unspecified,
modifier = Modifier.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null
){
selectedTab = tabItems[index]
}
) )
}, },
label = { Text(item.title, color = if (selectedTab == tabItems[index]) item.selectedColor else item.normalColor) }, label = { Text(item.title, color = if (selectedTab == tabItems[index]) item.selectedColor else item.normalColor) },
selected = selectedTab == tabItems[index], selected = selectedTab == tabItems[index],
onClick = { selectedTab = tabItems[index] }, onClick = { selectedTab = tabItems[index] },
interactionSource = remember { MutableInteractionSource() },
colors = NavigationBarItemDefaults.colors( colors = NavigationBarItemDefaults.colors(
indicatorColor = Color.Transparent indicatorColor = Color.Transparent, // 去掉选中时的椭圆背景
selectedIconColor = Color.Unspecified,
unselectedIconColor = Color.Unspecified
) )
) )
} }
@ -222,6 +232,9 @@ fun MainScreen(generalViewModel: GeneralViewModel, loginViewModel: LoginViewMode
composable(ScreenRoute.AboutMine.route) { composable(ScreenRoute.AboutMine.route) {
AboutScreen(navController = navController) AboutScreen(navController = navController)
} }
composable(ScreenRoute.DeleteAccount.route) {
DeleteAccountScreen(navController = navController)
}
// 登录页面Login // 登录页面Login
composable(ScreenRoute.Login.route) { composable(ScreenRoute.Login.route) {

View File

@ -222,13 +222,11 @@ fun UpdateDialog(
) { ) {
// 执行下载更新 // 执行下载更新
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// isStartDown.value = true
onStatusChange(false, false, url) onStatusChange(false, false, url)
}else{ }else{
when { when {
// 情况 A已获得权限 // 情况 A已获得权限
storagePermissionState.status.isGranted -> { storagePermissionState.status.isGranted -> {
// isStartDown.value = true
onStatusChange(false, false, url) onStatusChange(false, false, url)
} }
// 情况 B需要向用户解释之前拒绝过但未勾选“不再询问” // 情况 B需要向用户解释之前拒绝过但未勾选“不再询问”

View File

@ -54,6 +54,7 @@ import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import coil3.compose.AsyncImage import coil3.compose.AsyncImage
import com.img.rabbit.R import com.img.rabbit.R
import com.img.rabbit.components.CenterToast
import com.img.rabbit.pages.LoadingCallback import com.img.rabbit.pages.LoadingCallback
import com.img.rabbit.provider.storage.GlobalStateManager import com.img.rabbit.provider.storage.GlobalStateManager
import com.img.rabbit.provider.storage.PreferenceUtil import com.img.rabbit.provider.storage.PreferenceUtil
@ -90,7 +91,7 @@ fun HomeScreen(
BackHandler(enabled = (currentRoute == ScreenRoute.Home.route)) { BackHandler(enabled = (currentRoute == ScreenRoute.Home.route)) {
val currentTime = System.currentTimeMillis() val currentTime = System.currentTimeMillis()
if (currentTime - lastClickTime > 2000) { if (currentTime - lastClickTime > 2000) {
Toast.makeText(context, "再按一次退出应用", Toast.LENGTH_SHORT).show() CenterToast.show("再按一次退出应用")
lastClickTime = currentTime lastClickTime = currentTime
} else { } else {
(context as? Activity)?.finish() (context as? Activity)?.finish()
@ -470,7 +471,7 @@ fun HomeScreen(
val uniVersion = val uniVersion =
PreferenceUtil.getUserConfig()?.config?.uniVersionEntity?.firstOrNull { it.unimp_type == item.type } PreferenceUtil.getUserConfig()?.config?.uniVersionEntity?.firstOrNull { it.unimp_type == item.type }
if(uniVersion == null){ if(uniVersion == null){
Toast.makeText(context, "无可用资源...", Toast.LENGTH_SHORT).show() CenterToast.show("无可用资源...")
return@clickable return@clickable
} }
val uniMpId = uniVersion.unimp_id val uniMpId = uniVersion.unimp_id

View File

@ -48,6 +48,7 @@ import androidx.navigation.compose.rememberNavController
import coil3.compose.AsyncImage import coil3.compose.AsyncImage
import com.img.rabbit.BuildConfig import com.img.rabbit.BuildConfig
import com.img.rabbit.R import com.img.rabbit.R
import com.img.rabbit.components.CenterToast
import com.img.rabbit.provider.storage.GlobalStateManager import com.img.rabbit.provider.storage.GlobalStateManager
import com.img.rabbit.provider.storage.PreferenceUtil import com.img.rabbit.provider.storage.PreferenceUtil
import com.img.rabbit.route.ScreenRoute import com.img.rabbit.route.ScreenRoute
@ -81,7 +82,7 @@ fun MineScreen(
BackHandler(enabled = (currentRoute == ScreenRoute.Mine.route)) { BackHandler(enabled = (currentRoute == ScreenRoute.Mine.route)) {
val currentTime = System.currentTimeMillis() val currentTime = System.currentTimeMillis()
if (currentTime - lastClickTime > 2000) { if (currentTime - lastClickTime > 2000) {
Toast.makeText(context, "再按一次退出应用", Toast.LENGTH_SHORT).show() CenterToast.show("再按一次退出应用")
lastClickTime = currentTime lastClickTime = currentTime
} else { } else {
(context as? Activity)?.finish() (context as? Activity)?.finish()
@ -194,8 +195,7 @@ fun MineScreen(
userInfo?.user_id userInfo?.user_id
) )
clipboard.setPrimaryClip(clip) clipboard.setPrimaryClip(clip)
Toast.makeText(context, "已复制到剪贴板", Toast.LENGTH_SHORT) CenterToast.show("已复制到剪贴板")
.show()
} }
} }
){ ){
@ -388,7 +388,7 @@ fun MineScreen(
interactionSource = remember { MutableInteractionSource() } interactionSource = remember { MutableInteractionSource() }
) { ) {
if (!generalViewModel.api.isWXAppInstalled) { if (!generalViewModel.api.isWXAppInstalled) {
Toast.makeText(context, "未安装微信客户端", Toast.LENGTH_SHORT).show() CenterToast.show("未安装微信客户端")
}else if(userInfo != null){ }else if(userInfo != null){
viewModel.requestServiceLink(context, generalViewModel.api) viewModel.requestServiceLink(context, generalViewModel.api)
} }
@ -455,7 +455,7 @@ fun MineScreen(
GlobalStateManager(context).storeGlobalUpdateNotify(true) GlobalStateManager(context).storeGlobalUpdateNotify(true)
} }
} else { } else {
Toast.makeText(context, tips, Toast.LENGTH_SHORT).show() CenterToast.show(tips)
} }
} }
}, },

View File

@ -1,12 +1,14 @@
@file:OptIn(ExperimentalPermissionsApi::class)
package com.img.rabbit.pages.screen.make package com.img.rabbit.pages.screen.make
import android.Manifest
import android.content.Context import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.util.Log import android.util.Log
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.Canvas import androidx.compose.foundation.Canvas
@ -24,6 +26,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
@ -63,10 +66,15 @@ import androidx.compose.ui.unit.toSize
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import coil3.compose.AsyncImage import coil3.compose.AsyncImage
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState
import com.google.accompanist.permissions.shouldShowRationale
import com.img.rabbit.R import com.img.rabbit.R
import com.img.rabbit.bean.local.ClothingBean import com.img.rabbit.bean.local.ClothingBean
import com.img.rabbit.bean.local.HairstyleBean import com.img.rabbit.bean.local.HairstyleBean
import com.img.rabbit.components.AppearanceType import com.img.rabbit.components.AppearanceType
import com.img.rabbit.components.CenterToast
import com.img.rabbit.components.DrawingBoardPicker import com.img.rabbit.components.DrawingBoardPicker
import com.img.rabbit.config.CommonData.clothingForFemales import com.img.rabbit.config.CommonData.clothingForFemales
import com.img.rabbit.config.CommonData.clothingForMans import com.img.rabbit.config.CommonData.clothingForMans
@ -170,6 +178,14 @@ fun CutoutScreen(navController: NavController) {
val selectedSize = remember { mutableStateOf(resizes.first { it.width == widthParam && it.height == heightParam }) } val selectedSize = remember { mutableStateOf(resizes.first { it.width == widthParam && it.height == heightParam }) }
val storagePermissionState = rememberPermissionState(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
Manifest.permission.READ_MEDIA_IMAGES // Android 13+ 使用具体媒体权限
} else {
Manifest.permission.WRITE_EXTERNAL_STORAGE // 旧版本使用常规存储权限
}
)
// 图片选择启动器 // 图片选择启动器
val imagePickerLauncher = rememberLauncherForActivityResult( val imagePickerLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.GetContent() contract = ActivityResultContracts.GetContent()
@ -200,7 +216,7 @@ fun CutoutScreen(navController: NavController) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
context.mainExecutor.execute { context.mainExecutor.execute {
isLoading.value = false isLoading.value = false
Toast.makeText(context, "抠图失败,请重试", Toast.LENGTH_SHORT).show() CenterToast.show("抠图失败,请重试")
} }
} }
} }
@ -245,21 +261,18 @@ fun CutoutScreen(navController: NavController) {
imagePickerLauncher.launch("image/*") imagePickerLauncher.launch("image/*")
} }
Column( Column(
modifier = Modifier.fillMaxSize().background(Color(0xFFF4F4F4)) modifier = Modifier.fillMaxSize().background(Color(0xFFF4F4F4)).navigationBarsPadding()
) { ) {
TitleBar(navController = navController, paddingValues = it, title = "", showSave = true){ TitleBar(navController = navController, paddingValues = it, title = "", showSave = true){
// 保存图片 // 保存图片
coroutineScope.launch { coroutineScope.launch {
// 从 Layer 捕获 Bitmap // 从 Layer 捕获 Bitmap
val bitmap = graphicsLayer.toImageBitmap().asAndroidBitmap() val bitmap = graphicsLayer.toImageBitmap().asAndroidBitmap()
// 保存图片到系统相册(图片已按比例裁剪) // // 保存图片到系统相册(图片已按比例裁剪)
saveCanvasToGallery(context, bitmap, ExportFormat.JPG){fileName, isSuccess -> // saveCanvasToGallery(context, bitmap, ExportFormat.JPG){fileName, isSuccess ->
if(isSuccess){ // val tips = if(isSuccess){ "已保存为: $fileName" }else{ "保存失败" }
Toast.makeText(context, "已保存为: $fileName", Toast.LENGTH_SHORT).show() // CenterToast.show(tips)
}else{ // }
Toast.makeText(context, "保存失败", Toast.LENGTH_SHORT).show()
}
}
/* /*
// 保存图片到系统相册(指定尺寸如果targetWidth与targetHeight比原始值小太多会导致图片模糊) // 保存图片到系统相册(指定尺寸如果targetWidth与targetHeight比原始值小太多会导致图片模糊)
@ -271,6 +284,33 @@ fun CutoutScreen(navController: NavController) {
} }
} }
*/ */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// 保存图片到系统相册(图片已按比例裁剪)
saveCanvasToGallery(context, bitmap, ExportFormat.JPG){fileName, isSuccess ->
val tips = if(isSuccess){ "已保存为: $fileName" }else{ "保存失败" }
CenterToast.show(tips)
}
}else{
when {
// 情况 A已获得权限
storagePermissionState.status.isGranted -> {
// 保存图片到系统相册(图片已按比例裁剪)
saveCanvasToGallery(context, bitmap, ExportFormat.JPG){fileName, isSuccess ->
val tips = if(isSuccess){ "已保存为: $fileName" }else{ "保存失败" }
CenterToast.show(tips)
}
}
// 情况 B需要向用户解释之前拒绝过但未勾选“不再询问”
storagePermissionState.status.shouldShowRationale -> {
storagePermissionState.launchPermissionRequest()
}
// 情况 C从未请求过权限或已被彻底拒绝
else -> {
storagePermissionState.launchPermissionRequest()
}
}
}
} }
} }

View File

@ -1,7 +1,6 @@
package com.img.rabbit.pages.screen.make package com.img.rabbit.pages.screen.make
import android.net.Uri import android.net.Uri
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
@ -13,6 +12,7 @@ import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
@ -33,6 +33,7 @@ import androidx.compose.ui.unit.sp
import androidx.navigation.NavController import androidx.navigation.NavController
import coil3.compose.AsyncImage import coil3.compose.AsyncImage
import com.img.rabbit.R import com.img.rabbit.R
import com.img.rabbit.components.CenterToast
import com.img.rabbit.components.DrawingBoardFormatPicker import com.img.rabbit.components.DrawingBoardFormatPicker
import com.img.rabbit.config.CommonData.formats import com.img.rabbit.config.CommonData.formats
import com.img.rabbit.pages.toolbar.TitleBar import com.img.rabbit.pages.toolbar.TitleBar
@ -66,7 +67,7 @@ fun FormatScreen(navController: NavController) {
imagePickerLauncher.launch("image/*") imagePickerLauncher.launch("image/*")
} }
Column( Column(
modifier = Modifier.fillMaxSize().background(Color(0xFFF4F4F4)) modifier = Modifier.fillMaxSize().background(Color(0xFFF4F4F4)).navigationBarsPadding()
) { ) {
TitleBar(navController = navController, paddingValues = it, title = "", showSave = true) { TitleBar(navController = navController, paddingValues = it, title = "", showSave = true) {
val bitmap = selectedImageUri.value?.let {uri-> val bitmap = selectedImageUri.value?.let {uri->
@ -87,11 +88,8 @@ fun FormatScreen(navController: NavController) {
sourceBitmap = bitmap, sourceBitmap = bitmap,
format = format, format = format,
onSubmitResult = { fileName, isSuccess -> onSubmitResult = { fileName, isSuccess ->
if (isSuccess) { val tips = if (isSuccess) { "已保存至 $fileName" } else { "保存失败" }
Toast.makeText(context, "已保存至 $fileName", Toast.LENGTH_SHORT).show() CenterToast.show(tips)
} else {
Toast.makeText(context, "保存失败", Toast.LENGTH_SHORT).show()
}
} }
) )
} }

View File

@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
@ -56,6 +57,7 @@ import kotlinx.coroutines.withContext
import androidx.compose.ui.graphics.asAndroidBitmap import androidx.compose.ui.graphics.asAndroidBitmap
import com.img.rabbit.components.CenterToast
import io.moyuru.cropify.Cropify import io.moyuru.cropify.Cropify
import io.moyuru.cropify.CropifyOption import io.moyuru.cropify.CropifyOption
import io.moyuru.cropify.rememberCropifyState import io.moyuru.cropify.rememberCropifyState
@ -97,7 +99,7 @@ fun LongImageScreen(navController: NavController) {
mediaPickerLauncher.launch(matisse) mediaPickerLauncher.launch(matisse)
} }
Column ( Column (
modifier = Modifier.fillMaxSize().background(Color(0xFFF4F4F4)) modifier = Modifier.fillMaxSize().background(Color(0xFFF4F4F4)).navigationBarsPadding()
) { ) {
TitleBar( TitleBar(
navController = navController, navController = navController,
@ -107,11 +109,8 @@ fun LongImageScreen(navController: NavController) {
){ ){
coroutineScope.launch { coroutineScope.launch {
saveLongToGallery(context = context, items = imageItems, format = ExportFormat.JPG){ fileName, isSuccess -> saveLongToGallery(context = context, items = imageItems, format = ExportFormat.JPG){ fileName, isSuccess ->
if (isSuccess) { val tips = if (isSuccess) { "已保存至 $fileName" } else { "保存失败" }
Toast.makeText(context, "已保存至 $fileName", Toast.LENGTH_SHORT).show() CenterToast.show(tips)
} else {
Toast.makeText(context, "保存失败", Toast.LENGTH_SHORT).show()
}
} }
} }
} }

View File

@ -20,6 +20,7 @@ import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
@ -53,6 +54,7 @@ import androidx.compose.ui.unit.sp
import androidx.compose.ui.unit.toSize import androidx.compose.ui.unit.toSize
import androidx.navigation.NavController import androidx.navigation.NavController
import com.img.rabbit.R import com.img.rabbit.R
import com.img.rabbit.components.CenterToast
import com.img.rabbit.components.DrawingBoardCertificatePicker import com.img.rabbit.components.DrawingBoardCertificatePicker
import com.img.rabbit.config.CommonData.resizes import com.img.rabbit.config.CommonData.resizes
import com.img.rabbit.pages.toolbar.TitleBar import com.img.rabbit.pages.toolbar.TitleBar
@ -117,7 +119,7 @@ fun ResizeScreen(navController: NavController) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
context.mainExecutor.execute { context.mainExecutor.execute {
isLoading.value = false isLoading.value = false
Toast.makeText(context, "加载失败,请重试", Toast.LENGTH_SHORT).show() CenterToast.show("加载失败,请重试")
} }
} }
} }
@ -141,7 +143,7 @@ fun ResizeScreen(navController: NavController) {
} }
Column( Column(
modifier = Modifier.fillMaxSize().background(Color(0xFFF4F4F4)) modifier = Modifier.fillMaxSize().background(Color(0xFFF4F4F4)).navigationBarsPadding()
) { ) {
TitleBar(navController = navController, paddingValues = it, title = "", showSave = true){ TitleBar(navController = navController, paddingValues = it, title = "", showSave = true){
// 保存图片 // 保存图片
@ -150,11 +152,8 @@ fun ResizeScreen(navController: NavController) {
val bitmap = graphicsLayer.toImageBitmap().asAndroidBitmap() val bitmap = graphicsLayer.toImageBitmap().asAndroidBitmap()
// 保存图片到系统相册(图片已按比例裁剪) // 保存图片到系统相册(图片已按比例裁剪)
saveCanvasToGallery(context, bitmap, ExportFormat.JPG){fileName, isSuccess -> saveCanvasToGallery(context, bitmap, ExportFormat.JPG){fileName, isSuccess ->
if(isSuccess){ val tips = if(isSuccess){ "已保存为: $fileName" }else{ "保存失败" }
Toast.makeText(context, "已保存为: $fileName", Toast.LENGTH_SHORT).show() CenterToast.show(tips)
}else{
Toast.makeText(context, "保存失败", Toast.LENGTH_SHORT).show()
}
} }
/* /*

View File

@ -13,13 +13,16 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -38,6 +41,7 @@ import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.google.gson.JsonArray import com.google.gson.JsonArray
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.img.rabbit.components.CenterToast
import com.img.rabbit.components.ImagePicker import com.img.rabbit.components.ImagePicker
import com.img.rabbit.pages.toolbar.TitleBar import com.img.rabbit.pages.toolbar.TitleBar
import com.img.rabbit.viewmodel.FeedbackViewModel import com.img.rabbit.viewmodel.FeedbackViewModel
@ -46,17 +50,18 @@ import okhttp3.RequestBody.Companion.toRequestBody
@Composable @Composable
fun FeedbackScreen(navController: NavHostController, viewModel: FeedbackViewModel = viewModel()) { fun FeedbackScreen(navController: NavHostController, viewModel: FeedbackViewModel = viewModel()) {
val context = LocalContext.current val context = LocalContext.current
val scrollState = rememberScrollState()
LaunchedEffect(viewModel.errorState.value) { LaunchedEffect(viewModel.errorState.value) {
if(viewModel.errorState.value != null){ if(viewModel.errorState.value != null){
Toast.makeText(context, viewModel.errorState.value?.message, Toast.LENGTH_SHORT).show() viewModel.errorState.value?.message?.let { CenterToast.show(it) }
} }
viewModel.errorState.value = null viewModel.errorState.value = null
} }
Scaffold{ Scaffold{
Column( Column(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize().navigationBarsPadding()
) { ) {
TitleBar(navController = navController, paddingValues = it, title = "意见反馈") TitleBar(navController = navController, paddingValues = it, title = "意见反馈")
Box( Box(
@ -67,7 +72,7 @@ fun FeedbackScreen(navController: NavHostController, viewModel: FeedbackViewMode
){ ){
// 意见反馈内容 // 意见反馈内容
Column( Column(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize().verticalScroll(scrollState)
) { ) {
// 意见反馈类型 // 意见反馈类型
Row( Row(
@ -421,6 +426,7 @@ fun FeedbackScreen(navController: NavHostController, viewModel: FeedbackViewMode
) )
} }
} }
Box(modifier = Modifier.fillMaxWidth().height(98.dp))
} }
@ -439,7 +445,7 @@ fun FeedbackScreen(navController: NavHostController, viewModel: FeedbackViewMode
interactionSource = remember { MutableInteractionSource() } interactionSource = remember { MutableInteractionSource() }
) { ) {
if (viewModel.feedbackMore.isEmpty()) { if (viewModel.feedbackMore.isEmpty()) {
Toast.makeText(context, "请填写详细问题或意见...", Toast.LENGTH_SHORT).show() CenterToast.show("请填写详细问题或意见...")
return@clickable return@clickable
} }
// 提交反馈 // 提交反馈

View File

@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
@ -29,7 +30,7 @@ import com.img.rabbit.R
fun OnlineServiceScreen(navController: NavHostController) { fun OnlineServiceScreen(navController: NavHostController) {
Scaffold{ Scaffold{
Column( Column(
modifier = Modifier.fillMaxSize().padding(it) modifier = Modifier.fillMaxSize().padding(it).navigationBarsPadding()
) { ) {
// 顶部栏 // 顶部栏
Row( Row(

View File

@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.layout.wrapContentSize
@ -66,7 +67,7 @@ fun SettingScreen(navController: NavHostController, loginViewModel: LoginViewMod
Scaffold{ Scaffold{
Column( Column(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize().navigationBarsPadding()
) { ) {
TitleBar(navController = navController, paddingValues = it, title = "设置") TitleBar(navController = navController, paddingValues = it, title = "设置")
@ -257,6 +258,48 @@ fun SettingScreen(navController: NavHostController, loginViewModel: LoginViewMod
) )
} }
Image(
painter = painterResource(id = R.mipmap.ic_arrow_right),
contentDescription = null,
contentScale = ContentScale.FillWidth,
modifier = Modifier
.wrapContentSize()
.padding(end = 12.dp)
.align(Alignment.CenterVertically)
)
}
Box(
modifier = Modifier.fillMaxWidth().height(0.5.dp).padding(horizontal = 12.dp).background(
Color(0x4DBBBBBB)
)
)
Row(
modifier = Modifier
.fillMaxWidth()
.height(52.dp)
.clickable(
indication = null,
interactionSource = remember { MutableInteractionSource() }
) {
// 跳转注销账号页面
navController.navigate("deleteAccount")
},
verticalAlignment = Alignment.CenterVertically
) {
Box(
modifier = Modifier.weight(1f)
){
Text(
text = "注销账号",
fontSize = 14.sp,
fontWeight = FontWeight.Bold,
color = Color(0xFF1A1A1A),
modifier = Modifier
.wrapContentSize()
.padding(start = 8.dp)
)
}
Image( Image(
painter = painterResource(id = R.mipmap.ic_arrow_right), painter = painterResource(id = R.mipmap.ic_arrow_right),
contentDescription = null, contentDescription = null,

View File

@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.layout.wrapContentSize
@ -43,14 +44,14 @@ fun AboutScreen(navController: NavHostController) {
Scaffold{ Scaffold{
val context = LocalContext.current val context = LocalContext.current
Column( Column(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize().navigationBarsPadding()
) { ) {
TitleBar(navController = navController, paddingValues = it, title = "关于我们") TitleBar(navController = navController, paddingValues = it, title = "关于我们")
Box( Box(
modifier = Modifier.fillMaxSize().padding(start = 17.dp, end = 17.dp) modifier = Modifier.fillMaxSize().padding(start = 17.dp, end = 17.dp)
){ ){
//TODO 设置内容 // 设置内容
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()

View File

@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
@ -45,6 +46,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.img.rabbit.R import com.img.rabbit.R
import com.img.rabbit.components.CenterToast
import com.img.rabbit.pages.toolbar.TitleBar import com.img.rabbit.pages.toolbar.TitleBar
import com.img.rabbit.provider.storage.PreferenceUtil import com.img.rabbit.provider.storage.PreferenceUtil
import com.img.rabbit.utils.AppEventBus import com.img.rabbit.utils.AppEventBus
@ -66,7 +68,7 @@ fun AccountBindScreen(navController: NavHostController, viewModel: AccountBindVi
LaunchedEffect(viewModel.unBindState.value) { LaunchedEffect(viewModel.unBindState.value) {
if(viewModel.unBindState.value != null){ if(viewModel.unBindState.value != null){
val loginInfo = viewModel.unBindState.value?.data val loginInfo = viewModel.unBindState.value?.data
Toast.makeText(context, "解绑成功!", Toast.LENGTH_SHORT).show() CenterToast.show("解绑成功!")
AppEventBus.post( LoginBindEvent.Bind(userId = loginInfo?.user_id?:"", loginType = null, isBind = false, data = loginInfo) ) AppEventBus.post( LoginBindEvent.Bind(userId = loginInfo?.user_id?:"", loginType = null, isBind = false, data = loginInfo) )
val popped = navController.popBackStack(route = "home", inclusive = true) val popped = navController.popBackStack(route = "home", inclusive = true)
@ -80,14 +82,14 @@ fun AccountBindScreen(navController: NavHostController, viewModel: AccountBindVi
} }
LaunchedEffect(viewModel.errorState.value) { LaunchedEffect(viewModel.errorState.value) {
if(viewModel.errorState.value != null){ if(viewModel.errorState.value != null){
Toast.makeText(context, "解绑失败...", Toast.LENGTH_SHORT).show() CenterToast.show("解绑失败...")
viewModel.errorState.value = null viewModel.errorState.value = null
} }
} }
Scaffold{ Scaffold{
Box( Box(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize().navigationBarsPadding()
){ ){
Column( Column(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()

View File

@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
@ -47,6 +48,7 @@ import androidx.navigation.compose.rememberNavController
import coil3.compose.AsyncImage import coil3.compose.AsyncImage
import com.img.rabbit.R import com.img.rabbit.R
import com.img.rabbit.bean.response.UserInfoEntity import com.img.rabbit.bean.response.UserInfoEntity
import com.img.rabbit.components.CenterToast
import com.img.rabbit.pages.dialog.TipsDialog import com.img.rabbit.pages.dialog.TipsDialog
import com.img.rabbit.pages.toolbar.TitleBar import com.img.rabbit.pages.toolbar.TitleBar
import com.img.rabbit.provider.storage.PreferenceUtil import com.img.rabbit.provider.storage.PreferenceUtil
@ -76,7 +78,7 @@ fun AccountManagerScreen(navController: NavHostController, viewModel: AccountMan
loginInfo?.let { PreferenceUtil.saveLoginInfo(it) } loginInfo?.let { PreferenceUtil.saveLoginInfo(it) }
PreferenceUtil.saveAccessToken(viewModel.switchState.value?.data?.token) PreferenceUtil.saveAccessToken(viewModel.switchState.value?.data?.token)
AppEventBus.post( LoginBindEvent.Login(userId = loginInfo?.user_id?:"", loginType = null, isLogin = true, data = loginInfo) ) AppEventBus.post( LoginBindEvent.Login(userId = loginInfo?.user_id?:"", loginType = null, isLogin = true, data = loginInfo) )
Toast.makeText(context, "切换账号成功!", Toast.LENGTH_SHORT).show() CenterToast.show("切换账号成功!")
//延迟执行,确保返回时,接口已经拿到最新的用户信息 //延迟执行,确保返回时,接口已经拿到最新的用户信息
delay(500) delay(500)
@ -86,14 +88,14 @@ fun AccountManagerScreen(navController: NavHostController, viewModel: AccountMan
} }
LaunchedEffect(viewModel.errorState.value) { LaunchedEffect(viewModel.errorState.value) {
if(viewModel.errorState.value != null){ if(viewModel.errorState.value != null){
Toast.makeText(context, "切换账号失败...", Toast.LENGTH_SHORT).show() CenterToast.show("切换账号失败...")
viewModel.errorState.value = null viewModel.errorState.value = null
} }
} }
Scaffold{ Scaffold{
Box( Box(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize().navigationBarsPadding()
){ ){
Image( Image(
painter = painterResource(id = R.mipmap.ic_account_switch_top_mask), painter = painterResource(id = R.mipmap.ic_account_switch_top_mask),

View File

@ -21,6 +21,7 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
@ -65,6 +66,7 @@ import com.g.gysdk.GYManager
import com.g.gysdk.GYResponse import com.g.gysdk.GYResponse
import com.g.gysdk.GyCallBack import com.g.gysdk.GyCallBack
import com.img.rabbit.R import com.img.rabbit.R
import com.img.rabbit.components.CenterToast
import com.img.rabbit.config.Constants.agreementUrl import com.img.rabbit.config.Constants.agreementUrl
import com.img.rabbit.config.Constants.privacyUrl import com.img.rabbit.config.Constants.privacyUrl
import com.img.rabbit.pages.toolbar.TitleBar import com.img.rabbit.pages.toolbar.TitleBar
@ -102,12 +104,12 @@ fun BindScreen(navController: NavHostController, viewModel: BindViewModel = view
LaunchedEffect(viewModel.bindState.value) { LaunchedEffect(viewModel.bindState.value) {
if (viewModel.bindState.value != null && viewModel.bindState.value?.data?.token != null) { if (viewModel.bindState.value != null && viewModel.bindState.value?.data?.token != null) {
val loginInfo = viewModel.bindState.value?.data val loginInfo = viewModel.bindState.value?.data
Toast.makeText(context, "绑定成功!", Toast.LENGTH_SHORT).show() CenterToast.show("绑定成功!")
AppEventBus.post( LoginBindEvent.Bind(userId = loginInfo?.user_id?:"", loginType = null, isBind = true, data = loginInfo) ) AppEventBus.post( LoginBindEvent.Bind(userId = loginInfo?.user_id?:"", loginType = null, isBind = true, data = loginInfo) )
navController.popBackStack() navController.popBackStack()
}else if (viewModel.bindState.value != null){ }else if (viewModel.bindState.value != null){
Toast.makeText(context, "绑定失败!", Toast.LENGTH_SHORT).show() CenterToast.show("绑定失败...")
} }
viewModel.bindState.value = null viewModel.bindState.value = null
} }
@ -116,9 +118,9 @@ fun BindScreen(navController: NavHostController, viewModel: BindViewModel = view
// 登录成功后,保存 token // 登录成功后,保存 token
LaunchedEffect(viewModel.errorState.value) { LaunchedEffect(viewModel.errorState.value) {
if (viewModel.errorState.value != null) { if (viewModel.errorState.value != null) {
Toast.makeText(context, viewModel.errorState.value?.message?: "绑定失败", Toast.LENGTH_SHORT).show() CenterToast.show(viewModel.errorState.value?.message?: "绑定失败...")
}else if (viewModel.bindState.value != null){ }else if (viewModel.bindState.value != null){
Toast.makeText(context, "绑定失败!", Toast.LENGTH_SHORT).show() CenterToast.show("绑定失败...")
} }
viewModel.errorState.value = null viewModel.errorState.value = null
} }
@ -141,7 +143,7 @@ fun BindScreen(navController: NavHostController, viewModel: BindViewModel = view
Scaffold{ Scaffold{
Box( Box(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize().navigationBarsPadding()
) { ) {
Image( Image(
painter = painterResource(id = R.mipmap.ic_main_previous_mask), painter = painterResource(id = R.mipmap.ic_main_previous_mask),
@ -742,7 +744,7 @@ private fun CaptchaBindScreen(context: Context, viewModel: BindViewModel) {
*/ */
private fun validatePhoneEmpty(context: Context, viewModel: BindViewModel, showToast: Boolean = false): Boolean { private fun validatePhoneEmpty(context: Context, viewModel: BindViewModel, showToast: Boolean = false): Boolean {
if (showToast && viewModel.userName.value.isEmpty()) { if (showToast && viewModel.userName.value.isEmpty()) {
Toast.makeText(context, "请输入手机号", Toast.LENGTH_SHORT).show() CenterToast.show("请输入手机号")
} }
return viewModel.userName.value.isNotEmpty() return viewModel.userName.value.isNotEmpty()
} }
@ -753,11 +755,11 @@ private fun validatePhoneEmpty(context: Context, viewModel: BindViewModel, showT
private fun validateCaptchaLoginEmpty(context: Context, viewModel: BindViewModel, showToast: Boolean = false): Boolean { private fun validateCaptchaLoginEmpty(context: Context, viewModel: BindViewModel, showToast: Boolean = false): Boolean {
if (showToast) { if (showToast) {
if(viewModel.userName.value.isEmpty()){ if(viewModel.userName.value.isEmpty()){
Toast.makeText(context, "请输入手机号", Toast.LENGTH_SHORT).show() CenterToast.show("请输入手机号")
}else if(viewModel.captcha.value.isEmpty()){ }else if(viewModel.captcha.value.isEmpty()){
Toast.makeText(context, "请输入验证码", Toast.LENGTH_SHORT).show() CenterToast.show("请输入验证码")
}else if(!viewModel.isPolicyAgreement.value){ }else if(!viewModel.isPolicyAgreement.value){
Toast.makeText(context, "请同意用户协议和隐私政策", Toast.LENGTH_SHORT).show() CenterToast.show("请同意用户协议和隐私政策")
} }
} }
return viewModel.userName.value.isNotEmpty() && viewModel.captcha.value.isNotEmpty() && viewModel.isPolicyAgreement.value return viewModel.userName.value.isNotEmpty() && viewModel.captcha.value.isNotEmpty() && viewModel.isPolicyAgreement.value
@ -819,11 +821,7 @@ private fun WxBindScreen(
// 打开微信登录 // 打开微信登录
viewModel.requestWithWechatAuth(context, generalViewModel.api) viewModel.requestWithWechatAuth(context, generalViewModel.api)
} else { } else {
Toast.makeText( CenterToast.show("请先同意用户协议和隐私政策")
context,
"请先同意用户协议和隐私政策",
Toast.LENGTH_SHORT
).show()
} }
} }
) { ) {

View File

@ -0,0 +1,446 @@
package com.img.rabbit.pages.screen.mine.setting
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Checkbox
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.img.rabbit.R
import com.img.rabbit.components.CenterToast
import com.img.rabbit.pages.toolbar.TitleBar
import com.img.rabbit.viewmodel.DeleteAccountViewModel
@Composable
fun DeleteAccountScreen(navController: NavHostController,viewModel: DeleteAccountViewModel = viewModel()) {
val inputTextValue = "我自愿注销本账号"
var isRights by remember { mutableStateOf(false) }//权益
var isDispute by remember { mutableStateOf(false) }//纠纷
var isDuty by remember { mutableStateOf(false) }//责任
var isIrrecoverable by remember { mutableStateOf(false) }//不可恢复
var inputText by remember { mutableStateOf("") }//文字
LaunchedEffect(viewModel.resultState.value) {
if (viewModel.resultState.value != null) {
CenterToast.show("注销成功!")
navController.popBackStack()
}
}
LaunchedEffect(viewModel.errorState.value) {
if (viewModel.errorState.value != null) {
CenterToast.show("注销失败...")
}
}
Scaffold{
Column(
modifier = Modifier.fillMaxSize().navigationBarsPadding().background(Color(0xFFF9F9F9))
) {
TitleBar(navController = navController, paddingValues = it, title = "注销账号")
Box(
modifier = Modifier.fillMaxSize().padding(start = 17.dp, end = 17.dp)
){
// 设置内容
Column(
modifier = Modifier
.fillMaxSize()
.padding(top = 16.dp)
.verticalScroll(rememberScrollState())
){
Image(
painter = painterResource(id = R.mipmap.ic_warning),
contentDescription = null,
contentScale = ContentScale.FillWidth,
modifier = Modifier.size(86.dp).align(Alignment.CenterHorizontally)
)
Text(
text = "为保证你的账号安全,在你提交的注销申请生效前,需要同时满足以下条件:",
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.align(Alignment.CenterHorizontally),
color = Color(0xFF3D3D3D)
)
Column(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(top = 16.dp, bottom = 16.dp)
.align(Alignment.CenterHorizontally)
.background(Color(0xFFFFFFFF), shape = RoundedCornerShape(12.dp))
) {
//权益
Row(
modifier = Modifier
.fillMaxWidth()
.padding(start = 16.dp, end = 16.dp, top = 16.dp)
) {
Text(
text = "1.放弃当前的VIP权益",
fontSize = 15.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.weight(1f),
color = Color(0xFF1A1A1A)
)
Checkbox(
checked = isRights,
onCheckedChange = { isChecked ->
isRights = isChecked
},
modifier = Modifier
.align(Alignment.CenterVertically)
.size(16.dp)
.scale(0.35f)
.padding(start = 6.dp)
.background(
if (isRights) Color(0xFF252525)
else Color.Transparent,
shape = RoundedCornerShape(36.dp)
)
.border(
width = 1.dp,
color = if (isRights) Color(0xFF252525)
else Color(0xFFCCCCCC),
shape = RoundedCornerShape(36.dp)
)
.align(Alignment.CenterVertically),
colors = androidx.compose.material3.CheckboxDefaults.colors(
checkedColor = Color.Transparent, // 隐藏默认背景
uncheckedColor = Color.Transparent, // 隐藏默认背景
checkmarkColor = Color.White
)
)
}
Text(
text = "当前充值的VIP我们不会退款请解除你的自动续费如果有同意请打勾",
fontSize = 13.sp,
fontWeight = FontWeight.Normal,
modifier = Modifier
.padding(top = 4.dp, start = 30.dp, end = 57.dp),
color = Color(0xFF767676)
)
//纠纷
Row(
modifier = Modifier
.fillMaxWidth()
.padding(start = 16.dp, end = 16.dp, top = 16.dp)
) {
Text(
text = "2.当前账号没有违规及其他的法律纠纷",
fontSize = 15.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.weight(1f),
color = Color(0xFF1A1A1A)
)
Checkbox(
checked = isDispute,
onCheckedChange = { isChecked ->
isDispute = isChecked
},
modifier = Modifier
.align(Alignment.CenterVertically)
.size(16.dp)
.scale(0.35f)
.padding(start = 6.dp)
.background(
if (isDispute) Color(0xFF252525)
else Color.Transparent,
shape = RoundedCornerShape(36.dp)
)
.border(
width = 1.dp,
color = if (isDispute) Color(0xFF252525)
else Color(0xFFCCCCCC),
shape = RoundedCornerShape(36.dp)
)
.align(Alignment.CenterVertically),
colors = androidx.compose.material3.CheckboxDefaults.colors(
checkedColor = Color.Transparent, // 隐藏默认背景
uncheckedColor = Color.Transparent, // 隐藏默认背景
checkmarkColor = Color.White
)
)
}
Text(
text = "同意请打勾",
fontSize = 13.sp,
fontWeight = FontWeight.Normal,
modifier = Modifier
.padding(top = 4.dp, start = 30.dp, end = 57.dp),
color = Color(0xFF767676)
)
//责任
Row(
modifier = Modifier
.fillMaxWidth()
.padding(start = 16.dp, end = 16.dp, top = 16.dp)
) {
Text(
text = "3.确认是账号本人进行注销操作,自愿承担后果",
fontSize = 15.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.weight(1f),
color = Color(0xFF1A1A1A)
)
Checkbox(
checked = isDuty,
onCheckedChange = { isChecked ->
isDuty = isChecked
},
modifier = Modifier
.align(Alignment.CenterVertically)
.size(16.dp)
.scale(0.35f)
.padding(start = 6.dp)
.background(
if (isDuty) Color(0xFF252525)
else Color.Transparent,
shape = RoundedCornerShape(36.dp)
)
.border(
width = 1.dp,
color = if (isDuty) Color(0xFF252525)
else Color(0xFFCCCCCC),
shape = RoundedCornerShape(36.dp)
)
.align(Alignment.CenterVertically),
colors = androidx.compose.material3.CheckboxDefaults.colors(
checkedColor = Color.Transparent, // 隐藏默认背景
uncheckedColor = Color.Transparent, // 隐藏默认背景
checkmarkColor = Color.White
)
)
}
Text(
text = "同意请打勾",
fontSize = 13.sp,
fontWeight = FontWeight.Normal,
modifier = Modifier
.padding(top = 4.dp, start = 30.dp, end = 57.dp),
color = Color(0xFF767676)
)
//不可恢复
Row(
modifier = Modifier
.fillMaxWidth()
.padding(start = 16.dp, end = 16.dp, top = 16.dp)
) {
Text(
text = "4.账号注销后账号不可登录,不可恢复",
fontSize = 15.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.weight(1f),
color = Color(0xFF1A1A1A)
)
Checkbox(
checked = isIrrecoverable,
onCheckedChange = { isChecked ->
isIrrecoverable = isChecked
},
modifier = Modifier
.align(Alignment.CenterVertically)
.size(16.dp)
.scale(0.35f)
.padding(start = 6.dp)
.background(
if (isIrrecoverable) Color(0xFF252525)
else Color.Transparent,
shape = RoundedCornerShape(36.dp)
)
.border(
width = 1.dp,
color = if (isIrrecoverable) Color(0xFF252525)
else Color(0xFFCCCCCC),
shape = RoundedCornerShape(36.dp)
)
.align(Alignment.CenterVertically),
colors = androidx.compose.material3.CheckboxDefaults.colors(
checkedColor = Color.Transparent, // 隐藏默认背景
uncheckedColor = Color.Transparent, // 隐藏默认背景
checkmarkColor = Color.White
)
)
}
Text(
text = "同意请打勾",
fontSize = 13.sp,
fontWeight = FontWeight.Normal,
modifier = Modifier
.padding(top = 4.dp, start = 30.dp, end = 57.dp),
color = Color(0xFF767676)
)
//文字前面意愿
Row(
modifier = Modifier
.fillMaxWidth()
.padding(start = 16.dp, end = 16.dp, top = 16.dp)
) {
Text(
text = "5.请在输入框中输入以下文字",
fontSize = 15.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.weight(1f),
color = Color(0xFF1A1A1A)
)
Box(modifier = Modifier.size(16.dp))
}
Text(
text = inputTextValue,
fontSize = 16.sp,
fontWeight = FontWeight.Normal,
modifier = Modifier
.padding(top = 4.dp, start = 30.dp, end = 57.dp),
color = Color(0xFFF64545)
)
Box(
modifier = Modifier
.fillMaxWidth()
.height(56.dp)
.padding(start = 16.dp, end = 16.dp, top = 16.dp)
.background(Color(0xFFF6F6F6), RoundedCornerShape(8.dp)).border(
width = 1.dp,
color = Color(0xFFDEDEDE),
shape = RoundedCornerShape(8.dp)
)
){
CustomTextField(value = inputText, onValueChange = {input-> inputText = input })
}
Box(modifier = Modifier.height(14.dp))
}
Box(
modifier = Modifier
.fillMaxWidth()
.height(56.dp)
.background(Color(0xFFFF4F4F).copy(
alpha = if(isValid(isRights, isDispute, isDuty, isIrrecoverable, inputText, inputTextValue))1f else 0.5f
), shape = RoundedCornerShape(197.dp))
.clickable(indication = null, interactionSource = remember { MutableInteractionSource() }) {
if(isValid(isRights, isDispute, isDuty, isIrrecoverable, inputText, inputTextValue)){
// 处理确认注销逻辑
viewModel.deleteAccount()
}
}
){
Text(
text = "确认注销",
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
color = Color(0xFFFFFFFF),
modifier = Modifier
.align(Alignment.Center)
)
}
Box(modifier = Modifier.height(56.dp))
}
}
}
}
}
@Composable
fun CustomTextField(
value: String,
onValueChange: (String) -> Unit,
placeholder: String = ""
) {
BasicTextField(
value = value,
onValueChange = onValueChange,
modifier = Modifier
.fillMaxWidth()
.height(56.dp)
.background(Color(0xFFF6F6F6), RoundedCornerShape(8.dp))
.padding(horizontal = 16.dp),
// 核心:处理占位符和对齐
decorationBox = { innerTextField ->
Box(
contentAlignment = Alignment.CenterStart, // 垂直居中
modifier = Modifier.fillMaxSize()
) {
if (value.isEmpty()) {
Text(text = placeholder, color = Color.Gray, fontSize = 14.sp)
}
innerTextField() // 实际的文本输入区域
}
},
cursorBrush = SolidColor(Color.Blue), // 自定义光标颜色
textStyle = TextStyle(color = Color.Black, fontSize = 16.sp)
)
}
private fun isValid(isRights: Boolean, isDispute: Boolean, isDuty: Boolean, isIrrecoverable: Boolean, input: String, @Suppress(
"SameParameterValue"
) inputValue: String): Boolean {
return isRights && isDispute && isDuty && isIrrecoverable && input == inputValue
}
@Preview(showBackground = true)
@Composable
private fun PreviewDeleteAccountScreen(){
DeleteAccountScreen(navController = rememberNavController())
}

View File

@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
@ -34,7 +35,7 @@ import com.img.rabbit.pages.toolbar.TitleBar
fun CameraGuideScreen(navController: NavController) { fun CameraGuideScreen(navController: NavController) {
Scaffold { Scaffold {
Box( Box(
modifier = Modifier.fillMaxSize().background(Color(0xFFF4F4F4)) modifier = Modifier.fillMaxSize().background(Color(0xFFF4F4F4)).navigationBarsPadding()
) { ) {
Column( Column(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),

View File

@ -34,7 +34,7 @@ import com.img.rabbit.route.ScreenRoute
@Composable @Composable
fun TitleBar(navController: NavController?, paddingValues: PaddingValues, title: String? = "", showSave: Boolean = false, showBreak: Boolean = true, onSubmit: (() -> Unit)? = null) { fun TitleBar(navController: NavController?, paddingValues: PaddingValues, title: String? = "", showSave: Boolean = false, showBreak: Boolean = true, onSubmit: (() -> Unit)? = null) {
Box( Box(
modifier = Modifier.fillMaxWidth().padding(paddingValues) modifier = Modifier.fillMaxWidth().padding(top = paddingValues.calculateTopPadding())
){ ){
Row( Row(
modifier = Modifier modifier = Modifier

View File

@ -28,5 +28,6 @@ sealed class ScreenRoute(val route: String) {
object BindAccount : ScreenRoute("bindAccount") object BindAccount : ScreenRoute("bindAccount")
object ManagerAccount : ScreenRoute("managerAccount") object ManagerAccount : ScreenRoute("managerAccount")
object AboutMine : ScreenRoute("aboutMine") object AboutMine : ScreenRoute("aboutMine")
object DeleteAccount : ScreenRoute("deleteAccount")
object NetError : ScreenRoute("netError") object NetError : ScreenRoute("netError")
} }

View File

@ -1,15 +1,8 @@
package com.img.rabbit.utils package com.img.rabbit.utils
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.util.Log import android.util.Log
import android.widget.Toast
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import com.dcloud.android.downloader.domain.DownloadInfo
import com.github.gzuliyujiang.oaid.DeviceIdentifier import com.github.gzuliyujiang.oaid.DeviceIdentifier
import com.google.gson.Gson
import com.img.rabbit.BuildConfig import com.img.rabbit.BuildConfig
import com.img.rabbit.bean.response.UniVersionEntity import com.img.rabbit.bean.response.UniVersionEntity
import com.img.rabbit.components.CenterToast import com.img.rabbit.components.CenterToast

View File

@ -14,6 +14,7 @@ import com.google.gson.JsonObject
import com.img.rabbit.bean.local.ErrorBean import com.img.rabbit.bean.local.ErrorBean
import com.img.rabbit.bean.local.OnekeyPreLogin import com.img.rabbit.bean.local.OnekeyPreLogin
import com.img.rabbit.bean.response.LoginInfoEntity import com.img.rabbit.bean.response.LoginInfoEntity
import com.img.rabbit.components.CenterToast
import com.img.rabbit.pages.screen.mine.setting.BindScreenType import com.img.rabbit.pages.screen.mine.setting.BindScreenType
import com.img.rabbit.provider.api.ApiManager import com.img.rabbit.provider.api.ApiManager
import com.img.rabbit.provider.api.ResultVo import com.img.rabbit.provider.api.ResultVo
@ -207,14 +208,14 @@ class BindViewModel : BaseViewModel() {
if (isPolicyAgreement.value) { if (isPolicyAgreement.value) {
doWechatAuth(context, wxApi) doWechatAuth(context, wxApi)
}else{ }else{
Toast.makeText(context, "请先同意用户协议和隐私政策", Toast.LENGTH_SHORT).show() CenterToast.show("请先同意用户协议和隐私政策")
} }
} }
//获取微信授权 //获取微信授权
private fun doWechatAuth(context: Context, wxApi: IWXAPI) { private fun doWechatAuth(context: Context, wxApi: IWXAPI) {
if (!wxApi.isWXAppInstalled) { if (!wxApi.isWXAppInstalled) {
Toast.makeText(context, "您没有安装微信客户端,请先下载安装", Toast.LENGTH_SHORT).show() CenterToast.show("您没有安装微信客户端,请先下载安装")
return return
} }
isBindWxAuthor = true isBindWxAuthor = true

View File

@ -0,0 +1,32 @@
package com.img.rabbit.viewmodel
import androidx.compose.runtime.mutableStateOf
import com.img.rabbit.bean.local.ErrorBean
import com.img.rabbit.bean.local.NotifyBean
import com.img.rabbit.provider.api.ApiManager
import com.img.rabbit.provider.storage.PreferenceUtil
import com.img.rabbit.utils.AppEventBus
import com.img.rabbit.utils.LoginBindEvent
class DeleteAccountViewModel : BaseViewModel() {
// 结果状态
val resultState = mutableStateOf<NotifyBean?>(null)
// 错误状态
val errorState = mutableStateOf<ErrorBean?>(null)
fun deleteAccount() {
isLoading.value = true // 开始加载
mLaunch {
val response = ApiManager.serviceVo.userDestroy()
if (response.status) {
resultState.value = NotifyBean(response.code.toString(), response.message.ifEmpty { "已注销!" })
PreferenceUtil.clearLogin()
AppEventBus.post( LoginBindEvent.Login(userId = null, loginType = PreferenceUtil.getLoginType(), isLogin = false, data = null) )
}else{
errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "注销失败..." })
}
isLoading.value = false // 开始加载
}
}
}

View File

@ -4,7 +4,6 @@ import android.app.Activity
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
import android.util.Log import android.util.Log
import android.widget.Toast
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.State import androidx.compose.runtime.State
@ -21,6 +20,7 @@ import com.img.rabbit.bean.local.OnekeyPreLogin
import com.img.rabbit.bean.local.toAlipayResult import com.img.rabbit.bean.local.toAlipayResult
import com.img.rabbit.bean.response.LoginInfoEntity import com.img.rabbit.bean.response.LoginInfoEntity
import com.img.rabbit.bean.response.UserConfigEntity import com.img.rabbit.bean.response.UserConfigEntity
import com.img.rabbit.components.CenterToast
import com.img.rabbit.provider.api.ApiManager import com.img.rabbit.provider.api.ApiManager
import com.img.rabbit.provider.api.ResultVo import com.img.rabbit.provider.api.ResultVo
import com.img.rabbit.provider.storage.GlobalStateManager import com.img.rabbit.provider.storage.GlobalStateManager
@ -270,7 +270,7 @@ class LoginViewModel : BaseViewModel() {
fun authorWechat(context: Context, wxApi:IWXAPI) { fun authorWechat(context: Context, wxApi:IWXAPI) {
if (isPolicyAgreement.value) { if (isPolicyAgreement.value) {
if (!wxApi.isWXAppInstalled) { if (!wxApi.isWXAppInstalled) {
Toast.makeText(context, "您没有安装微信客户端,请先下载安装", Toast.LENGTH_SHORT).show() CenterToast.show("您没有安装微信客户端,请先下载安装")
return return
} }
isLoginWxAuthor = true isLoginWxAuthor = true
@ -279,7 +279,7 @@ class LoginViewModel : BaseViewModel() {
req.state = context.packageName + Math.random() * 1000 + "_phone" req.state = context.packageName + Math.random() * 1000 + "_phone"
wxApi.sendReq(req) wxApi.sendReq(req)
}else{ }else{
Toast.makeText(context, "请先同意用户协议和隐私政策", Toast.LENGTH_SHORT).show() CenterToast.show("请先同意用户协议和隐私政策")
} }
} }
@ -331,7 +331,7 @@ class LoginViewModel : BaseViewModel() {
private fun authorAlipay(context: Context, authParam: String){ private fun authorAlipay(context: Context, authParam: String){
if(authParam.isEmpty()){ if(authParam.isEmpty()){
Toast.makeText(context, "请先获取支付宝登录授权码", Toast.LENGTH_SHORT).show() CenterToast.show("请先获取支付宝登录授权码")
return return
} }
// 发送请求获取支付宝登录授权码 // 发送请求获取支付宝登录授权码
@ -436,13 +436,7 @@ class LoginViewModel : BaseViewModel() {
mLaunch { mLaunch {
val response = ApiManager.serviceVo.logout() val response = ApiManager.serviceVo.logout()
if (response.status) { if (response.status) {
//logoutState.value = response
PreferenceUtil.clearLogin() PreferenceUtil.clearLogin()
// setLogin(false)
// 跳转登录页面
// GlobalScope.launch {
// GlobalStateManager(context).storeGlobalLogoutNotify(true)
// }
AppEventBus.post( LoginBindEvent.Login(userId = null, loginType = PreferenceUtil.getLoginType(), isLogin = false, data = null) ) AppEventBus.post( LoginBindEvent.Login(userId = null, loginType = PreferenceUtil.getLoginType(), isLogin = false, data = null) )
} else { } else {
errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "退出登录失败" }) errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "退出登录失败" })

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -13,7 +13,7 @@ constraintlayout = "2.1.4"
splashscreen = "1.0.1" splashscreen = "1.0.1"
datastoreCore = "1.2.0" datastoreCore = "1.2.0"
datastorePreferences = "1.1.1" datastorePreferences = "1.1.1"
multidex = "2.0.1" #multidex = "2.0.1"
# Compose Version # Compose Version
composeBom = "2024.05.00" composeBom = "2024.05.00"
@ -80,7 +80,7 @@ kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serializa
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" } androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" }
androidx-datastore-core = { group = "androidx.datastore", name = "datastore-core", version.ref = "datastoreCore" } androidx-datastore-core = { group = "androidx.datastore", name = "datastore-core", version.ref = "datastoreCore" }
androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" } androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" }
multidex = { module = "androidx.multidex:multidex", version.ref = "multidex" } #multidex = { module = "androidx.multidex:multidex", version.ref = "multidex" }
# Compose dependencies # Compose dependencies
androidx-compose-bom = { module = "androidx.compose:compose-bom", version.ref = "composeBom" } androidx-compose-bom = { module = "androidx.compose:compose-bom", version.ref = "composeBom" }