|
|
@ -6,6 +6,7 @@ import androidx.compose.animation.Crossfade |
|
|
|
import androidx.compose.animation.animateColor |
|
|
|
import androidx.compose.animation.animateColor |
|
|
|
import androidx.compose.animation.core.* |
|
|
|
import androidx.compose.animation.core.* |
|
|
|
import androidx.compose.foundation.Image |
|
|
|
import androidx.compose.foundation.Image |
|
|
|
|
|
|
|
import androidx.compose.foundation.background |
|
|
|
import androidx.compose.foundation.border |
|
|
|
import androidx.compose.foundation.border |
|
|
|
import androidx.compose.foundation.clickable |
|
|
|
import androidx.compose.foundation.clickable |
|
|
|
import androidx.compose.foundation.layout.* |
|
|
|
import androidx.compose.foundation.layout.* |
|
|
@ -14,24 +15,29 @@ import androidx.compose.runtime.* |
|
|
|
import androidx.compose.runtime.livedata.observeAsState |
|
|
|
import androidx.compose.runtime.livedata.observeAsState |
|
|
|
import androidx.compose.ui.Alignment |
|
|
|
import androidx.compose.ui.Alignment |
|
|
|
import androidx.compose.ui.Modifier |
|
|
|
import androidx.compose.ui.Modifier |
|
|
|
|
|
|
|
import androidx.compose.ui.focus.FocusRequester |
|
|
|
|
|
|
|
import androidx.compose.ui.focus.focusRequester |
|
|
|
import androidx.compose.ui.graphics.Color |
|
|
|
import androidx.compose.ui.graphics.Color |
|
|
|
import androidx.compose.ui.graphics.DefaultAlpha |
|
|
|
import androidx.compose.ui.graphics.DefaultAlpha |
|
|
|
import androidx.compose.ui.graphics.ImageBitmap |
|
|
|
import androidx.compose.ui.graphics.ImageBitmap |
|
|
|
import androidx.compose.ui.layout.ContentScale |
|
|
|
import androidx.compose.ui.layout.ContentScale |
|
|
|
import androidx.compose.ui.platform.LocalContext |
|
|
|
import androidx.compose.ui.platform.LocalContext |
|
|
|
|
|
|
|
import androidx.compose.ui.platform.LocalFocusManager |
|
|
|
import androidx.compose.ui.res.painterResource |
|
|
|
import androidx.compose.ui.res.painterResource |
|
|
|
|
|
|
|
import androidx.compose.ui.text.input.TextFieldValue |
|
|
|
import androidx.compose.ui.text.style.TextOverflow |
|
|
|
import androidx.compose.ui.text.style.TextOverflow |
|
|
|
import androidx.compose.ui.tooling.preview.Preview |
|
|
|
import androidx.compose.ui.tooling.preview.Preview |
|
|
|
import androidx.compose.ui.unit.dp |
|
|
|
import androidx.compose.ui.unit.dp |
|
|
|
import androidx.lifecycle.LiveData |
|
|
|
import androidx.lifecycle.LiveData |
|
|
|
import androidx.lifecycle.MutableLiveData |
|
|
|
import androidx.lifecycle.MutableLiveData |
|
|
|
|
|
|
|
import androidx.lifecycle.ViewModel |
|
|
|
import androidx.lifecycle.viewmodel.compose.viewModel |
|
|
|
import androidx.lifecycle.viewmodel.compose.viewModel |
|
|
|
import androidx.navigation.NavHostController |
|
|
|
import androidx.navigation.NavHostController |
|
|
|
import com.gyf.csams.MainApplication |
|
|
|
import com.gyf.csams.MainApplication |
|
|
|
import com.gyf.csams.R |
|
|
|
import com.gyf.csams.R |
|
|
|
import com.gyf.csams.main.model.MarqueeViewModel |
|
|
|
import com.gyf.csams.main.model.MarqueeViewModel |
|
|
|
import com.gyf.lib.uikit.* |
|
|
|
import com.gyf.lib.uikit.* |
|
|
|
import com.gyf.lib.uikit.theme.CSAMSTheme |
|
|
|
import com.orhanobut.logger.Logger |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* 淡入淡出并且颜色变化文本 |
|
|
|
* 淡入淡出并且颜色变化文本 |
|
|
@ -137,37 +143,45 @@ enum class ActivityDetailMenu(override val menuName: String) : TopBarMenu { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
interface SendInterface { |
|
|
|
* 评论数据状态 |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
abstract class AbstractComment : ViewModel() { |
|
|
|
/** |
|
|
|
/** |
|
|
|
* 弹窗状态 |
|
|
|
* 弹窗状态 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
val _openDialog: MutableLiveData<Boolean> |
|
|
|
protected val _openDialog: MutableLiveData<Boolean> = MutableLiveData() |
|
|
|
val openDialog: LiveData<Boolean> |
|
|
|
val openDialog: LiveData<Boolean> = _openDialog |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* 编辑内容 |
|
|
|
* 编辑内容 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
val newContent: StringForm |
|
|
|
abstract val newContent: ValidStringForm |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* 打开弹窗 |
|
|
|
* 打开弹窗 |
|
|
|
* |
|
|
|
* |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
fun openDialog() |
|
|
|
fun openDialog() { |
|
|
|
|
|
|
|
_openDialog.postValue(true) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* 关闭弹窗 |
|
|
|
* 关闭弹窗 |
|
|
|
* |
|
|
|
* |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
fun closeDialog() |
|
|
|
fun closeDialog() { |
|
|
|
|
|
|
|
_openDialog.postValue(false) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* 发送评论 |
|
|
|
* 发送评论 |
|
|
|
* |
|
|
|
* |
|
|
|
* @param callback |
|
|
|
* @param callback |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
fun send(callback: (message: String) -> Unit) |
|
|
|
abstract fun send(callback: (message: String) -> Unit) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
@ -177,22 +191,27 @@ interface SendInterface { |
|
|
|
* @param model |
|
|
|
* @param model |
|
|
|
* @param scaffoldModel |
|
|
|
* @param scaffoldModel |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
@Composable |
|
|
|
@Composable |
|
|
|
fun <T : SendInterface> SendComment(model: T, scaffoldModel: ScaffoldModel = viewModel()) { |
|
|
|
fun <T : AbstractComment> SendComment(model: T, scaffoldModel: ScaffoldModel = viewModel()) { |
|
|
|
val openDialog by model.openDialog.observeAsState() |
|
|
|
val openDialog by model.openDialog.observeAsState() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val status by model.newContent.statusForm.observeAsState() |
|
|
|
if (openDialog == true) { |
|
|
|
if (openDialog == true) { |
|
|
|
AlertDialog(onDismissRequest = { /*TODO*/ }, |
|
|
|
|
|
|
|
|
|
|
|
AlertDialog( |
|
|
|
|
|
|
|
onDismissRequest = { /*TODO*/ }, |
|
|
|
buttons = { |
|
|
|
buttons = { |
|
|
|
Row( |
|
|
|
Row( |
|
|
|
modifier = Modifier |
|
|
|
modifier = Modifier.fillMaxWidth(), |
|
|
|
.padding(10.dp) |
|
|
|
|
|
|
|
.fillMaxWidth(), |
|
|
|
|
|
|
|
horizontalArrangement = Arrangement.SpaceEvenly |
|
|
|
horizontalArrangement = Arrangement.SpaceEvenly |
|
|
|
) { |
|
|
|
) { |
|
|
|
OutlinedButton(onClick = { |
|
|
|
OutlinedButton(onClick = { |
|
|
|
model.send { scaffoldModel.update(message = it) } |
|
|
|
model.send { |
|
|
|
}) { |
|
|
|
model.closeDialog() |
|
|
|
|
|
|
|
scaffoldModel.update(message = it) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, enabled = status == FormStatus.Valid) { |
|
|
|
Text(text = "发送") |
|
|
|
Text(text = "发送") |
|
|
|
} |
|
|
|
} |
|
|
|
OutlinedButton(onClick = { |
|
|
|
OutlinedButton(onClick = { |
|
|
@ -204,13 +223,12 @@ fun <T : SendInterface> SendComment(model: T, scaffoldModel: ScaffoldModel = vie |
|
|
|
}, text = { |
|
|
|
}, text = { |
|
|
|
Column(modifier = Modifier.padding(10.dp)) { |
|
|
|
Column(modifier = Modifier.padding(10.dp)) { |
|
|
|
Card( |
|
|
|
Card( |
|
|
|
backgroundColor = MaterialTheme.colors.background, |
|
|
|
backgroundColor = MaterialTheme.colors.background |
|
|
|
modifier = Modifier.padding(10.dp) |
|
|
|
|
|
|
|
) { |
|
|
|
) { |
|
|
|
BaseTextField( |
|
|
|
BaseTextField( |
|
|
|
form = model.newContent, modifier = Modifier |
|
|
|
modifier = Modifier.fillMaxWidth(), |
|
|
|
.fillMaxWidth() |
|
|
|
form = model.newContent, |
|
|
|
.height(200.dp) |
|
|
|
isError = status !== FormStatus.Valid |
|
|
|
) |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -309,17 +327,18 @@ fun TextTopAppBar( |
|
|
|
* 跑马灯 |
|
|
|
* 跑马灯 |
|
|
|
* |
|
|
|
* |
|
|
|
* @param model |
|
|
|
* @param model |
|
|
|
* @param content |
|
|
|
|
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@Composable |
|
|
|
@Composable |
|
|
|
fun Marquee( |
|
|
|
fun Marquee( |
|
|
|
model: MarqueeViewModel = viewModel(), content: @Composable BoxScope.( |
|
|
|
model: MarqueeViewModel = viewModel() |
|
|
|
model: MarqueeViewModel, |
|
|
|
|
|
|
|
value: State<Float> |
|
|
|
|
|
|
|
) -> Unit |
|
|
|
|
|
|
|
) { |
|
|
|
) { |
|
|
|
|
|
|
|
val poetryIndex: Int by model.marqueeIndex.observeAsState(0) |
|
|
|
|
|
|
|
val marqueeTexts by model.marqueeTexts.observeAsState(mutableListOf()) |
|
|
|
|
|
|
|
val m = |
|
|
|
|
|
|
|
if (marqueeTexts.isEmpty()) "欢迎大家踊跃留言" else marqueeTexts[poetryIndex % marqueeTexts.size].message |
|
|
|
val delayMillis = 2000 |
|
|
|
val delayMillis = 2000 |
|
|
|
|
|
|
|
val durationMillis = m.length * 300 |
|
|
|
|
|
|
|
Logger.d("durationMillis=${durationMillis}") |
|
|
|
Column { |
|
|
|
Column { |
|
|
|
BoxWithConstraints { |
|
|
|
BoxWithConstraints { |
|
|
|
val transition = rememberInfiniteTransition() |
|
|
|
val transition = rememberInfiniteTransition() |
|
|
@ -328,12 +347,15 @@ fun Marquee( |
|
|
|
initialValue = 0F, |
|
|
|
initialValue = 0F, |
|
|
|
targetValue = maxWidth.value, |
|
|
|
targetValue = maxWidth.value, |
|
|
|
animationSpec = infiniteRepeatable( |
|
|
|
animationSpec = infiniteRepeatable( |
|
|
|
animation = tween(durationMillis = 3000, delayMillis = delayMillis), |
|
|
|
animation = tween(durationMillis = durationMillis, delayMillis = delayMillis), |
|
|
|
repeatMode = RepeatMode.Restart |
|
|
|
repeatMode = RepeatMode.Restart |
|
|
|
) |
|
|
|
) |
|
|
|
) |
|
|
|
) |
|
|
|
Box(modifier = Modifier.fillMaxWidth()) { |
|
|
|
Box(modifier = Modifier.fillMaxWidth()) { |
|
|
|
content(model = model, value = offset) |
|
|
|
MarqueeText( |
|
|
|
|
|
|
|
model = model, |
|
|
|
|
|
|
|
offset = offset |
|
|
|
|
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (offset.value.toInt() == maxWidth.value.toInt()) { |
|
|
|
if (offset.value.toInt() == maxWidth.value.toInt()) { |
|
|
@ -352,11 +374,9 @@ fun Marquee( |
|
|
|
@Composable |
|
|
|
@Composable |
|
|
|
fun MarqueeText(model: MarqueeViewModel = viewModel(), offset: State<Float>) { |
|
|
|
fun MarqueeText(model: MarqueeViewModel = viewModel(), offset: State<Float>) { |
|
|
|
val poetryIndex: Int by model.marqueeIndex.observeAsState(0) |
|
|
|
val poetryIndex: Int by model.marqueeIndex.observeAsState(0) |
|
|
|
|
|
|
|
val marqueeTexts by model.marqueeTexts.observeAsState(mutableListOf()) |
|
|
|
// Text(text = "$poetryIndex") |
|
|
|
|
|
|
|
// Text(text = "offset.value=${offset.value}") |
|
|
|
|
|
|
|
Text( |
|
|
|
Text( |
|
|
|
text = model.marqueeTexts[poetryIndex % model.marqueeTexts.size], |
|
|
|
text = if (marqueeTexts.isEmpty()) "欢迎大家踊跃留言" else marqueeTexts[poetryIndex % marqueeTexts.size].message, |
|
|
|
modifier = Modifier.offset(x = offset.value.dp), |
|
|
|
modifier = Modifier.offset(x = offset.value.dp), |
|
|
|
maxLines = 1, |
|
|
|
maxLines = 1, |
|
|
|
overflow = TextOverflow.Ellipsis |
|
|
|
overflow = TextOverflow.Ellipsis |
|
|
@ -587,8 +607,29 @@ fun MyBottomAppBarPreview() { |
|
|
|
|
|
|
|
|
|
|
|
@Preview |
|
|
|
@Preview |
|
|
|
@Composable |
|
|
|
@Composable |
|
|
|
fun TestPreview() { |
|
|
|
fun MainContent() { |
|
|
|
CSAMSTheme { |
|
|
|
Column( |
|
|
|
Text(text = "fuckyou") |
|
|
|
Modifier |
|
|
|
|
|
|
|
.background(Color(0xFFEDEAE0)) |
|
|
|
|
|
|
|
.fillMaxSize() |
|
|
|
|
|
|
|
.padding(32.dp), |
|
|
|
|
|
|
|
verticalArrangement = Arrangement.spacedBy(24.dp) |
|
|
|
|
|
|
|
) { |
|
|
|
|
|
|
|
var textState by remember { mutableStateOf(TextFieldValue()) } |
|
|
|
|
|
|
|
val localFocusManager = LocalFocusManager.current |
|
|
|
|
|
|
|
val focusRequester = FocusRequester() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BaseTextField( |
|
|
|
|
|
|
|
modifier = Modifier |
|
|
|
|
|
|
|
.focusRequester(focusRequester) |
|
|
|
|
|
|
|
.fillMaxWidth(), form = StringForm(formDesc = "", textLength = 5) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Button(onClick = { |
|
|
|
|
|
|
|
localFocusManager.clearFocus() |
|
|
|
|
|
|
|
}) { |
|
|
|
|
|
|
|
Text(text = "Clear Focus") |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |