Skip to content

Commit

Permalink
Merge pull request #364 from Nexters/feature/Boolti-339
Browse files Browse the repository at this point in the history
Boolti-339 프로필 편집 - 링크, SNS 목록 순서 변경
  • Loading branch information
mangbaam authored Jan 12, 2025
2 parents 68259ac + 66093b6 commit 5e41055
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 31 deletions.
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ timber = "5.0.1"
mockk = "1.13.8"
tosspayments = "0.1.15"
immutable = "0.3.7"
reorderable = "0.9.6"

[libraries]
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activity-ktx" }
Expand Down Expand Up @@ -115,6 +116,7 @@ retrofit2-kotlinx-serialization-converter = { module = "com.jakewharton.retrofit
timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" }
mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" }
immutable = { group = "org.jetbrains.kotlinx", name = "kotlinx-collections-immutable", version.ref = "immutable" }
reorderable = { group = "org.burnoutcrew.composereorderable", name = "reorderable", version.ref = "reorderable" }

[plugins]
android-application = { id = "com.android.application", version.ref = "android" }
Expand Down
1 change: 1 addition & 0 deletions presentation/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ dependencies {

implementation(libs.timber)
implementation(libs.zxing.android.embedded)
implementation(libs.reorderable)

androidTestImplementation(libs.bundles.android.test)
androidTestImplementation(platform(libs.andoridx.compose.compose.bom))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.text.KeyboardOptions
Expand Down Expand Up @@ -72,6 +75,11 @@ import com.nexters.boolti.presentation.util.ObserveAsEvents
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.Flow
import org.burnoutcrew.reorderable.ReorderableItem
import org.burnoutcrew.reorderable.ReorderableState
import org.burnoutcrew.reorderable.detectReorder
import org.burnoutcrew.reorderable.rememberReorderableLazyListState
import org.burnoutcrew.reorderable.reorderable
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
Expand Down Expand Up @@ -147,6 +155,8 @@ fun ProfileEditScreen(
onClickAddLink = { navigateToLinkEdit(null) },
onClickEditSns = { sns -> navigateToSnsEdit(sns) },
onClickEditLink = { link -> navigateToLinkEdit(link) },
onReorderSns = viewModel::reorderSns,
onReorderLink = viewModel::reorderLink,
)
}

Expand All @@ -170,6 +180,8 @@ fun ProfileEditScreen(
onClickAddLink: () -> Unit,
onClickEditSns: (Sns) -> Unit,
onClickEditLink: (Link) -> Unit,
onReorderSns: (from: Int, to: Int) -> Unit,
onReorderLink: (from: Int, to: Int) -> Unit,
) {
val scrollState = rememberScrollState()
val snackbarHostState = LocalSnackbarController.current
Expand Down Expand Up @@ -334,43 +346,91 @@ fun ProfileEditScreen(
)
}

val snsReorderState = rememberReorderableLazyListState(
onMove = { from, to ->
onReorderSns(from.index - 1, to.index - 1)
},
)
Section(
modifier = Modifier.padding(top = 12.dp),
title = stringResource(R.string.profile_edit_sns_title),
) {
Column {
LinkAddButton(
modifier = Modifier.padding(top = 4.dp),
label = stringResource(R.string.sns_add),
onClick = onClickAddSns,
enabled = !saving,
)
snsList.forEach { sns ->
SnsItem(
modifier = Modifier.padding(top = 12.dp),
sns = sns,
) { if (!saving) onClickEditSns(sns) }
LazyColumn(
state = snsReorderState.listState,
modifier = Modifier
.heightIn(max = 100.dp * (snsList.size + 1)) // 대충 넉넉하게 잡은 높이
.reorderable(snsReorderState),
) {
item(
contentType = "SnsAddButton",
) {
LinkAddButton(
modifier = Modifier.padding(top = 4.dp),
label = stringResource(R.string.sns_add),
onClick = onClickAddSns,
enabled = !saving,
)
}
items(
items = snsList,
key = { it.id },
contentType = { "SnsItem" },
) { sns ->
ReorderableItem(
state = snsReorderState,
key = sns.id,
) {
SnsItem(
modifier = Modifier.padding(top = 12.dp),
sns = sns,
reorderableState = snsReorderState,
) { if (!saving) onClickEditSns(sns) }
}
}
}
}

val linkReorderState = rememberReorderableLazyListState(
onMove = { from, to ->
onReorderLink(from.index - 1, to.index - 1)
},
)
Section(
modifier = Modifier.padding(top = 12.dp),
title = stringResource(R.string.label_links),
) {
Column {
LinkAddButton(
modifier = Modifier.padding(top = 4.dp),
label = stringResource(R.string.link_add_btn),
onClick = onClickAddLink,
enabled = !saving,
)
links.forEach { link ->
LinkItem(
modifier = Modifier.padding(top = 12.dp),
title = link.name,
url = link.url,
) { if (!saving) onClickEditLink(link) }
LazyColumn(
state = linkReorderState.listState,
modifier = Modifier
.heightIn(max = 100.dp * (links.size + 1)) // 대충 넉넉하게 잡은 높이
.reorderable(linkReorderState),
) {
item(
contentType = "LinkAddButton",
) {
LinkAddButton(
modifier = Modifier.padding(top = 4.dp),
label = stringResource(R.string.link_add_btn),
onClick = onClickAddLink,
enabled = !saving,
)
}
items(
items = links,
key = { it.id },
contentType = { "LinkItem" },
) { link ->
ReorderableItem(
state = linkReorderState,
key = link.id,
) {
LinkItem(
modifier = Modifier.padding(top = 12.dp),
title = link.name,
url = link.url,
reorderableState = linkReorderState,
) { if (!saving) onClickEditLink(link) }
}
}
}
}
Expand Down Expand Up @@ -454,6 +514,7 @@ private fun LinkAddButton(
private fun SnsItem(
sns: Sns,
modifier: Modifier = Modifier,
reorderableState: ReorderableState<*>,
onClickEdit: () -> Unit,
) {
Row(
Expand Down Expand Up @@ -488,10 +549,13 @@ private fun SnsItem(
color = Grey15,
)
Icon(
modifier = Modifier.size(20.dp),
imageVector = ImageVector.vectorResource(R.drawable.ic_edit_pen),
modifier = Modifier
.padding(start = 20.dp)
.size(20.dp)
.detectReorder(reorderableState),
imageVector = ImageVector.vectorResource(R.drawable.ic_reordable_handle),
tint = Grey50,
contentDescription = stringResource(R.string.link_edit),
contentDescription = stringResource(R.string.sns_reorder_description),
)
}
}
Expand All @@ -500,6 +564,7 @@ private fun SnsItem(
private fun LinkItem(
title: String,
url: String,
reorderableState: ReorderableState<*>,
modifier: Modifier = Modifier,
onClickEdit: () -> Unit,
) {
Expand Down Expand Up @@ -533,10 +598,11 @@ private fun LinkItem(
Icon(
modifier = Modifier
.padding(start = 20.dp)
.size(20.dp),
imageVector = ImageVector.vectorResource(R.drawable.ic_edit_pen),
.size(20.dp)
.detectReorder(reorderableState),
imageVector = ImageVector.vectorResource(R.drawable.ic_reordable_handle),
tint = Grey50,
contentDescription = stringResource(R.string.link_edit),
contentDescription = stringResource(R.string.link_reorder_description),
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,28 @@ class ProfileEditViewModel @Inject constructor(
event(ProfileEditEvent.OnSnsRemoved)
}

fun reorderSns(from: Int, to: Int) {
val snsList = uiState.value.snsList.toMutableList()
if (from !in snsList.indices || to !in snsList.indices) return

_uiState.update {
it.copy(
snsList = snsList.apply { add(to, removeAt(from)) },
)
}
}

fun reorderLink(from: Int, to: Int) {
val links = uiState.value.links.toMutableList()
if (from !in links.indices || to !in links.indices) return

_uiState.update {
it.copy(
links = links.apply { add(to, removeAt(from)) },
)
}
}

fun completeEdits(thumbnailFile: File?) {
viewModelScope.launch(recordExceptionHandler) {
_uiState.update { it.copy(saving = true) }
Expand Down
27 changes: 27 additions & 0 deletions presentation/src/main/res/drawable/ic_reordable_handle.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M4,12H20"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#434753"
android:strokeLineCap="round"/>
<path
android:pathData="M4,6H20"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#434753"
android:strokeLineCap="round"/>
<path
android:pathData="M4,18H20"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#434753"
android:strokeLineCap="round"/>
</vector>
2 changes: 2 additions & 0 deletions presentation/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@
<string name="sns_add_msg">SNS를 추가했어요</string>
<string name="sns_edit_msg">SNS를 편집했어요</string>
<string name="sns_remove_msg">SNS를 삭제했어요</string>
<string name="sns_reorder_description">SNS 순서 변경</string>
<string name="sns_username_placeholder">ex) boolti_official</string>
<string name="sns_username_contains_at_error">\@을 제외한 Username을 입력해 주세요</string>
<string name="contains_unsupported_char_error">지원하지 않는 특수문자가 포함되어 있습니다</string>
Expand All @@ -310,6 +311,7 @@
<string name="link_add_btn">링크 추가</string>
<string name="link_add">링크 추가</string>
<string name="link_edit">링크 편집</string>
<string name="link_reorder_description">링크 순서 변경</string>
<string name="link_remove">링크 삭제</string>
<string name="link_name">링크 이름</string>
<string name="link_url">URL</string>
Expand Down

0 comments on commit 5e41055

Please sign in to comment.