package com.runt.open.mvi.views import android.util.Log import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Card import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.Layout import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Popup import com.runt.open.mvi.data.LoadingState import com.runt.open.mvi.data.MessageState import com.runt.open.mvi.data.PopupMessage /** * @author Runt(qingingrunt2010@qq.com) * @purpose * @date 5/18/25 */ /** * 超出父容器 */ @Composable fun UnboundedBox( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout(content, modifier) { measurables, parent -> // 给子树宽高用"无限"上限测量 val loose = Constraints( minWidth = 0, minHeight = 0, maxWidth = Int.MAX_VALUE, maxHeight = Int.MAX_VALUE ) val placeables = measurables.map { it.measure(loose) } // 自己仍按父约束的大小布局(不撑爆父) val w = parent.maxWidth val h = parent.maxHeight layout(w, h) { // 放在(0,0)。如需往外探出,可用负偏移:placeRelative(-50, 0) placeables.forEach { it.placeRelative(0, 0) } } } } @Composable fun LoadingDialog( loadingState : LoadingState) { if (loadingState.isVisible) { Dialog(onDismissRequest = {}) { Column( modifier = Modifier .size(140.dp) .clip(RoundedCornerShape(16.dp)) .background(Color.White), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { CircularProgressIndicator() Spacer(modifier = Modifier.height(12.dp)) Text( text = loadingState.message, fontSize = 14.sp, color = Color.Black ) } } } } @Composable fun MessageDialog(message : MessageState){ if(message.isVisible){ Dialog(onDismissRequest = { //系统响应 Log.i("PublicViews" , "MessageDialog: onDismiss") if(message.touchOutside){ message.setDismiss.invoke() message.onDismissRequest.invoke() } }) { Card( modifier = Modifier .fillMaxWidth() .wrapContentHeight() .padding(16.dp), shape = RoundedCornerShape(16.dp), ) { Column(modifier = Modifier.wrapContentHeight()){ Text(text = message.title, fontSize = 16.sp, modifier = Modifier .fillMaxWidth() .padding(top = 20.dp , start = 20.dp) .wrapContentSize(Alignment.Center), textAlign = TextAlign.Center) Text( text = message.message, modifier = Modifier .fillMaxWidth() .wrapContentSize() .padding(top = 30.dp , bottom = 20.dp , start = 14.dp , end = 15.dp) .wrapContentSize(Alignment.Center), textAlign = TextAlign.Center, ) Row (modifier = Modifier.padding(start = 15.dp, end = 15.dp, bottom = 20.dp)){ if(!message.cancelText.equals("")){ Spacer(modifier = Modifier.weight(1f)) Button(onClick = { if(message.cancelDissmiss){ message.setDismiss.invoke() message.onDismissRequest.invoke() } message.onCancelRequest.invoke() }, colors = ButtonDefaults.buttonColors( containerColor = Color.Gray, // 背景色 contentColor = Color.White, // 文字/图标颜色 disabledContainerColor = Color.Gray // 禁用时背景色 ),) { Text(text = message.cancelText) } } Spacer(modifier = Modifier.weight(1f)) Button(onClick = { if(message.confirmDissmiss){ message.setDismiss.invoke() message.onDismissRequest.invoke() } message.onConfirmRequest.invoke() }) { Text(text = message.confirmText) } } } } } } } @Composable fun PopupWindow(popupMessage : PopupMessage){ if(popupMessage.isVisible){ Popup( alignment = Alignment.TopCenter, ) { Surface( modifier = Modifier .fillMaxWidth() .wrapContentHeight() .padding(10.dp), shadowElevation = 2.dp, border = BorderStroke(1.dp, Color.Gray) , shape = RoundedCornerShape(8.dp) ) { Column( modifier = Modifier.padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { Text(popupMessage.title) Spacer(modifier = Modifier.height(16.dp)) Text(popupMessage.message) Spacer(modifier = Modifier.height(15.dp)) } } } } } @Composable fun TitleBarView(title:String,onBackClick:()->Unit){ Row(modifier = Modifier .wrapContentSize(Alignment.Center) .height(50.dp), verticalAlignment = Alignment.CenterVertically) { Spacer(modifier = Modifier.size(15.dp)) IconButton(onClick = onBackClick, modifier = Modifier.size(30.dp,30.dp)) { Icon(Icons.Default.ArrowBack, contentDescription = null, tint = Color.Black) } Text(text = "${title}", modifier = Modifier .weight(1f) .fillMaxWidth() .wrapContentSize(Alignment.Center)) Spacer(modifier = Modifier.size(30.dp)) Spacer(modifier = Modifier.size(15.dp)) } } @Preview @Composable fun previewLayout(){ MessageDialog(message = MessageState(cancelText = "lll")) }