From ea18f9f9358c5ddf6b95e7ff75d8895fe0f0883b Mon Sep 17 00:00:00 2001 From: unam Date: Wed, 3 Jan 2024 05:26:37 +0900 Subject: [PATCH 01/21] =?UTF-8?q?[FEAT/#16]=20asset=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20=EB=B0=8F=20=EC=BB=A8=EB=B2=A4=EC=85=98=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/drawable/ic_card_penguin.xml | 18 ++++++++++++++++++ ...s_0_grey_50.xml => shape_rect0_grey_50.xml} | 0 ..._grey_500.xml => shape_rect10_grey_500.xml} | 0 .../res/drawable/shape_rect12_grey_900.xml | 7 +++++++ ...16_grey_50.xml => shape_rect16_grey_50.xml} | 0 .../main/res/drawable/shape_rect4_grey_800.xml | 7 +++++++ app/src/main/res/layout/fragment_home.xml | 8 ++++---- .../main/res/layout/item_recommend_meet.xml | 2 +- 8 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 app/src/main/res/drawable/ic_card_penguin.xml rename app/src/main/res/drawable/{radius_0_grey_50.xml => shape_rect0_grey_50.xml} (100%) rename app/src/main/res/drawable/{radius_10_grey_500.xml => shape_rect10_grey_500.xml} (100%) create mode 100644 app/src/main/res/drawable/shape_rect12_grey_900.xml rename app/src/main/res/drawable/{radius_16_grey_50.xml => shape_rect16_grey_50.xml} (100%) create mode 100644 app/src/main/res/drawable/shape_rect4_grey_800.xml diff --git a/app/src/main/res/drawable/ic_card_penguin.xml b/app/src/main/res/drawable/ic_card_penguin.xml new file mode 100644 index 00000000..6a05cb03 --- /dev/null +++ b/app/src/main/res/drawable/ic_card_penguin.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/drawable/radius_0_grey_50.xml b/app/src/main/res/drawable/shape_rect0_grey_50.xml similarity index 100% rename from app/src/main/res/drawable/radius_0_grey_50.xml rename to app/src/main/res/drawable/shape_rect0_grey_50.xml diff --git a/app/src/main/res/drawable/radius_10_grey_500.xml b/app/src/main/res/drawable/shape_rect10_grey_500.xml similarity index 100% rename from app/src/main/res/drawable/radius_10_grey_500.xml rename to app/src/main/res/drawable/shape_rect10_grey_500.xml diff --git a/app/src/main/res/drawable/shape_rect12_grey_900.xml b/app/src/main/res/drawable/shape_rect12_grey_900.xml new file mode 100644 index 00000000..2af053aa --- /dev/null +++ b/app/src/main/res/drawable/shape_rect12_grey_900.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/radius_16_grey_50.xml b/app/src/main/res/drawable/shape_rect16_grey_50.xml similarity index 100% rename from app/src/main/res/drawable/radius_16_grey_50.xml rename to app/src/main/res/drawable/shape_rect16_grey_50.xml diff --git a/app/src/main/res/drawable/shape_rect4_grey_800.xml b/app/src/main/res/drawable/shape_rect4_grey_800.xml new file mode 100644 index 00000000..557cf020 --- /dev/null +++ b/app/src/main/res/drawable/shape_rect4_grey_800.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index ea6e85dd..ab73766d 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -22,7 +22,7 @@ android:layout_height="120dp" android:layout_marginStart="20dp" android:layout_marginTop="16dp" - android:background="@drawable/radius_16_grey_50" + android:background="@drawable/shape_rect16_grey_50" app:layout_constraintEnd_toStartOf="@id/vWork" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/appBar" /> @@ -59,7 +59,7 @@ android:layout_height="120dp" android:layout_marginStart="12dp" android:layout_marginEnd="20dp" - android:background="@drawable/radius_16_grey_50" + android:background="@drawable/shape_rect16_grey_50" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/vConcerned" app:layout_constraintTop_toTopOf="@id/vConcerned" /> @@ -96,7 +96,7 @@ android:layout_height="120dp" android:layout_marginStart="20dp" android:layout_marginTop="16dp" - android:background="@drawable/radius_16_grey_50" + android:background="@drawable/shape_rect16_grey_50" app:layout_constraintEnd_toStartOf="@id/vProject" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/vConcerned" /> @@ -133,7 +133,7 @@ android:layout_height="120dp" android:layout_marginStart="12dp" android:layout_marginEnd="20dp" - android:background="@drawable/radius_16_grey_50" + android:background="@drawable/shape_rect16_grey_50" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/vStudy" app:layout_constraintTop_toTopOf="@id/vStudy" /> diff --git a/app/src/main/res/layout/item_recommend_meet.xml b/app/src/main/res/layout/item_recommend_meet.xml index 20843234..59f90e80 100644 --- a/app/src/main/res/layout/item_recommend_meet.xml +++ b/app/src/main/res/layout/item_recommend_meet.xml @@ -19,7 +19,7 @@ style="@style/ta.caption.2" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:background="@drawable/radius_0_grey_50" + android:background="@drawable/shape_rect0_grey_50" android:paddingHorizontal="6dp" android:paddingVertical="4dp" android:textColor="@color/grey_700" From 02e1f580034e5b3d2c1c3e553f042edde6e37153 Mon Sep 17 00:00:00 2001 From: MinseoShindor Date: Tue, 9 Jan 2024 16:29:08 +0900 Subject: [PATCH 02/21] =?UTF-8?q?[feat/#24]=20viewmodel=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0&=20Image=20=EC=B2=A8=EB=B6=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 1 + app/src/main/AndroidManifest.xml | 10 +- .../teumteum/presentation/MainActivity.kt | 10 ++ .../presentation/home/HomeFragment.kt | 13 +- .../teumteum/presentation/moim/MoimAddress.kt | 49 +++++++ .../presentation/moim/MoimCreateName.kt | 26 ++-- .../presentation/moim/MoimCreateTopic.kt | 69 ++++----- .../presentation/moim/MoimDateTime.kt | 132 ++++++++++++++++++ .../presentation/moim/MoimFragment.kt | 61 ++++++++ .../presentation/moim/MoimIntroduce.kt | 111 ++++++++++----- .../presentation/moim/MoimViewModel.kt | 118 ++++++++++++++++ .../res/drawable-night/ic_floating_btn.xml | 13 ++ app/src/main/res/drawable/ic_floating_btn.xml | 13 ++ .../main/res/drawable/progress_bar_color.xml | 19 +++ app/src/main/res/layout/activity_main.xml | 1 + app/src/main/res/layout/fragment_home.xml | 12 ++ app/src/main/res/layout/fragment_moim.xml | 36 +++++ app/src/main/res/values/strings.xml | 22 +++ .../base/component/compose/TmDivider.kt | 15 ++ 19 files changed, 642 insertions(+), 89 deletions(-) create mode 100644 app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimAddress.kt create mode 100644 app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimDateTime.kt create mode 100644 app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimFragment.kt create mode 100644 app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimViewModel.kt create mode 100644 app/src/main/res/drawable-night/ic_floating_btn.xml create mode 100644 app/src/main/res/drawable/ic_floating_btn.xml create mode 100644 app/src/main/res/drawable/progress_bar_color.xml create mode 100644 app/src/main/res/layout/fragment_moim.xml create mode 100644 core/base/src/main/java/com/teumteum/base/component/compose/TmDivider.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 36f467ec..40d0ee9d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("teumteum.android.application") id("teumteum.android.androidHilt") + alias(libs.plugins.androidKotlin) } dependencies { implementation(project(":core:base")) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 072317ab..722e13f1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,6 +4,7 @@ + + + + + - - - - diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/MainActivity.kt b/app/src/main/java/com/teumteum/teumteum/presentation/MainActivity.kt index c36191f6..7fa70777 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/MainActivity.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/MainActivity.kt @@ -1,7 +1,9 @@ package com.teumteum.teumteum.presentation import android.os.Bundle +import android.view.View import androidx.fragment.app.commit +import androidx.lifecycle.VIEW_MODEL_STORE_OWNER_KEY import com.teumteum.base.BindingActivity import com.teumteum.teumteum.R import com.teumteum.teumteum.databinding.ActivityMainBinding @@ -33,6 +35,14 @@ class MainActivity : BindingActivity(R.layout.activity_main } } + fun hideBottomNavi() { + binding.btmNavi.visibility = View.GONE + } + + fun showBottomNavi() { + binding.btmNavi.visibility = View.VISIBLE + } + private fun replaceFragment(menuItemId: Int) { try { supportFragmentManager.commit { diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/home/HomeFragment.kt b/app/src/main/java/com/teumteum/teumteum/presentation/home/HomeFragment.kt index 0106e46b..c6bbc4c7 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/home/HomeFragment.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/home/HomeFragment.kt @@ -8,6 +8,8 @@ import com.teumteum.base.component.appbar.AppBarMenu import com.teumteum.base.databinding.LayoutCommonAppbarBinding import com.teumteum.teumteum.R import com.teumteum.teumteum.databinding.FragmentHomeBinding +import com.teumteum.teumteum.presentation.MainActivity +import com.teumteum.teumteum.presentation.moim.MoimFragment import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -16,6 +18,7 @@ class HomeFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initAppBarLayout() + binding.floatingBtn.setOnClickListener { navigateToMoimFragment() } } companion object { @@ -38,7 +41,7 @@ class HomeFragment : AppBarMenu.IconStyle( resourceId = R.drawable.ic_search, useRippleEffect = false, - clickEvent = null + clickEvent = { } ), AppBarMenu.IconStyle( resourceId = R.drawable.ic_alarm_active, @@ -47,4 +50,12 @@ class HomeFragment : ) ) } + + private fun navigateToMoimFragment() { + (activity as? MainActivity)?.hideBottomNavi() + requireActivity().supportFragmentManager.beginTransaction() + .replace(R.id.fl_main, MoimFragment()) + .addToBackStack(null) + .commit() + } } \ No newline at end of file diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimAddress.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimAddress.kt new file mode 100644 index 00000000..7fd19408 --- /dev/null +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimAddress.kt @@ -0,0 +1,49 @@ +package com.teumteum.teumteum.presentation.moim + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.teumteum.base.component.compose.TmMarginVerticalSpacer +import com.teumteum.base.component.compose.theme.TmTypo +import com.teumteum.base.component.compose.theme.TmtmColorPalette +import com.teumteum.teumteum.R + +@Composable +fun MoimAddress() { + Column( + modifier = Modifier + .fillMaxSize() + .background(color = TmtmColorPalette.current.GreyWhite), + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.Top, + ) { + CreateMoimTitle(string = stringResource(id = R.string.moim_address_title)) + } + +} + +@Composable +fun MoimAddressColumn() { + Column(modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(horizontal = 20.dp) + ) { + Text( + text = stringResource(id = R.string.moim_address_label1), + style = TmTypo.current.Body2, + color = TmtmColorPalette.current.color_text_body_quaternary + ) + TmMarginVerticalSpacer(size = 8) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimCreateName.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimCreateName.kt index de38218b..df41cec0 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimCreateName.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimCreateName.kt @@ -8,35 +8,37 @@ import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.teumteum.base.component.compose.TeumDivider import com.teumteum.base.component.compose.TmMarginVerticalSpacer import com.teumteum.base.component.compose.theme.TmTypo import com.teumteum.base.component.compose.theme.TmtmColorPalette +import com.teumteum.teumteum.R @Composable -fun MoimCreateName() { +fun MoimCreateName(viewModel: MoimViewModel) { + val title by viewModel.title.collectAsState() Column( modifier = Modifier .fillMaxSize() - .padding(horizontal = 20.dp) .background(color = TmtmColorPalette.current.GreyWhite), horizontalAlignment = Alignment.Start, verticalArrangement = Arrangement.Top, ) { - CreateMoimTitle(string = "모임 이름을 작성해 주세요") + CreateMoimTitle(string = stringResource(id = R.string.moim_name_title)) TmMarginVerticalSpacer(size = 28) - CreateNameContent() + CreateNameContent(viewModel) Spacer(modifier = Modifier.weight(1f)) - TeumDivider() - MoimCreateBtn(text = "다음") + MoimCreateBtn(text= stringResource(id = R.string.moim_next_btn), viewModel = viewModel, isEnabled = title.length in 2..32) TmMarginVerticalSpacer(size = 24) } } @Composable -fun CreateNameContent() { +fun CreateNameContent(viewModel: MoimViewModel) { Column(modifier = Modifier .fillMaxWidth() .wrapContentHeight() @@ -44,14 +46,14 @@ fun CreateNameContent() { ) { Text(text = "모임 이름", style= TmTypo.current.Body2, color= TmtmColorPalette.current.color_text_body_quaternary) TmMarginVerticalSpacer(size = 8) - CreateTextField(placeHolder = "모임 이름을 작성해주세요") + MoimNameTextField(viewModel = viewModel, placeHolder = stringResource(id = R.string.moim_name_title)) } } @Composable -fun CreateTextField(placeHolder: String) { - var text by remember { mutableStateOf("") } +fun MoimNameTextField(viewModel: MoimViewModel, placeHolder: String) { + val text by viewModel.title.collectAsState() val maxChar = 32 OutlinedTextField( @@ -62,7 +64,7 @@ fun CreateTextField(placeHolder: String) { placeholder = { Text(text =placeHolder, style= TmTypo.current.Body1, color = TmtmColorPalette.current.color_text_body_quinary)}, onValueChange = { newText -> if (newText.length <= maxChar) { - text = newText + viewModel.updateTitle(newText) } }, colors = TextFieldDefaults.outlinedTextFieldColors( @@ -79,5 +81,5 @@ fun CreateTextField(placeHolder: String) { @Preview @Composable fun preview2() { - MoimCreateName() + MoimDateTime() } \ No newline at end of file diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimCreateTopic.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimCreateTopic.kt index aaa6be9f..4fbe86aa 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimCreateTopic.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimCreateTopic.kt @@ -1,5 +1,6 @@ package com.teumteum.teumteum.presentation.moim +import android.util.Log import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -21,58 +22,51 @@ import androidx.compose.material.Divider import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.teumteum.base.component.compose.TeumDivider import com.teumteum.base.component.compose.TmMarginVerticalSpacer import com.teumteum.teumteum.R import com.teumteum.base.component.compose.theme.TmTypo import com.teumteum.base.component.compose.theme.TmtmColorPalette @Composable -fun MoimCreateTopic() { +fun MoimCreateTopic(viewModel: MoimViewModel) { + val topicIndex = remember { mutableStateOf(-1) } Column( modifier = Modifier .fillMaxSize() - .padding(horizontal = 20.dp) .background(color = TmtmColorPalette.current.GreyWhite), horizontalAlignment = Alignment.Start, verticalArrangement = Arrangement.Top, ) { - CreateMoimTitle(string = "어떤 주제로 모임을 만들까요?") - CreateTopicContent() + CreateMoimTitle(string = stringResource(id = R.string.moim_topic_title)) + CreateTopicContent(viewModel, topicIndex) Spacer(modifier = Modifier.weight(1f)) TeumDivider() - MoimCreateBtn(text = "다음") + MoimCreateBtn(text = stringResource(id = R.string.moim_next_btn), isEnabled = topicIndex.value >=0, viewModel = viewModel) TmMarginVerticalSpacer(size = 24) } } @Composable -fun TeumDivider() { - Divider( - color = TmtmColorPalette.current.ColorDivider, - thickness = 1.dp, - startIndent = 0.dp - ) -} - - -@Composable -fun MoimCreateBtn(text: String) { - var isClicked: Boolean = false - val buttonColors = if (isClicked) TmtmColorPalette.current.color_button_active else TmtmColorPalette.current.Gray200 - val textColors = if(isClicked) TmtmColorPalette.current.GreyWhite else TmtmColorPalette.current.Gray300 +fun MoimCreateBtn(text: String, viewModel: MoimViewModel ,isEnabled: Boolean) { + val buttonColors = if (isEnabled) TmtmColorPalette.current.color_button_active else TmtmColorPalette.current.Gray200 + val textColors = if(isEnabled) TmtmColorPalette.current.GreyWhite else TmtmColorPalette.current.Gray300 androidx.compose.material3.Button( modifier = Modifier .fillMaxWidth() .height(76.dp) .padding(horizontal = 20.dp, vertical = 10.dp), - onClick = { !isClicked }, + enabled = isEnabled, + onClick = { viewModel.goToNextScreen() }, colors = ButtonDefaults.buttonColors(containerColor = buttonColors), shape = RoundedCornerShape(size = 4.dp) ) { @@ -100,16 +94,25 @@ fun CreateMoimTitle(string:String) { } @Composable -fun CreateTopicContent() { - val selectedTopicIndex = remember { mutableStateOf(-1) } - LazyColumn { +fun CreateTopicContent(viewModel: MoimViewModel, topicIndex: MutableState) { + LazyColumn( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Top + ) { itemsIndexed(TopicType.values()) { index, topicType -> - val isSelected = index == selectedTopicIndex.value + val isSelected = index == topicIndex.value CreateTopicItem( title = topicType.title, subTitle = topicType.subTitle, isSelected = isSelected, - onItemSelected = { selectedTopicIndex.value = index } + onItemSelected = { + topicIndex.value = index + viewModel.updateTopic(topicType) + Log.d("moim_topic", topicType.toString()) + } ) TmMarginVerticalSpacer(size = 12) } @@ -126,7 +129,7 @@ fun CreateTopicItem( val radioIcon = if (isSelected) R.drawable.ic_radio_active else R.drawable.ic_radio Box( modifier = Modifier - .width(360.dp) + .fillMaxWidth() .height(92.dp) .clickable(onClick = onItemSelected) .padding(horizontal = 20.dp) @@ -159,18 +162,4 @@ fun CreateTopicItem( ) } } -} - -enum class TopicType(val value: String, val title: String ,val subTitle: String) { - SHARING_WORRIES("고민_나누기", "고민 나누기", "직무,커리어 고민을 나눠보세요"), - STUDY("스터디", "스터디", "관심 분야 스터디로 목표를 달성해요"), - GROUP_WORK("모여서_작업", "모여서 작업", "다같이 모여서 작업해요(모각코,모각일)"), - SIDE_PROJECT("사이드_프로젝트", "사이드 프로젝트","사이드 프로젝트로 팀을 꾸리고 성장하세요") - -} - -@Preview -@Composable -fun previewtmtm1() { - MoimCreateTopic() } \ No newline at end of file diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimDateTime.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimDateTime.kt new file mode 100644 index 00000000..d2d58359 --- /dev/null +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimDateTime.kt @@ -0,0 +1,132 @@ +package com.teumteum.teumteum.presentation.moim + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +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.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.TextFieldDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.teumteum.base.component.compose.TeumDivider +import com.teumteum.base.component.compose.TmMarginVerticalSpacer +import com.teumteum.base.component.compose.theme.TmTypo +import com.teumteum.base.component.compose.theme.TmtmColorPalette +import com.teumteum.teumteum.R +import java.time.LocalDate +import java.time.LocalTime +import java.time.format.DateTimeFormatter +import java.time.format.TextStyle +import java.util.Locale + + +@Composable +fun MoimDateTime() { + Column( + modifier = Modifier + .fillMaxSize() + .background(color = TmtmColorPalette.current.GreyWhite), + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.Top, + ) { + CreateMoimTitle(string = stringResource(id = R.string.moim_datetime_title)) + TmMarginVerticalSpacer(size = 28) + MoimDateColumn() + TmMarginVerticalSpacer(size = 20) + MoimTimeColumn() + Spacer(modifier = Modifier.weight(1f)) + TeumDivider() +// MoimCreateBtn(text = "다음") + TmMarginVerticalSpacer(size = 24) + } +} + +@Composable +fun MoimDateColumn() { + Column(modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(horizontal = 20.dp) + ) { + Text(text = stringResource(id = R.string.moim_datetime_label1), style= TmTypo.current.Body2, color= TmtmColorPalette.current.color_text_body_quaternary) + TmMarginVerticalSpacer(size = 8) + MoimDateInputField(placeHolder = stringResource(id = R.string.moim_datetime_placeholder1)) + + } +} + +@Composable +fun MoimTimeColumn() { + Column(modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(horizontal = 20.dp) + ) { + Text( + text = stringResource(id = R.string.moim_datetime_label2), + style = TmTypo.current.Body2, + color = TmtmColorPalette.current.color_text_body_quaternary + ) + TmMarginVerticalSpacer(size = 8) + MoimDateInputField(placeHolder = stringResource(id = R.string.moim_datetime_placeholder2)) + } +} + +@Composable +fun MoimDateInputField(placeHolder:String) { + var text by remember { mutableStateOf("") } + var dayOfWeek by remember { mutableStateOf(null) } + + OutlinedTextField( + value = text, + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight(), + placeholder = { Text(text =placeHolder, style= TmTypo.current.Body1, color = TmtmColorPalette.current.color_text_body_quinary)}, + onValueChange = { newText -> + text = newText + dayOfWeek = formatDate(newText) + }, + colors = TextFieldDefaults.outlinedTextFieldColors( + textColor = TmtmColorPalette.current.color_text_body_primary, + focusedBorderColor = TmtmColorPalette.current.elevation_color_elevation_level01, + unfocusedBorderColor = TmtmColorPalette.current.elevation_color_elevation_level01, + unfocusedLabelColor = TmtmColorPalette.current.color_text_body_quinary, + focusedLabelColor = TmtmColorPalette.current.color_text_body_quinary, + backgroundColor = TmtmColorPalette.current.elevation_color_elevation_level01 + ), + ) + if (dayOfWeek != null) { + Text(text = "$text $dayOfWeek", style=TmTypo.current.Body1, color = TmtmColorPalette.current.color_text_body_primary) + } +} + +fun formatTime(input: String): String? { + return try { + val localTime = LocalTime.parse(input, DateTimeFormatter.ofPattern("HHmm")) + localTime.format(DateTimeFormatter.ofPattern("hh:mm a")) + } catch (e: Exception) { + null + } +} + +fun formatDate(input: String): String? { + return try { + val parsedDate = LocalDate.parse(input, DateTimeFormatter.ofPattern("MM월 dd일")) + parsedDate.dayOfWeek.getDisplayName(TextStyle.FULL, Locale.getDefault()) + } catch (e: Exception) { + null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimFragment.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimFragment.kt new file mode 100644 index 00000000..d4e7d894 --- /dev/null +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimFragment.kt @@ -0,0 +1,61 @@ +package com.teumteum.teumteum.presentation.moim + +import android.animation.ObjectAnimator +import android.database.Observable +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.activity.OnBackPressedCallback +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope +import com.teumteum.base.BindingFragment +import com.teumteum.teumteum.R +import com.teumteum.teumteum.databinding.FragmentMoimBinding +import java.util.concurrent.TimeUnit + + +class MoimFragment : + BindingFragment(R.layout.fragment_moim) { + private val viewModel: MoimViewModel by viewModels() + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + lifecycleScope.launchWhenStarted { + viewModel.currentStep.collect {currentStep -> + animateProgressBar(currentStep) + } + } + + binding.composeMoim.setContent { + val screenState by viewModel.screenState.collectAsState() + when (screenState) { + ScreenState.Topic -> MoimCreateTopic(viewModel) + ScreenState.Name -> MoimCreateName(viewModel) + ScreenState.Introduce -> MoimIntroduce(viewModel) + ScreenState.DateTime -> MoimDateTime() + ScreenState.Address -> MoimAddress() + else -> {} + } + } + requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, callback) + } + + val callback = object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + viewModel.goPreviousScreen() + } + } + + private fun animateProgressBar(targetStep: Int) { + val targetProgress = targetStep * 100 + 100 + ObjectAnimator.ofInt(binding.progressBar, "progress", targetProgress) + .setDuration(500) + .start() + } + companion object { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimIntroduce.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimIntroduce.kt index 57c1f05e..4c8aa2c2 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimIntroduce.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimIntroduce.kt @@ -1,9 +1,12 @@ package com.teumteum.teumteum.presentation.moim -import androidx.annotation.IntegerRes +import android.net.Uri +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.StringRes import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -12,55 +15,63 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.OutlinedTextField import androidx.compose.material.TextFieldDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import coil.compose.rememberImagePainter +import coil.size.Scale +import coil.transform.CircleCropTransformation +import com.teumteum.base.component.compose.TeumDivider import com.teumteum.base.component.compose.TmMarginHorizontalSpacer -import com.teumteum.base.component.compose.TmMarginVerticalSpacer import com.teumteum.teumteum.R +import com.teumteum.base.component.compose.TmMarginVerticalSpacer import com.teumteum.base.component.compose.theme.TmTypo import com.teumteum.base.component.compose.theme.TmtmColorPalette @Composable -fun MoimIntroduce() { +fun MoimIntroduce(viewModel: MoimViewModel) { + val introduce by viewModel.introduction.collectAsState() Column( modifier = Modifier .fillMaxSize() - .padding(horizontal = 20.dp) .background(color = TmtmColorPalette.current.GreyWhite), horizontalAlignment = Alignment.Start, verticalArrangement = Arrangement.Top, ) { - CreateMoimTitle(string="모임을 소개해 주세요") + CreateMoimTitle(string= stringResource(id = R.string.moim_introduce_title)) TmMarginVerticalSpacer(size = 28) - MoimIntroColumn() + MoimIntroColumn(viewModel) TmMarginVerticalSpacer(size = 20) TeumDivider() TmMarginVerticalSpacer(size = 20) - MoimPhotoColumn() + MoimPhotoColumn(viewModel) Spacer(modifier = Modifier.weight(1f)) TeumDivider() - MoimCreateBtn(text = "다음") + MoimCreateBtn(text = stringResource(id = R.string.moim_next_btn), viewModel = viewModel, isEnabled = introduce.isNotEmpty()) } } @Composable -fun MoimIntroColumn() { +fun MoimIntroColumn(viewModel: MoimViewModel) { Column( modifier = Modifier .fillMaxWidth() @@ -68,7 +79,7 @@ fun MoimIntroColumn() { horizontalAlignment = Alignment.Start, verticalArrangement = Arrangement.Top, ) { - MoimInputField() + MoimInputField(viewModel) TmMarginVerticalSpacer(size = 24) MoimSystemText(text = R.string.moim_introduce_system_text) @@ -102,8 +113,8 @@ fun MoimSystemText(@StringRes text: Int) { } @Composable -fun MoimInputField() { - var text by remember { mutableStateOf("") } +fun MoimInputField(viewModel: MoimViewModel) { + val text by viewModel.introduction.collectAsState() OutlinedTextField( value = text, @@ -111,8 +122,8 @@ fun MoimInputField() { .fillMaxWidth() .padding(horizontal = 20.dp) .height(272.dp), - placeholder = { Text(text ="모임을 소개해 주세요", style= TmTypo.current.Body1, color = TmtmColorPalette.current.color_text_body_quinary) }, - onValueChange = { text = it }, + placeholder = { Text(text = stringResource(id = R.string.moim_introduce_title), style= TmTypo.current.Body1, color = TmtmColorPalette.current.color_text_body_quinary) }, + onValueChange = { newText-> viewModel.updateIntroduce(newText) }, colors = TextFieldDefaults.outlinedTextFieldColors( textColor = TmtmColorPalette.current.color_text_body_primary, focusedBorderColor = TmtmColorPalette.current.elevation_color_elevation_level01, @@ -126,7 +137,17 @@ fun MoimInputField() { } @Composable -fun MoimPhotoColumn() { +fun MoimPhotoColumn(viewModel: MoimViewModel) { + val imageUri by viewModel.imageUri.collectAsState() + val context = LocalContext.current + + val launcher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.GetMultipleContents(), + onResult = { uris: List -> + viewModel.addImages(uris, context) + } + ) + Column( modifier = Modifier .fillMaxWidth() @@ -137,7 +158,7 @@ fun MoimPhotoColumn() { ) { Row(modifier = Modifier .fillMaxWidth() - .padding(horizontal=20.dp) + .padding(horizontal = 20.dp) .wrapContentHeight(), horizontalArrangement = Arrangement.Start, verticalAlignment = Alignment.CenterVertically @@ -147,23 +168,49 @@ fun MoimPhotoColumn() { Text(text = stringResource(id = R.string.moim_introduce_title2_photo), style= TmTypo.current.Body2, color= TmtmColorPalette.current.color_text_headline_teritary) } TmMarginVerticalSpacer(size = 8) - MoimPhotoInput() + MoimPhotoInput(imageUri) { launcher.launch("image/*") } TmMarginVerticalSpacer(size = 8) MoimSystemText(text = R.string.moim_introduce_system_photo) } } @Composable -fun MoimPhotoInput() { - Image( - painter = painterResource(id = R.drawable.ic_input_photo), - contentDescription = null - ) - +fun MoimPhotoInput( + attachedImages: List, + onAddImage: () -> Unit, +) { + LazyRow( + modifier = Modifier.padding(horizontal = 20.dp) + ) { + items(attachedImages) { imageUri -> + Image( + painter = rememberImagePainter( + data = imageUri, + builder = { + scale(Scale.FILL) + } + ), + contentDescription = "Attached Image", + modifier = Modifier + .size(72.dp, 73.dp) + .padding(4.dp) + .clip(RoundedCornerShape(4.dp)), + contentScale = ContentScale.Crop + ) + } + if (attachedImages.size < 5) { + item { + Image( + painter = painterResource(id = R.drawable.ic_input_photo), + contentDescription = "Add Image", + modifier = Modifier + .size(72.dp, 73.dp) + .padding(4.dp) + .clickable { onAddImage() } + ) + } + } + } } -@Preview -@Composable -fun previewPhoto() { - MoimIntroduce() -} \ No newline at end of file + diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimViewModel.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimViewModel.kt new file mode 100644 index 00000000..4961e2f2 --- /dev/null +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimViewModel.kt @@ -0,0 +1,118 @@ +package com.teumteum.teumteum.presentation.moim + +import android.content.Context +import android.net.Uri +import android.provider.OpenableColumns +import android.util.Log +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import javax.inject.Inject + +@HiltViewModel +class MoimViewModel @Inject constructor( + +): ViewModel() { + + private val _screenState = MutableStateFlow(ScreenState.Topic) + val screenState: StateFlow = _screenState.asStateFlow() + + private val _currentStep = MutableStateFlow(1) + val currentStep: StateFlow = _currentStep.asStateFlow() + + private val _topic = MutableStateFlow(null) + val topic: StateFlow = _topic.asStateFlow() + + private val _title = MutableStateFlow("") + val title : StateFlow = _title.asStateFlow() + + private val _introduction = MutableStateFlow("") + val introduction: StateFlow = _introduction.asStateFlow() + + private val _imageUri = MutableStateFlow>(emptyList()) + val imageUri: StateFlow> = _imageUri.asStateFlow() + + fun updateTopic(topicType: TopicType) { + _topic.value = topicType + } + + fun updateTitle(title: String) { + _title.value = title + } + + fun updateIntroduce(introduce: String) { + _introduction.value = introduce + } + + fun addImages(uris: List, context: Context) { + val currentList = _imageUri.value.toMutableList() + for (uri in uris) { + val size = getFileSize(uri, context) + if (size <= 10 * 1024 * 1024 && currentList.size < 5) { // 10MB 이하이고, 현재 리스트 크기가 5 미만인 경우 + currentList.add(uri) + } + } + _imageUri.value = currentList.take(5) + } + fun goToNextScreen() { + _screenState.value = + when(_screenState.value) { + ScreenState.Topic -> ScreenState.Name + ScreenState.Name -> ScreenState.Introduce + ScreenState.Introduce -> ScreenState.DateTime + ScreenState.DateTime -> ScreenState.Address + else -> ScreenState.Create + } + goToNextStep() + Log.d("currentStep", _currentStep.value.toString()) + } + + fun goPreviousScreen() { + _screenState.value = + when(_screenState.value) { + ScreenState.Create -> ScreenState.Address + ScreenState.Address -> ScreenState.DateTime + ScreenState.DateTime -> ScreenState.Introduce + ScreenState.Introduce -> ScreenState.Name + else -> ScreenState.Topic + } + goToPreviousStep() + } + + fun goToNextStep() { + val nextStep = _currentStep.value + 1 + _currentStep.value = nextStep.coerceIn(1, 6) + } + + fun goToPreviousStep() { + val previousStep = _currentStep.value - 1 + _currentStep.value = previousStep.coerceAtLeast(1) + } + + fun getFileSize(uri: Uri, context: Context): Long { + val cursor = context.contentResolver.query(uri, null, null, null, null) + val sizeIndex = cursor?.getColumnIndex(OpenableColumns.SIZE) + cursor?.moveToFirst() + val size = sizeIndex?.let { cursor.getLong(it) } ?: 0L + cursor?.close() + return size + } + + + + +} + +enum class TopicType(val value: String, val title: String ,val subTitle: String) { + SHARING_WORRIES("고민_나누기", "고민 나누기", "직무,커리어 고민을 나눠보세요"), + STUDY("스터디", "스터디", "관심 분야 스터디로 목표를 달성해요"), + GROUP_WORK("모여서_작업", "모여서 작업", "다같이 모여서 작업해요(모각코,모각일)"), + SIDE_PROJECT("사이드_프로젝트", "사이드 프로젝트","사이드 프로젝트로 팀을 꾸리고 성장하세요") + +} + +enum class ScreenState { + Topic, Name, Introduce, DateTime, Address, People, Create +} \ No newline at end of file diff --git a/app/src/main/res/drawable-night/ic_floating_btn.xml b/app/src/main/res/drawable-night/ic_floating_btn.xml new file mode 100644 index 00000000..adea4f49 --- /dev/null +++ b/app/src/main/res/drawable-night/ic_floating_btn.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_floating_btn.xml b/app/src/main/res/drawable/ic_floating_btn.xml new file mode 100644 index 00000000..adea4f49 --- /dev/null +++ b/app/src/main/res/drawable/ic_floating_btn.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/progress_bar_color.xml b/app/src/main/res/drawable/progress_bar_color.xml new file mode 100644 index 00000000..ffbac682 --- /dev/null +++ b/app/src/main/res/drawable/progress_bar_color.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 7de68625..513388d7 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -25,6 +25,7 @@ android:id="@+id/btm_navi" android:layout_width="0dp" android:layout_height="57dp" + android:visibility="visible" android:background="@color/grey_white" app:itemBackground="@color/transparent" app:itemIconTint="@color/selector_bottom_menu" diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index ea6e85dd..0c149ef5 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -209,5 +209,17 @@ app:layout_constraintTop_toBottomOf="@id/tvRecommendMeet" tools:listitem="@layout/item_recommend_meet" /> + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_moim.xml b/app/src/main/res/layout/fragment_moim.xml new file mode 100644 index 00000000..fd9085ef --- /dev/null +++ b/app/src/main/res/layout/fragment_moim.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b1b4f340..0e841595 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -13,6 +13,7 @@ 사이드 프로젝트 사이드 프로젝트\n팀을 구해보세요 판교 추천 모임 + 모임생성으로 이동하는 버튼 시작하기 나를 대표하는\n소개서를 만들어보세요 @@ -22,9 +23,30 @@ 틈틈의 인증 시스템들로\n안전한 네트워킹을 즐겨보세요 회사/학교 인증, 지인 인증, 리뷰 등으로\n안전한 네트워킹을 즐겨보세요 + 어떤 주제로 모임을 만들까요? + 다음 + + 모임 이름을 작성해 주세요 + + 모임을 소개해 주세요 추천 수가 20개가 넘는 인기글의 경우 스팸 광고를 차단하기 위해 게시글 수정이 불가합니다. 사진 등록 최대 5장 1장 이상의 사진을 필수로 등록해주세요. + 모임 일정을 정해주세요 + 날짜 + 00월 00일 0요일 + 시간 + 오후 00시 + + 모임 일정을 정해주세요 + 도로명 주소 + 도로명 주소를 입력해 주세요 + 상세 주소를 입력해 주세요 + + 모임 참여 인원을 설정해 주세요 + 안전한 모임을 위해 최소 3명 이상 최대 6명 참여자가 필요해요 + + Hello blank fragment \ No newline at end of file diff --git a/core/base/src/main/java/com/teumteum/base/component/compose/TmDivider.kt b/core/base/src/main/java/com/teumteum/base/component/compose/TmDivider.kt new file mode 100644 index 00000000..266a15c0 --- /dev/null +++ b/core/base/src/main/java/com/teumteum/base/component/compose/TmDivider.kt @@ -0,0 +1,15 @@ +package com.teumteum.base.component.compose + +import androidx.compose.material.Divider +import androidx.compose.runtime.Composable +import androidx.compose.ui.unit.dp +import com.teumteum.base.component.compose.theme.TmtmColorPalette + +@Composable +fun TeumDivider() { + Divider( + color = TmtmColorPalette.current.ColorDivider, + thickness = 1.dp, + startIndent = 0.dp + ) +} \ No newline at end of file From 269f06444f89083b6b7bdb099ed65f02211f240e Mon Sep 17 00:00:00 2001 From: Leekangmin Date: Tue, 9 Jan 2024 18:01:37 +0900 Subject: [PATCH 03/21] =?UTF-8?q?[feat/#11]=20=EC=B6=94=EC=B2=9C=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=EC=96=B4=20=EC=95=84=EC=9D=B4=ED=85=9C=20?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../drawable/shape_outline_level3_200dp.xml | 5 +++++ app/src/main/res/layout/item_keyword_list.xml | 22 +++++++++++++++++++ app/src/main/res/values/strings.xml | 3 +++ core/base/src/main/res/values/themes.xml | 1 - 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/drawable/shape_outline_level3_200dp.xml create mode 100644 app/src/main/res/layout/item_keyword_list.xml diff --git a/app/src/main/res/drawable/shape_outline_level3_200dp.xml b/app/src/main/res/drawable/shape_outline_level3_200dp.xml new file mode 100644 index 00000000..3b9d32c4 --- /dev/null +++ b/app/src/main/res/drawable/shape_outline_level3_200dp.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_keyword_list.xml b/app/src/main/res/layout/item_keyword_list.xml new file mode 100644 index 00000000..ac4f7567 --- /dev/null +++ b/app/src/main/res/layout/item_keyword_list.xml @@ -0,0 +1,22 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b1b4f340..1e2f9d20 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -27,4 +27,7 @@ 최대 5장 1장 이상의 사진을 필수로 등록해주세요. + 검색어를 입력해 주세요 + 추천 검색어 + \ No newline at end of file diff --git a/core/base/src/main/res/values/themes.xml b/core/base/src/main/res/values/themes.xml index b0c1aa2e..4a1f0eea 100644 --- a/core/base/src/main/res/values/themes.xml +++ b/core/base/src/main/res/values/themes.xml @@ -155,7 +155,6 @@ From 7624aa6d9ba2f54e0126cd7163c6e41e55de7c14 Mon Sep 17 00:00:00 2001 From: Leekangmin Date: Tue, 9 Jan 2024 18:02:04 +0900 Subject: [PATCH 04/21] =?UTF-8?q?[feat/#11]=20=EA=B7=B8=EB=A3=B9=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20=ED=99=94=EB=A9=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../group/search/SearchActivity.kt | 4 + app/src/main/res/layout/activity_search.xml | 83 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchActivity.kt create mode 100644 app/src/main/res/layout/activity_search.xml diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchActivity.kt b/app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchActivity.kt new file mode 100644 index 00000000..dcf303ef --- /dev/null +++ b/app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchActivity.kt @@ -0,0 +1,4 @@ +package com.teumteum.teumteum.presentation.group.search + +class SearchActivity { +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml new file mode 100644 index 00000000..f9ed5d5f --- /dev/null +++ b/app/src/main/res/layout/activity_search.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file From 89e55fc9336ff586b9b18dd907979da116343d5d Mon Sep 17 00:00:00 2001 From: Leekangmin Date: Wed, 10 Jan 2024 01:00:10 +0900 Subject: [PATCH 05/21] =?UTF-8?q?[feat/#11]=20GroupRepository=20=EC=9E=84?= =?UTF-8?q?=EC=8B=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 2 ++ .../teumteum/teumteum/di/RepositoryModule.kt | 7 ++++++ .../data/repository/GroupRepositoryImpl.kt | 22 +++++++++++++++++++ .../domain/repository/GroupRepository.kt | 7 ++++++ 4 files changed, 38 insertions(+) create mode 100644 core/data/src/main/java/com/teumteum/data/repository/GroupRepositoryImpl.kt create mode 100644 core/domain/src/main/java/com/teumteum/domain/repository/GroupRepository.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 072317ab..23631f48 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -32,6 +32,8 @@ + \ No newline at end of file diff --git a/app/src/main/java/com/teumteum/teumteum/di/RepositoryModule.kt b/app/src/main/java/com/teumteum/teumteum/di/RepositoryModule.kt index a400d7d7..e3400db3 100644 --- a/app/src/main/java/com/teumteum/teumteum/di/RepositoryModule.kt +++ b/app/src/main/java/com/teumteum/teumteum/di/RepositoryModule.kt @@ -1,11 +1,14 @@ package com.teumteum.teumteum.di +import com.teumteum.data.repository.GroupRepositoryImpl import com.teumteum.data.repository.HomeRepositoryImpl import com.teumteum.data.repository.SampleRepositoryImpl +import com.teumteum.domain.repository.GroupRepository import com.teumteum.domain.repository.HomeRepository import com.teumteum.domain.repository.SampleRepository import dagger.Binds import dagger.Module +import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import javax.inject.Singleton @@ -21,4 +24,8 @@ interface RepositoryModule { @Singleton @Binds fun bindHomeRepository(homeRepositoryImpl: HomeRepositoryImpl): HomeRepository + + @Singleton + @Binds + fun provideGroupRepository(groupRepositoryImpl: GroupRepositoryImpl): GroupRepository } \ No newline at end of file diff --git a/core/data/src/main/java/com/teumteum/data/repository/GroupRepositoryImpl.kt b/core/data/src/main/java/com/teumteum/data/repository/GroupRepositoryImpl.kt new file mode 100644 index 00000000..480f6d46 --- /dev/null +++ b/core/data/src/main/java/com/teumteum/data/repository/GroupRepositoryImpl.kt @@ -0,0 +1,22 @@ +package com.teumteum.data.repository + +import com.teumteum.domain.entity.Group +import com.teumteum.domain.repository.GroupRepository +import javax.inject.Inject + +class GroupRepositoryImpl @Inject constructor( + +): GroupRepository { + override suspend fun getSearchGroup(keyword: String): Result> { + return runCatching { + listOf( + Group(1L, 1L, "모각작", "모여서 작업할 사람", "나는 소개", listOf("", ""), "1월 10일 오후 07:00"), + Group(2L, 2L, "모각작", "모여서 작업 안할 사람", "나는 소개", listOf("", ""), "1월 21일 오후 04:00"), + Group(3L, 3L, "모각작", "모여서 작업 하기 싫은 사람", "나는 소개", listOf("", ""), "1월 26일 오후 11:00"), + Group(4L, 4L, "모각작", "모여서 작업 하고 싶은 사람", "나는 소개", listOf("", ""), "2월 13일 오전 11:00"), + Group(5L, 5L, "모각작", "모일 사람", "나는 소개", listOf("", ""), "4월 06일 오후 04:00"), + Group(6L, 6L, "모각작", "안 모일 사람", "나는 소개", listOf("", ""), "11월 16일 오후 08:00"), + ) + } + } +} \ No newline at end of file diff --git a/core/domain/src/main/java/com/teumteum/domain/repository/GroupRepository.kt b/core/domain/src/main/java/com/teumteum/domain/repository/GroupRepository.kt new file mode 100644 index 00000000..d6d39c3d --- /dev/null +++ b/core/domain/src/main/java/com/teumteum/domain/repository/GroupRepository.kt @@ -0,0 +1,7 @@ +package com.teumteum.domain.repository + +import com.teumteum.domain.entity.Group + +interface GroupRepository { + suspend fun getSearchGroup(keyword: String): Result> +} \ No newline at end of file From c6d8e1789348d81108d03b44f3390747187de2d9 Mon Sep 17 00:00:00 2001 From: Leekangmin Date: Wed, 10 Jan 2024 01:01:27 +0900 Subject: [PATCH 06/21] =?UTF-8?q?[feat/#11]=20GroupService=20=EC=A0=95?= =?UTF-8?q?=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/group/GroupListActivity.kt | 12 +++---- .../data/model/response/ResponseGroup.kt | 31 +++++++++++++++++++ .../com/teumteum/data/service/GroupService.kt | 20 ++++++++++++ .../java/com/teumteum/domain/entity/Group.kt | 1 + 4 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 core/data/src/main/java/com/teumteum/data/model/response/ResponseGroup.kt create mode 100644 core/data/src/main/java/com/teumteum/data/service/GroupService.kt diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/group/GroupListActivity.kt b/app/src/main/java/com/teumteum/teumteum/presentation/group/GroupListActivity.kt index 3291e4bd..29657bb0 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/group/GroupListActivity.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/group/GroupListActivity.kt @@ -26,12 +26,12 @@ class GroupListActivity : BindingActivity(R.layout.act binding.rvGroupList.adapter = adapter adapter.setItems( listOf( - Group(1L, "모각작", "모여서 작업할 사람", "나는 소개", listOf("", ""), "1월 10일 오후 07:00"), - Group(2L, "모각작", "모여서 작업 안할 사람", "나는 소개", listOf("", ""), "1월 21일 오후 04:00"), - Group(3L, "모각작", "모여서 작업 하기 싫은 사람", "나는 소개", listOf("", ""), "1월 26일 오후 11:00"), - Group(4L, "모각작", "모여서 작업 하고 싶은 사람", "나는 소개", listOf("", ""), "2월 13일 오전 11:00"), - Group(5L, "모각작", "모일 사람", "나는 소개", listOf("", ""), "4월 06일 오후 04:00"), - Group(6L, "모각작", "안 모일 사람", "나는 소개", listOf("", ""), "11월 16일 오후 08:00"), + Group(1L, 1L,"모각작", "모여서 작업할 사람", "나는 소개", listOf("", ""), "1월 10일 오후 07:00"), + Group(2L, 2L,"모각작", "모여서 작업 안할 사람", "나는 소개", listOf("", ""), "1월 21일 오후 04:00"), + Group(3L, 3L,"모각작", "모여서 작업 하기 싫은 사람", "나는 소개", listOf("", ""), "1월 26일 오후 11:00"), + Group(4L, 4L,"모각작", "모여서 작업 하고 싶은 사람", "나는 소개", listOf("", ""), "2월 13일 오전 11:00"), + Group(5L, 5L,"모각작", "모일 사람", "나는 소개", listOf("", ""), "4월 06일 오후 04:00"), + Group(6L, 6L,"모각작", "안 모일 사람", "나는 소개", listOf("", ""), "11월 16일 오후 08:00"), ) ) } diff --git a/core/data/src/main/java/com/teumteum/data/model/response/ResponseGroup.kt b/core/data/src/main/java/com/teumteum/data/model/response/ResponseGroup.kt new file mode 100644 index 00000000..3c480f05 --- /dev/null +++ b/core/data/src/main/java/com/teumteum/data/model/response/ResponseGroup.kt @@ -0,0 +1,31 @@ +package com.teumteum.data.model.response + +import com.teumteum.domain.entity.Group + +data class ResponseGroup( + val data: ResponseGroupData, + val hasNext: Boolean +) { + data class ResponseGroupData( + val meetings: List + ) { + data class ResponseMeeting( + val hostId: Int, + val id: Int, + val introduction: String, + val meetingArea: ResponseMeetingArea, + val numberOfRecruits: Int, + val participantIds: List, + val photoUrls: List, + val promiseDateTime: String, + val title: String, + val topic: String + ) { + data class ResponseMeetingArea( + val city: String, + val street: String, + val zipCode: String + ) + } + } +} \ No newline at end of file diff --git a/core/data/src/main/java/com/teumteum/data/service/GroupService.kt b/core/data/src/main/java/com/teumteum/data/service/GroupService.kt new file mode 100644 index 00000000..efa79232 --- /dev/null +++ b/core/data/src/main/java/com/teumteum/data/service/GroupService.kt @@ -0,0 +1,20 @@ +package com.teumteum.data.service + +import com.teumteum.data.model.response.ResponseGetRecommendMeet +import com.teumteum.data.model.response.ResponseGroup +import retrofit2.http.GET +import retrofit2.http.Query + +interface GroupService { + @GET("meetings") + suspend fun getGroups( + @Query("size") size: Int, + @Query("page") page: Int, + @Query("sort") sort: String, + @Query("isOpen") isOpen: Boolean, + @Query("topic") topic: String?, + @Query("meetingAreaStreet") meetingAreaStreet: String?, + @Query("participantUserId") participantUserId: Long?, + @Query("searchWord") searchWord: String? + ): ResponseGroup +} \ No newline at end of file diff --git a/core/domain/src/main/java/com/teumteum/domain/entity/Group.kt b/core/domain/src/main/java/com/teumteum/domain/entity/Group.kt index 2a41093d..34bd0d7f 100644 --- a/core/domain/src/main/java/com/teumteum/domain/entity/Group.kt +++ b/core/domain/src/main/java/com/teumteum/domain/entity/Group.kt @@ -2,6 +2,7 @@ package com.teumteum.domain.entity data class Group( val id: Long, + val hostId: Long, val topic: String, val name: String, val introduction: String, From a79372f106b695581787bb4d8e5bdd6de1b35eee Mon Sep 17 00:00:00 2001 From: Leekangmin Date: Wed, 10 Jan 2024 01:01:58 +0900 Subject: [PATCH 07/21] =?UTF-8?q?[feat/#11]=20=EA=B2=80=EC=83=89=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../group/search/SearchActivity.kt | 64 +++++++- .../group/search/SearchViewModel.kt | 46 ++++++ app/src/main/res/layout/activity_search.xml | 152 ++++++++++-------- 3 files changed, 195 insertions(+), 67 deletions(-) create mode 100644 app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchViewModel.kt diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchActivity.kt b/app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchActivity.kt index dcf303ef..6263fca8 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchActivity.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchActivity.kt @@ -1,4 +1,66 @@ package com.teumteum.teumteum.presentation.group.search -class SearchActivity { +import android.os.Bundle +import android.util.Log +import androidx.activity.viewModels +import androidx.core.view.isVisible +import androidx.lifecycle.flowWithLifecycle +import androidx.lifecycle.lifecycleScope +import com.teumteum.base.BindingActivity +import com.teumteum.teumteum.R +import com.teumteum.teumteum.databinding.ActivitySearchBinding +import com.teumteum.teumteum.presentation.group.GroupListAdapter +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach + +@AndroidEntryPoint +class SearchActivity: BindingActivity(R.layout.activity_search) { + private val viewModel by viewModels() + private lateinit var keywordAdapter: keywordAdapter + private lateinit var groupListAdapter: GroupListAdapter + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + binding.viewModel = viewModel + initView() + observe() + } + + private fun initView() { + keywordAdapter = keywordAdapter { + + } + binding.rvRecommendKeyword.adapter = keywordAdapter + keywordAdapter.setItems(viewModel.keywordList) + + groupListAdapter = GroupListAdapter { + + } + binding.rvGroupList.adapter = groupListAdapter + } + + @OptIn(FlowPreview::class) + private fun observe() { + viewModel.searchData.flowWithLifecycle(lifecycle) + .onEach { + binding.clRecommendKeyword.isVisible = it is SearchUiState.Init + when(it) { + is SearchUiState.Success -> { + groupListAdapter.setItems(it.data) + } + else -> {} + } + }.launchIn(lifecycleScope) + + viewModel.etSearch.flowWithLifecycle(lifecycle) + .debounce(1000) + .onEach { + if (it.isNotEmpty()) { + viewModel.getSearchGroup(it) + } + }.launchIn(lifecycleScope) + } } \ No newline at end of file diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchViewModel.kt b/app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchViewModel.kt new file mode 100644 index 00000000..2de6300d --- /dev/null +++ b/app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchViewModel.kt @@ -0,0 +1,46 @@ +package com.teumteum.teumteum.presentation.group.search + +import android.util.Log +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.teumteum.domain.entity.Group +import com.teumteum.domain.repository.GroupRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch + +@HiltViewModel +class SearchViewModel @Inject constructor( + private val repository: GroupRepository +): ViewModel() { + val etSearch = MutableStateFlow("") + + val isInputBlank = etSearch.value.isBlank() + + val keywordList = listOf("스터디", "독서", "외주", "모여서 각자 일하기", "커리어", "직무 고민", "사이드 프로젝트", "N잡") + + private val _searchData = MutableStateFlow(SearchUiState.Init) + val searchData: StateFlow = _searchData + + fun getSearchGroup(keyword: String) { + viewModelScope.launch { + repository.getSearchGroup(keyword) + .onSuccess { + if (it.isEmpty()) { + _searchData.value = SearchUiState.Failure("실패") + } else { + _searchData.value = SearchUiState.Success(it) + } + } + } + } + +} + +sealed interface SearchUiState { + object Init: SearchUiState + data class Success(val data: List): SearchUiState + data class Failure(val msg: String): SearchUiState +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml index f9ed5d5f..15df4440 100644 --- a/app/src/main/res/layout/activity_search.xml +++ b/app/src/main/res/layout/activity_search.xml @@ -1,83 +1,103 @@ - + xmlns:tools="http://schemas.android.com/tools"> - + - - - - - + + + android:layout_height="match_parent"> - + + - + + + + + app:layout_constraintTop_toBottomOf="@id/view_division_search"> + + + + + + + - \ No newline at end of file + \ No newline at end of file From 370475922f934e2ccc0adf2e8f439ea140e4e258 Mon Sep 17 00:00:00 2001 From: Leekangmin Date: Wed, 10 Jan 2024 01:02:16 +0900 Subject: [PATCH 08/21] =?UTF-8?q?[feat/#11]=20=EC=B6=94=EC=B2=9C=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EC=96=B4=EB=8E=81=ED=84=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../group/search/KeywordAdapter.kt | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 app/src/main/java/com/teumteum/teumteum/presentation/group/search/KeywordAdapter.kt diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/group/search/KeywordAdapter.kt b/app/src/main/java/com/teumteum/teumteum/presentation/group/search/KeywordAdapter.kt new file mode 100644 index 00000000..afdebc53 --- /dev/null +++ b/app/src/main/java/com/teumteum/teumteum/presentation/group/search/KeywordAdapter.kt @@ -0,0 +1,43 @@ +package com.teumteum.teumteum.presentation.group.search + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.teumteum.teumteum.databinding.ItemKeywordListBinding + +class keywordAdapter(private val itemClick: (String) -> (Unit)): RecyclerView.Adapter() { + private val keywordList = mutableListOf() + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): KeywordAdapter { + val binding = ItemKeywordListBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false, + ) + return KeywordAdapter(binding, itemClick) + } + + override fun onBindViewHolder(holder: KeywordAdapter, position: Int) { + holder.onBind(keywordList[position]) + } + + override fun getItemCount(): Int = keywordList.size + + fun setItems(newItems: List) { + keywordList.clear() + keywordList.addAll(newItems) + notifyDataSetChanged() + } + + class KeywordAdapter( + private val binding: ItemKeywordListBinding, + private val itemClick: (String) -> (Unit) + ): RecyclerView.ViewHolder(binding.root) { + fun onBind(keyword: String) { + binding.tvKeyword.text = keyword + + binding.root.setOnClickListener { + itemClick(keyword) + } + } + } +} \ No newline at end of file From 6165d5c5ebcd060fa9b1b6067b45c1f2af02bf4e Mon Sep 17 00:00:00 2001 From: unam Date: Wed, 10 Jan 2024 01:54:03 +0900 Subject: [PATCH 09/21] =?UTF-8?q?[feat/#16]=20=EC=B9=B4=EB=93=9C=20?= =?UTF-8?q?=EC=A0=84=EB=A9=B4=20=EB=B7=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/custom/view/FrontCardView.kt | 288 ++++++++++++++++++ .../util/custom/view/model/FrontCard.kt | 13 + .../main/res/layout/fragment_teum_teum.xml | 18 +- app/src/main/res/values/attrs.xml | 10 + app/src/main/res/values/strings.xml | 6 + app/src/main/res/values/themes.xml | 13 - 6 files changed, 329 insertions(+), 19 deletions(-) create mode 100644 app/src/main/java/com/teumteum/teumteum/util/custom/view/FrontCardView.kt create mode 100644 app/src/main/java/com/teumteum/teumteum/util/custom/view/model/FrontCard.kt diff --git a/app/src/main/java/com/teumteum/teumteum/util/custom/view/FrontCardView.kt b/app/src/main/java/com/teumteum/teumteum/util/custom/view/FrontCardView.kt new file mode 100644 index 00000000..1d34ed86 --- /dev/null +++ b/app/src/main/java/com/teumteum/teumteum/util/custom/view/FrontCardView.kt @@ -0,0 +1,288 @@ +package com.teumteum.teumteum.util.custom.view + +import android.content.Context +import android.content.res.ColorStateList +import android.util.AttributeSet +import android.util.TypedValue +import android.widget.ImageView +import android.widget.TextView +import androidx.cardview.widget.CardView +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.content.ContextCompat +import androidx.core.content.res.ResourcesCompat +import com.teumteum.teumteum.R +import com.teumteum.teumteum.util.custom.view.model.FrontCard +import com.teumteum.teumteum.util.extension.dpToPx + +/** + * 카드 전면 뷰 + * + * xml, compose 모든 환경에서 뷰를 재활용 할 수 있게 커스텀뷰로 제작 + */ +class FrontCardView : CardView { + private val matchParent = ConstraintLayout.LayoutParams.PARENT_ID + private var frontCard = FrontCard() + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + init(context, attrs) + } + + constructor(context: Context) : super(context) { + init(context, null) + } + + /** + * 컴포즈 환경에서 FrontCard 객체 생성 + */ + fun getInstance(frontCard: FrontCard) { + this.frontCard = frontCard + setUpViews() + } + + + /** + * 뷰가 생성되어 layout에 추가된 후 xml의 값이 뷰에 적용 + */ + private fun init(context: Context, attrs: AttributeSet?) { + setFrontCardBackground(context) + addView(createLayoutAndViews(context)) + applyXmlAttributes(context, attrs) + } + + /** + * 카드 배경 설정 + */ + private fun setFrontCardBackground(context: Context) { + setCardBackgroundColor( + ColorStateList.valueOf( + ContextCompat.getColor( + context, + R.color.grey_900 + ) + ) + ) + radius = 12.dpToPx(context).toFloat() + layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT) + } + + /** + * 커스텀뷰의 속성 값을 xml에 입력한 값으로 초기화 + */ + private fun applyXmlAttributes(context: Context, attrs: AttributeSet?) { + context.theme.obtainStyledAttributes(attrs, R.styleable.CardFrontView, 0, 0).apply { + try { + frontCard.name = getString(R.styleable.CardFrontView_name) ?: "" + frontCard.company = getString(R.styleable.CardFrontView_company) ?: "" + frontCard.job = getString(R.styleable.CardFrontView_job) ?: "" + frontCard.level = getString(R.styleable.CardFrontView_level) ?: "" + frontCard.area = getString(R.styleable.CardFrontView_area) ?: "" + frontCard.mbti = getString(R.styleable.CardFrontView_mbti) ?: "" + frontCard.characterResId = getResourceId(R.styleable.CardFrontView_image, 0) + } finally { + recycle() + } + } + setUpViews() + } + + private fun setUpViews() { + setTextView(tvName, frontCard.name) + setTextView(tvCompany, frontCard.company) + setTextView(tvJob, frontCard.job) + setTextView(tvLevel, frontCard.level) + setTextView(tvArea, frontCard.area) + setTextView(tvMbti, frontCard.mbti) + setImageViewResource(tvCharacter, frontCard.characterResId) + } + + private fun setTextView(viewId: Int, text: String) { + val textView = findViewById(viewId) + textView?.text = text + } + + private fun setImageViewResource(viewId: Int, resId: Int) { + val imageView = findViewById(viewId) + imageView?.setImageResource(resId) + } + + /** + * layout과 그 안에 포함시킬 뷰 추가 + */ + private fun createLayoutAndViews(context: Context) = ConstraintLayout(context).apply { + id = clCardFront + layoutParams = + ConstraintLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT) + + addTextView( + context, + id = tvName, + text = context.getString(R.string.front_card_name), + textColor = R.color.grey_50, + textSizeSp = 30f, + fontFamily = R.font.pretendard_bold, + lineHeightDp = 36, + topToTopOf = matchParent, + startToStartOf = matchParent, + marginTop = 40, + marginStart = 32 + ) + addTextView( + context, + id = tvCompany, + text = context.getString(R.string.front_card_company), + textColor = R.color.grey_400, + textSizeSp = 16f, + fontFamily = R.font.pretendard_semibold, + lineHeightDp = 22, + startToStartOf = tvName, + marginTop = 20, + topToBottomOf = tvName + ) + addTextView( + context, + id = tvJob, + text = context.getString(R.string.front_card_job), + textColor = R.color.grey_50, + textSizeSp = 18f, + fontFamily = R.font.pretendard_bold, + lineHeightDp = 24, + startToStartOf = tvName, + marginTop = 6, + topToBottomOf = tvCompany + ) + addTextView( + context, + id = tvLevel, + text = context.getString(R.string.front_card_level), + textColor = R.color.grey_300, + textSizeSp = 12f, + fontFamily = R.font.pretendard_regular, + lineHeightDp = 18, + marginTop = 6, + paddingStart = 8, + paddingEnd = 8, + paddingTop = 2, + paddingBottom = 2, + startToStartOf = tvName, + topToBottomOf = tvJob, + background = R.drawable.shape_rect4_grey_800 + ) + addTextView( + context, + id = tvArea, + text = context.getString(R.string.front_card_area), + textColor = R.color.grey_400, + textSizeSp = 12f, + fontFamily = R.font.pretendard_regular, + lineHeightDp = 18, + marginTop = 6, + startToStartOf = tvName, + bottomToTopOf = tvMbti + ) + addTextView( + context, + id = tvMbti, + text = context.getString(R.string.front_card_mbti), + textColor = R.color.grey_50, + textSizeSp = 20f, + fontFamily = R.font.pretendard_bold, + lineHeightDp = 28, + marginBottom = 32, + startToStartOf = tvName, + bottomToBottomOf = matchParent + ) + addImageView( + context, + id = tvCharacter, + drawableRes = R.drawable.ic_card_penguin + ) + } + + private fun ConstraintLayout.addTextView( + context: Context, + id: Int, + text: String? = "", + textColor: Int = R.color.grey_50, + textSizeSp: Float, + fontFamily: Int, + lineHeightDp: Int, + marginTop: Int = 0, + marginBottom: Int = 0, + marginStart: Int = 0, + marginEnd: Int = 0, + paddingStart: Int = 0, + paddingEnd: Int = 0, + paddingTop: Int = 0, + paddingBottom: Int = 0, + topToTopOf: Int? = null, + topToBottomOf: Int? = null, + bottomToTopOf: Int? = null, + bottomToBottomOf: Int? = null, + startToStartOf: Int? = null, + startToEndOf: Int? = null, + endToEndOf: Int? = null, + endToStartOf: Int? = null, + background: Int? = null + ) { + val textView = TextView(context).apply { + this.id = id + layoutParams = ConstraintLayout.LayoutParams( + ConstraintLayout.LayoutParams.MATCH_CONSTRAINT, + ConstraintLayout.LayoutParams.WRAP_CONTENT + ).apply { + topToTopOf?.let { topToTop = it } + topToBottomOf?.let { topToBottom = it } + bottomToTopOf?.let { bottomToTop = it } + bottomToBottomOf?.let { bottomToBottom = it } + startToStartOf?.let { startToStart = it } + startToEndOf?.let { startToEnd = it } + endToEndOf?.let { endToEnd = it } + endToStartOf?.let { endToStart = it } + + this.topMargin = marginTop.dpToPx(context) + this.bottomMargin = marginBottom.dpToPx(context) + this.marginStart = marginStart.dpToPx(context) + this.marginEnd = marginEnd.dpToPx(context) + } + this.text = text + setTextColor(ContextCompat.getColor(context, textColor)) + setTextSize(TypedValue.COMPLEX_UNIT_SP, textSizeSp) + this.lineHeight = lineHeightDp.dpToPx(context) + letterSpacing = 0f + typeface = ResourcesCompat.getFont(context, fontFamily) + setPadding( + paddingStart.dpToPx(context), + paddingTop.dpToPx(context), + paddingEnd.dpToPx(context), + paddingBottom.dpToPx(context) + ) + background?.let { setBackgroundResource(it) } + } + addView(textView) + } + + private fun ConstraintLayout.addImageView(context: Context, id: Int, drawableRes: Int) { + val imageView = ImageView(context).apply { + this.id = id + layoutParams = + ConstraintLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT) + .apply { + bottomToBottom = matchParent + endToEnd = matchParent + } + setImageResource(drawableRes) + } + addView(imageView) + } + + companion object { + const val clCardFront = 0 + const val tvName = 1 + const val tvCompany = 2 + const val tvJob = 3 + const val tvLevel = 4 + const val tvArea = 5 + const val tvMbti = 6 + const val tvCharacter = 7 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/teumteum/teumteum/util/custom/view/model/FrontCard.kt b/app/src/main/java/com/teumteum/teumteum/util/custom/view/model/FrontCard.kt new file mode 100644 index 00000000..c9fa992c --- /dev/null +++ b/app/src/main/java/com/teumteum/teumteum/util/custom/view/model/FrontCard.kt @@ -0,0 +1,13 @@ +package com.teumteum.teumteum.util.custom.view.model + +import com.teumteum.teumteum.R + +data class FrontCard( + var name: String = "디프만", + var company: String = "@직장,학교명", + var job: String = "직무명", + var level: String = "lv.3층", + var area: String = "선택 지역에 사는", + var mbti: String = "MBTI", + var characterResId: Int = R.drawable.ic_card_penguin +) diff --git a/app/src/main/res/layout/fragment_teum_teum.xml b/app/src/main/res/layout/fragment_teum_teum.xml index e555f4fa..18b7e9a8 100644 --- a/app/src/main/res/layout/fragment_teum_teum.xml +++ b/app/src/main/res/layout/fragment_teum_teum.xml @@ -7,15 +7,21 @@ - + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 40381765..bccfe7d2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -13,4 +13,10 @@ 사이드 프로젝트 사이드 프로젝트\n팀을 구해보세요 판교 추천 모임 + MBTI + 선택 지역에 사는 + lv.3층 + 직무명 + \@직장,학교명 + 디프만 \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 5386e8ee..777a329e 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -90,7 +90,6 @@ 30sp 36sp 0 - false @font/pretendard_bold @@ -98,7 +97,6 @@ 28sp 36sp 0 - false @font/pretendard_bold @@ -106,7 +104,6 @@ 24sp 32sp 0 - false @font/pretendard_bold @@ -114,7 +111,6 @@ 20sp 28sp 0 - false @font/pretendard_bold @@ -122,7 +118,6 @@ 18sp 24sp 0 - false @font/pretendard_bold @@ -130,7 +125,6 @@ 16sp 22sp 0 - false @font/pretendard_semibold @@ -138,7 +132,6 @@ 16sp 22sp 0 - false @font/pretendard_medium @@ -146,7 +139,6 @@ 14sp 20sp 0 - false @font/pretendard_semibold @@ -154,35 +146,30 @@ 16sp 24sp -0.5 - false @font/pretendard_regular From 002f5ce0c38a1b8dfb549bdecbabc509971ea2a0 Mon Sep 17 00:00:00 2001 From: MinseoShindor Date: Wed, 10 Jan 2024 22:24:56 +0900 Subject: [PATCH 10/21] =?UTF-8?q?[feat/#24]=20viewmodel=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0=20&=20date-time=20format=20=EC=84=A4=EC=A0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../teumteum/presentation/moim/MoimAddress.kt | 68 ++++++++- .../presentation/moim/MoimCreateName.kt | 6 - .../presentation/moim/MoimCreateTopic.kt | 1 + .../presentation/moim/MoimDateTime.kt | 79 ++++++---- .../presentation/moim/MoimFragment.kt | 5 +- .../presentation/moim/MoimIntroduce.kt | 3 +- .../teumteum/presentation/moim/MoimPeople.kt | 144 ++++++++++++++++++ .../presentation/moim/MoimViewModel.kt | 82 ++++++++++ .../res/drawable-night/ic_system_minus.xml | 10 ++ .../res/drawable-night/ic_system_plus.xml | 10 ++ app/src/main/res/drawable/ic_system_fill.xml | 10 ++ app/src/main/res/drawable/ic_system_minus.xml | 10 ++ app/src/main/res/drawable/ic_system_plus.xml | 10 ++ app/src/main/res/values/strings.xml | 2 + .../compileKotlin/cacheable/last-build.bin | Bin 18 -> 18 bytes .../local-state/build-history.bin | Bin 31 -> 31 bytes .../convention/build/libs/convention.jar | Bin 47184 -> 47184 bytes .../base/component/compose/theme/Color.kt | 2 +- 18 files changed, 397 insertions(+), 45 deletions(-) create mode 100644 app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimPeople.kt create mode 100644 app/src/main/res/drawable-night/ic_system_minus.xml create mode 100644 app/src/main/res/drawable-night/ic_system_plus.xml create mode 100644 app/src/main/res/drawable/ic_system_fill.xml create mode 100644 app/src/main/res/drawable/ic_system_minus.xml create mode 100644 app/src/main/res/drawable/ic_system_plus.xml diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimAddress.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimAddress.kt index 7fd19408..86f8e6bc 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimAddress.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimAddress.kt @@ -7,19 +7,29 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.TextFieldDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import com.teumteum.base.component.compose.TeumDivider import com.teumteum.base.component.compose.TmMarginVerticalSpacer import com.teumteum.base.component.compose.theme.TmTypo import com.teumteum.base.component.compose.theme.TmtmColorPalette import com.teumteum.teumteum.R @Composable -fun MoimAddress() { +fun MoimAddress(viewModel: MoimViewModel) { + val people by viewModel.title.collectAsState() Column( modifier = Modifier .fillMaxSize() @@ -28,12 +38,21 @@ fun MoimAddress() { verticalArrangement = Arrangement.Top, ) { CreateMoimTitle(string = stringResource(id = R.string.moim_address_title)) + TmMarginVerticalSpacer(size = 28) + MoimAddress1Column() + TmMarginVerticalSpacer(size = 20) + MoimAddress2Column() + + TeumDivider() + MoimCreateBtn(text = stringResource(id = R.string.moim_next_btn), isEnabled = people.isNotEmpty() , viewModel = viewModel) + TmMarginVerticalSpacer(size = 24) + } } @Composable -fun MoimAddressColumn() { +fun MoimAddress1Column() { Column(modifier = Modifier .fillMaxWidth() .wrapContentHeight() @@ -45,5 +64,50 @@ fun MoimAddressColumn() { color = TmtmColorPalette.current.color_text_body_quaternary ) TmMarginVerticalSpacer(size = 8) + MoimAddressInputField(placeHolder = stringResource(id = R.string.moim_address_placeholdler1)) } +} + +@Composable +fun MoimAddress2Column() { + Column(modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(horizontal = 20.dp) + ) { + Text( + text = stringResource(id = R.string.moim_address_label2), + style = TmTypo.current.Body2, + color = TmtmColorPalette.current.color_text_body_quaternary + ) + TmMarginVerticalSpacer(size = 8) + MoimAddressInputField(placeHolder = stringResource(id = R.string.moim_address_placeholder2)) + } +} + +@Composable +fun MoimAddressInputField( + placeHolder:String, + isTimeField: Boolean = false +) { + var text by remember { mutableStateOf("") } + + OutlinedTextField( + value = text, + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight(), + placeholder = { Text(text =placeHolder, style= TmTypo.current.Body1, color = TmtmColorPalette.current.color_text_body_quinary)}, + onValueChange = { newText -> + text = newText + }, + colors = TextFieldDefaults.outlinedTextFieldColors( + textColor = TmtmColorPalette.current.color_text_body_primary, + focusedBorderColor = TmtmColorPalette.current.elevation_color_elevation_level01, + unfocusedBorderColor = TmtmColorPalette.current.elevation_color_elevation_level01, + unfocusedLabelColor = TmtmColorPalette.current.color_text_body_quinary, + focusedLabelColor = TmtmColorPalette.current.color_text_body_quinary, + backgroundColor = TmtmColorPalette.current.elevation_color_elevation_level01 + ), + ) } \ No newline at end of file diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimCreateName.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimCreateName.kt index df41cec0..be2c321e 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimCreateName.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimCreateName.kt @@ -76,10 +76,4 @@ fun MoimNameTextField(viewModel: MoimViewModel, placeHolder: String) { backgroundColor = TmtmColorPalette.current.elevation_color_elevation_level01 ), ) -} - -@Preview -@Composable -fun preview2() { - MoimDateTime() } \ No newline at end of file diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimCreateTopic.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimCreateTopic.kt index 4fbe86aa..6f580ebb 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimCreateTopic.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimCreateTopic.kt @@ -31,6 +31,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.viewinterop.AndroidView import com.teumteum.base.component.compose.TeumDivider import com.teumteum.base.component.compose.TmMarginVerticalSpacer import com.teumteum.teumteum.R diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimDateTime.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimDateTime.kt index d2d58359..093d267d 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimDateTime.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimDateTime.kt @@ -8,10 +8,13 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.OutlinedTextField import androidx.compose.material.TextFieldDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -19,6 +22,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import com.teumteum.base.component.compose.TeumDivider import com.teumteum.base.component.compose.TmMarginVerticalSpacer @@ -33,7 +37,9 @@ import java.util.Locale @Composable -fun MoimDateTime() { +fun MoimDateTime(viewModel: MoimViewModel) { + val time by viewModel.time.collectAsState() + val date by viewModel.date.collectAsState() Column( modifier = Modifier .fillMaxSize() @@ -43,18 +49,21 @@ fun MoimDateTime() { ) { CreateMoimTitle(string = stringResource(id = R.string.moim_datetime_title)) TmMarginVerticalSpacer(size = 28) - MoimDateColumn() + MoimDateColumn(viewModel) TmMarginVerticalSpacer(size = 20) - MoimTimeColumn() + MoimTimeColumn(viewModel) Spacer(modifier = Modifier.weight(1f)) TeumDivider() -// MoimCreateBtn(text = "다음") + MoimCreateBtn( + text = stringResource(id = R.string.moim_next_btn), + viewModel = viewModel, + isEnabled = time.isNotEmpty() && date.isNotEmpty()) TmMarginVerticalSpacer(size = 24) } } @Composable -fun MoimDateColumn() { +fun MoimDateColumn(viewModel: MoimViewModel) { Column(modifier = Modifier .fillMaxWidth() .wrapContentHeight() @@ -62,13 +71,16 @@ fun MoimDateColumn() { ) { Text(text = stringResource(id = R.string.moim_datetime_label1), style= TmTypo.current.Body2, color= TmtmColorPalette.current.color_text_body_quaternary) TmMarginVerticalSpacer(size = 8) - MoimDateInputField(placeHolder = stringResource(id = R.string.moim_datetime_placeholder1)) + MoimDateInputField( + placeHolder = stringResource(id = R.string.moim_datetime_placeholder1), + viewModel = viewModel + ) } } @Composable -fun MoimTimeColumn() { +fun MoimTimeColumn(viewModel: MoimViewModel) { Column(modifier = Modifier .fillMaxWidth() .wrapContentHeight() @@ -80,25 +92,47 @@ fun MoimTimeColumn() { color = TmtmColorPalette.current.color_text_body_quaternary ) TmMarginVerticalSpacer(size = 8) - MoimDateInputField(placeHolder = stringResource(id = R.string.moim_datetime_placeholder2)) + MoimDateInputField( + placeHolder = stringResource(id = R.string.moim_datetime_placeholder2), + viewModel = viewModel, + isTimeField = true + ) } } @Composable -fun MoimDateInputField(placeHolder:String) { +fun MoimDateInputField( + placeHolder:String, + viewModel: MoimViewModel, + isTimeField: Boolean = false +) { var text by remember { mutableStateOf("") } - var dayOfWeek by remember { mutableStateOf(null) } + val time by viewModel.time.collectAsState() + val date by viewModel.date.collectAsState() + + LaunchedEffect(isTimeField, time, date) { + text = if (isTimeField) time else date + } OutlinedTextField( value = text, modifier = Modifier .fillMaxWidth() .wrapContentHeight(), + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Number + ), placeholder = { Text(text =placeHolder, style= TmTypo.current.Body1, color = TmtmColorPalette.current.color_text_body_quinary)}, onValueChange = { newText -> text = newText - dayOfWeek = formatDate(newText) - }, + if (newText.length == 4) { + if (isTimeField) { + viewModel.updateTime(newText) + } else { + viewModel.updateDate(newText) + } + } + }, colors = TextFieldDefaults.outlinedTextFieldColors( textColor = TmtmColorPalette.current.color_text_body_primary, focusedBorderColor = TmtmColorPalette.current.elevation_color_elevation_level01, @@ -108,25 +142,4 @@ fun MoimDateInputField(placeHolder:String) { backgroundColor = TmtmColorPalette.current.elevation_color_elevation_level01 ), ) - if (dayOfWeek != null) { - Text(text = "$text $dayOfWeek", style=TmTypo.current.Body1, color = TmtmColorPalette.current.color_text_body_primary) - } } - -fun formatTime(input: String): String? { - return try { - val localTime = LocalTime.parse(input, DateTimeFormatter.ofPattern("HHmm")) - localTime.format(DateTimeFormatter.ofPattern("hh:mm a")) - } catch (e: Exception) { - null - } -} - -fun formatDate(input: String): String? { - return try { - val parsedDate = LocalDate.parse(input, DateTimeFormatter.ofPattern("MM월 dd일")) - parsedDate.dayOfWeek.getDisplayName(TextStyle.FULL, Locale.getDefault()) - } catch (e: Exception) { - null - } -} \ No newline at end of file diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimFragment.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimFragment.kt index d4e7d894..ebfb642a 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimFragment.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimFragment.kt @@ -35,8 +35,9 @@ class MoimFragment : ScreenState.Topic -> MoimCreateTopic(viewModel) ScreenState.Name -> MoimCreateName(viewModel) ScreenState.Introduce -> MoimIntroduce(viewModel) - ScreenState.DateTime -> MoimDateTime() - ScreenState.Address -> MoimAddress() + ScreenState.DateTime -> MoimDateTime(viewModel) + ScreenState.Address -> MoimAddress(viewModel) + ScreenState.People -> MoimPeople(viewModel) else -> {} } } diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimIntroduce.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimIntroduce.kt index 4c8aa2c2..f46ddca9 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimIntroduce.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimIntroduce.kt @@ -48,6 +48,7 @@ import com.teumteum.base.component.compose.theme.TmtmColorPalette @Composable fun MoimIntroduce(viewModel: MoimViewModel) { val introduce by viewModel.introduction.collectAsState() + val photo by viewModel.imageUri.collectAsState() Column( modifier = Modifier .fillMaxSize() @@ -66,7 +67,7 @@ fun MoimIntroduce(viewModel: MoimViewModel) { MoimPhotoColumn(viewModel) Spacer(modifier = Modifier.weight(1f)) TeumDivider() - MoimCreateBtn(text = stringResource(id = R.string.moim_next_btn), viewModel = viewModel, isEnabled = introduce.isNotEmpty()) + MoimCreateBtn(text = stringResource(id = R.string.moim_next_btn), viewModel = viewModel, isEnabled = introduce.isNotEmpty() && photo.isNotEmpty()) } } diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimPeople.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimPeople.kt new file mode 100644 index 00000000..e376f072 --- /dev/null +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimPeople.kt @@ -0,0 +1,144 @@ +package com.teumteum.teumteum.presentation.moim + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +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.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.modifier.modifierLocalMapOf +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.teumteum.base.component.compose.TeumDivider +import com.teumteum.base.component.compose.TmMarginHorizontalSpacer +import com.teumteum.base.component.compose.TmMarginVerticalSpacer +import com.teumteum.base.component.compose.theme.TmTypo +import com.teumteum.base.component.compose.theme.TmtmColorPalette +import com.teumteum.teumteum.R + +@Composable +fun MoimPeople(viewModel: MoimViewModel) { + val people by viewModel.people.collectAsState() + Column( + modifier = Modifier + .fillMaxSize() + .background(color = TmtmColorPalette.current.GreyWhite), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Top, + ) { + CreateMoimTitle(string = stringResource(id = R.string.moim_people_title)) + TmMarginVerticalSpacer(size = 28) + + PeopleContent(viewModel) + TmMarginVerticalSpacer(size = 39) + PeopleSystemText() + + Spacer(modifier= Modifier.weight(1f)) + TeumDivider() + MoimCreateBtn(text = stringResource(id = R.string.moim_next_btn), isEnabled = people in 3..6, viewModel = viewModel) + TmMarginVerticalSpacer(size = 24) + } +} + +@Composable +fun PeopleContent( + viewModel: MoimViewModel +) { + val people by viewModel.people.collectAsState() + Row(modifier = Modifier + .width(181.dp) + .wrapContentHeight(), + horizontalArrangement = Arrangement.spacedBy(20.dp, Alignment.Start), + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(id = R.drawable.ic_system_minus), + contentDescription = "image description", + contentScale = ContentScale.None, + modifier = Modifier.clickable { + viewModel.downPeople() + } + ) + + Box(modifier = Modifier + .width(77.dp) + .height(80.dp) + .background( + color = TmtmColorPalette.current.elevation_color_elevation_level01, + shape = RoundedCornerShape(8.dp) + ) + .padding(horizontal = 10.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "${people}명", + style= TmTypo.current.HeadLine2, + color= TmtmColorPalette.current.color_text_button_secondary_default, + modifier = Modifier.align(Alignment.Center) + ) + } + + Image( + painter = painterResource(id = R.drawable.ic_system_plus), + contentDescription = "image description", + contentScale = ContentScale.None, + modifier = Modifier.clickable { + viewModel.upPeople() + } + ) + } +} + +@Composable +fun PeopleSystemText() { + Box(modifier = Modifier + .fillMaxWidth() + .height(64.dp) + .padding(horizontal = 20.dp) + .background( + color = TmtmColorPalette.current.elevation_color_elevation_level01, + shape = RoundedCornerShape(8.dp) + ) + ) { + Row(modifier = Modifier + .fillMaxWidth() + .fillMaxHeight() + .padding(horizontal = 16.dp), + horizontalArrangement = Arrangement.Start, + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(id = R.drawable.ic_system_fill), + contentDescription =null, + modifier = Modifier.padding(vertical =0.dp) + ) + TmMarginHorizontalSpacer(size = 6) + Text( + text = stringResource(id = R.string.moim_peoople_system), + style= TmTypo.current.Body3, + color = TmtmColorPalette.current.color_text_caption_teritary_default, + modifier = Modifier + .width(202.dp) + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimViewModel.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimViewModel.kt index 4961e2f2..d8c18e8a 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimViewModel.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimViewModel.kt @@ -9,6 +9,13 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalTime +import java.time.Year +import java.time.format.DateTimeFormatter +import java.time.format.TextStyle +import java.util.Locale import javax.inject.Inject @HiltViewModel @@ -34,6 +41,16 @@ class MoimViewModel @Inject constructor( private val _imageUri = MutableStateFlow>(emptyList()) val imageUri: StateFlow> = _imageUri.asStateFlow() + private val _date = MutableStateFlow("") + val date : StateFlow = _date.asStateFlow() + + private val _time = MutableStateFlow("") + val time : StateFlow = _time.asStateFlow() + + private val _people = MutableStateFlow(2) + val people: StateFlow = _people.asStateFlow() + + fun updateTopic(topicType: TopicType) { _topic.value = topicType } @@ -46,6 +63,31 @@ class MoimViewModel @Inject constructor( _introduction.value = introduce } + fun updateDate(input: String) { + if (input.length == 4) { + _date.value = formatDateAndDay(input) + } + } + + fun updateTime(input: String): String { + val formattedTime = formatTime(input) + _time.value = formattedTime + return formattedTime + } + + + fun upPeople() { + if(_people.value < 6) { + _people.value +=1 + } + } + + fun downPeople() { + if(_people.value > 1) { + _people.value -=1 + } + } + fun addImages(uris: List, context: Context) { val currentList = _imageUri.value.toMutableList() for (uri in uris) { @@ -56,6 +98,45 @@ class MoimViewModel @Inject constructor( } _imageUri.value = currentList.take(5) } + + + fun formatTime(input: String): String { + return try { + val parsedTime = LocalTime.parse(input, DateTimeFormatter.ofPattern("HHmm")) + parsedTime.format(DateTimeFormatter.ofPattern("hh:mm a", Locale.getDefault())) + } catch (e: Exception) { + input // 실패시 원본 입력 반환 + } + } + + fun formatDateAndDay(input: String): String { + return try { + val currentYear = Year.now().value + val parsedDate = LocalDate.parse("$currentYear$input", DateTimeFormatter.ofPattern("yyyyMMdd")) + val formattedDate = parsedDate.format(DateTimeFormatter.ofPattern("MM월 dd일")) + val dayOfWeek = parsedDate.dayOfWeek.getDisplayName(TextStyle.FULL, Locale.KOREAN) + "$formattedDate $dayOfWeek" + } catch (e: Exception) { + input // 실패시 원본 입력 반환 + } + } + + fun dateTimeToServer(): Pair? { + return try { + // 날짜 format - "yyyy-MM-dd" + val localDate = LocalDate.parse(date.value, DateTimeFormatter.ofPattern("yyyy-MM-dd")) + val formattedDate = localDate.format(DateTimeFormatter.ISO_LOCAL_DATE) + + // 시간 format - "HH:mm:ss" + val localTime = LocalTime.parse(time.value, DateTimeFormatter.ofPattern("HH:mm")) + val formattedTime = localTime.format(DateTimeFormatter.ISO_LOCAL_TIME) + + Pair(formattedDate, formattedTime) + } catch (e: Exception) { + null + } + } + fun goToNextScreen() { _screenState.value = when(_screenState.value) { @@ -63,6 +144,7 @@ class MoimViewModel @Inject constructor( ScreenState.Name -> ScreenState.Introduce ScreenState.Introduce -> ScreenState.DateTime ScreenState.DateTime -> ScreenState.Address + ScreenState.Address -> ScreenState.People else -> ScreenState.Create } goToNextStep() diff --git a/app/src/main/res/drawable-night/ic_system_minus.xml b/app/src/main/res/drawable-night/ic_system_minus.xml new file mode 100644 index 00000000..f613b68b --- /dev/null +++ b/app/src/main/res/drawable-night/ic_system_minus.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable-night/ic_system_plus.xml b/app/src/main/res/drawable-night/ic_system_plus.xml new file mode 100644 index 00000000..0f2a7ae7 --- /dev/null +++ b/app/src/main/res/drawable-night/ic_system_plus.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_system_fill.xml b/app/src/main/res/drawable/ic_system_fill.xml new file mode 100644 index 00000000..e66c9666 --- /dev/null +++ b/app/src/main/res/drawable/ic_system_fill.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_system_minus.xml b/app/src/main/res/drawable/ic_system_minus.xml new file mode 100644 index 00000000..8eb3802c --- /dev/null +++ b/app/src/main/res/drawable/ic_system_minus.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_system_plus.xml b/app/src/main/res/drawable/ic_system_plus.xml new file mode 100644 index 00000000..16cf7286 --- /dev/null +++ b/app/src/main/res/drawable/ic_system_plus.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0e841595..b055a023 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -42,6 +42,7 @@ 모임 일정을 정해주세요 도로명 주소 + 상세 주소 도로명 주소를 입력해 주세요 상세 주소를 입력해 주세요 @@ -49,4 +50,5 @@ 안전한 모임을 위해 최소 3명 이상 최대 6명 참여자가 필요해요 Hello blank fragment + \ No newline at end of file diff --git a/build-logic/convention/build/kotlin/compileKotlin/cacheable/last-build.bin b/build-logic/convention/build/kotlin/compileKotlin/cacheable/last-build.bin index 9572bc2966f615139491f36c25f8a5c98aa3dfc9..cb426538558c895bacf2398e4ec87cd832d10abe 100644 GIT binary patch literal 18 YcmZ4UmVvdLhk=2y=ab>1*$hAc06BmKPXGV_ literal 18 YcmZ4UmVvdLhk=2y=gC#IpA0|%06O{whX4Qo diff --git a/build-logic/convention/build/kotlin/compileKotlin/local-state/build-history.bin b/build-logic/convention/build/kotlin/compileKotlin/local-state/build-history.bin index 9845d8506102ca510e5e86ca67c9dcb10a067e15..b15fcf463097f43f5401ce1771e627a139c16a98 100644 GIT binary patch literal 31 dcmZ4UmVvcgk^ur385kIQJ{dlm4dpX1003rx1zi9D literal 31 dcmZ4UmVvcgk^ur385kIQo?KP?3FR{|003zb1(g5* diff --git a/build-logic/convention/build/libs/convention.jar b/build-logic/convention/build/libs/convention.jar index 5e39bb402e7d692ee9ba1f3f8fff4917a76718fa..da913212cc8806c44aa5c0531ff6f4cb7e574842 100644 GIT binary patch delta 938 zcmXZaT}V@57zgle=cL2hF2WVKG`(4@)?-FTMBCXQccXE8L zLZMbGW;;u+YYd!3WgRz@p{odZOTe273ARL81+B_z*sHX_SIQldV!rApk3g4woI}u^ zbCfDywf{J7Dl?N_`b;IY*aIC_u%yn2QSCAxjgIGir;o!00gQ^xMOV;bpNdn`EPG)n zmK47ks?ZRPrGMpM?erqFG?gK$JTw(hFkStb&Yj$9qZyrbih>_D6SdaWCuk+V_gxmw z`M5tyt-*s^=$!Y5pYz(x_NKfi;TAKmQ0Uam?ldyvs%&wt)j~t1j^z|soJsoLaAuY& zIUP|7CN7mx>sRMX+B(_QLtE{A9-8?*Am56c)za|%;A3iqZr#Y@-ezv2W~c&o4D~?X zbrmvKH`Kd(rKe?HcR5VDH*?Z077AM7!`t3_ zu*P=*KJv9oPs}#>O~?xcJ-g=5MeOmLVaneE>jGpX;6T1IXoshRv~wc39{ED>0Bj5$ zg5$FKVX9x0{UB=&H)HOm>_Ye~@{=Ry;FpnlxG94FIqQowAfJoS-m?4qkPpbt%WfN` z-+ov2&*&-4oec9XgeI1HH^{SxW-yh*Tk%Nlm5)zw8d5QDXn(2dUB%?C5+{iLnEo(30(Mopy6E!y76EK3M1q)jB3j)+SR`i`(qs1Y#%FU&hQDUFUGT8gf zRE9m@Of|H}QvO#7R!q)8Nmm`AmHXCW3MOkm)43BHoYW&Y-cj(wX{FN2#uSa@cf8KS zIq&zxsWh-}J)QIBz*Am7d)-|{kD@I$p5p{9b9pSxvNT_wYPC~SxqBf6c2Ao2n@)bD zm4fy-1>+YgsPya7bDBEQ(M3~TJrec&?o(dH$Lgthdf*|IA~&w(X%_KjRySA$+XuTK z@4W(uQK8J_wwKtAkcpA{yA$U?E~DXoHzx3v39Hv5*`2lCTS&2-D2*@G9gp;k~davLB8q z8ir{7yy9C$TeKN{*A-`?r;r~TJ_ElDH^Q|s{O7DEwiEeOjOJF{-Hp6YaawWX2;Kd* z;-8V@=sPO6!Hn#Lm2rB5Aw| Date: Wed, 10 Jan 2024 23:11:15 +0900 Subject: [PATCH 11/21] =?UTF-8?q?[feat/#24]=20WebView=20=EB=8F=84=EB=A1=9C?= =?UTF-8?q?=EB=AA=85=EC=A3=BC=EC=86=8C=20API=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/teumteum/teumteum/WebviewFragment.kt | 24 ++++++++ .../com/teumteum/teumteum/di/NetworkStatus.kt | 22 +++++++ .../teumteum/presentation/moim/MoimAddress.kt | 11 +++- .../presentation/moim/MoimFragment.kt | 11 ++++ .../presentation/moim/MoimViewModel.kt | 8 ++- .../drawable/ic_baseline_arrow_back_24.xml | 5 ++ app/src/main/res/layout/fragment_moim.xml | 3 +- app/src/main/res/layout/fragment_webview.xml | 59 +++++++++++++++++++ app/src/main/res/values/strings.xml | 2 + 9 files changed, 138 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/com/teumteum/teumteum/WebviewFragment.kt create mode 100644 app/src/main/java/com/teumteum/teumteum/di/NetworkStatus.kt create mode 100644 app/src/main/res/drawable/ic_baseline_arrow_back_24.xml create mode 100644 app/src/main/res/layout/fragment_webview.xml diff --git a/app/src/main/java/com/teumteum/teumteum/WebviewFragment.kt b/app/src/main/java/com/teumteum/teumteum/WebviewFragment.kt new file mode 100644 index 00000000..36d4fa1c --- /dev/null +++ b/app/src/main/java/com/teumteum/teumteum/WebviewFragment.kt @@ -0,0 +1,24 @@ +package com.teumteum.teumteum + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.lifecycle.lifecycleScope +import com.teumteum.base.BindingFragment +import com.teumteum.teumteum.databinding.FragmentWebviewBinding + + +class WebviewFragment : + BindingFragment(R.layout.fragment_webview){ + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + } + + companion object { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/teumteum/teumteum/di/NetworkStatus.kt b/app/src/main/java/com/teumteum/teumteum/di/NetworkStatus.kt new file mode 100644 index 00000000..4ddac28a --- /dev/null +++ b/app/src/main/java/com/teumteum/teumteum/di/NetworkStatus.kt @@ -0,0 +1,22 @@ +package com.teumteum.teumteum.di + +import android.content.Context +import android.net.ConnectivityManager +import android.net.NetworkInfo + +object NetworkStatus { + const val TYPE_WIFI = 1 + const val TYPE_MOBILE = 2 + const val TYPE_NOT_CONNECTED = 3 + + fun getConnectivityStatus(context: Context): Int { + val manager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val networkInfo: NetworkInfo? = manager.activeNetworkInfo + + return when { + networkInfo?.type == ConnectivityManager.TYPE_MOBILE -> TYPE_MOBILE + networkInfo?.type == ConnectivityManager.TYPE_WIFI -> TYPE_WIFI + else -> TYPE_NOT_CONNECTED + } + } +} diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimAddress.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimAddress.kt index 86f8e6bc..11f51521 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimAddress.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimAddress.kt @@ -1,6 +1,8 @@ package com.teumteum.teumteum.presentation.moim +import android.content.Context import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize @@ -11,7 +13,6 @@ import androidx.compose.material.OutlinedTextField import androidx.compose.material.TextFieldDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -19,6 +20,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.teumteum.base.component.compose.TeumDivider @@ -88,7 +90,7 @@ fun MoimAddress2Column() { @Composable fun MoimAddressInputField( placeHolder:String, - isTimeField: Boolean = false + context: Context = LocalContext.current ) { var text by remember { mutableStateOf("") } @@ -96,7 +98,10 @@ fun MoimAddressInputField( value = text, modifier = Modifier .fillMaxWidth() - .wrapContentHeight(), + .wrapContentHeight() + .clickable { + + }, placeholder = { Text(text =placeHolder, style= TmTypo.current.Body1, color = TmtmColorPalette.current.color_text_body_quinary)}, onValueChange = { newText -> text = newText diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimFragment.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimFragment.kt index ebfb642a..6ceddae8 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimFragment.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimFragment.kt @@ -6,7 +6,9 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Toast import androidx.activity.OnBackPressedCallback +import androidx.compose.material.Snackbar import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.fragment.app.viewModels @@ -14,6 +16,7 @@ import androidx.lifecycle.lifecycleScope import com.teumteum.base.BindingFragment import com.teumteum.teumteum.R import com.teumteum.teumteum.databinding.FragmentMoimBinding +import com.teumteum.teumteum.di.NetworkStatus import java.util.concurrent.TimeUnit @@ -56,6 +59,14 @@ class MoimFragment : .setDuration(500) .start() } + + private fun goToWebFragment() { + val status = NetworkStatus.getConnectivityStatus(requireContext()) + if (status == NetworkStatus.TYPE_MOBILE || status == NetworkStatus.TYPE_WIFI) { + } else { + Toast.makeText(context, "인터넷 연결을 확인해주세요.", Toast.LENGTH_SHORT).show() + } + } companion object { } diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimViewModel.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimViewModel.kt index d8c18e8a..3634a271 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimViewModel.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimViewModel.kt @@ -145,7 +145,8 @@ class MoimViewModel @Inject constructor( ScreenState.Introduce -> ScreenState.DateTime ScreenState.DateTime -> ScreenState.Address ScreenState.Address -> ScreenState.People - else -> ScreenState.Create + ScreenState.People -> ScreenState.Create + else -> ScreenState.Webview } goToNextStep() Log.d("currentStep", _currentStep.value.toString()) @@ -158,7 +159,8 @@ class MoimViewModel @Inject constructor( ScreenState.Address -> ScreenState.DateTime ScreenState.DateTime -> ScreenState.Introduce ScreenState.Introduce -> ScreenState.Name - else -> ScreenState.Topic + ScreenState.Name -> ScreenState.Topic + else -> ScreenState.Address } goToPreviousStep() } @@ -196,5 +198,5 @@ enum class TopicType(val value: String, val title: String ,val subTitle: String) } enum class ScreenState { - Topic, Name, Introduce, DateTime, Address, People, Create + Topic, Name, Introduce, DateTime, Address, People, Create, Webview } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml b/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml new file mode 100644 index 00000000..e21bb36a --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_moim.xml b/app/src/main/res/layout/fragment_moim.xml index fd9085ef..43aea7aa 100644 --- a/app/src/main/res/layout/fragment_moim.xml +++ b/app/src/main/res/layout/fragment_moim.xml @@ -19,9 +19,10 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b055a023..accd6e18 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -15,6 +15,8 @@ 판교 추천 모임 모임생성으로 이동하는 버튼 + 원래의 프래그먼트로 이동하는 버튼 + 시작하기 나를 대표하는\n소개서를 만들어보세요 틈틈의 소개서 만들기 기능으로\n나를 대표하는 카드를 만들어보세요 From 993953350e1fc6d92915a25d9d408f64f4f55f02 Mon Sep 17 00:00:00 2001 From: MinseoShindor Date: Thu, 11 Jan 2024 00:33:40 +0900 Subject: [PATCH 12/21] =?UTF-8?q?[feat/#24]=20Navigation(MainActivity)=20?= =?UTF-8?q?=EC=A0=84=EB=A9=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../teumteum/presentation/MainActivity.kt | 48 ++----------- .../presentation/home/HomeFragment.kt | 8 +-- .../presentation/moim/MoimFragment.kt | 20 ++++-- .../presentation/moim/MoimViewModel.kt | 8 ++- .../util/custom/view/FrontCardView.kt | 44 ++++++------ app/src/main/res/layout/activity_main.xml | 5 +- app/src/main/res/layout/fragment_webview.xml | 2 - app/src/main/res/navigation/nav_graph.xml | 66 ++++++++++++++++++ app/src/main/res/values/strings.xml | 6 ++ .../compileKotlin/cacheable/last-build.bin | Bin 18 -> 18 bytes .../local-state/build-history.bin | Bin 31 -> 31 bytes .../convention/build/libs/convention.jar | Bin 47184 -> 47184 bytes 12 files changed, 127 insertions(+), 80 deletions(-) create mode 100644 app/src/main/res/navigation/nav_graph.xml diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/MainActivity.kt b/app/src/main/java/com/teumteum/teumteum/presentation/MainActivity.kt index 7fa70777..f8838e84 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/MainActivity.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/MainActivity.kt @@ -2,37 +2,22 @@ package com.teumteum.teumteum.presentation import android.os.Bundle import android.view.View -import androidx.fragment.app.commit -import androidx.lifecycle.VIEW_MODEL_STORE_OWNER_KEY +import androidx.navigation.fragment.NavHostFragment +import androidx.navigation.ui.setupWithNavController import com.teumteum.base.BindingActivity import com.teumteum.teumteum.R import com.teumteum.teumteum.databinding.ActivityMainBinding -import com.teumteum.teumteum.presentation.home.HomeFragment -import com.teumteum.teumteum.presentation.mypage.MyPageFragment -import com.teumteum.teumteum.presentation.teumteum.TeumTeumFragment import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint class MainActivity : BindingActivity(R.layout.activity_main) { + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - initView() - setUpListener() - } - - private fun initView() { - val initialFragment = HomeFragment() - supportFragmentManager.commit { - add(R.id.fl_main, initialFragment) - } - } - - private fun setUpListener() { - binding.btmNavi.setOnItemSelectedListener { - replaceFragment(it.itemId) - true - } + val navHostFragment = supportFragmentManager.findFragmentById(R.id.fl_main) as NavHostFragment + val navController = navHostFragment.navController + binding.btmNavi.setupWithNavController(navController) } fun hideBottomNavi() { @@ -43,24 +28,5 @@ class MainActivity : BindingActivity(R.layout.activity_main binding.btmNavi.visibility = View.VISIBLE } - private fun replaceFragment(menuItemId: Int) { - try { - supportFragmentManager.commit { - replace( - R.id.fl_main, when (menuItemId) { - R.id.bottom_menu_home -> HomeFragment() - R.id.bottom_menu_teum_teum -> TeumTeumFragment() - R.id.bottom_menu_my_page -> MyPageFragment() - else -> throw IllegalArgumentException("${this@MainActivity::class.java.simpleName} unkown menuItemId") - } - ) - } - } catch (e: IllegalArgumentException) { - supportFragmentManager.commit { - replace(R.id.fl_main, HomeFragment()) - } - } - } - companion object {} -} \ No newline at end of file +} diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/home/HomeFragment.kt b/app/src/main/java/com/teumteum/teumteum/presentation/home/HomeFragment.kt index c6bbc4c7..c92a749c 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/home/HomeFragment.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/home/HomeFragment.kt @@ -2,6 +2,7 @@ package com.teumteum.teumteum.presentation.home import android.os.Bundle import android.view.View +import androidx.navigation.fragment.findNavController import com.teumteum.base.BindingFragment import com.teumteum.base.component.appbar.AppBarLayout import com.teumteum.base.component.appbar.AppBarMenu @@ -52,10 +53,7 @@ class HomeFragment : } private fun navigateToMoimFragment() { - (activity as? MainActivity)?.hideBottomNavi() - requireActivity().supportFragmentManager.beginTransaction() - .replace(R.id.fl_main, MoimFragment()) - .addToBackStack(null) - .commit() + findNavController().navigate(R.id.action_homeFragment_to_moimFragment) } + } \ No newline at end of file diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimFragment.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimFragment.kt index 6ceddae8..bfb9c6c4 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimFragment.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimFragment.kt @@ -1,28 +1,30 @@ package com.teumteum.teumteum.presentation.moim import android.animation.ObjectAnimator -import android.database.Observable import android.os.Bundle -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import android.widget.Toast import androidx.activity.OnBackPressedCallback -import androidx.compose.material.Snackbar import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope +import androidx.navigation.fragment.findNavController import com.teumteum.base.BindingFragment import com.teumteum.teumteum.R import com.teumteum.teumteum.databinding.FragmentMoimBinding import com.teumteum.teumteum.di.NetworkStatus -import java.util.concurrent.TimeUnit - +import com.teumteum.teumteum.presentation.MainActivity class MoimFragment : BindingFragment(R.layout.fragment_moim) { private val viewModel: MoimViewModel by viewModels() + + override fun onResume() { + super.onResume() + (activity as MainActivity).hideBottomNavi() + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -49,7 +51,11 @@ class MoimFragment : val callback = object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { - viewModel.goPreviousScreen() + if (viewModel.screenState.value == ScreenState.Topic) { + findNavController().navigate(R.id.action_moimFragment_to_homeFragment) + } else { + viewModel.goPreviousScreen() + } } } diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimViewModel.kt b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimViewModel.kt index 3634a271..2cc9b1cb 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimViewModel.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/moim/MoimViewModel.kt @@ -146,7 +146,7 @@ class MoimViewModel @Inject constructor( ScreenState.DateTime -> ScreenState.Address ScreenState.Address -> ScreenState.People ScreenState.People -> ScreenState.Create - else -> ScreenState.Webview + else -> _screenState.value } goToNextStep() Log.d("currentStep", _currentStep.value.toString()) @@ -160,11 +160,15 @@ class MoimViewModel @Inject constructor( ScreenState.DateTime -> ScreenState.Introduce ScreenState.Introduce -> ScreenState.Name ScreenState.Name -> ScreenState.Topic - else -> ScreenState.Address + else -> _screenState.value } goToPreviousStep() } + fun goBackToHomeScreen() { + + } + fun goToNextStep() { val nextStep = _currentStep.value + 1 _currentStep.value = nextStep.coerceIn(1, 6) diff --git a/app/src/main/java/com/teumteum/teumteum/util/custom/view/FrontCardView.kt b/app/src/main/java/com/teumteum/teumteum/util/custom/view/FrontCardView.kt index 1d34ed86..c94d0b46 100644 --- a/app/src/main/java/com/teumteum/teumteum/util/custom/view/FrontCardView.kt +++ b/app/src/main/java/com/teumteum/teumteum/util/custom/view/FrontCardView.kt @@ -57,7 +57,7 @@ class FrontCardView : CardView { ColorStateList.valueOf( ContextCompat.getColor( context, - R.color.grey_900 + com.teumteum.base.R.color.grey_900 ) ) ) @@ -69,15 +69,15 @@ class FrontCardView : CardView { * 커스텀뷰의 속성 값을 xml에 입력한 값으로 초기화 */ private fun applyXmlAttributes(context: Context, attrs: AttributeSet?) { - context.theme.obtainStyledAttributes(attrs, R.styleable.CardFrontView, 0, 0).apply { + context.theme.obtainStyledAttributes(attrs, com.teumteum.base.R.styleable.CardFrontView, 0, 0).apply { try { - frontCard.name = getString(R.styleable.CardFrontView_name) ?: "" - frontCard.company = getString(R.styleable.CardFrontView_company) ?: "" - frontCard.job = getString(R.styleable.CardFrontView_job) ?: "" - frontCard.level = getString(R.styleable.CardFrontView_level) ?: "" - frontCard.area = getString(R.styleable.CardFrontView_area) ?: "" - frontCard.mbti = getString(R.styleable.CardFrontView_mbti) ?: "" - frontCard.characterResId = getResourceId(R.styleable.CardFrontView_image, 0) + frontCard.name = getString(com.teumteum.base.R.styleable.CardFrontView_name) ?: "" + frontCard.company = getString(com.teumteum.base.R.styleable.CardFrontView_company) ?: "" + frontCard.job = getString(com.teumteum.base.R.styleable.CardFrontView_job) ?: "" + frontCard.level = getString(com.teumteum.base.R.styleable.CardFrontView_level) ?: "" + frontCard.area = getString(com.teumteum.base.R.styleable.CardFrontView_area) ?: "" + frontCard.mbti = getString(com.teumteum.base.R.styleable.CardFrontView_mbti) ?: "" + frontCard.characterResId = getResourceId(com.teumteum.base.R.styleable.CardFrontView_image, 0) } finally { recycle() } @@ -117,9 +117,9 @@ class FrontCardView : CardView { context, id = tvName, text = context.getString(R.string.front_card_name), - textColor = R.color.grey_50, + textColor = com.teumteum.base.R.color.grey_50, textSizeSp = 30f, - fontFamily = R.font.pretendard_bold, + fontFamily = com.teumteum.base.R.font.pretendard_bold, lineHeightDp = 36, topToTopOf = matchParent, startToStartOf = matchParent, @@ -130,9 +130,9 @@ class FrontCardView : CardView { context, id = tvCompany, text = context.getString(R.string.front_card_company), - textColor = R.color.grey_400, + textColor = com.teumteum.base.R.color.grey_400, textSizeSp = 16f, - fontFamily = R.font.pretendard_semibold, + fontFamily = com.teumteum.base.R.font.pretendard_semibold, lineHeightDp = 22, startToStartOf = tvName, marginTop = 20, @@ -142,9 +142,9 @@ class FrontCardView : CardView { context, id = tvJob, text = context.getString(R.string.front_card_job), - textColor = R.color.grey_50, + textColor = com.teumteum.base.R.color.grey_50, textSizeSp = 18f, - fontFamily = R.font.pretendard_bold, + fontFamily = com.teumteum.base.R.font.pretendard_bold, lineHeightDp = 24, startToStartOf = tvName, marginTop = 6, @@ -154,9 +154,9 @@ class FrontCardView : CardView { context, id = tvLevel, text = context.getString(R.string.front_card_level), - textColor = R.color.grey_300, + textColor = com.teumteum.base.R.color.grey_300, textSizeSp = 12f, - fontFamily = R.font.pretendard_regular, + fontFamily = com.teumteum.base.R.font.pretendard_regular, lineHeightDp = 18, marginTop = 6, paddingStart = 8, @@ -171,9 +171,9 @@ class FrontCardView : CardView { context, id = tvArea, text = context.getString(R.string.front_card_area), - textColor = R.color.grey_400, + textColor = com.teumteum.base.R.color.grey_400, textSizeSp = 12f, - fontFamily = R.font.pretendard_regular, + fontFamily = com.teumteum.base.R.font.pretendard_regular, lineHeightDp = 18, marginTop = 6, startToStartOf = tvName, @@ -183,9 +183,9 @@ class FrontCardView : CardView { context, id = tvMbti, text = context.getString(R.string.front_card_mbti), - textColor = R.color.grey_50, + textColor = com.teumteum.base.R.color.grey_50, textSizeSp = 20f, - fontFamily = R.font.pretendard_bold, + fontFamily = com.teumteum.base.R.font.pretendard_bold, lineHeightDp = 28, marginBottom = 32, startToStartOf = tvName, @@ -202,7 +202,7 @@ class FrontCardView : CardView { context: Context, id: Int, text: String? = "", - textColor: Int = R.color.grey_50, + textColor: Int = com.teumteum.base.R.color.grey_50, textSizeSp: Float, fontFamily: Int, lineHeightDp: Int, diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 513388d7..fa6c96be 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -12,12 +12,15 @@ android:layout_height="match_parent" tools:context=".presentation.MainActivity"> - diff --git a/app/src/main/res/layout/fragment_webview.xml b/app/src/main/res/layout/fragment_webview.xml index 8ed623da..b725f0f7 100644 --- a/app/src/main/res/layout/fragment_webview.xml +++ b/app/src/main/res/layout/fragment_webview.xml @@ -7,8 +7,6 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index eae75378..0ad5c21d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -36,6 +36,12 @@ 최대 5장 1장 이상의 사진을 필수로 등록해주세요. + 모임 일정을 정해주세요 + 날짜 + 시간 + 00월 00일 + 오후 00시 + 모임 일정을 정해주세요 도로명 주소 상세 주소 diff --git a/build-logic/convention/build/kotlin/compileKotlin/cacheable/last-build.bin b/build-logic/convention/build/kotlin/compileKotlin/cacheable/last-build.bin index cb426538558c895bacf2398e4ec87cd832d10abe..2bccdb55f776d18bc9827fb7928179fbf1054fec 100644 GIT binary patch literal 18 YcmZ4UmVvdLhk=2y=kpuoLkvIw06Ojka{vGU literal 18 YcmZ4UmVvdLhk=2y=ab>1*$hAc06BmKPXGV_ diff --git a/build-logic/convention/build/kotlin/compileKotlin/local-state/build-history.bin b/build-logic/convention/build/kotlin/compileKotlin/local-state/build-history.bin index b15fcf463097f43f5401ce1771e627a139c16a98..d4db701c81cc731ddf3b8a3907405a046e304258 100644 GIT binary patch literal 31 dcmZ4UmVvcgk^ur385kIQKEF{u1m!a@003yA1%Utn literal 31 dcmZ4UmVvcgk^ur385kIQJ{dlm4dpX1003rx1zi9D diff --git a/build-logic/convention/build/libs/convention.jar b/build-logic/convention/build/libs/convention.jar index da913212cc8806c44aa5c0531ff6f4cb7e574842..dc47069567f4b414074efa2940b4cb4115a149a6 100644 GIT binary patch delta 938 zcmXZaUr1AN6bJBocW*kZ?IB!&OVbB$;TVRH28jlktFHF33Bddh&W0=%luAueKTppC7A{j3$fV7KIyi&Z~)1iJjg z9D?40gS7Hh`;S&Ki=U{l>7EWF#FWm6R_zi$wN4g&r`AYG5Up~1*(H?3PvvRseI}G+ z&o`ll_81L+m01> zcZ^EId+X_(H~XLR+U)1H6+Mb{Sa^ofsYQp&C>mGf%d?$UYBD&NQebtZXuojcBdrv4 z$0(ROUrD837oXGA>7G8C>KKry=l76uD;}|tn&*ZeQYn1nS{`T0K1;($HS8YggS`7P z6y3d0@9EDyt?2Vq!IWnMZn4z63U2qVhlAcm_|m%>7E9ZpQ`!L^ORaF3?*hE(y8|2i zXW;|?DY!0RhNWJ;cqLGXSPEERI?w@|f@C!4M7})afX72Lb1JkJ`Fv;(Yz^;&lZyIL zT0f`wR?!k^N8feD`N&D+N5@XXFJsNHHj4jT9Ei3cpN-Po%DcOe4=K(mZW^a=zpeOZ z{22O<$Xzfk+hJ9V?qF0=n4r6HPjsTLiQDidgW0?3imya`D}D$rOps?12atbAxc&pE Co)+c+ delta 938 zcmXZaT}V@57zgle=cL2hF2WVKG`(4@)?-FTMBCXQccXE8L zLZMbGW;;u+YYd!3WgRz@p{odZOTe273ARL81+B_z*sHX_SIQldV!rApk3g4woI}u^ zbCfDywf{J7Dl?N_`b;IY*aIC_u%yn2QSCAxjgIGir;o!00gQ^xMOV;bpNdn`EPG)n zmK47ks?ZRPrGMpM?erqFG?gK$JTw(hFkStb&Yj$9qZyrbih>_D6SdaWCuk+V_gxmw z`M5tyt-*s^=$!Y5pYz(x_NKfi;TAKmQ0Uam?ldyvs%&wt)j~t1j^z|soJsoLaAuY& zIUP|7CN7mx>sRMX+B(_QLtE{A9-8?*Am56c)za|%;A3iqZr#Y@-ezv2W~c&o4D~?X zbrmvKH`Kd(rKe?HcR5VDH*?Z077AM7!`t3_ zu*P=*KJv9oPs}#>O~?xcJ-g=5MeOmLVaneE>jGpX;6T1IXoshRv~wc39{ED>0Bj5$ zg5$FKVX9x0{UB=&H)HOm>_Ye~@{=Ry;FpnlxG94FIqQowAfJoS-m?4qkPpbt%WfN` z-+ov2&*&-4oec9XgeI1HH^{SxW-yh*Tk%Nlm5)zw8d5 Date: Thu, 11 Jan 2024 01:29:38 +0900 Subject: [PATCH 13/21] =?UTF-8?q?[feat/#24]=20Navigation=20BottomNavi=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../teumteum/presentation/MainActivity.kt | 1 + app/src/main/res/menu/main_bottom_menu.xml | 6 +-- app/src/main/res/navigation/nav_graph.xml | 48 +++++++++--------- .../compileKotlin/cacheable/last-build.bin | Bin 18 -> 18 bytes .../local-state/build-history.bin | Bin 31 -> 31 bytes .../convention/build/libs/convention.jar | Bin 47184 -> 47184 bytes 6 files changed, 28 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/MainActivity.kt b/app/src/main/java/com/teumteum/teumteum/presentation/MainActivity.kt index f8838e84..3c7354aa 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/MainActivity.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/MainActivity.kt @@ -3,6 +3,7 @@ package com.teumteum.teumteum.presentation import android.os.Bundle import android.view.View import androidx.navigation.fragment.NavHostFragment +import androidx.navigation.ui.NavigationUI import androidx.navigation.ui.setupWithNavController import com.teumteum.base.BindingActivity import com.teumteum.teumteum.R diff --git a/app/src/main/res/menu/main_bottom_menu.xml b/app/src/main/res/menu/main_bottom_menu.xml index f47f4457..71f5406e 100644 --- a/app/src/main/res/menu/main_bottom_menu.xml +++ b/app/src/main/res/menu/main_bottom_menu.xml @@ -2,19 +2,19 @@ - + app:startDestination="@id/fragment_home"> + android:label="HomeFragment"> + app:destination="@id/fragment_moim" /> + android:id="@+id/action_homeFragment_to_fragment_my_page" + app:destination="@id/fragment_my_page" /> + android:id="@+id/action_homeFragment_to_fragment_teum_teum" + app:destination="@id/fragment_teum_teum" /> + android:label="MoimFragment" + tools:layout="@layout/fragment_moim"> + app:destination="@id/fragment_web_view" /> - + app:destination="@id/fragment_home" /> + app:destination="@id/fragment_moim" /> + android:label="TeumTeumFragment" + tools:layout="@layout/fragment_teum_teum"/> + android:label="MyPageFragment" + tools:layout="@layout/fragment_my_page"/> \ No newline at end of file diff --git a/build-logic/convention/build/kotlin/compileKotlin/cacheable/last-build.bin b/build-logic/convention/build/kotlin/compileKotlin/cacheable/last-build.bin index 2bccdb55f776d18bc9827fb7928179fbf1054fec..a8eb0635f2f17a972ae31ea0813f8640a46dc086 100644 GIT binary patch literal 18 YcmZ4UmVvdLhk=2y=ZkF93kDzn060YjDgXcg literal 18 YcmZ4UmVvdLhk=2y=kpuoLkvIw06Ojka{vGU diff --git a/build-logic/convention/build/kotlin/compileKotlin/local-state/build-history.bin b/build-logic/convention/build/kotlin/compileKotlin/local-state/build-history.bin index d4db701c81cc731ddf3b8a3907405a046e304258..e7a1c2941b9664484d2b9ae2c16cbfa8742e749f 100644 GIT binary patch literal 31 ccmZ4UmVvcgk^ur385kIQzQ{Jcfbtm_0Az~=H~;_u literal 31 dcmZ4UmVvcgk^ur385kIQKEF{u1m!a@003yA1%Utn diff --git a/build-logic/convention/build/libs/convention.jar b/build-logic/convention/build/libs/convention.jar index dc47069567f4b414074efa2940b4cb4115a149a6..d83ad3f8c2143e3b895951a8fffe465620f09798 100644 GIT binary patch delta 744 zcmXBQT}V@590u^Svs0dGc@bO08jgf5Xc-G*&?bE`%aWN3sWC(%1%pydMq5S{eL#vD zawvj=Ks#q1kNe2e!iZpk7kVMAy2(f-N0ArNKpJ@yo#+4FyuUrq`+v{NyF!UClz2;X zqgk+WoG5Y$al{hinESFO503+aLRNPJT#r;6QWcwoiUQ`;L8HER&<-; z{jHsXu|4*ylIq_(=6FoMwN-;9+W`Z8`%V=@`m}xB3{zDaru68Z2k515uJ2&Z?M7R2 z`)PW==O5F%ya~OrFo$;A$lVAe7Zd#aGXt)ntN)bn!Oczv9q3L_FdgY276ZMtSh!kdCQF)nZH#_ z{hvDvbl2>?e!A=IK$7|=ak_|vTzdCDlKuOoG565wa%9H`4Sg8u9Uu$rZd v4!(*a4Kdaj^-~d)FBltBy+~bp3>5VyQ2RO#CK;|AJ$y8G*(i0(n;`!mr$Ydv delta 744 zcmXBSZAepL6bJBo?^Z6GevmC<4M)KyG>wHZXwzIW%NKlENR1H^6&RFaF?uD6Qb_3q zc_@N{K)rWfuY1YcViCatKiG$0)t8E9}GqiS|Fwm*;oSdCqwb2X3w?<%*KI zughSx2!hEZ1jI>mRB9F{Z|uOSxN&~)mQS`>^nrt73%Dg706DR=L%Nvk4d*c+p^f|~c`+m@Ci>*C$Z)wkyYu$dzdqVGMilP70M)WU7(v-hHu%G%r z9)Dx3ZWi5PTQ+gRZxjTpiS>;%u!gz{y)f8DH9OC2C4(bhsn;1@p?K4!G?~5HNclh4 z-_oqbo8vUAcOpjjfA8|mr&*BdRv%<3uRU5fNdb{5GZ(PAL-v4>ycgV-gW$c~4(v)d zIIZ-9*Gd>{i(LbcV^bh7dj-6jrN_LgACW`0vwNxqpR(En3hGJFF-Iilh7i?iA#hfs zDOqg~qLMZM4$mJ08ICPZ$;+J29ADxnN*;1biSvktlNZ6yH_1bBVZ*(gLXfS uAiBd@<+Lr(a!)wx3+GTWq~kYb1-%C}KBFDyInFdKK9xRIzSGUmgVKKhi0AGA From ceec170e9fb2c6400e45a2fb7434838b427ca59f Mon Sep 17 00:00:00 2001 From: Leekangmin Date: Thu, 11 Jan 2024 16:24:43 +0900 Subject: [PATCH 14/21] [feat/#11] ServiceModule GroupService provide --- app/src/main/java/com/teumteum/teumteum/di/ServiceModule.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/com/teumteum/teumteum/di/ServiceModule.kt b/app/src/main/java/com/teumteum/teumteum/di/ServiceModule.kt index 272266d5..2734908a 100644 --- a/app/src/main/java/com/teumteum/teumteum/di/ServiceModule.kt +++ b/app/src/main/java/com/teumteum/teumteum/di/ServiceModule.kt @@ -1,6 +1,7 @@ package com.teumteum.teumteum.di +import com.teumteum.data.service.GroupService import com.teumteum.data.service.HomeService import com.teumteum.data.service.SampleService import dagger.Module @@ -22,4 +23,9 @@ object ServiceModule { @Provides fun provideHomeService(teumteumRetrofit: Retrofit) = teumteumRetrofit.create(HomeService::class.java) + + @Singleton + @Provides + fun provideGroupService(retrofit: Retrofit) = + retrofit.create(GroupService::class.java) } \ No newline at end of file From b48dab988a9576cb2b1990a3a59ee5911c4dfb85 Mon Sep 17 00:00:00 2001 From: Leekangmin Date: Thu, 11 Jan 2024 16:25:26 +0900 Subject: [PATCH 15/21] =?UTF-8?q?[feat/#11]=20Group=20->=20Meeting=20?= =?UTF-8?q?=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/group/GroupListActivity.kt | 14 +++++++------- .../presentation/group/GroupListAdapter.kt | 12 ++++++------ .../java/com/teumteum/domain/entity/Meeting.kt | 11 +++++++++++ 3 files changed, 24 insertions(+), 13 deletions(-) create mode 100644 core/domain/src/main/java/com/teumteum/domain/entity/Meeting.kt diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/group/GroupListActivity.kt b/app/src/main/java/com/teumteum/teumteum/presentation/group/GroupListActivity.kt index 29657bb0..40f8191b 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/group/GroupListActivity.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/group/GroupListActivity.kt @@ -3,7 +3,7 @@ package com.teumteum.teumteum.presentation.group import android.os.Bundle import android.widget.Toast import com.teumteum.base.BindingActivity -import com.teumteum.domain.entity.Group +import com.teumteum.domain.entity.Meeting import com.teumteum.teumteum.R import com.teumteum.teumteum.databinding.ActivityGroupListBinding @@ -26,12 +26,12 @@ class GroupListActivity : BindingActivity(R.layout.act binding.rvGroupList.adapter = adapter adapter.setItems( listOf( - Group(1L, 1L,"모각작", "모여서 작업할 사람", "나는 소개", listOf("", ""), "1월 10일 오후 07:00"), - Group(2L, 2L,"모각작", "모여서 작업 안할 사람", "나는 소개", listOf("", ""), "1월 21일 오후 04:00"), - Group(3L, 3L,"모각작", "모여서 작업 하기 싫은 사람", "나는 소개", listOf("", ""), "1월 26일 오후 11:00"), - Group(4L, 4L,"모각작", "모여서 작업 하고 싶은 사람", "나는 소개", listOf("", ""), "2월 13일 오전 11:00"), - Group(5L, 5L,"모각작", "모일 사람", "나는 소개", listOf("", ""), "4월 06일 오후 04:00"), - Group(6L, 6L,"모각작", "안 모일 사람", "나는 소개", listOf("", ""), "11월 16일 오후 08:00"), + Meeting(1L, 1L,"모각작", "모여서 작업할 사람", "나는 소개", listOf("", ""), "1월 10일 오후 07:00"), + Meeting(2L, 2L,"모각작", "모여서 작업 안할 사람", "나는 소개", listOf("", ""), "1월 21일 오후 04:00"), + Meeting(3L, 3L,"모각작", "모여서 작업 하기 싫은 사람", "나는 소개", listOf("", ""), "1월 26일 오후 11:00"), + Meeting(4L, 4L,"모각작", "모여서 작업 하고 싶은 사람", "나는 소개", listOf("", ""), "2월 13일 오전 11:00"), + Meeting(5L, 5L,"모각작", "모일 사람", "나는 소개", listOf("", ""), "4월 06일 오후 04:00"), + Meeting(6L, 6L,"모각작", "안 모일 사람", "나는 소개", listOf("", ""), "11월 16일 오후 08:00"), ) ) } diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/group/GroupListAdapter.kt b/app/src/main/java/com/teumteum/teumteum/presentation/group/GroupListAdapter.kt index 018a1f56..ddeda0cc 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/group/GroupListAdapter.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/group/GroupListAdapter.kt @@ -3,12 +3,12 @@ package com.teumteum.teumteum.presentation.group import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView -import com.teumteum.domain.entity.Group +import com.teumteum.domain.entity.Meeting import com.teumteum.teumteum.databinding.ItemGroupListBinding -class GroupListAdapter(private val itemClick: (Group) -> (Unit)) : +class GroupListAdapter(private val itemClick: (Meeting) -> (Unit)) : RecyclerView.Adapter() { - private val groupList = mutableListOf() + private val groupList = mutableListOf() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GroupListViewHolder { val binding = ItemGroupListBinding.inflate( @@ -25,7 +25,7 @@ class GroupListAdapter(private val itemClick: (Group) -> (Unit)) : override fun getItemCount(): Int = groupList.size - fun setItems(newItems: List) { + fun setItems(newItems: List) { groupList.clear() groupList.addAll(newItems) notifyDataSetChanged() @@ -33,9 +33,9 @@ class GroupListAdapter(private val itemClick: (Group) -> (Unit)) : class GroupListViewHolder( private val binding: ItemGroupListBinding, - private val itemClick: (Group) -> (Unit) + private val itemClick: (Meeting) -> (Unit) ) : RecyclerView.ViewHolder(binding.root) { - fun onBind(item: Group) { + fun onBind(item: Meeting) { binding.tvGroupName.text = item.name binding.tvTitleBadge.text = item.topic binding.tvDate.text = item.date diff --git a/core/domain/src/main/java/com/teumteum/domain/entity/Meeting.kt b/core/domain/src/main/java/com/teumteum/domain/entity/Meeting.kt new file mode 100644 index 00000000..a18d671c --- /dev/null +++ b/core/domain/src/main/java/com/teumteum/domain/entity/Meeting.kt @@ -0,0 +1,11 @@ +package com.teumteum.domain.entity + +data class Meeting( + val id: Long, + val hostId: Long, + val topic: String, + val name: String, + val introduction: String, + val photoUrls: List, + val date: String +) \ No newline at end of file From e83986d5c8d1d70a1d051a05caa529447a5282b1 Mon Sep 17 00:00:00 2001 From: Leekangmin Date: Thu, 11 Jan 2024 16:25:51 +0900 Subject: [PATCH 16/21] [feat/#11] ContextExtension --- app/src/main/res/values/strings.xml | 3 ++ .../base/util/extension/ContextExtension.kt | 29 +++++++++++++++++++ .../java/com/teumteum/domain/entity/Group.kt | 11 ------- 3 files changed, 32 insertions(+), 11 deletions(-) create mode 100644 core/base/src/main/java/com/teumteum/base/util/extension/ContextExtension.kt delete mode 100644 core/domain/src/main/java/com/teumteum/domain/entity/Group.kt diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1e2f9d20..8c8e98a8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -29,5 +29,8 @@ 검색어를 입력해 주세요 추천 검색어 + 검색어를 입력하세요 + 에 대한 검색 결과가 없습니다. + \'%1$s\' \ No newline at end of file diff --git a/core/base/src/main/java/com/teumteum/base/util/extension/ContextExtension.kt b/core/base/src/main/java/com/teumteum/base/util/extension/ContextExtension.kt new file mode 100644 index 00000000..23f23798 --- /dev/null +++ b/core/base/src/main/java/com/teumteum/base/util/extension/ContextExtension.kt @@ -0,0 +1,29 @@ +package com.teumteum.base.util.extension + +import android.app.Activity +import android.content.Context +import android.view.View +import android.view.inputmethod.InputMethodManager +import android.widget.Toast +import androidx.annotation.StringRes +import com.google.android.material.snackbar.Snackbar + +fun Context.toast(message: String) { + Toast.makeText(this, message, Toast.LENGTH_SHORT).show() +} + +fun Context.longToast(message: String) { + Toast.makeText(this, message, Toast.LENGTH_LONG).show() +} + +fun Context.snackBar(anchorView: View, message: () -> String) { + Snackbar.make(anchorView, message(), Snackbar.LENGTH_SHORT).show() +} + +fun Context.stringOf(@StringRes resId: Int) = getString(resId) + +fun Context.hideKeyboard(view: View) { + val inputMethodManager = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager + inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0) +} + diff --git a/core/domain/src/main/java/com/teumteum/domain/entity/Group.kt b/core/domain/src/main/java/com/teumteum/domain/entity/Group.kt deleted file mode 100644 index 34bd0d7f..00000000 --- a/core/domain/src/main/java/com/teumteum/domain/entity/Group.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.teumteum.domain.entity - -data class Group( - val id: Long, - val hostId: Long, - val topic: String, - val name: String, - val introduction: String, - val photoUrls: List, - val date: String -) \ No newline at end of file From 0329d9e8a9928220948a1646521b9ba284bacdca Mon Sep 17 00:00:00 2001 From: Leekangmin Date: Thu, 11 Jan 2024 16:26:20 +0900 Subject: [PATCH 17/21] =?UTF-8?q?[feat/#11]=20=EB=AA=A8=EC=9E=84=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20UI=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/layout/activity_search.xml | 69 ++++++++++++++++++++- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml index 15df4440..a15bca6d 100644 --- a/app/src/main/res/layout/activity_search.xml +++ b/app/src/main/res/layout/activity_search.xml @@ -18,7 +18,8 @@ android:id="@+id/iv_back" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="20dp" + android:layout_marginStart="16dp" + android:padding="4dp" android:src="@drawable/ic_arrow_left_l" app:layout_constraintBottom_toBottomOf="@id/et_search" app:layout_constraintStart_toStartOf="parent" @@ -32,20 +33,35 @@ android:layout_marginEnd="8dp" android:background="@color/transparent" android:hint="@string/group_search_hint" + android:inputType="text" + android:maxLines="1" android:paddingVertical="13dp" android:text="@={viewModel.etSearch}" android:textAppearance="@style/ta.body.1" android:textColor="@color/text_body_primary" android:textColorHint="@color/text_body_quinary" - app:layout_constraintEnd_toStartOf="@id/iv_search" + app:layout_constraintEnd_toStartOf="@id/iv_clear" app:layout_constraintStart_toEndOf="@id/iv_back" app:layout_constraintTop_toTopOf="parent" /> + + + + + + + + + + + + \ No newline at end of file From a33db6d345f53f7b71325d42466896accdf7fd34 Mon Sep 17 00:00:00 2001 From: Leekangmin Date: Thu, 11 Jan 2024 16:26:54 +0900 Subject: [PATCH 18/21] [feat/#11] RemoteGroupDataSource --- .../remote/RemoteGroupDataSource.kt | 22 +++++++++++++++++++ .../com/teumteum/data/service/GroupService.kt | 5 ++--- 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 core/data/src/main/java/com/teumteum/data/datasource/remote/RemoteGroupDataSource.kt diff --git a/core/data/src/main/java/com/teumteum/data/datasource/remote/RemoteGroupDataSource.kt b/core/data/src/main/java/com/teumteum/data/datasource/remote/RemoteGroupDataSource.kt new file mode 100644 index 00000000..837b6825 --- /dev/null +++ b/core/data/src/main/java/com/teumteum/data/datasource/remote/RemoteGroupDataSource.kt @@ -0,0 +1,22 @@ +package com.teumteum.data.datasource.remote + +import com.teumteum.data.model.response.ResponseGroup +import com.teumteum.data.service.GroupService +import javax.inject.Inject + +class RemoteGroupDataSource @Inject constructor( + private val service: GroupService +) { + suspend fun getGroups( + size: Int, + page: Int, + sort: String, + isOpen: Boolean, + topic: String? = null, + meetingAreaStreet: String? = null, + participantUserId: Long? = null, + searchWord: String? = null + ): ResponseGroup { + return service.getGroups(size, page, sort, isOpen, topic, meetingAreaStreet, participantUserId, searchWord) + } +} \ No newline at end of file diff --git a/core/data/src/main/java/com/teumteum/data/service/GroupService.kt b/core/data/src/main/java/com/teumteum/data/service/GroupService.kt index efa79232..72ee9464 100644 --- a/core/data/src/main/java/com/teumteum/data/service/GroupService.kt +++ b/core/data/src/main/java/com/teumteum/data/service/GroupService.kt @@ -1,6 +1,5 @@ package com.teumteum.data.service -import com.teumteum.data.model.response.ResponseGetRecommendMeet import com.teumteum.data.model.response.ResponseGroup import retrofit2.http.GET import retrofit2.http.Query @@ -8,9 +7,9 @@ import retrofit2.http.Query interface GroupService { @GET("meetings") suspend fun getGroups( - @Query("size") size: Int, + @Query("size") size: Int = 20, @Query("page") page: Int, - @Query("sort") sort: String, + @Query("sort") sort: String = "id,desc", @Query("isOpen") isOpen: Boolean, @Query("topic") topic: String?, @Query("meetingAreaStreet") meetingAreaStreet: String?, From f6b8e0b837511bd6cca78dbb0c343e0479cde170 Mon Sep 17 00:00:00 2001 From: Leekangmin Date: Thu, 11 Jan 2024 16:27:20 +0900 Subject: [PATCH 19/21] =?UTF-8?q?[feat/#11]=20GroupRepository=20=EB=AA=A8?= =?UTF-8?q?=EC=9E=84=20=EA=B2=80=EC=83=89=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/model/response/ResponseGroup.kt | 10 +++++--- .../data/repository/GroupRepositoryImpl.kt | 24 +++++++++---------- .../domain/repository/GroupRepository.kt | 4 ++-- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/core/data/src/main/java/com/teumteum/data/model/response/ResponseGroup.kt b/core/data/src/main/java/com/teumteum/data/model/response/ResponseGroup.kt index 3c480f05..6f714bb3 100644 --- a/core/data/src/main/java/com/teumteum/data/model/response/ResponseGroup.kt +++ b/core/data/src/main/java/com/teumteum/data/model/response/ResponseGroup.kt @@ -1,6 +1,6 @@ package com.teumteum.data.model.response -import com.teumteum.domain.entity.Group +import com.teumteum.domain.entity.Meeting data class ResponseGroup( val data: ResponseGroupData, @@ -10,8 +10,8 @@ data class ResponseGroup( val meetings: List ) { data class ResponseMeeting( - val hostId: Int, - val id: Int, + val hostId: Long, + val id: Long, val introduction: String, val meetingArea: ResponseMeetingArea, val numberOfRecruits: Int, @@ -26,6 +26,10 @@ data class ResponseGroup( val street: String, val zipCode: String ) + + fun toMeeting(): Meeting { + return Meeting(id, hostId, topic, title, introduction, photoUrls, promiseDateTime) + } } } } \ No newline at end of file diff --git a/core/data/src/main/java/com/teumteum/data/repository/GroupRepositoryImpl.kt b/core/data/src/main/java/com/teumteum/data/repository/GroupRepositoryImpl.kt index 480f6d46..f3bf478b 100644 --- a/core/data/src/main/java/com/teumteum/data/repository/GroupRepositoryImpl.kt +++ b/core/data/src/main/java/com/teumteum/data/repository/GroupRepositoryImpl.kt @@ -1,22 +1,22 @@ package com.teumteum.data.repository -import com.teumteum.domain.entity.Group +import com.teumteum.data.datasource.remote.RemoteGroupDataSource +import com.teumteum.domain.entity.Meeting import com.teumteum.domain.repository.GroupRepository import javax.inject.Inject class GroupRepositoryImpl @Inject constructor( - -): GroupRepository { - override suspend fun getSearchGroup(keyword: String): Result> { + private val dataSource: RemoteGroupDataSource +) : GroupRepository { + override suspend fun getSearchGroup(page: Int, keyword: String): Result> { return runCatching { - listOf( - Group(1L, 1L, "모각작", "모여서 작업할 사람", "나는 소개", listOf("", ""), "1월 10일 오후 07:00"), - Group(2L, 2L, "모각작", "모여서 작업 안할 사람", "나는 소개", listOf("", ""), "1월 21일 오후 04:00"), - Group(3L, 3L, "모각작", "모여서 작업 하기 싫은 사람", "나는 소개", listOf("", ""), "1월 26일 오후 11:00"), - Group(4L, 4L, "모각작", "모여서 작업 하고 싶은 사람", "나는 소개", listOf("", ""), "2월 13일 오전 11:00"), - Group(5L, 5L, "모각작", "모일 사람", "나는 소개", listOf("", ""), "4월 06일 오후 04:00"), - Group(6L, 6L, "모각작", "안 모일 사람", "나는 소개", listOf("", ""), "11월 16일 오후 08:00"), - ) + dataSource.getGroups( + size = 20, + page = page, + sort = "id,desc", + isOpen = true, + searchWord = keyword + ).data.meetings.map { it.toMeeting() } } } } \ No newline at end of file diff --git a/core/domain/src/main/java/com/teumteum/domain/repository/GroupRepository.kt b/core/domain/src/main/java/com/teumteum/domain/repository/GroupRepository.kt index d6d39c3d..b0d1819d 100644 --- a/core/domain/src/main/java/com/teumteum/domain/repository/GroupRepository.kt +++ b/core/domain/src/main/java/com/teumteum/domain/repository/GroupRepository.kt @@ -1,7 +1,7 @@ package com.teumteum.domain.repository -import com.teumteum.domain.entity.Group +import com.teumteum.domain.entity.Meeting interface GroupRepository { - suspend fun getSearchGroup(keyword: String): Result> + suspend fun getSearchGroup(page: Int, keyword: String): Result> } \ No newline at end of file From f2cbaffad7b8fdce0a49f1eef8affb14ecf00a76 Mon Sep 17 00:00:00 2001 From: Leekangmin Date: Thu, 11 Jan 2024 16:28:24 +0900 Subject: [PATCH 20/21] =?UTF-8?q?[feat/#11]=20=EB=AA=A8=EC=9E=84=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../group/search/KeywordAdapter.kt | 3 +- .../group/search/SearchActivity.kt | 64 +++++++++++++------ .../group/search/SearchViewModel.kt | 36 +++++++---- 3 files changed, 71 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/group/search/KeywordAdapter.kt b/app/src/main/java/com/teumteum/teumteum/presentation/group/search/KeywordAdapter.kt index afdebc53..cb7334b8 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/group/search/KeywordAdapter.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/group/search/KeywordAdapter.kt @@ -5,7 +5,8 @@ import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.teumteum.teumteum.databinding.ItemKeywordListBinding -class keywordAdapter(private val itemClick: (String) -> (Unit)): RecyclerView.Adapter() { +class KeywordAdapter(private val itemClick: (String) -> (Unit)) : + RecyclerView.Adapter() { private val keywordList = mutableListOf() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): KeywordAdapter { val binding = ItemKeywordListBinding.inflate( diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchActivity.kt b/app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchActivity.kt index 6263fca8..65435605 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchActivity.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchActivity.kt @@ -1,65 +1,93 @@ package com.teumteum.teumteum.presentation.group.search import android.os.Bundle -import android.util.Log import androidx.activity.viewModels +import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope import com.teumteum.base.BindingActivity +import com.teumteum.base.util.extension.hideKeyboard +import com.teumteum.base.util.extension.toast import com.teumteum.teumteum.R import com.teumteum.teumteum.databinding.ActivitySearchBinding import com.teumteum.teumteum.presentation.group.GroupListAdapter import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.FlowPreview -import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @AndroidEntryPoint -class SearchActivity: BindingActivity(R.layout.activity_search) { +class SearchActivity : BindingActivity(R.layout.activity_search) { private val viewModel by viewModels() - private lateinit var keywordAdapter: keywordAdapter + private lateinit var keywordAdapter: KeywordAdapter private lateinit var groupListAdapter: GroupListAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding.viewModel = viewModel initView() + initEvent() observe() } - private fun initView() { - keywordAdapter = keywordAdapter { + private fun initView() { + initKeywordAdapter() + initGroupListAdapter() + } + private fun initKeywordAdapter() { + keywordAdapter = KeywordAdapter { + binding.etSearch.setText(it) + viewModel.initCurrentPage(it) + hideKeyboard(binding.root) } binding.rvRecommendKeyword.adapter = keywordAdapter keywordAdapter.setItems(viewModel.keywordList) + } + private fun initGroupListAdapter() { groupListAdapter = GroupListAdapter { - + //TODO 그룹 상세보기로 이동하는 로직 들어가야 함 } binding.rvGroupList.adapter = groupListAdapter } - @OptIn(FlowPreview::class) + private fun initEvent() { + binding.ivSearch.setOnClickListener { + if (viewModel.isInputBlank) { + toast(getString(R.string.group_search_empty_keyword)) + } else { + viewModel.initCurrentPage() + hideKeyboard(binding.root) + } + } + + binding.ivClear.setOnClickListener { + binding.etSearch.text.clear() + } + + binding.etSearch.setOnFocusChangeListener { _, hasFocus -> + binding.ivClear.isVisible = (hasFocus) + } + } + private fun observe() { viewModel.searchData.flowWithLifecycle(lifecycle) .onEach { binding.clRecommendKeyword.isVisible = it is SearchUiState.Init - when(it) { + binding.rvGroupList.isGone = it is SearchUiState.Init || it is SearchUiState.Empty + binding.clEmpty.isVisible = it is SearchUiState.Empty + when (it) { is SearchUiState.Success -> { groupListAdapter.setItems(it.data) } - else -> {} - } - }.launchIn(lifecycleScope) - viewModel.etSearch.flowWithLifecycle(lifecycle) - .debounce(1000) - .onEach { - if (it.isNotEmpty()) { - viewModel.getSearchGroup(it) + is SearchUiState.Empty -> { + binding.tvEmptyGroupTitle.text = + getString(R.string.group_search_keyword, it.keyword) + } + + else -> {} } }.launchIn(lifecycleScope) } diff --git a/app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchViewModel.kt b/app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchViewModel.kt index 2de6300d..1ddeb9c4 100644 --- a/app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchViewModel.kt +++ b/app/src/main/java/com/teumteum/teumteum/presentation/group/search/SearchViewModel.kt @@ -1,46 +1,56 @@ package com.teumteum.teumteum.presentation.group.search -import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.teumteum.domain.entity.Group +import com.teumteum.domain.entity.Meeting import com.teumteum.domain.repository.GroupRepository import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch +import javax.inject.Inject @HiltViewModel class SearchViewModel @Inject constructor( private val repository: GroupRepository -): ViewModel() { +) : ViewModel() { val etSearch = MutableStateFlow("") - val isInputBlank = etSearch.value.isBlank() + val isInputBlank + get() = etSearch.value.isBlank() + + private var currentPage = 0 - val keywordList = listOf("스터디", "독서", "외주", "모여서 각자 일하기", "커리어", "직무 고민", "사이드 프로젝트", "N잡") + val keywordList = + listOf("스터디", "독서", "외주", "모여서 각자 일하기", "커리어", "직무 고민", "사이드 프로젝트", "N잡") private val _searchData = MutableStateFlow(SearchUiState.Init) val searchData: StateFlow = _searchData - fun getSearchGroup(keyword: String) { + fun initCurrentPage(keyword: String? = null) { + currentPage = 0 + getSearchGroup(keyword) + } + + fun getSearchGroup(keyword: String? = null) { viewModelScope.launch { - repository.getSearchGroup(keyword) + repository.getSearchGroup(currentPage++, keyword ?: etSearch.value) .onSuccess { if (it.isEmpty()) { - _searchData.value = SearchUiState.Failure("실패") + _searchData.value = SearchUiState.Empty(keyword ?: etSearch.value) } else { _searchData.value = SearchUiState.Success(it) } + }.onFailure { + _searchData.value = SearchUiState.Failure("실패") } } } - } sealed interface SearchUiState { - object Init: SearchUiState - data class Success(val data: List): SearchUiState - data class Failure(val msg: String): SearchUiState + object Init : SearchUiState + data class Empty(val keyword: String) : SearchUiState + data class Success(val data: List) : SearchUiState + data class Failure(val msg: String) : SearchUiState } \ No newline at end of file From f57cf5a7a44b58a5da2fa83a4089cb64a5f33eed Mon Sep 17 00:00:00 2001 From: Leekangmin Date: Thu, 11 Jan 2024 16:56:15 +0900 Subject: [PATCH 21/21] [feat/#11] SearchActivity exported false --- app/src/main/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 85dea0d2..3fb3003a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -35,7 +35,7 @@ android:exported="true"> + android:exported="false" /> \ No newline at end of file