留言区对接服务端接口

登录token更新结构
Dialog组件优化
master
pan 3 years ago
parent bfdd997ae8
commit 306d953e76
  1. 6
      foreground/src/main/java/com/gyf/csams/Api.kt
  2. 15
      foreground/src/main/java/com/gyf/csams/InitViewModel.kt
  3. 23
      foreground/src/main/java/com/gyf/csams/account/model/AccountViewModel.kt
  4. 44
      foreground/src/main/java/com/gyf/csams/activity/model/ActivityDetailViewModel.kt
  5. 13
      foreground/src/main/java/com/gyf/csams/activity/model/ApplyActViewModel.kt
  6. 18
      foreground/src/main/java/com/gyf/csams/activity/ui/ActivityDetailActivity.kt
  7. 10
      foreground/src/main/java/com/gyf/csams/activity/ui/ApplyActActivity.kt
  8. 154
      foreground/src/main/java/com/gyf/csams/main/model/MainViewModel.kt
  9. 29
      foreground/src/main/java/com/gyf/csams/main/ui/MainActivity.kt
  10. 115
      foreground/src/main/java/com/gyf/csams/uikit/BaseView.kt
  11. 10
      foreground/src/main/java/com/gyf/csams/uikit/ViewModel.kt
  12. 30
      foreground/src/main/java/com/gyf/csams/util/ContextUtil.kt
  13. 9
      foreground/src/main/java/com/gyf/csams/util/TokenUtil.kt
  14. 8
      lib/src/main/java/com/gyf/lib/uikit/BaseTextField.kt
  15. 4
      lib/src/main/java/com/gyf/lib/util/HttpUtil.kt

@ -30,7 +30,9 @@ enum class AccountApi(val path: String) : UrlPath {
}
enum class MainApi(val path: String) : UrlPath {
HotActivity("/hotActivity");
HotActivity("/hotActivity"),
LeaveMessage("/leaveMessage"),
GetMessage("getMessage");
override fun build(): String {
return "/api/main/${this.path}"
@ -51,4 +53,6 @@ class Api {
const val NOT_IMPL_TIP = "功能尚未实现!"
const val UNKNOW_ERROR = "出现未知异常,请联系管理员"

@ -5,18 +5,13 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.gyf.csams.util.AppDatabase
import com.gyf.csams.util.SimpleCallback
import com.gyf.csams.util.Token
import com.gyf.csams.util.TokenManager
import com.gyf.csams.util.*
import com.gyf.lib.util.ApiResponse
import com.gyf.lib.util.HttpClient
import com.orhanobut.logger.Logger
import kotlinx.coroutines.launch
data class TokenVo(val token: String, val studentId: String)
class InitViewModel : ViewModel() {
/**
@ -80,11 +75,9 @@ class InitViewModel : ViewModel() {
onFail = { TODO("token校验失败") },
type = object : TypeToken<ApiResponse<Boolean>>() {}.type
),
jsonBody = Gson().toJson(
TokenVo(
token = currentToken.token,
studentId = currentToken.studentId
)
jsonParam = TokenVo(
token = currentToken.token,
studentId = currentToken.studentId
)
)
} else if (tokenList != null && tokenList.size > 1) {

@ -7,7 +7,6 @@ import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.gyf.csams.AccountApi
import com.gyf.csams.Api
@ -16,8 +15,8 @@ import com.gyf.csams.account.ui.AccountRoute
import com.gyf.csams.main.ui.MainActivity
import com.gyf.csams.util.AppDatabase
import com.gyf.csams.util.SimpleCallback
import com.gyf.csams.util.Token
import com.gyf.csams.util.TokenManager
import com.gyf.csams.util.TokenResDto
import com.gyf.lib.uikit.FormStatus
import com.gyf.lib.uikit.StringForm
import com.gyf.lib.uikit.ValidStringForm
@ -59,9 +58,6 @@ data class UserLoginVo(val studentId: String, val password: String, val device:
*/
data class DialogMessage(val message: String, val userResDto: UserResDto?)
typealias Token = TokenResDto
/**
* 注册表单
*/
@ -227,11 +223,9 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
onFail = onFail,
type = object : TypeToken<ApiResponse<UserResDto>>() {}.type
),
jsonBody = Gson().toJson(
UserVo(
studentId = "${studentId.formValue.value}",
name = "${name.formValue.value}"
)
jsonParam = UserVo(
studentId = "${studentId.formValue.value}",
name = "${name.formValue.value}"
)
)
resetForm()
@ -269,12 +263,11 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
Logger.i(it.message)
callback(it.message)
val context = getApplication<Application>().applicationContext
val token = it.body?.token
if (token != null) {
it.body?.let {
val db = AppDatabase.getInstance(context)
viewModelScope.launch {
TokenManager.token = token
db?.tokenDao()?.save(token = token)
TokenManager.token = it
db?.tokenDao()?.save(token = it)
}.invokeOnCompletion {
context.startActivity(Intent(context, MainActivity::class.java))
_finishLogin.postValue(true)
@ -284,7 +277,7 @@ class AccountViewModel(application: Application) : AndroidViewModel(application)
onFail = { callback(it) },
type = object : TypeToken<ApiResponse<Token>>() {}.type
),
param = UserLoginVo(
jsonParam = UserLoginVo(
studentId = studentId,
password = password,
device = "${Build.MANUFACTURER} ${Build.MODEL}"

@ -5,11 +5,11 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.csams.uikit.AbstractComment
import com.gyf.csams.uikit.ActivityDetailMenu
import com.gyf.csams.uikit.SendInterface
import com.gyf.csams.uikit.TopMenuInterface
import com.gyf.lib.ScrollList
import com.gyf.lib.uikit.StringForm
import com.gyf.lib.uikit.ValidStringForm
import com.gyf.lib.util.randomChinese
import com.gyf.lib.util.randomDateTime
import com.gyf.lib.util.randomNum
@ -244,42 +244,36 @@ class ActivityMemberViewModel : ScrollList<ActivityMemberVo>() {
data class BBSVo(val studentId: String, val name: String, val createTime: Date, val content: String)
class T
class BBSCommentModel : AbstractComment() {
override val newContent = ValidStringForm(formDesc = "评论内容", textLength = 80)
/**
* TODO 发送评论
*
* @param callback
*/
override fun send(callback: (message: String) -> Unit) {
callback(NOT_IMPL_TIP)
}
}
/**
* 交流区数据状态管理
*
*/
class BBSViewModel : ScrollList<BBSVo>(), SendInterface {
class BBSViewModel : ScrollList<BBSVo>() {
override val initSize: Int = 10
val title = "发送评论"
override val newContent = StringForm(formDesc = "评论内容", textLength = 80)
override val _openDialog = MutableLiveData<Boolean>()
override val openDialog: LiveData<Boolean> = _openDialog
init {
load()
}
override fun openDialog() {
_openDialog.value = true
}
override fun closeDialog() {
_openDialog.value = false
}
/**
* TODO 发送评论
*
* @param callback
*/
override fun send(callback: (message: String) -> Unit) {
callback(NOT_IMPL_TIP)
}
/**
* TODO 加载评论
*

@ -4,7 +4,6 @@ import android.app.Activity
import android.app.Application
import android.content.Context
import android.graphics.BitmapFactory
import android.view.inputmethod.InputMethodManager
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
@ -21,6 +20,7 @@ import com.baidu.mapapi.search.sug.SuggestionSearchOption
import com.gyf.csams.MyLocationListener
import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.csams.R
import com.gyf.csams.util.ContextUtil
import com.gyf.lib.uikit.ScaffoldModel
import com.gyf.lib.uikit.StringForm
import com.gyf.lib.util.DATETIME_FORMAT
@ -430,15 +430,6 @@ class ApplyActViewModel(application: Application) : AndroidViewModel(application
private lateinit var marker: MarkerOptions
fun hideKeyBoard(activity: Activity?) {
Logger.i("隐藏软键盘")
activity?.apply {
val imm = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
window.peekDecorView()?.let {
imm.hideSoftInputFromWindow(it.windowToken, 0)
}
}
}
fun createMapView(context: Context): MapView {
val mapView = MapView(context).apply {
@ -451,7 +442,7 @@ class ApplyActViewModel(application: Application) : AndroidViewModel(application
map.setMapStatus(mapStatus(mCenter = mCenter))
map.setOnMapTouchListener {
hideKeyBoard(context as Activity)
ContextUtil.hideKeyBoard(context as Activity)
}
map.setOnMarkerClickListener {

@ -365,7 +365,11 @@ class ActivityDetailActivity : ComponentActivity() {
*
*/
@Composable
private fun BBS(model: BBSViewModel = viewModel(), scaffoldModel: ScaffoldModel = viewModel()) {
private fun BBS(
model: BBSViewModel = viewModel(),
scaffoldModel: ScaffoldModel = viewModel(),
bbsCommentModel: BBSCommentModel = viewModel()
) {
MainColumnFrame(background = {
Background(
image = BackgroundImage.ActivityBBS,
@ -380,15 +384,7 @@ class ActivityDetailActivity : ComponentActivity() {
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically
) {
// IconToggleButton(checked = false, onCheckedChange = { /*TODO*/ }) {
// Row(horizontalArrangement = Arrangement.SpaceEvenly) {
// Icon(painter = painterResource(id = R.drawable.ic_configuration), contentDescription = null)
// }
// }
// Text(text = "")
IconButton(onClick = { model.openDialog() }) {
IconButton(onClick = { bbsCommentModel.openDialog() }) {
Icon(
painter = painterResource(id = R.drawable.ic_editor),
contentDescription = null
@ -396,7 +392,7 @@ class ActivityDetailActivity : ComponentActivity() {
}
}
SendComment(model = model)
SendComment(model = bbsCommentModel)
Box(
modifier = Modifier

@ -21,6 +21,7 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
@ -40,7 +41,10 @@ import com.gyf.csams.activity.model.ApplyActViewModel
import com.gyf.csams.uikit.Background
import com.gyf.csams.uikit.BackgroundImage
import com.gyf.csams.uikit.DescCard
import com.gyf.lib.uikit.*
import com.gyf.lib.uikit.BaseTextField
import com.gyf.lib.uikit.BodyS
import com.gyf.lib.uikit.MainColumnFrame
import com.gyf.lib.uikit.ScaffoldModel
import com.gyf.lib.util.BottomButton
import com.gyf.lib.util.format
import com.orhanobut.logger.Logger
@ -252,7 +256,7 @@ class ApplyActActivity : AppCompatActivity() {
sugResult: List<SuggestionResult.SuggestionInfo>
) {
val state = rememberLazyListState()
val focusManager = LocalFocusManager.current
LazyColumn(modifier = modifier, state = state) {
sugResult.forEach {
item {
@ -261,7 +265,7 @@ class ApplyActActivity : AppCompatActivity() {
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = {
model.hideKeyBoard(this@ApplyActActivity)
focusManager.clearFocus()
model.locateSuggestPoi(suggestInfo = it)
})
) {

@ -7,17 +7,19 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.gson.reflect.TypeToken
import com.gyf.csams.AccountApi
import com.gyf.csams.Api
import com.gyf.csams.NOT_IMPL_TIP
import com.gyf.csams.*
import com.gyf.csams.account.ui.AccountActivity
import com.gyf.csams.uikit.SendInterface
import com.gyf.csams.uikit.AbstractComment
import com.gyf.csams.uikit.OnlyToken
import com.gyf.csams.util.AppDatabase
import com.gyf.csams.util.SimpleCallback
import com.gyf.csams.util.Token
import com.gyf.csams.util.TokenManager
import com.gyf.lib.ScrollList
import com.gyf.lib.uikit.FormStatus
import com.gyf.lib.uikit.PersonInfoVo
import com.gyf.lib.uikit.StringForm
import com.gyf.lib.uikit.ValidStringForm
import com.gyf.lib.util.ApiResponse
import com.gyf.lib.util.HttpClient
import com.gyf.lib.util.randomChinese
@ -27,31 +29,112 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
data class LeaveMessageFormatVo(val message: String, val studentId: String)
/**
* 跑马灯
*
*/
class MarqueeViewModel : ViewModel() {
class MarqueeViewModel : AbstractComment() {
private val _marqueeTexts = MutableLiveData<List<LeaveMessageFormatVo>>()
val marqueeTexts = listOf("床前明月光", "疑是地上霜", "举头望明月", "低头思故乡")
val marqueeTexts: LiveData<List<LeaveMessageFormatVo>> = _marqueeTexts
private val _marqueeIndex = MutableLiveData(0)
var marqueeIndex: LiveData<Int> = _marqueeIndex
private var marqueeJob: Job? = null
override val newContent: ValidStringForm =
object : ValidStringForm(formDesc = "留言", textLength = 20) {
override fun check() {
_formValue.value?.let {
if (it.contains("\n")) _statusForm.value =
FormStatus.FormatError else _statusForm.value = FormStatus.Valid
}
}
}
/**
*
* @param callback
*/
override fun send(callback: (message: String) -> Unit) {
TokenManager.token.let {
if (it != null) {
viewModelScope.launch {
HttpClient.post(url = Api.buildUrl(MainApi.LeaveMessage),
SimpleCallback<Boolean>(
action = "发送留言", onSuccess = {
if (it.body == true) {
callback("留言发送成功")
newContent.clean()
_marqueeTexts.value?.apply {
val c = mutableListOf<LeaveMessageFormatVo>()
c.add(
LeaveMessageFormatVo(
message = "${TokenManager.token?.name}说:${newContent.formValue.value}",
studentId = "${TokenManager.token?.studentId}"
)
)
c.addAll(this)
_marqueeTexts.postValue(c)
}
} else {
callback("留言发送失败")
}
}, onFail = {
callback("留言发送失败")
}, type = object : TypeToken<ApiResponse<Boolean>>() {}.type
),
jsonParam = LeaveMessageVo(
message = newContent.formValue.value ?: "",
token = it
)
)
}
} else {
callback(UNKNOW_ERROR)
}
}
}
fun loadMessage(callback: (message: String) -> Unit) {
viewModelScope.launch {
HttpClient.post(
Api.buildUrl(MainApi.GetMessage),
SimpleCallback<List<LeaveMessageFormatVo>>(action = "获取留言", onSuccess = {
// callback(it.message)
Logger.i(it.message)
it.body?.let {
_marqueeTexts.postValue(it)
}
}, onFail = {
Logger.e(it)
callback("留言获取失败")
}, type = object : TypeToken<ApiResponse<List<LeaveMessageFormatVo>>>() {}.type),
jsonParam = OnlyToken()
)
}
}
fun addAsync(delayMillis: Int) {
if (marqueeJob == null || marqueeJob?.isCompleted == true) {
marqueeJob = viewModelScope.launch {
_marqueeIndex.postValue(
if (_marqueeIndex.value == marqueeTexts.size - 1) 0 else _marqueeIndex.value?.plus(
1
_marqueeTexts.value?.apply {
_marqueeIndex.postValue(
if (_marqueeIndex.value == size - 1) 0 else _marqueeIndex.value?.plus(
1
)
)
)
delay(timeMillis = delayMillis.toLong())
delay(timeMillis = delayMillis.toLong())
}
}
}
}
}
/**
@ -61,32 +144,51 @@ class MarqueeViewModel : ViewModel() {
*/
data class AssociationListVo(val name: String)
data class LeaveMessageVo(val message: String, val token: Token)
/**
* 主页
*
*/
class MainViewModel : ViewModel(), SendInterface {
class MainViewModel : AbstractComment() {
override val _openDialog: MutableLiveData<Boolean> = MutableLiveData()
override val openDialog: LiveData<Boolean> = _openDialog
override val newContent: StringForm = StringForm(formDesc = "留言", textLength = 30)
override fun openDialog() {
_openDialog.value = true
}
override fun closeDialog() {
_openDialog.value = false
}
override val newContent: ValidStringForm =
object : ValidStringForm(formDesc = "留言", textLength = 20) {
override fun check() {
_formValue.value?.let {
if (it.contains("\n")) _statusForm.value =
FormStatus.FormatError else _statusForm.value = FormStatus.Valid
}
}
}
/**
* TODO 发送留言
*
* @param callback
*/
override fun send(callback: (message: String) -> Unit) {
callback(NOT_IMPL_TIP)
TokenManager.token.let {
if (it != null) {
viewModelScope.launch {
HttpClient.post(url = Api.buildUrl(MainApi.LeaveMessage),
SimpleCallback<Boolean>(
action = "发送留言", onSuccess = {
callback("留言发送${if (it.body == true) "成功" else "失败"}")
}, onFail = {
callback("留言发送失败")
}, type = object : TypeToken<ApiResponse<Boolean>>() {}.type
),
jsonParam = LeaveMessageVo(
message = newContent.formValue.value ?: "",
token = it
)
)
}
} else {
callback(UNKNOW_ERROR)
}
}
}
}
@ -245,7 +347,7 @@ class CenterViewModel : ViewModel() {
}, onFail = { callback("退出登陆失败") },
type = object : TypeToken<ApiResponse<Boolean>>() {}.type
),
param = UserLogoutVo(studentId = studentId)
jsonParam = UserLogoutVo(studentId = studentId)
)
}
} else {

@ -30,7 +30,10 @@ import com.gyf.csams.R
import com.gyf.csams.activity.ui.ActivityDetailActivity
import com.gyf.csams.association.ui.AssociationActivity
import com.gyf.csams.association.ui.RegAssociationActivity
import com.gyf.csams.main.model.*
import com.gyf.csams.main.model.AssociationListVo
import com.gyf.csams.main.model.CenterViewModel
import com.gyf.csams.main.model.ListViewModel
import com.gyf.csams.main.model.MarqueeViewModel
import com.gyf.csams.message.ui.MessageActivity
import com.gyf.csams.uikit.*
import com.gyf.lib.uikit.*
@ -52,17 +55,19 @@ class MainActivity : ComponentActivity() {
setContent {
TestBody { nav, s ->
TestBody { nav, scaffoldState ->
NavHost(navController = nav, startDestination = MainMenu.Main.name) {
composable(MainMenu.Main.name) {
Main(navController = nav)
ShowSnackbar(scaffoldState = scaffoldState)
}
composable(MainMenu.List.name) {
AssociationList(navController = nav)
ShowSnackbar(scaffoldState = scaffoldState)
}
composable(MainMenu.Center.name) {
Center(navController = nav)
ShowSnackbar(scaffoldState = s)
ShowSnackbar(scaffoldState = scaffoldState)
}
}
@ -384,33 +389,33 @@ class MainActivity : ComponentActivity() {
private fun MessageBoard(
modifier: Modifier = Modifier,
model: MarqueeViewModel = viewModel(),
mainViewModel: MainViewModel = viewModel()
scaffoldModel: ScaffoldModel = viewModel()
) {
model.loadMessage {
scaffoldModel.update(message = it)
}
Card(modifier = modifier, backgroundColor = MaterialTheme.colors.background) {
Row(
verticalAlignment = Alignment.CenterVertically
) {
IconButton(onClick = { mainViewModel.openDialog() }) {
IconButton(onClick = { model.openDialog() }) {
Icon(
painter = painterResource(id = R.drawable.ic_comments),
contentDescription = null,
)
}
SendComment(model = mainViewModel)
SendComment(model = model)
Row(
horizontalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxWidth()
) {
Marquee(model = model) { model, value ->
MarqueeText(
model = model,
offset = value
)
}
Marquee(model = model)
}
}

@ -6,6 +6,7 @@ import androidx.compose.animation.Crossfade
import androidx.compose.animation.animateColor
import androidx.compose.animation.core.*
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
@ -14,24 +15,29 @@ import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
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.DefaultAlpha
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.gyf.csams.MainApplication
import com.gyf.csams.R
import com.gyf.csams.main.model.MarqueeViewModel
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>
val openDialog: LiveData<Boolean>
protected val _openDialog: MutableLiveData<Boolean> = MutableLiveData()
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
*/
fun send(callback: (message: String) -> Unit)
abstract fun send(callback: (message: String) -> Unit)
}
/**
@ -177,22 +191,27 @@ interface SendInterface {
* @param model
* @param scaffoldModel
*/
@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 status by model.newContent.statusForm.observeAsState()
if (openDialog == true) {
AlertDialog(onDismissRequest = { /*TODO*/ },
AlertDialog(
onDismissRequest = { /*TODO*/ },
buttons = {
Row(
modifier = Modifier
.padding(10.dp)
.fillMaxWidth(),
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
OutlinedButton(onClick = {
model.send { scaffoldModel.update(message = it) }
}) {
model.send {
model.closeDialog()
scaffoldModel.update(message = it)
}
}, enabled = status == FormStatus.Valid) {
Text(text = "发送")
}
OutlinedButton(onClick = {
@ -204,13 +223,12 @@ fun <T : SendInterface> SendComment(model: T, scaffoldModel: ScaffoldModel = vie
}, text = {
Column(modifier = Modifier.padding(10.dp)) {
Card(
backgroundColor = MaterialTheme.colors.background,
modifier = Modifier.padding(10.dp)
backgroundColor = MaterialTheme.colors.background
) {
BaseTextField(
form = model.newContent, modifier = Modifier
.fillMaxWidth()
.height(200.dp)
modifier = Modifier.fillMaxWidth(),
form = model.newContent,
isError = status !== FormStatus.Valid
)
}
}
@ -309,17 +327,18 @@ fun TextTopAppBar(
* 跑马灯
*
* @param model
* @param content
*/
@Composable
fun Marquee(
model: MarqueeViewModel = viewModel(), content: @Composable BoxScope.(
model: MarqueeViewModel,
value: State<Float>
) -> Unit
model: MarqueeViewModel = viewModel()
) {
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 durationMillis = m.length * 300
Logger.d("durationMillis=${durationMillis}")
Column {
BoxWithConstraints {
val transition = rememberInfiniteTransition()
@ -328,12 +347,15 @@ fun Marquee(
initialValue = 0F,
targetValue = maxWidth.value,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = 3000, delayMillis = delayMillis),
animation = tween(durationMillis = durationMillis, delayMillis = delayMillis),
repeatMode = RepeatMode.Restart
)
)
Box(modifier = Modifier.fillMaxWidth()) {
content(model = model, value = offset)
MarqueeText(
model = model,
offset = offset
)
}
if (offset.value.toInt() == maxWidth.value.toInt()) {
@ -352,11 +374,9 @@ fun Marquee(
@Composable
fun MarqueeText(model: MarqueeViewModel = viewModel(), offset: State<Float>) {
val poetryIndex: Int by model.marqueeIndex.observeAsState(0)
// Text(text = "$poetryIndex")
// Text(text = "offset.value=${offset.value}")
val marqueeTexts by model.marqueeTexts.observeAsState(mutableListOf())
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),
maxLines = 1,
overflow = TextOverflow.Ellipsis
@ -587,8 +607,29 @@ fun MyBottomAppBarPreview() {
@Preview
@Composable
fun TestPreview() {
CSAMSTheme {
Text(text = "fuckyou")
fun MainContent() {
Column(
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")
}
}
}

@ -9,6 +9,8 @@ import androidx.lifecycle.viewModelScope
import com.google.gson.reflect.TypeToken
import com.gyf.csams.R
import com.gyf.csams.util.SimpleCallback
import com.gyf.csams.util.Token
import com.gyf.csams.util.TokenManager
import com.gyf.lib.util.HttpClient
import com.gyf.lib.util.ImageUtil
import com.orhanobut.logger.Logger
@ -17,6 +19,14 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
sealed class BaseVo {
abstract val token: Token
}
data class OnlyToken(
override val token: Token = TokenManager.token ?: throw IllegalArgumentException("无法获取token")
) : BaseVo()
class ImageModel(application: Application, private val urlPath: String) :
AndroidViewModel(application) {
private val _image = MutableLiveData<ImageBitmap>()

@ -0,0 +1,30 @@
package com.gyf.csams.util
import android.app.Activity
import android.view.View
import android.view.inputmethod.InputMethodManager
import com.orhanobut.logger.Logger
object ContextUtil {
fun hideKeyBoard(activity: Activity?) {
Logger.i("隐藏软键盘")
activity?.apply {
val imm = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
window.peekDecorView()?.let {
imm.hideSoftInputFromWindow(it.windowToken, 0)
}
}
}
fun testHideKeyBoard(activity: Activity) {
Logger.i("隐藏软键盘")
val imm = activity.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
//Find the currently focused view, so we can grab the correct window token from it.
var view: View? = activity.currentFocus
//If no view currently has focus, create a new one, just so we can grab a window token from it
if (view == null) {
view = View(activity)
}
imm.hideSoftInputFromWindow(view.windowToken, 0)
}
}

@ -13,16 +13,19 @@ import androidx.room.*
data class Token(
@PrimaryKey val studentId: String,
@ColumnInfo val token: String,
@ColumnInfo val createTime: Long
@ColumnInfo val createTime: Long,
@ColumnInfo val name: String
)
//data class TokenVo(val token:String,val studentId:String)
/**
* 令牌传输
*
* @property isValid
* @property token
*/
data class TokenResDto(val isValid: Boolean, val token: Token?)
data class TokenVo(val token: String, val studentId: String)
@Dao
interface TokenDao {

@ -65,6 +65,10 @@ open class StringForm(formDesc: String, val textLength: Int) :
}
Logger.i("${formDesc}更新值:${_formValue.value}")
}
fun clean() {
_formValue.postValue("")
}
}
open class ValidStringForm(formDesc: String, textLength: Int) : StringForm(formDesc, textLength) {
@ -79,7 +83,9 @@ open class ValidStringForm(formDesc: String, textLength: Int) : StringForm(formD
}
}
protected open fun check() {}
protected open fun check() {
_statusForm.value = FormStatus.Valid
}
}
/**

@ -105,8 +105,8 @@ object HttpClient {
call.enqueue(callback)
}
fun post(url: String, callback: Callback, param: Any) {
val jsonBody = json.toJson(param)
fun post(url: String, callback: Callback, jsonParam: Any) {
val jsonBody = json.toJson(jsonParam)
Logger.json(jsonBody)
val request = Request.Builder()
.url(url)

Loading…
Cancel
Save