package com.gyf.csams.association.ui import android.content.Intent import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.ManagedActivityResultLauncher import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.setContent import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.Image import androidx.compose.foundation.border import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.window.PopupProperties import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import com.gyf.csams.R import com.gyf.csams.activity.ui.ApplyActActivity import com.gyf.csams.association.model.* import com.gyf.csams.uikit.* import com.gyf.lib.uikit.* import com.gyf.lib.util.TokenManager import com.orhanobut.logger.Logger import kotlinx.coroutines.delay /** * 社团界面 * */ class AssociationActivity : ComponentActivity() { private val associationId: Int get() { val id = intent.getIntExtra( AssociationActivity::class.java.name, 0 ) return if (id == 0) throw IllegalArgumentException("社团id:${id}不合法,初始化失败") else id } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { NavBody { nav, scaffoldState -> val model: AssociationViewModel = viewModel() val currentMenuName: AssociationMenu by model.currentMenu.observeAsState( AssociationMenu.startMenu ) val expanded by model.expanded.observeAsState(false) //TODO重命名操作反馈 val rename = rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) { if (it.resultCode == RESULT_OK) { val m = it.data?.getStringExtra(RenameActivity::class.java.name) Logger.i("社团重命名返回:${m}") model.update(message = m) } } val examResult = rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) { if (it.resultCode == RESULT_OK) { val m = it.data?.getStringExtra(ExamActivity::class.java.name) Logger.i("试卷提交结果:${m}") model.update(message = m) } } Column { TextTopAppBar(nav = nav, currentMenuName = currentMenuName.menuName, menuNames = AssociationMenu.values(), iconMenu = { model.switchType() }) { Row { DropdownMenu( expanded = expanded, onDismissRequest = { }, properties = PopupProperties() ) { when { TokenManager.getUserInfo()?.associationVo?.associationId == associationId && TokenManager.getUserInfo()?.isHead == true -> { DropdownMenuItem(onClick = { startActivity( Intent( this@AssociationActivity, ApplyActActivity::class.java ).apply { putExtra( AssociationActivity::class.java.name, associationId ) } ) model.close() }) { Row(verticalAlignment = Alignment.CenterVertically) { Text(text = getString(R.string.apply_act_menu)) Icon( painter = painterResource(id = R.drawable.ic_add_fill), contentDescription = null ) } } DropdownMenuItem(onClick = { startActivity( Intent( this@AssociationActivity, ExamActivity::class.java ).apply { putExtra( AssociationActivity::class.java.name, associationId ) putExtra( ExamActivityType::name.name, ExamActivityType.SET_EXAM ) }) model.close() }) { Row(verticalAlignment = Alignment.CenterVertically) { Text(text = getString(R.string.set_exam_menu)) Icon( painter = painterResource(id = R.drawable.ic_editor), contentDescription = null ) } } DropdownMenuItem(onClick = { startActivity( Intent( this@AssociationActivity, AuditJoinActivity::class.java ).apply { putExtra( AssociationActivity::class.java.name, associationId ) }) model.close() }) { Row(verticalAlignment = Alignment.CenterVertically) { Text(text = ("入团审核")) Icon( painter = painterResource(id = R.drawable.ic_exchange_rate), contentDescription = null ) } } DropdownMenuItem(onClick = { rename.launch(Intent( this@AssociationActivity, RenameActivity::class.java ).apply { putExtra( AssociationActivity::class.java.name, associationId ) }) model.close() }) { Row(verticalAlignment = Alignment.CenterVertically) { Text(text = getString(R.string.rename_menu)) Icon( painter = painterResource(id = R.drawable.ic_exchange_rate), contentDescription = null ) } } } TokenManager.getUserInfo()?.associationVo == null -> DropdownMenuItem( onClick = { model.applyAssociation(associationId = associationId) { model.update(applyAssociationResultVo = it) } model.close() }) { Row(verticalAlignment = Alignment.CenterVertically) { Text(text = getString(R.string.join_association)) Icon( painter = painterResource(id = R.drawable.ic_add_account), contentDescription = null ) } } } DropdownMenuItem(onClick = { model.close() }) { Row(verticalAlignment = Alignment.CenterVertically) { Icon( painter = painterResource(id = R.drawable.ic_arrow_up), contentDescription = null, modifier = Modifier .height(30.dp) .fillMaxWidth() ) } } } } } NavHost( navController = nav, startDestination = AssociationMenu.startMenu.name ) { composable(AssociationMenu.Member.name) { model.clickMenu(AssociationMenu.Member) Member() ShowTip(model = model, examResult = examResult) ShowSnackbar(scaffoldState = scaffoldState) } composable(AssociationMenu.Main.name) { model.clickMenu(AssociationMenu.Main) Main() ShowTip(model = model, examResult = examResult) ShowSnackbar(scaffoldState = scaffoldState) } composable(AssociationMenu.ActivityList.name) { model.clickMenu(AssociationMenu.ActivityList) AssociationList() ShowTip(model = model, examResult = examResult) ShowSnackbar(scaffoldState = scaffoldState) } } } } } } /** * 显示提示 * * @param model * @param examResult */ @Composable private fun ShowTip( model: AssociationViewModel = viewModel(), examResult: ManagedActivityResultLauncher ) { val scaffoldModel: ScaffoldModel = viewModel() val message by model.dropMenuMessage.observeAsState() message?.let { scaffoldModel.update(message = message, actionLabel = "刷新") val s by scaffoldModel.data.observeAsState() if (s == null) { model.update(message = null) } LaunchedEffect(message) { delay(it.length * 300L) model.update(message = null) } } val applyAssociationResultVo by model.applyAssociationResultVo.observeAsState() applyAssociationResultVo?.let { when { it.result == true && it.hasPaper == true -> scaffoldModel.update( message = "申请此社团需要完成一份笔试题,点击确认获取试卷", actionLabel = "确认" ) { examResult.launch( Intent( this@AssociationActivity, ExamActivity::class.java ).apply { putExtra(AssociationActivity::class.java.name, associationId) putExtra( ExamActivityType::name.name, ExamActivityType.JOIN_Association ) }) } it.result == true -> scaffoldModel.update( message = "入团申请发送成功,请耐心等待审核结果", actionLabel = "收到" ) it.associationVo != null -> scaffoldModel.update( message = "您已申请进入${it.associationVo?.name},请耐心等待审核结果", actionLabel = "收到" ) else -> scaffoldModel.update( message = "入团申请发送失败!", actionLabel = "确认" ) } model.update(applyAssociationResultVo = null) } } /** * 社团成员 * */ @Composable private fun Member() { MainColumnFrame(background = { Background(image = BackgroundImage.AssociationMain) }) { val searchWeight = 0.2F Search( modifier = Modifier .fillMaxWidth() .weight(searchWeight) ) MemberList( modifier = Modifier .fillMaxWidth() .weight(1 - searchWeight) ) } } /** * 检索成员 * */ @Composable private fun Search( modifier: Modifier = Modifier, model: MemberViewModel = viewModel() ) { Column(modifier = modifier.fillMaxSize()) { Spacer(modifier = Modifier.weight(0.5F)) Row( modifier = Modifier .fillMaxWidth() .weight(0.5F), verticalAlignment = Alignment.CenterVertically ) { val textFieldWeight = 0.4F val buttonWeight = 0.2F val spaceWeight = (1 - textFieldWeight - buttonWeight) / 3 Spacer(modifier = Modifier.weight((spaceWeight))) BaseTextField( modifier = Modifier.weight(textFieldWeight), form = model.name, singeLine = true ) Spacer(modifier = Modifier.weight(spaceWeight)) OutlinedButton( onClick = { model.load(associationId) }, modifier = Modifier.weight(buttonWeight) ) { Text(text = stringResource(id = R.string.search_btn)) } Spacer(modifier = Modifier.weight(spaceWeight)) } } } /** * 成员列表 * */ @Composable private fun MemberList( modifier: Modifier = Modifier, model: MemberViewModel = viewModel() ) { model.load(associationId) val data by model.data.observeAsState() val listState = rememberLazyListState() LazyColumn( state = listState, modifier = modifier, verticalArrangement = Arrangement.spacedBy(space = 10.dp, alignment = Alignment.CenterVertically) ) { data?.forEach { item { Profile(modifier = Modifier.height(300.dp), personInfoVo = it, readOnly = true) } } } } /** * 社团主页 * */ @Composable private fun Main(model: AssociationViewModel = viewModel()) { LaunchedEffect(associationId) { model.load(associationId) } MainColumnFrame(background = { Background(image = BackgroundImage.AssociationMain, alpha = 0.7F) }) { val nameW = 0.1F val cardW = 0.66F * 0.4F Name( modifier = Modifier .fillMaxWidth() .weight(nameW) ) val associationVo by model.associationVo.observeAsState() associationVo?.associationVo?.desc?.let { DescCard( modifier = Modifier .weight(cardW) .fillMaxWidth(), content = it ) } Commander( modifier = Modifier.weight(cardW) ) Showcase(modifier = Modifier.weight(1F - nameW - cardW - cardW)) } } /** * 社团名字 * * @param modifier */ @Composable private fun Name(modifier: Modifier, model: AssociationViewModel = viewModel()) { val associationVo by model.associationVo.observeAsState() Box(modifier = modifier) { Image( painter = painterResource(id = R.drawable.association_name_border), contentDescription = null, contentScale = ContentScale.FillBounds, modifier = Modifier.fillMaxSize() ) Column { Spacer(modifier = Modifier.weight(1.7F / 3)) Row( modifier = Modifier .fillMaxWidth() .weight(1F / 3), horizontalArrangement = Arrangement.Center ) { associationVo?.associationVo?.name?.let { Text(text = it) } } Spacer(modifier = Modifier.weight(0.3F / 3)) } } } /** * 团长名字 * * @param modifier */ @Composable private fun Commander(modifier: Modifier, model: AssociationViewModel = viewModel()) { Box(modifier = modifier, contentAlignment = Alignment.Center) { Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) { Image( painter = painterResource(id = R.drawable.persion_name_border), contentDescription = null ) } val info by model.associationVo.observeAsState() info?.head?.let { Text(text = it.name) } } } /** * 风采展示区 * * @param modifier */ @Composable private fun Showcase(modifier: Modifier) { Box(modifier = modifier, contentAlignment = Alignment.Center) { Image( painter = painterResource(id = R.drawable.showcase_border), contentDescription = null, modifier = Modifier.fillMaxSize() ) Image( painter = painterResource(id = R.drawable.ic_launcher_foreground), contentDescription = null ) } } /** * 活动列表 * */ @Composable private fun AssociationList() { MainColumnFrame(background = { Background( image = BackgroundImage.AssociationMain, alpha = 07F ) }) { HistoryActivityList( modifier = Modifier .fillMaxWidth() .border(width = 1.dp, color = MaterialTheme.colors.onBackground) ) } } /** * 进行中的活动 * */ @Composable private fun OngoingActivity( modifier: Modifier = Modifier ) { Row(modifier = modifier, horizontalArrangement = Arrangement.Center) { val weight = 0.5F val spaceWeight = (1 - 0.5F) / 2 Spacer(modifier = Modifier.weight(spaceWeight)) Poster(modifier = Modifier.weight(weight)) Spacer(modifier = Modifier.weight(spaceWeight)) } } /** * 历史活动列表 * * @param modifier */ @Composable private fun HistoryActivityList( modifier: Modifier, model: HistoryActViewModel = viewModel() ) { LaunchedEffect(associationId) { model.load(associationId = associationId) } val list by model.data.observeAsState() if (list?.size == 0) { Row(modifier = Modifier.fillMaxWidth()) { Text(text = "目前社团没有任何活动") } } else { Activities(list = list, modifier = modifier) } } @Preview @Composable fun NamePreview() { Divider(color = MaterialTheme.colors.background) } }