package com.runt.open.mvi.views
|
|
import android.text.TextUtils
|
import android.util.Log
|
import android.widget.Toast
|
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.heightIn
|
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.wrapContentHeight
|
import androidx.compose.foundation.layout.wrapContentSize
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material3.AlertDialog
|
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.material3.TextButton
|
import androidx.compose.material3.TextField
|
import androidx.compose.runtime.Composable
|
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.clip
|
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.layout.Layout
|
import androidx.compose.ui.text.TextStyle
|
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.OpenApplication
|
import com.runt.open.mvi.data.InputMessageState
|
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.cancelDismiss){
|
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.confirmDismiss){
|
message.setDismiss.invoke()
|
message.onDismissRequest.invoke()
|
}
|
message.onConfirmRequest.invoke()
|
}) {
|
Text(text = message.confirmText)
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
@Composable
|
fun InputDialog(message : InputMessageState) {
|
if(!message.isVisible){
|
return
|
}
|
var text by remember {
|
mutableStateOf(message.message)
|
}
|
var modifier : Modifier;
|
var keyboardType = message.inputType;
|
if (message.maxLines == 1) {
|
modifier = Modifier.width(260.dp).height(50.dp).padding(0.dp)
|
} else {
|
modifier = Modifier.width(260.dp).padding(0.dp).heightIn(min = 50.dp, max = 200.dp)
|
}
|
AlertDialog(onDismissRequest = {
|
if(message.touchOutside){
|
message.setDismiss.invoke()
|
message.onDismissRequest.invoke()
|
}
|
} , confirmButton = {
|
TextButton(onClick = {
|
if (message.minLength > 0 || message.maxLength > 0 || !TextUtils.isEmpty(message.regex)) {
|
var flag = true;
|
if(text.length < message.minLength){
|
flag = false;
|
}
|
if(text.length > message.maxLength && message.maxLength > 0){
|
flag = false;
|
}
|
if (!message.regex.isEmpty() && !message.regex.toRegex().matches(text)) {
|
flag = false;
|
}
|
if(flag){
|
if(message.confirmDismiss){
|
message.setDismiss.invoke()
|
message.onDismissRequest.invoke()
|
}
|
message.onConfirmRequest(text)
|
} else {
|
Toast.makeText(OpenApplication.getApplication() , message.hint , Toast.LENGTH_SHORT).show();
|
}
|
} else {
|
if(message.confirmDismiss){
|
message.setDismiss.invoke()
|
message.onDismissRequest.invoke()
|
}
|
message.onConfirmRequest(text)
|
}
|
}) {
|
Text(text = message.confirmText)
|
}
|
} , dismissButton = {
|
TextButton(onClick = {
|
if(message.cancelDismiss){
|
message.setDismiss.invoke()
|
message.onDismissRequest.invoke()
|
}
|
message.onCancelRequest.invoke()
|
}) {
|
Text(text = message.cancelText)
|
}
|
} , title = {
|
Text(text = message.title , fontSize = 16.sp)
|
} , text = {
|
TextField(value = text , onValueChange = { //val pattern = """(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]""".toRegex()
|
text = it;
|
} , singleLine = message.maxLines == 1 , maxLines = if(message.maxLines < 1) Int.MAX_VALUE else message.maxLines, modifier = modifier , keyboardOptions = KeyboardOptions(keyboardType = keyboardType) , placeholder = {
|
Text(text = message.hint , fontSize = 14.sp)
|
} , textStyle = TextStyle(fontSize = 14.sp , color = Color.Black))
|
})
|
}
|
|
@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"))
|
}
|