-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature] #13 포킷 추가 화면 구현 #15
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
5f751e5
[BASE] #13 feature:addpokit 모듈 생성
l5x5l fb3e800
[BASE] #13 이미지 선택부분을 제외한 포킷 추가 화면 구현
l5x5l 29d281f
[FEATURE] #13 포킷 프로필 선택부분 구현
l5x5l 318788b
[CHORE] #13 ktlint 적용
l5x5l 06578b7
[CHORE] #13 포킷 이름 최대 글자수 상수로 분리
l5x5l 8a2b365
[CHORE] #13 core 모듈 resource를 사용하는 부분을 alias import로 변경
l5x5l File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
plugins { | ||
alias(libs.plugins.com.android.library) | ||
alias(libs.plugins.org.jetbrains.kotlin.android) | ||
} | ||
|
||
android { | ||
namespace = "com.strayalpaca.addpokit" | ||
compileSdk = 34 | ||
|
||
defaultConfig { | ||
minSdk = 24 | ||
|
||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" | ||
consumerProguardFiles("consumer-rules.pro") | ||
} | ||
|
||
buildTypes { | ||
release { | ||
isMinifyEnabled = false | ||
proguardFiles( | ||
getDefaultProguardFile("proguard-android-optimize.txt"), | ||
"proguard-rules.pro" | ||
) | ||
} | ||
} | ||
buildFeatures { | ||
compose = true | ||
} | ||
composeOptions { | ||
kotlinCompilerExtensionVersion = "1.5.1" | ||
} | ||
compileOptions { | ||
sourceCompatibility = JavaVersion.VERSION_1_8 | ||
targetCompatibility = JavaVersion.VERSION_1_8 | ||
} | ||
kotlinOptions { | ||
jvmTarget = "1.8" | ||
} | ||
} | ||
|
||
dependencies { | ||
|
||
implementation(libs.androidx.core.ktx) | ||
implementation(libs.androidx.lifecycle.runtime.ktx) | ||
implementation(libs.androidx.activity.compose) | ||
implementation(platform(libs.androidx.compose.bom)) | ||
implementation(libs.androidx.ui) | ||
implementation(libs.androidx.ui.graphics) | ||
implementation(libs.androidx.ui.tooling.preview) | ||
implementation(libs.androidx.material3) | ||
testImplementation(libs.junit) | ||
androidTestImplementation(libs.androidx.junit) | ||
androidTestImplementation(libs.androidx.espresso.core) | ||
androidTestImplementation(platform(libs.androidx.compose.bom)) | ||
androidTestImplementation(libs.androidx.ui.test.junit4) | ||
debugImplementation(libs.androidx.ui.tooling) | ||
debugImplementation(libs.androidx.ui.test.manifest) | ||
|
||
implementation(libs.orbit.compose) | ||
implementation(libs.orbit.core) | ||
implementation(libs.orbit.viewmodel) | ||
|
||
implementation(project(":core:ui")) | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Add project specific ProGuard rules here. | ||
# You can control the set of applied configuration files using the | ||
# proguardFiles setting in build.gradle. | ||
# | ||
# For more details, see | ||
# http://developer.android.com/guide/developing/tools/proguard.html | ||
|
||
# If your project uses WebView with JS, uncomment the following | ||
# and specify the fully qualified class name to the JavaScript interface | ||
# class: | ||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
# public *; | ||
#} | ||
|
||
# Uncomment this to preserve the line number information for | ||
# debugging stack traces. | ||
#-keepattributes SourceFile,LineNumberTable | ||
|
||
# If you keep the line number information, uncomment this to | ||
# hide the original source file name. | ||
#-renamesourcefileattribute SourceFile |
22 changes: 22 additions & 0 deletions
22
feature/addpokit/src/androidTest/java/com/strayalpaca/addpokit/ExampleInstrumentedTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.strayalpaca.addpokit | ||
|
||
import androidx.test.ext.junit.runners.AndroidJUnit4 | ||
import androidx.test.platform.app.InstrumentationRegistry | ||
import org.junit.Assert.assertEquals | ||
import org.junit.Test | ||
import org.junit.runner.RunWith | ||
|
||
/** | ||
* Instrumented test, which will execute on an Android device. | ||
* | ||
* See [testing documentation](http://d.android.com/tools/testing). | ||
*/ | ||
@RunWith(AndroidJUnit4::class) | ||
class ExampleInstrumentedTest { | ||
@Test | ||
fun useAppContext() { | ||
// Context of the app under test. | ||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext | ||
assertEquals("com.strayalpaca.addpokit.test", appContext.packageName) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> | ||
|
||
</manifest> |
259 changes: 259 additions & 0 deletions
259
feature/addpokit/src/main/java/com/strayalpaca/addpokit/AddPokitScreen.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,259 @@ | ||
package com.strayalpaca.addpokit | ||
|
||
import androidx.compose.foundation.Image | ||
import androidx.compose.foundation.background | ||
import androidx.compose.foundation.border | ||
import androidx.compose.foundation.clickable | ||
import androidx.compose.foundation.layout.Arrangement | ||
import androidx.compose.foundation.layout.Box | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.Spacer | ||
import androidx.compose.foundation.layout.fillMaxSize | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.foundation.layout.height | ||
import androidx.compose.foundation.layout.offset | ||
import androidx.compose.foundation.layout.padding | ||
import androidx.compose.foundation.layout.size | ||
import androidx.compose.foundation.layout.width | ||
import androidx.compose.foundation.lazy.LazyColumn | ||
import androidx.compose.foundation.lazy.grid.GridCells | ||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid | ||
import androidx.compose.foundation.lazy.grid.items | ||
import androidx.compose.foundation.lazy.items | ||
import androidx.compose.foundation.shape.CircleShape | ||
import androidx.compose.foundation.shape.RoundedCornerShape | ||
import androidx.compose.material3.CircularProgressIndicator | ||
import androidx.compose.material3.Text | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.collectAsState | ||
import androidx.compose.runtime.derivedStateOf | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.runtime.remember | ||
import androidx.compose.ui.Alignment | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.draw.clip | ||
import androidx.compose.ui.graphics.ColorFilter | ||
import androidx.compose.ui.res.painterResource | ||
import androidx.compose.ui.res.stringResource | ||
import androidx.compose.ui.unit.dp | ||
import com.strayalpaca.addpokit.components.atom.PokitProfileImage | ||
import com.strayalpaca.addpokit.components.block.Toolbar | ||
import com.strayalpaca.addpokit.model.AddPokitScreenState | ||
import com.strayalpaca.addpokit.model.AddPokitScreenStep | ||
import com.strayalpaca.addpokit.model.AddPokitSideEffect | ||
import com.strayalpaca.addpokit.model.Pokit | ||
import com.strayalpaca.addpokit.model.PokitProfile | ||
import com.strayalpaca.addpokit.model.samplePokitProfileList | ||
import com.strayalpaca.addpokit.utils.BackPressHandler | ||
import org.orbitmvi.orbit.compose.collectSideEffect | ||
import pokitmons.pokit.core.ui.components.atom.button.PokitButton | ||
import pokitmons.pokit.core.ui.components.atom.button.attributes.PokitButtonSize | ||
import pokitmons.pokit.core.ui.components.block.labeledinput.LabeledInput | ||
import pokitmons.pokit.core.ui.components.block.pokitlist.PokitList | ||
import pokitmons.pokit.core.ui.components.block.pokitlist.attributes.PokitListState | ||
import pokitmons.pokit.core.ui.components.template.bottomsheet.PokitBottomSheet | ||
import pokitmons.pokit.core.ui.theme.PokitTheme | ||
import pokitmons.pokit.core.ui.R.drawable as coreDrawable | ||
import pokitmons.pokit.core.ui.R.string as coreString | ||
|
||
@Composable | ||
fun AddPokitScreenContainer( | ||
viewModel: AddPokitViewModel, | ||
onBackPressed: () -> Unit, | ||
) { | ||
val state by viewModel.container.stateFlow.collectAsState() | ||
val pokitName by viewModel.pokitName.collectAsState() | ||
|
||
val saveButtonEnable = remember { | ||
derivedStateOf { | ||
state.step != AddPokitScreenStep.POKIT_SAVE_LOADING && | ||
state.step != AddPokitScreenStep.POKIT_LIST_LOADING && | ||
state.pokitInputErrorMessage == null && | ||
state.pokitProfile != null | ||
} | ||
} | ||
|
||
viewModel.collectSideEffect { sideEffect -> | ||
when (sideEffect) { | ||
AddPokitSideEffect.AddPokitSuccess -> { | ||
onBackPressed() | ||
} | ||
|
||
AddPokitSideEffect.OnNavigationBack -> { | ||
onBackPressed() | ||
} | ||
} | ||
} | ||
|
||
BackPressHandler(onBackPressed = viewModel::onBackPressed) | ||
|
||
AddPokitScreen( | ||
pokitName = pokitName, | ||
state = state, | ||
saveButtonEnable = saveButtonEnable.value, | ||
onclickAddPokit = viewModel::savePokit, | ||
inputPokitName = viewModel::inputPokitName, | ||
onBackPressed = viewModel::onBackPressed, | ||
hideProfileSelectBottomSheet = viewModel::hidePokitProfileSelectBottomSheet, | ||
showSelectProfileBottomSheet = viewModel::showPokitProfileSelectBottomSheet, | ||
selectPokitProfileImage = viewModel::selectPoktiProfile | ||
) | ||
} | ||
|
||
@Composable | ||
fun AddPokitScreen( | ||
pokitName: String = "", | ||
state: AddPokitScreenState = AddPokitScreenState(), | ||
saveButtonEnable: Boolean = true, | ||
onclickAddPokit: () -> Unit = {}, | ||
inputPokitName: (String) -> Unit = {}, | ||
onBackPressed: () -> Unit = {}, | ||
hideProfileSelectBottomSheet: () -> Unit = {}, | ||
showSelectProfileBottomSheet: () -> Unit = {}, | ||
selectPokitProfileImage: (PokitProfile) -> Unit = {}, | ||
) { | ||
Column( | ||
modifier = Modifier | ||
.fillMaxSize() | ||
.padding(vertical = 16.dp), | ||
horizontalAlignment = Alignment.CenterHorizontally | ||
) { | ||
Toolbar( | ||
onClickBack = onBackPressed, | ||
title = stringResource(id = R.string.title_add_pokit) | ||
) | ||
|
||
Box(modifier = Modifier.size(80.dp)) { | ||
Image( | ||
painter = painterResource(id = coreDrawable.icon_24_google), | ||
contentDescription = null, | ||
modifier = Modifier | ||
.size(80.dp) | ||
.clip(shape = RoundedCornerShape(12.dp)) | ||
) | ||
|
||
Box( | ||
modifier = Modifier | ||
.align(Alignment.BottomEnd) | ||
.offset(x = 7.dp, y = (-7).dp) | ||
.size(24.dp) | ||
.background( | ||
color = PokitTheme.colors.inverseWh, | ||
shape = CircleShape | ||
) | ||
.border( | ||
width = 1.dp, | ||
color = PokitTheme.colors.borderSecondary, | ||
shape = CircleShape | ||
) | ||
.clip( | ||
shape = CircleShape | ||
) | ||
.clickable( | ||
onClick = showSelectProfileBottomSheet | ||
) | ||
.padding(3.dp) | ||
) { | ||
Image( | ||
painter = painterResource(id = coreDrawable.icon_24_edit), | ||
contentDescription = "null", | ||
modifier = Modifier | ||
.size(18.dp), | ||
colorFilter = ColorFilter.tint( | ||
color = PokitTheme.colors.iconTertiary | ||
) | ||
) | ||
} | ||
} | ||
|
||
Spacer(modifier = Modifier.height(12.dp)) | ||
|
||
LabeledInput( | ||
modifier = Modifier.padding(horizontal = 20.dp), | ||
label = stringResource(id = R.string.pokit_name), | ||
inputText = pokitName, | ||
hintText = stringResource(id = R.string.placeholder_pokit_name), | ||
onChangeText = inputPokitName, | ||
isError = state.pokitInputErrorMessage != null, | ||
sub = state.pokitInputErrorMessage?.let { stringResource(id = it.resourceId) } ?: "", | ||
enable = (state.step != AddPokitScreenStep.POKIT_SAVE_LOADING), | ||
maxLength = 10 | ||
) | ||
|
||
Spacer(modifier = Modifier.height(28.dp)) | ||
|
||
Text( | ||
modifier = Modifier | ||
.fillMaxWidth() | ||
.padding(horizontal = 20.dp), | ||
text = stringResource(id = R.string.my_pokit), | ||
style = PokitTheme.typography.body2Medium.copy(color = PokitTheme.colors.textSecondary) | ||
) | ||
|
||
Spacer(modifier = Modifier.height(8.dp)) | ||
|
||
Box( | ||
modifier = Modifier | ||
.fillMaxSize() | ||
.weight(1f), | ||
contentAlignment = Alignment.Center | ||
) { | ||
LazyColumn( | ||
modifier = Modifier.fillMaxSize() | ||
) { | ||
items(state.pokitList) { item: Pokit -> | ||
PokitList( | ||
item = item, | ||
title = item.title, | ||
sub = stringResource(id = coreString.pokit_count_format, item.count), | ||
onClickKebab = {}, | ||
onClickItem = {}, | ||
state = PokitListState.DEFAULT | ||
) | ||
} | ||
} | ||
|
||
if (state.step == AddPokitScreenStep.POKIT_LIST_LOADING) { | ||
CircularProgressIndicator( | ||
modifier = Modifier.width(64.dp), | ||
color = PokitTheme.colors.brand, | ||
trackColor = PokitTheme.colors.backgroundSecondary | ||
) | ||
} | ||
} | ||
|
||
Box( | ||
modifier = Modifier | ||
.fillMaxWidth() | ||
.padding(horizontal = 20.dp) | ||
) { | ||
PokitButton( | ||
text = stringResource(id = R.string.save), | ||
icon = null, | ||
onClick = onclickAddPokit, | ||
modifier = Modifier.fillMaxWidth(), | ||
size = PokitButtonSize.LARGE, | ||
enable = saveButtonEnable | ||
) | ||
} | ||
|
||
if (state.step == AddPokitScreenStep.SELECT_PROFILE) { | ||
PokitBottomSheet(onHideBottomSheet = hideProfileSelectBottomSheet) { | ||
LazyVerticalGrid( | ||
modifier = Modifier.padding(vertical = 12.dp, horizontal = 40.dp), | ||
columns = GridCells.Adaptive(66.dp), | ||
horizontalArrangement = Arrangement.spacedBy(20.dp), | ||
verticalArrangement = Arrangement.spacedBy(12.dp) | ||
) { | ||
items(samplePokitProfileList) { profileImage -> | ||
PokitProfileImage( | ||
pokitProfile = profileImage, | ||
onClick = selectPokitProfileImage, | ||
focused = (state.pokitProfile?.id == profileImage.id) | ||
) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
함수참조를 사용했을 때 이점이 있나요?.? (몰라서 그럼!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
compose에서 함수참조를 사용할 경우 람다 함수로 넘겨줄 때보다 불필요한 reompocse를 줄일 수 있습니다!
lambda 메서드를 사용하게 되면, 매 recompose 단계마다 람다 함수가 생성되게 되는데, 이 경우 이전 인자로 들어온 람다 함수와는 다른 객체로 인식되게 되어 Recompose가 발생할 수 있는 걸로 알고있어요 (object의 equals시 주소값을 기준으로 비교하므로)
이를 막기 위해서 매번 객체가 생성되는 방식인 lambda 대신, 주소값이 항상 일정한 특정 객체의 함수를 참조하는 방식으로 구현했습니다.
만약 람다 함수가 더 편한 케이스에는 remember를 사용하여 아래와 같이 작성할 수 있습니다!
참고한 블로그입니다!
Gotchas in Jetpack Compose Recomposition