Skip to content

daily-edit 모듈을 현재는 일과수정으로만 사용하는데 일과추가로도 사용할 수 있게 확장하기  #164

@theBettor

Description

@theBettor

일과는 총 3가지의 모듈을 사용한다.

  1. daily화면
  2. daily-expand화면 : 상단의 icon을 통해 접근
  3. 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()
        }
    }
}

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status

No status

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions