-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Milestone
Description
일과는 총 3가지의 모듈을 사용한다.
- daily화면
- daily-expand화면 : 상단의 icon을 통해 접근
- dialy-edit화면 : fab를 통해 접근
Q1. 현재는 fab를 통해 일과를 추가하려는 기능만 사용하려고 한다.(의도대로 구현이 마무리 되었는지는 모르겠음) -> viewModel에 일과를 추가생성하는 코드가 필요하겠다.
Q2. 그런데 위의 3번에서 fab를 통한 접근 뿐만 아니라, ExpandScreen에서도 동일한 모듈(동일한 layout)을 사용하여 일과를 추가하는 것이 아닌 일과를 수정할 수 있게 하고싶다.
Q3. 당연히 Expand는 뷰모델을 통해 선택한 일과에 대한 정보를 보여주고 있을 것이며, ExpandScreen에서 파라미터로 daily-edit모듈을 요청할 때, 기존의 정보를 수정하는 것이니 뷰모델을 통해 해당 일과에 대한 정보를 daily-edit로 보내줘야 할 것이다.
Q4. 이러한 접근이 모듈을 재사용하는 것이 맞는지, 유지보수 측면에서 좋은 방법인지 궁금하다.
- 참고 : composable 함수에 인자를 전달해서 수정, 추가 Mode 값에 따라 화면을 보여주면 될 것 같은데요? 라는 피드백을 받은 적이 있다.
일단은 참고로 daily화면 먼저 완성하는게 좋을테니 코드를 첨부해본다.
@Composable
internal fun DailyRoute(
dailyExpandPageRequest: () -> Unit,
dailyEditPageRequest: () -> Unit,
) {
val context = LocalContext.current
val dailyViewModel: DailyViewModel = hiltViewModel()
val uiState by dailyViewModel.dailyUiState
if (!uiState.isLoading) {
DailyScreen(
progress = 0f,
onDailyRoutineClick = {},
onDailyRoutineCheckChanged = { _, _ -> },
dailyRoutine = uiState.daily.collectAsLazyPagingItems(),
dailyExpandPageRequest = dailyExpandPageRequest,
dailyEditPageRequest = dailyEditPageRequest,
uiState = uiState
)
}
LaunchedEffect(Unit) {
dailyViewModel.sideEffect.collect { sideEffect ->
when (sideEffect) {
is DailySideEffect.LoadError -> {
Toast.makeText(context, "데이터를 불러오지 못하였습니다.", Toast.LENGTH_SHORT).show()
}
}
}
}
}
@Composable
internal fun DailyScreen(
// TODO: Route
progress: Float, // 진행률 (0f부터 1f까지의 값)
onDailyRoutineClick: (String) -> Unit, // id
onDailyRoutineCheckChanged: (String, Boolean) -> Unit, // id, checked
dailyRoutine: LazyPagingItems<CheckableData<Todo>>,
dailyExpandPageRequest: () -> Unit,
dailyEditPageRequest: () -> Unit,
uiState: DailyUiState,
) {
Scaffold(
topBar = {
AppBar(
navigation = {
Text(
text = buildAnnotatedString {
withStyle(style = SpanStyle(color = BL)) {
append(stringArrayResource(id = R.array.text_title_appbar)[0])
}
withStyle(style = SpanStyle(color = MainGreen)) {
append(stringArrayResource(id = R.array.text_title_appbar)[1])
}
},
fontFamily = PretendardFontFamily,
fontWeight = FontWeight.Bold,
fontSize = 22.sp
)
},
actions = {
Image(
painter = painterResource(ic_edit),
contentDescription = "edit",
modifier = Modifier
.padding(end = 21.dp)
.clickable { dailyExpandPageRequest() }
)
},
modifier = Modifier
.padding(horizontal = 20.dp)
)
},
floatingActionButton = {
FloatingActionButton(
onClick = { dailyEditPageRequest() },
containerColor = MainGreen,
shape = CircleShape,
contentColor = Color.White,
modifier = Modifier.padding(bottom = 12.dp, end = 12.dp)
) {
Icon(
imageVector = Icons.Default.Add,
contentDescription = "일과 추가"
)
}
}
) { scaffoldPaddingValues ->
LazyColumn(
verticalArrangement = Arrangement.spacedBy(1.dp),
modifier = Modifier
.fillMaxWidth()
.padding(scaffoldPaddingValues)
) {
item {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 20.dp, vertical = 17.dp) // 패딩 조정
) {
Text(
text = "완료된 일과에 응원의 한 마디를 남겨요!",
fontFamily = PretendardFontFamily,
fontWeight = FontWeight.Medium,
fontSize = 18.sp,
color = G5,
modifier = Modifier.fillMaxWidth() // 가로 너비 최대 설정
)
Spacer(modifier = Modifier.height(4.dp)) // 간격 추가
Text(
text = "33% 완료",
fontFamily = PretendardFontFamily,
fontWeight = FontWeight.Bold,
fontSize = 24.sp,
color = MainGreen,
modifier = Modifier.fillMaxWidth()
)
Box(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 20.dp)
.height(8.dp)
.clip(RoundedCornerShape(4.dp))
.background(Color.LightGray) // 배경 색상
) {
LinearProgressIndicator(
progress = { progress },
modifier = Modifier
.fillMaxWidth()
.height(8.dp)
.clip(RoundedCornerShape(4.dp)),
color = Color(0xFF4CAF50) // 프로그레스 바 색상
)
}
}
}
items(dailyRoutine.itemCount) { index ->
val lastDateTime =
if (index > 0) dailyRoutine.peek(index - 1)?.data?.dateTime else null
val dateTime = dailyRoutine.peek(index)?.data?.dateTime
val title = dailyRoutine[index]?.data?.title
DailyRoutineCard(
onCheckedChange = {
val data = dailyRoutine[index]?.data ?: return@DailyRoutineCard
dailyRoutine.itemSnapshotList.items[index].checked.value = it
onDailyRoutineCheckChanged(data.id, it)
},
checked = dailyRoutine[index]?.checked?.value ?: false,
dateTime = dateTime?.stringHour() ?: "",
text = title ?: "",
modifier = Modifier
.padding(horizontal = 24.dp)
.noRippleClickable {
val data = dailyRoutine[index]?.data ?: return@noRippleClickable
onDailyRoutineClick(data.id)
}
)
}
if (dailyRoutine.itemCount != 0) {
item {
Box(modifier = Modifier.height(20.dp))
}
}
}
}
}@HiltViewModel
internal class DailyViewModel @Inject constructor(
private val getUserInfoUseCase: GetUserInfoUseCase,
private val getDailyRoutineUseCase: GetDailyRoutineUseCase,
) : ViewModel() {
var dailyUiState = mutableStateOf(DailyUiState())
private set
private val _sideEffect = Channel<DailySideEffect>()
val sideEffect = _sideEffect.receiveAsFlow()
init {
load()
}
private fun load() = viewModelScope.launch {
try {
val user = getUserInfoUseCase().first()
val todo = getDailyRoutineUseCase().map { pagingData ->
pagingData.map {
CheckableData(it, mutableStateOf(it.isFinished))
}
}
dailyUiState.value = DailyUiState(user = user, daily = todo, isLoading = false)
} catch (e: Exception) {
_sideEffect.send(DailySideEffect.LoadError(e))
e.printStackTrace()
}
}
}Reactions are currently unavailable