Skip to content

Commit

Permalink
[Feature] 관계 수정 & 등록 구체화 (#62)
Browse files Browse the repository at this point in the history
* [Refactor]: 관계 등록 기능 구조 변경 -> 등록 + 수정

* [Feat]: relation 모델 구현

* [Feat]: destination 연걸, edit,add 구분

* [Feat]: Relation usecase 기능 추가

* [Fix]: Textfield focus 밖으로 빼기

* [Fix]: Textfield focus 수정

* [Fix]: Snackbar ui 수정

* [Feat]: 관게 등록 & 수정 구체화

* [Chore]: 코드 포맷 변경
  • Loading branch information
jinuemong authored Feb 9, 2024
1 parent 0994f05 commit ee5fa79
Show file tree
Hide file tree
Showing 21 changed files with 1,227 additions and 554 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ package ac.dnd.bookkeeping.android.domain.usecase.feature.relation

import ac.dnd.bookkeeping.android.domain.model.feature.relation.KakaoFriendInfo
import ac.dnd.bookkeeping.android.domain.repository.KakaoFriendRepository
import javax.inject.Inject

class GetKakaoFriendInfoUseCase(
class GetKakaoFriendInfoUseCase @Inject constructor(
private val kakaoFriendRepository: KakaoFriendRepository
) {
suspend operator fun invoke(): Result<KakaoFriendInfo> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package ac.dnd.bookkeeping.android.presentation.common.view

import ac.dnd.bookkeeping.android.presentation.common.theme.Body1
import ac.dnd.bookkeeping.android.presentation.common.theme.Gray100
import ac.dnd.bookkeeping.android.presentation.common.theme.Gray800
import ac.dnd.bookkeeping.android.presentation.common.theme.Shapes
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

@Composable
fun SnackBarScreen(message: String) {
Expand All @@ -19,15 +21,22 @@ fun SnackBarScreen(message: String) {
.padding(20.dp)
.fillMaxWidth()
.background(
shape = RoundedCornerShape(10.dp),
color = Color.LightGray
shape = Shapes.medium,
color = Gray800
),
) {
Text(
text = message,
fontSize = 20.sp,
color = Color.White,
modifier = Modifier.padding(20.dp),
style = Body1.merge(
color = Gray100,
fontWeight = FontWeight.Normal
),
modifier = Modifier
.padding(
start = 16.dp,
end = 8.dp
)
.padding(vertical = 14.dp)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ fun TypingTextField(
hintText: String = "",
isError: Boolean = false,
isEnabled: Boolean = true,
isSingleLine: Boolean = true,
maxTextLength: Int = 100,
keyboardOptions: KeyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
visualTransformation: VisualTransformation = VisualTransformation.None,
Expand All @@ -71,15 +72,11 @@ fun TypingTextField(
leadingIconContent: (@Composable () -> Unit)? = null,
trailingIconContent: (@Composable () -> Unit)? = null,
errorMessageContent: (@Composable () -> Unit) = { },
onTextFieldFocusChange : (Boolean) -> Unit = {}
) {
val interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
var isTextFieldFocused by remember { mutableStateOf(false) }

val isSingleLine = when (textType) {
TypingTextFieldType.Basic -> true
TypingTextFieldType.LongSentence -> false
}

val currentColor =
if (isError) Negative else if (isTextFieldFocused) Primary3 else basicBorderColor
val currentColorState = animateColorAsState(
Expand All @@ -102,6 +99,7 @@ fun TypingTextField(
.wrapContentHeight()
.onFocusChanged {
isTextFieldFocused = it.isFocused
onTextFieldFocusChange(it.isFocused)
}
) {
BasicTextField(
Expand All @@ -116,20 +114,17 @@ fun TypingTextField(
textStyle = Body1.merge(
color = Gray800
),
singleLine = isSingleLine,
singleLine = if (textType == TypingTextFieldType.LongSentence) false else isSingleLine,
minLines = if (isSingleLine) 1 else 3,
keyboardOptions = keyboardOptions,
keyboardActions = KeyboardActions(

),
cursorBrush = SolidColor(value = currentColorState.value),
interactionSource = interactionSource,
) { textField ->
TextFieldDefaults.TextFieldDecorationBox(
value = text,
innerTextField = textField,
enabled = isEnabled,
singleLine = isSingleLine,
singleLine = if (textType == TypingTextFieldType.LongSentence) false else isSingleLine,
visualTransformation = visualTransformation,
interactionSource = interactionSource,
placeholder = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package ac.dnd.bookkeeping.android.presentation.model.relation

import ac.dnd.bookkeeping.android.domain.model.feature.relation.RelationDetailGroup
import ac.dnd.bookkeeping.android.domain.model.feature.relation.RelationDetailWithUserInfo
import android.os.Parcelable
import kotlinx.parcelize.Parcelize

@Parcelize
data class RelationDetailWithUserInfoModel(
val id: Long,
val name: String,
val imageUrl: String,
val memo: String,
val group: RelationDetailGroupModel,
val giveMoney: Long,
val takeMoney: Long
) : Parcelable

fun RelationDetailWithUserInfo.toUiModel(): RelationDetailWithUserInfoModel {
return RelationDetailWithUserInfoModel(
id = id,
name = name,
imageUrl = imageUrl,
memo = memo,
group = group.toUiModel(),
giveMoney = giveMoney,
takeMoney = takeMoney
)
}

@Parcelize
data class RelationDetailGroupModel(
val id: Long,
val name: String
) : Parcelable

fun RelationDetailGroup.toUiModel(): RelationDetailGroupModel {
return RelationDetailGroupModel(
id = id,
name = name
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package ac.dnd.bookkeeping.android.presentation.model.relation

enum class RelationType {
EDIT,
ADD
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package ac.dnd.bookkeeping.android.presentation.ui.main.home.common.relation.add
package ac.dnd.bookkeeping.android.presentation.ui.main.home.common.relation

object AddRelationConstant {
object RelationConstant {
const val ROUTE: String = "/addName"

const val ROUTE_ARGUMENT_MODEL = "relation"
const val CONTAIN_RELATION = "${ROUTE}/{${ROUTE_ARGUMENT_MODEL}}"
const val CONTAIN_RELATION = "$ROUTE/{$ROUTE_ARGUMENT_MODEL}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package ac.dnd.bookkeeping.android.presentation.ui.main.home.common.relation

import ac.dnd.bookkeeping.android.presentation.common.util.ErrorObserver
import ac.dnd.bookkeeping.android.presentation.model.relation.RelationDetailGroupModel
import ac.dnd.bookkeeping.android.presentation.model.relation.RelationDetailWithUserInfoModel
import ac.dnd.bookkeeping.android.presentation.model.relation.RelationType
import ac.dnd.bookkeeping.android.presentation.ui.main.ApplicationState
import androidx.compose.runtime.getValue
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable

fun NavGraphBuilder.RelationDestination(
appState: ApplicationState
) {
val defaultModel = RelationDetailWithUserInfoModel(
id = 0L,
name = "",
imageUrl = "",
memo = "",
group = RelationDetailGroupModel(
id = -1L,
name = ""
),
giveMoney = 0L,
takeMoney = 0L
)

composable(
route = RelationConstant.ROUTE
) {
val viewModel: RelationViewModel = hiltViewModel()

val model: RelationModel = let {
val state by viewModel.state.collectAsStateWithLifecycle()
val groups by viewModel.groups.collectAsStateWithLifecycle()

RelationModel(
state = state,
groups = groups,
relationDetail = defaultModel
)
}

ErrorObserver(viewModel)

RelationScreen(
relationType = RelationType.ADD,
appState = appState,
model = model,
event = viewModel.event,
intent = viewModel::onIntent,
handler = viewModel.handler
)
}

composable(
route = RelationConstant.CONTAIN_RELATION
) {
val relationModel = appState.navController.previousBackStackEntry
?.savedStateHandle
?.get<RelationDetailWithUserInfoModel>(RelationConstant.ROUTE_ARGUMENT_MODEL)
?: defaultModel

if (relationModel.id == -1L) {
appState.navController.popBackStack()
}

val viewModel: RelationViewModel = hiltViewModel()
val model: RelationModel = let {
val state by viewModel.state.collectAsStateWithLifecycle()
val groups by viewModel.groups.collectAsStateWithLifecycle()

RelationModel(
state = state,
groups = groups,
relationDetail = relationModel
)
}

ErrorObserver(viewModel)

RelationScreen(
relationType = RelationType.EDIT,
appState = appState,
model = model,
event = viewModel.event,
intent = viewModel::onIntent,
handler = viewModel.handler
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package ac.dnd.bookkeeping.android.presentation.ui.main.home.common.relation

sealed interface RelationEvent {
sealed interface AddRelation : RelationEvent {
data object Success : AddRelation
}

sealed interface EditRelation : RelationEvent {
data object Success : EditRelation
}

sealed interface DeleteRelation : RelationEvent {
data object Success : DeleteRelation
}

sealed interface LoadKakaoFriend : RelationEvent {
data class Success(
val name: String,
val imageUrl: String
) : LoadKakaoFriend
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ac.dnd.bookkeeping.android.presentation.ui.main.home.common.relation

sealed interface RelationIntent {
data class OnClickAdd(
val groupId: Long,
val name: String,
val imageUrl: String,
val memo: String
) : RelationIntent

data class OnClickEdit(
val id: Long,
val groupId: Long,
val name: String,
val imageUrl: String,
val memo: String
) : RelationIntent

data class OnClickDelete(
val id: Long
) : RelationIntent

data object OnClickLoadFriend : RelationIntent
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package ac.dnd.bookkeeping.android.presentation.ui.main.home.common.relation

import ac.dnd.bookkeeping.android.domain.model.feature.group.Group
import ac.dnd.bookkeeping.android.presentation.model.relation.RelationDetailWithUserInfoModel
import androidx.compose.runtime.Immutable

@Immutable
data class RelationModel(
val state: RelationState,
val relationDetail: RelationDetailWithUserInfoModel,
val groups: List<Group>
)
Loading

0 comments on commit ee5fa79

Please sign in to comment.