From 5ef34e42f98a3f0a7fa7b95538464236293f2488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=84=ED=95=B4=EC=84=B1?= Date: Fri, 16 Dec 2022 00:25:49 +0900 Subject: [PATCH] =?UTF-8?q?DEP-198=20=EB=A7=88=EC=9D=B4=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20ui=20=EC=A0=81=EC=9A=A9=20(#73)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: nickname 수정 dialog 추가 * refactor * ui: 습관 보관함 레이아웃 추가 * refactor: 사용하지 않는 파일 제외 * ui: 버전 정보 추가 * refactor: strings 로 상수 이동 * refactor: layout_hegiht wrap_content 사용하도록 개선 * refactor: string 변수로 추출 * refactor: 접근제어자 추가 * refactor: layoutParams lint error 해결 * docs: semantic versioning 방식으로 변경 * refactor: 안전한 방식으로 랜던값 생성 (kotlin:S2245) --- .idea/compiler.xml | 9 - .idea/misc.xml | 18 -- app/build.gradle | 7 +- app/src/main/AndroidManifest.xml | 5 + build.gradle | 6 + core-design-system/build.gradle | 1 + .../src/main/res/drawable/bg_oval_gray200.xml | 5 + .../main/res/drawable/bg_rect_main_r10.xml | 8 + .../bg_rect_white_r10_border_gray450.xml | 11 + .../main/res/drawable/bg_rect_white_r20.xml | 8 + .../src/main/res/drawable/ic_close_white.xml | 13 ++ .../src/main/res/drawable/ic_edit_gray450.xml | 9 + .../drawable/selector_switch_button_track.xml | 5 + .../main/res/drawable/shape_switch_thumb.xml | 15 ++ .../res/drawable/shape_switch_track_off.xml | 9 + .../res/drawable/shape_switch_track_on.xml | 9 + core/build.gradle | 1 + .../threedays/data/api/HabitService.kt | 3 + .../datasource/habit/HabitRemoteDataSource.kt | 1 + .../habit/HabitRemoteDataSourceImpl.kt | 38 ++++ .../threedays/data/entity/HabitEntity.kt | 4 +- .../data/repository/HabitRepositoryImpl.kt | 15 ++ .../threedays/domain/entity/habit/Habit.kt | 4 +- .../domain/repository/HabitRepository.kt | 1 + .../usecase/GetArchivedHabitsUseCase.kt | 15 ++ navigator/build.gradle | 1 + .../navigator/ArchivedHabitNavigator.kt | 3 + presentation/history/build.gradle | 1 + presentation/home/build.gradle | 1 + .../threedays/home/home/HabitViewHolder.kt | 2 +- .../threedays/home/home/model/HabitUI.kt | 8 +- presentation/mate/build.gradle | 1 + presentation/mypage/build.gradle | 3 + .../mypage/src/main/AndroidManifest.xml | 4 +- .../threedays/mypage/MyPageFragment.kt | 65 +++++- .../threedays/mypage/MyPageModule.kt | 15 ++ .../archived_habit/ArchivedHabitActivity.kt | 64 ++++++ .../archived_habit/ArchivedHabitAdapter.kt | 40 ++++ .../ArchivedHabitNavigatorImpl.kt | 12 ++ .../ArchivedHabitOnboardingSnackBar.kt | 45 ++++ .../mypage/archived_habit/ArchivedHabitUI.kt | 15 ++ .../archived_habit/ArchivedHabitViewHolder.kt | 29 +++ .../archived_habit/ArchivedHabitViewModel.kt | 36 ++++ .../nickname/EditNicknameDialogFragment.kt | 90 ++++++++ .../res/layout/activity_archived_habit.xml | 91 ++++++++ .../layout/fragment_edit_nickname_dialog.xml | 97 +++++++++ .../src/main/res/layout/fragment_my_page.xml | 204 +++++++++++++++++- .../main/res/layout/item_habit_archived.xml | 116 ++++++++++ .../snackbar_archived_habit_onboarding.xml | 56 +++++ .../mypage/src/main/res/values/strings.xml | 14 +- .../notification/NotificationActivity.kt | 4 - 51 files changed, 1184 insertions(+), 53 deletions(-) delete mode 100644 .idea/compiler.xml delete mode 100644 .idea/misc.xml create mode 100644 core-design-system/src/main/res/drawable/bg_oval_gray200.xml create mode 100644 core-design-system/src/main/res/drawable/bg_rect_main_r10.xml create mode 100644 core-design-system/src/main/res/drawable/bg_rect_white_r10_border_gray450.xml create mode 100644 core-design-system/src/main/res/drawable/bg_rect_white_r20.xml create mode 100644 core-design-system/src/main/res/drawable/ic_close_white.xml create mode 100644 core-design-system/src/main/res/drawable/ic_edit_gray450.xml create mode 100644 core-design-system/src/main/res/drawable/selector_switch_button_track.xml create mode 100644 core-design-system/src/main/res/drawable/shape_switch_thumb.xml create mode 100644 core-design-system/src/main/res/drawable/shape_switch_track_off.xml create mode 100644 core-design-system/src/main/res/drawable/shape_switch_track_on.xml create mode 100644 domain/src/main/java/com/depromeet/threedays/domain/usecase/GetArchivedHabitsUseCase.kt create mode 100644 navigator/src/main/java/com/depromeet/threedays/navigator/ArchivedHabitNavigator.kt create mode 100644 presentation/mypage/src/main/java/com/depromeet/threedays/mypage/MyPageModule.kt create mode 100644 presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitActivity.kt create mode 100644 presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitAdapter.kt create mode 100644 presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitNavigatorImpl.kt create mode 100644 presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitOnboardingSnackBar.kt create mode 100644 presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitUI.kt create mode 100644 presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitViewHolder.kt create mode 100644 presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitViewModel.kt create mode 100644 presentation/mypage/src/main/java/com/depromeet/threedays/mypage/nickname/EditNicknameDialogFragment.kt create mode 100644 presentation/mypage/src/main/res/layout/activity_archived_habit.xml create mode 100644 presentation/mypage/src/main/res/layout/fragment_edit_nickname_dialog.xml create mode 100644 presentation/mypage/src/main/res/layout/item_habit_archived.xml create mode 100644 presentation/mypage/src/main/res/layout/snackbar_archived_habit_onboarding.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index 0b8c8491..00000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 0863c24c..00000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index be26a1f4..9e1f3c6a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,11 +11,11 @@ android { compileSdk 33 defaultConfig { - applicationId "com.depromeet.threedays" + applicationId rootProject.ext.threeDaysApplicationId minSdk 26 targetSdk 33 - versionCode 2 - versionName "1.0" + versionCode rootProject.ext.threeDaysAppVersionCode + versionName rootProject.ext.threeDaysAppVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -49,6 +49,7 @@ dependencies { implementation(project(":presentation:notification")) implementation(project(":presentation:mate")) implementation(project(":presentation:onboarding")) + implementation(project(":presentation:mypage")) implementation(jetpackDeps) implementation(coroutines) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5a024f34..a1d734cd 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -50,6 +50,11 @@ + + + diff --git a/build.gradle b/build.gradle index 6306c00c..cf795fba 100644 --- a/build.gradle +++ b/build.gradle @@ -8,6 +8,12 @@ buildscript { //classpath 'com.google.gms:google-services:4.3.13' //classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.1' } + + ext { + threeDaysApplicationId = "com.depromeet.threedays" + threeDaysAppVersionCode = 2 + threeDaysAppVersionName = "0.0.1" + } } plugins { diff --git a/core-design-system/build.gradle b/core-design-system/build.gradle index b55aa7c2..721c9ae5 100644 --- a/core-design-system/build.gradle +++ b/core-design-system/build.gradle @@ -4,6 +4,7 @@ plugins { } android { + namespace 'com.depromeet.threedays.core_design_system' compileSdk 33 defaultConfig { diff --git a/core-design-system/src/main/res/drawable/bg_oval_gray200.xml b/core-design-system/src/main/res/drawable/bg_oval_gray200.xml new file mode 100644 index 00000000..d5ae0649 --- /dev/null +++ b/core-design-system/src/main/res/drawable/bg_oval_gray200.xml @@ -0,0 +1,5 @@ + + + + diff --git a/core-design-system/src/main/res/drawable/bg_rect_main_r10.xml b/core-design-system/src/main/res/drawable/bg_rect_main_r10.xml new file mode 100644 index 00000000..1634984d --- /dev/null +++ b/core-design-system/src/main/res/drawable/bg_rect_main_r10.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/core-design-system/src/main/res/drawable/bg_rect_white_r10_border_gray450.xml b/core-design-system/src/main/res/drawable/bg_rect_white_r10_border_gray450.xml new file mode 100644 index 00000000..b0dd4d98 --- /dev/null +++ b/core-design-system/src/main/res/drawable/bg_rect_white_r10_border_gray450.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/core-design-system/src/main/res/drawable/bg_rect_white_r20.xml b/core-design-system/src/main/res/drawable/bg_rect_white_r20.xml new file mode 100644 index 00000000..dc28c807 --- /dev/null +++ b/core-design-system/src/main/res/drawable/bg_rect_white_r20.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/core-design-system/src/main/res/drawable/ic_close_white.xml b/core-design-system/src/main/res/drawable/ic_close_white.xml new file mode 100644 index 00000000..e2721f25 --- /dev/null +++ b/core-design-system/src/main/res/drawable/ic_close_white.xml @@ -0,0 +1,13 @@ + + + diff --git a/core-design-system/src/main/res/drawable/ic_edit_gray450.xml b/core-design-system/src/main/res/drawable/ic_edit_gray450.xml new file mode 100644 index 00000000..218dfb6d --- /dev/null +++ b/core-design-system/src/main/res/drawable/ic_edit_gray450.xml @@ -0,0 +1,9 @@ + + + diff --git a/core-design-system/src/main/res/drawable/selector_switch_button_track.xml b/core-design-system/src/main/res/drawable/selector_switch_button_track.xml new file mode 100644 index 00000000..80076a73 --- /dev/null +++ b/core-design-system/src/main/res/drawable/selector_switch_button_track.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/core-design-system/src/main/res/drawable/shape_switch_thumb.xml b/core-design-system/src/main/res/drawable/shape_switch_thumb.xml new file mode 100644 index 00000000..86b121c5 --- /dev/null +++ b/core-design-system/src/main/res/drawable/shape_switch_thumb.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/core-design-system/src/main/res/drawable/shape_switch_track_off.xml b/core-design-system/src/main/res/drawable/shape_switch_track_off.xml new file mode 100644 index 00000000..5c261cd9 --- /dev/null +++ b/core-design-system/src/main/res/drawable/shape_switch_track_off.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/core-design-system/src/main/res/drawable/shape_switch_track_on.xml b/core-design-system/src/main/res/drawable/shape_switch_track_on.xml new file mode 100644 index 00000000..9961df62 --- /dev/null +++ b/core-design-system/src/main/res/drawable/shape_switch_track_on.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/core/build.gradle b/core/build.gradle index 4fdd5e6c..22c53464 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -8,6 +8,7 @@ plugins { } android { + namespace 'com.depromeet.threedays.core' compileSdk 33 defaultConfig { diff --git a/data/src/main/java/com/depromeet/threedays/data/api/HabitService.kt b/data/src/main/java/com/depromeet/threedays/data/api/HabitService.kt index 8a9b611c..c26e374d 100644 --- a/data/src/main/java/com/depromeet/threedays/data/api/HabitService.kt +++ b/data/src/main/java/com/depromeet/threedays/data/api/HabitService.kt @@ -14,6 +14,9 @@ interface HabitService { ): List + @GET("/api/v1/habits?status=ARCHIVED") + suspend fun getArchivedHabits(): List + // @GET("/api/v1/habits/{habitId}") // suspend fun getHabit( // @Body request: PostProductsRequest diff --git a/data/src/main/java/com/depromeet/threedays/data/datasource/habit/HabitRemoteDataSource.kt b/data/src/main/java/com/depromeet/threedays/data/datasource/habit/HabitRemoteDataSource.kt index 3ba7700b..67e4b73a 100644 --- a/data/src/main/java/com/depromeet/threedays/data/datasource/habit/HabitRemoteDataSource.kt +++ b/data/src/main/java/com/depromeet/threedays/data/datasource/habit/HabitRemoteDataSource.kt @@ -5,6 +5,7 @@ import com.depromeet.threedays.data.entity.HabitEntity interface HabitRemoteDataSource { suspend fun postHabit(habitEntity: HabitEntity) suspend fun getHabits(): List + suspend fun getArchivedHabits(): List //fun getHabit(habitId: Long): HabitEntity suspend fun updateHabit(habitId: Long) suspend fun deleteHabit(habitId: Long) diff --git a/data/src/main/java/com/depromeet/threedays/data/datasource/habit/HabitRemoteDataSourceImpl.kt b/data/src/main/java/com/depromeet/threedays/data/datasource/habit/HabitRemoteDataSourceImpl.kt index c8cdbeda..f1a9801b 100644 --- a/data/src/main/java/com/depromeet/threedays/data/datasource/habit/HabitRemoteDataSourceImpl.kt +++ b/data/src/main/java/com/depromeet/threedays/data/datasource/habit/HabitRemoteDataSourceImpl.kt @@ -2,6 +2,10 @@ package com.depromeet.threedays.data.datasource.habit import com.depromeet.threedays.data.api.HabitService import com.depromeet.threedays.data.entity.HabitEntity +import java.security.SecureRandom +import java.time.DayOfWeek +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter import javax.inject.Inject class HabitRemoteDataSourceImpl @Inject constructor( @@ -15,6 +19,40 @@ class HabitRemoteDataSourceImpl @Inject constructor( return habitService.getHabits() } + override suspend fun getArchivedHabits(): List { + return listOf( + HabitEntity( + 1, + memberId = 1, + title = "물 마시기", + imojiPath = "", + dayOfWeeks = listOf( + "MONDAY","TUESDAY","WEDNESDAY" + ), + reward = SecureRandom().nextInt(10), + color = "pink", + mate = null, + todayHabitAchievementId = null, + sequence = 1, + createAt = LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME), + ), + HabitEntity( + 2, + memberId = 1, + title = "영어 공부 1시간 하기", + imojiPath = "", + dayOfWeeks = DayOfWeek.values().map { it.name }.toList(), + reward = SecureRandom().nextInt(10), + color = "blue", + mate = null, + todayHabitAchievementId = null, + sequence = 1, + createAt = LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME), + ), + ) +// return habitService.getArchivedHabits() + } + // override fun getHabit(habitId: Long): HabitEntity { // // } diff --git a/data/src/main/java/com/depromeet/threedays/data/entity/HabitEntity.kt b/data/src/main/java/com/depromeet/threedays/data/entity/HabitEntity.kt index e263d767..31ce5ce9 100644 --- a/data/src/main/java/com/depromeet/threedays/data/entity/HabitEntity.kt +++ b/data/src/main/java/com/depromeet/threedays/data/entity/HabitEntity.kt @@ -7,10 +7,10 @@ class HabitEntity ( val memberId: Int, val title: String, val imojiPath: String, - val dayOfWeeks: ArrayList, + val dayOfWeeks: List, val reward: Int, val color: String, - val mate: Mate, + val mate: Mate?, val todayHabitAchievementId: Int?, // null이면 오늘 체크를 하지 않은 것 val sequence: Int, val createAt: String, diff --git a/data/src/main/java/com/depromeet/threedays/data/repository/HabitRepositoryImpl.kt b/data/src/main/java/com/depromeet/threedays/data/repository/HabitRepositoryImpl.kt index 579c4559..1888e6f5 100644 --- a/data/src/main/java/com/depromeet/threedays/data/repository/HabitRepositoryImpl.kt +++ b/data/src/main/java/com/depromeet/threedays/data/repository/HabitRepositoryImpl.kt @@ -30,6 +30,21 @@ class HabitRepositoryImpl @Inject constructor( } } + override suspend fun getArchivedHabits(): Flow>> { + return flow { + emit(DataState.loading()) + val response = habitRemoteDataSource.getArchivedHabits() + + if(response.isNotEmpty()) { + emit(DataState.success(data = response.map { it.toHabit() })) + } else { + emit(DataState.error(msg = "response has error")) + }.runCatching { + emit(DataState.fail("response is fail")) + } + } + } + // override suspend fun getHabit(habitId: Long): Habit { // // } diff --git a/domain/src/main/java/com/depromeet/threedays/domain/entity/habit/Habit.kt b/domain/src/main/java/com/depromeet/threedays/domain/entity/habit/Habit.kt index 3a43e1e6..2c7a2e93 100644 --- a/domain/src/main/java/com/depromeet/threedays/domain/entity/habit/Habit.kt +++ b/domain/src/main/java/com/depromeet/threedays/domain/entity/habit/Habit.kt @@ -8,10 +8,10 @@ data class Habit( val memberId: Int, val title: String, val imojiPath: String, - val dayOfWeeks: ArrayList, + val dayOfWeeks: List, val reward: Int, val color: Color, - val mate: Mate, + val mate: Mate?, val todayHabitAchievementId: Int?, // null이면 오늘 체크를 하지 않은 것 val sequence: Int, val createAt: String, diff --git a/domain/src/main/java/com/depromeet/threedays/domain/repository/HabitRepository.kt b/domain/src/main/java/com/depromeet/threedays/domain/repository/HabitRepository.kt index b944a1d3..4b4bb121 100644 --- a/domain/src/main/java/com/depromeet/threedays/domain/repository/HabitRepository.kt +++ b/domain/src/main/java/com/depromeet/threedays/domain/repository/HabitRepository.kt @@ -7,6 +7,7 @@ import kotlinx.coroutines.flow.Flow interface HabitRepository { suspend fun createHabit(habit: Habit) suspend fun getHabits(): Flow>> + suspend fun getArchivedHabits(): Flow>> //suspend fun getHabit(habitId: Long): Habit suspend fun updateHabit(habitId: Long) suspend fun deleteHabit(habitId: Long) diff --git a/domain/src/main/java/com/depromeet/threedays/domain/usecase/GetArchivedHabitsUseCase.kt b/domain/src/main/java/com/depromeet/threedays/domain/usecase/GetArchivedHabitsUseCase.kt new file mode 100644 index 00000000..73af83a1 --- /dev/null +++ b/domain/src/main/java/com/depromeet/threedays/domain/usecase/GetArchivedHabitsUseCase.kt @@ -0,0 +1,15 @@ +package com.depromeet.threedays.domain.usecase + +import com.depromeet.threedays.domain.entity.DataState +import com.depromeet.threedays.domain.entity.habit.Habit +import com.depromeet.threedays.domain.repository.HabitRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class GetArchivedHabitsUseCase @Inject constructor( + private val habitRepository: HabitRepository, +) { + suspend operator fun invoke(): Flow>> { + return habitRepository.getArchivedHabits() + } +} diff --git a/navigator/build.gradle b/navigator/build.gradle index c7be22de..46f4a30f 100644 --- a/navigator/build.gradle +++ b/navigator/build.gradle @@ -4,6 +4,7 @@ plugins { } android { + namespace 'com.depromeet.threedays.navigator' compileSdk 33 defaultConfig { diff --git a/navigator/src/main/java/com/depromeet/threedays/navigator/ArchivedHabitNavigator.kt b/navigator/src/main/java/com/depromeet/threedays/navigator/ArchivedHabitNavigator.kt new file mode 100644 index 00000000..3c19de39 --- /dev/null +++ b/navigator/src/main/java/com/depromeet/threedays/navigator/ArchivedHabitNavigator.kt @@ -0,0 +1,3 @@ +package com.depromeet.threedays.navigator + +interface ArchivedHabitNavigator : Navigator diff --git a/presentation/history/build.gradle b/presentation/history/build.gradle index 08b531fb..e701a950 100644 --- a/presentation/history/build.gradle +++ b/presentation/history/build.gradle @@ -6,6 +6,7 @@ plugins { } android { + namespace 'com.depromeet.threedays.history' compileSdk 33 defaultConfig { diff --git a/presentation/home/build.gradle b/presentation/home/build.gradle index b21a1615..626e41e2 100644 --- a/presentation/home/build.gradle +++ b/presentation/home/build.gradle @@ -12,6 +12,7 @@ android { } android { + namespace 'com.depromeet.threedays.home' compileSdk 33 defaultConfig { diff --git a/presentation/home/src/main/java/com/depromeet/threedays/home/home/HabitViewHolder.kt b/presentation/home/src/main/java/com/depromeet/threedays/home/home/HabitViewHolder.kt index 3c303438..9159d148 100644 --- a/presentation/home/src/main/java/com/depromeet/threedays/home/home/HabitViewHolder.kt +++ b/presentation/home/src/main/java/com/depromeet/threedays/home/home/HabitViewHolder.kt @@ -102,7 +102,7 @@ class HabitViewHolder(private val view: ItemHabitBinding) : RecyclerView.ViewHol } } - private fun convertDayListToString(dayOfWeeks: ArrayList): String { + private fun convertDayListToString(dayOfWeeks: List): String { return if (dayOfWeeks.size == 7) { "매일" } else if (dayOfWeeks.size == 5 diff --git a/presentation/home/src/main/java/com/depromeet/threedays/home/home/model/HabitUI.kt b/presentation/home/src/main/java/com/depromeet/threedays/home/home/model/HabitUI.kt index 74fd90fd..4917f457 100644 --- a/presentation/home/src/main/java/com/depromeet/threedays/home/home/model/HabitUI.kt +++ b/presentation/home/src/main/java/com/depromeet/threedays/home/home/model/HabitUI.kt @@ -9,7 +9,7 @@ data class HabitUI( val habitId: Int, val title: String, val imojiPath: String, - val dayOfWeeks: ArrayList, + val dayOfWeeks: List, val reward: Int, val todayHabitAchievementId: Int?, // null이면 오늘 체크를 하지 않은 것 val createAt: String, @@ -31,17 +31,17 @@ fun Habit.toHabitUI(): HabitUI { createAt = this.createAt, todayIndex = this.sequence % 3, isTodayChecked = this.todayHabitAchievementId != null, - checkedBackgroundResId = when(this.color) { + checkedBackgroundResId = when (this.color) { Color.GREEN -> R.drawable.selector_check_green Color.BLUE -> R.drawable.selector_check_blue Color.PINK -> R.drawable.selector_check_pink }, - checkableBackgroundResId = when(this.color) { + checkableBackgroundResId = when (this.color) { Color.GREEN -> R.drawable.selector_check_light_green Color.BLUE -> R.drawable.selector_check_light_blue Color.PINK -> R.drawable.selector_check_light_pink }, - checkableTextColor = when(this.color) { + checkableTextColor = when (this.color) { Color.GREEN -> core_color.color.green_50 Color.BLUE -> core_color.color.blue_50 Color.PINK -> core_color.color.pink_50 diff --git a/presentation/mate/build.gradle b/presentation/mate/build.gradle index e1e05e8a..ee2c0961 100644 --- a/presentation/mate/build.gradle +++ b/presentation/mate/build.gradle @@ -6,6 +6,7 @@ plugins { } android { + namespace 'com.depromeet.threedays.mate' compileSdk 33 defaultConfig { diff --git a/presentation/mypage/build.gradle b/presentation/mypage/build.gradle index e1e05e8a..d7d6b268 100644 --- a/presentation/mypage/build.gradle +++ b/presentation/mypage/build.gradle @@ -6,11 +6,14 @@ plugins { } android { + namespace 'com.depromeet.threedays.mypage' compileSdk 33 defaultConfig { minSdk 26 targetSdk 33 + versionCode rootProject.ext.threeDaysAppVersionCode + versionName rootProject.ext.threeDaysAppVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" diff --git a/presentation/mypage/src/main/AndroidManifest.xml b/presentation/mypage/src/main/AndroidManifest.xml index 5faefd9c..05c33307 100644 --- a/presentation/mypage/src/main/AndroidManifest.xml +++ b/presentation/mypage/src/main/AndroidManifest.xml @@ -1,5 +1,3 @@ - - + package="com.depromeet.threedays.mypage" /> diff --git a/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/MyPageFragment.kt b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/MyPageFragment.kt index 705d6707..21dca32c 100644 --- a/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/MyPageFragment.kt +++ b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/MyPageFragment.kt @@ -1,12 +1,75 @@ package com.depromeet.threedays.mypage +import android.content.pm.PackageManager +import android.content.pm.PackageManager.GET_CONFIGURATIONS +import android.os.Bundle +import android.view.View import androidx.fragment.app.viewModels import com.depromeet.threedays.core.BaseFragment +import com.depromeet.threedays.core.util.ThreeDaysToast import com.depromeet.threedays.mypage.databinding.FragmentMyPageBinding +import com.depromeet.threedays.mypage.nickname.EditNicknameDialogFragment +import com.depromeet.threedays.navigator.ArchivedHabitNavigator import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint -class MyPageFragment: BaseFragment(R.layout.fragment_my_page) { +class MyPageFragment : + BaseFragment(R.layout.fragment_my_page) { override val viewModel by viewModels() + @Inject + lateinit var archivedHabitNavigator: ArchivedHabitNavigator + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initEvent() + initView(view) + } + + /** + * 화면 초기화 + */ + private fun initView(view: View) { + // FIXME: getPackageInfo(String, PackageInfoFlags) 써보려했으나 에러나서 일단 동작하는 코드 사용함 + val versionName = view.context.packageManager.getPackageInfo("com.depromeet.threedays", 0,).versionName + binding.tvAppVersionName.text = versionName + } + + /** + * 이벤트 관련 작업 초기화 + */ + private fun initEvent() { + binding.ivHabitArchived.setOnClickListener { + onHabitArchivedButtonClicked() + } + binding.ivEdit.setOnClickListener { + onEditButtonClicked() + } + } + + private fun onHabitArchivedButtonClicked() { + val intent = archivedHabitNavigator.intent(requireContext()) + startActivity(intent) + } + + private fun onEditButtonClicked() { + val nickname = binding.tvNickname.text.toString() + EditNicknameDialogFragment( + nickname = nickname, + onSubmit = { ThreeDaysToast().show(requireContext(), "닉네임이 변경됐어요.") }, + ).show( + requireActivity().supportFragmentManager, + EditNicknameDialogFragment.TAG, + ) + } + + private fun onServicePolicyButtonClicked() { + TODO("이용 약관") + } + + private fun onPrivacyPolicyButtonClicked() { + TODO("개인정보처리방침") + } + } diff --git a/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/MyPageModule.kt b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/MyPageModule.kt new file mode 100644 index 00000000..5727c4dd --- /dev/null +++ b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/MyPageModule.kt @@ -0,0 +1,15 @@ +package com.depromeet.threedays.mypage + +import com.depromeet.threedays.mypage.archived_habit.ArchivedHabitNavigatorImpl +import com.depromeet.threedays.navigator.ArchivedHabitNavigator +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +internal abstract class MyPageModule { + @Binds + abstract fun bindArchivedHabitNavigator(navigator: ArchivedHabitNavigatorImpl): ArchivedHabitNavigator +} diff --git a/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitActivity.kt b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitActivity.kt new file mode 100644 index 00000000..29f1fc55 --- /dev/null +++ b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitActivity.kt @@ -0,0 +1,64 @@ +package com.depromeet.threedays.mypage.archived_habit + +import android.os.Bundle +import androidx.activity.viewModels +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.LinearLayoutManager +import com.depromeet.threedays.core.BaseActivity +import com.depromeet.threedays.mypage.R +import com.depromeet.threedays.mypage.databinding.ActivityArchivedHabitBinding +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch + +@AndroidEntryPoint +class ArchivedHabitActivity : + BaseActivity(R.layout.activity_archived_habit) { + private val viewModel by viewModels() + private lateinit var archivedHabitAdapter: ArchivedHabitAdapter + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + archivedHabitAdapter = ArchivedHabitAdapter() + initView() + + viewModel.fetchArchivedHabits() + setObserve() + } + + private fun setObserve() { + lifecycleScope.launch { + lifecycle.repeatOnLifecycle(androidx.lifecycle.Lifecycle.State.STARTED) { + viewModel.apply { + archivedHabits.collect { + archivedHabitAdapter.submitList(it) +// binding.containerNotificationEmpty.visibility = if (it.isEmpty()) View.VISIBLE else View.GONE + } + } + } + } + } + + private fun initView() { + binding.rvArchivedHabit.apply { + layoutManager = LinearLayoutManager(context) + adapter = archivedHabitAdapter + + val dividerItemDecoration = DividerItemDecoration(context, LinearLayoutManager.VERTICAL) + addItemDecoration(dividerItemDecoration) + } + + // 최초진입시 + val isFirst = true + if (isFirst) { + ArchivedHabitOnboardingSnackBar.show( + view = binding.flArchivedHabitOnboarding, + onAction = { + // TODO: 읽었다고 저장 + } + ) + } + } +} diff --git a/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitAdapter.kt b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitAdapter.kt new file mode 100644 index 00000000..24486f14 --- /dev/null +++ b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitAdapter.kt @@ -0,0 +1,40 @@ +package com.depromeet.threedays.mypage.archived_habit + +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter + +class ArchivedHabitAdapter : ListAdapter(DIFF_UTIL) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArchivedHabitViewHolder { + return ArchivedHabitViewHolder.create(parent, false) + } + + override fun onBindViewHolder(holder: ArchivedHabitViewHolder, position: Int) { + holder.onBind(getItem(position)) + } + + override fun getItemCount(): Int = currentList.size + + override fun getItemId(position: Int): Long { + return getItem(position).habitId + } + + companion object { + private val DIFF_UTIL = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame( + oldItem: ArchivedHabitUI, + newItem: ArchivedHabitUI + ): Boolean { + return oldItem.habitId == newItem.habitId + } + + override fun areContentsTheSame( + oldItem: ArchivedHabitUI, + newItem: ArchivedHabitUI + ): Boolean { + return oldItem == newItem + } + } + } +} diff --git a/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitNavigatorImpl.kt b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitNavigatorImpl.kt new file mode 100644 index 00000000..bd66c4fc --- /dev/null +++ b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitNavigatorImpl.kt @@ -0,0 +1,12 @@ +package com.depromeet.threedays.mypage.archived_habit + +import android.content.Context +import android.content.Intent +import com.depromeet.threedays.navigator.ArchivedHabitNavigator +import javax.inject.Inject + +class ArchivedHabitNavigatorImpl @Inject constructor() : ArchivedHabitNavigator { + override fun intent(context: Context): Intent { + return Intent(context, ArchivedHabitActivity::class.java) + } +} diff --git a/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitOnboardingSnackBar.kt b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitOnboardingSnackBar.kt new file mode 100644 index 00000000..62074d78 --- /dev/null +++ b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitOnboardingSnackBar.kt @@ -0,0 +1,45 @@ +package com.depromeet.threedays.mypage.archived_habit + +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.widget.FrameLayout +import androidx.core.content.ContextCompat +import com.depromeet.threedays.core.setOnSingleClickListener +import com.depromeet.threedays.mypage.R +import com.depromeet.threedays.mypage.databinding.SnackbarArchivedHabitOnboardingBinding +import com.google.android.material.snackbar.Snackbar + +class ArchivedHabitOnboardingSnackBar { + companion object { + fun show( + view: View, + onAction: () -> Unit + ) { + val binding = SnackbarArchivedHabitOnboardingBinding.inflate(LayoutInflater.from(view.context), null,false) + val snackbar = Snackbar.make( + view, + view.context.getString(R.string.archived_habit_onboarding_text), + Snackbar.LENGTH_INDEFINITE + ) + val snackBarLayout = snackbar.view as Snackbar.SnackbarLayout + + with(snackBarLayout) { + removeAllViews() + setPadding(0, 0, 0, 0) + setBackgroundColor(ContextCompat.getColor(context, android.R.color.transparent)) + addView(binding.root, 0) + + val params = layoutParams as FrameLayout.LayoutParams + params.gravity = Gravity.TOP + } + + binding.ivClose.setOnSingleClickListener { + onAction() + snackbar.dismiss() + } + + snackbar.show() + } + } +} diff --git a/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitUI.kt b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitUI.kt new file mode 100644 index 00000000..2c0535c2 --- /dev/null +++ b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitUI.kt @@ -0,0 +1,15 @@ +package com.depromeet.threedays.mypage.archived_habit + +import com.depromeet.threedays.domain.entity.habit.Habit + +data class ArchivedHabitUI( + val habitId: Long, + val title: String, +) { + companion object { + fun from(habit: Habit) = ArchivedHabitUI( + habitId = habit.habitId.toLong(), + title = habit.title, + ) + } +} diff --git a/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitViewHolder.kt b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitViewHolder.kt new file mode 100644 index 00000000..9c69410c --- /dev/null +++ b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitViewHolder.kt @@ -0,0 +1,29 @@ +package com.depromeet.threedays.mypage.archived_habit + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.depromeet.threedays.mypage.databinding.ItemHabitArchivedBinding + +class ArchivedHabitViewHolder( + private val binding: ItemHabitArchivedBinding, +) : RecyclerView.ViewHolder(binding.root) { + /** + * 데이터 연결해주는 작업 + */ + fun onBind(archivedHabitUI: ArchivedHabitUI) { + binding.tvTitle.text = archivedHabitUI.title + } + + companion object { + fun create(parent: ViewGroup, attachToParent: Boolean): ArchivedHabitViewHolder { + return ArchivedHabitViewHolder( + ItemHabitArchivedBinding.inflate( + LayoutInflater.from(parent.context), + parent, + attachToParent + ) + ) + } + } +} diff --git a/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitViewModel.kt b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitViewModel.kt new file mode 100644 index 00000000..af850c3f --- /dev/null +++ b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/archived_habit/ArchivedHabitViewModel.kt @@ -0,0 +1,36 @@ +package com.depromeet.threedays.mypage.archived_habit + +import androidx.lifecycle.viewModelScope +import com.depromeet.threedays.core.BaseViewModel +import com.depromeet.threedays.domain.entity.Status +import com.depromeet.threedays.domain.usecase.GetArchivedHabitsUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class ArchivedHabitViewModel @Inject constructor( + private val getArchivedHabitsUseCase: GetArchivedHabitsUseCase, +) : BaseViewModel() { + private val _archivedHabits: MutableStateFlow> = + MutableStateFlow(emptyList()) + val archivedHabits: StateFlow> + get() = _archivedHabits + + fun fetchArchivedHabits() { + viewModelScope.launch { + getArchivedHabitsUseCase().collect { response -> + when (response.status) { + Status.LOADING -> {} + Status.SUCCESS -> { + _archivedHabits.value = response.data!!.map { ArchivedHabitUI.from(it) } + } + Status.ERROR -> TODO() + Status.FAIL -> TODO() + } + } + } + } +} diff --git a/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/nickname/EditNicknameDialogFragment.kt b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/nickname/EditNicknameDialogFragment.kt new file mode 100644 index 00000000..2c823517 --- /dev/null +++ b/presentation/mypage/src/main/java/com/depromeet/threedays/mypage/nickname/EditNicknameDialogFragment.kt @@ -0,0 +1,90 @@ +package com.depromeet.threedays.mypage.nickname + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.widget.doAfterTextChanged +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.DialogFragment +import com.depromeet.threedays.mypage.R +import com.depromeet.threedays.core_design_system.R as CoreDesignSystemResources +import com.depromeet.threedays.mypage.databinding.FragmentEditNicknameDialogBinding + + +class EditNicknameDialogFragment( + val nickname: String, + val onSubmit: () -> Unit, +) : DialogFragment() { + private var _binding: FragmentEditNicknameDialogBinding? = null + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = DataBindingUtil.inflate(inflater, R.layout.fragment_edit_nickname_dialog, container, false) + binding.lifecycleOwner = viewLifecycleOwner + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + setLayout() + initView() + initEvent() + } + + private fun setLayout() { + requireNotNull(dialog).apply { + requireNotNull(window).apply { + setLayout( + (resources.displayMetrics.widthPixels * 0.78).toInt(), + ViewGroup.LayoutParams.WRAP_CONTENT + ) + setBackgroundDrawableResource(CoreDesignSystemResources.drawable.bg_rect_white_r18) + } + } + } + + private fun initView() { + binding.etNickname.apply { + setText(nickname) + + } +// requestFocus() +// val inputMethodManager = getSystemService(context, InputMethodManager::class.java) +// inputMethodManager?.showSoftInput(this, SHOW_IMPLICIT) + } + + private fun initEvent() { + binding.tvCancel.setOnClickListener { + dismiss() + } + binding.tvSubmit.setOnClickListener { + onSubmit() + dismiss() + } + + binding.etNickname.apply { + doAfterTextChanged { + if (text.isBlank()) { + // disabled + binding.tvSubmit.setBackgroundResource(CoreDesignSystemResources.drawable.bg_rect_gray200_r10) + val gray450 = context.getColor(CoreDesignSystemResources.color.gray_450) + binding.tvSubmit.setTextColor(gray450) + } else { + binding.tvSubmit.setBackgroundResource(CoreDesignSystemResources.drawable.bg_rect_main_r10) + val white = context.getColor(CoreDesignSystemResources.color.white) + binding.tvSubmit.setTextColor(white) + } + binding.tvCurrentLength.text = text.length.toString() + } + } + } + + companion object { + const val TAG = "EditNicknameDialogFragment" + } +} diff --git a/presentation/mypage/src/main/res/layout/activity_archived_habit.xml b/presentation/mypage/src/main/res/layout/activity_archived_habit.xml new file mode 100644 index 00000000..3414ecc5 --- /dev/null +++ b/presentation/mypage/src/main/res/layout/activity_archived_habit.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/presentation/mypage/src/main/res/layout/fragment_edit_nickname_dialog.xml b/presentation/mypage/src/main/res/layout/fragment_edit_nickname_dialog.xml new file mode 100644 index 00000000..b95aa296 --- /dev/null +++ b/presentation/mypage/src/main/res/layout/fragment_edit_nickname_dialog.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/presentation/mypage/src/main/res/layout/fragment_my_page.xml b/presentation/mypage/src/main/res/layout/fragment_my_page.xml index 6ad9a999..7a7d34e5 100644 --- a/presentation/mypage/src/main/res/layout/fragment_my_page.xml +++ b/presentation/mypage/src/main/res/layout/fragment_my_page.xml @@ -1,5 +1,6 @@ @@ -7,14 +8,209 @@ + android:layout_height="match_parent"> - + android:background="@color/gray_100" + tools:context=".MyPageFragment"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/presentation/mypage/src/main/res/layout/item_habit_archived.xml b/presentation/mypage/src/main/res/layout/item_habit_archived.xml new file mode 100644 index 00000000..fa117606 --- /dev/null +++ b/presentation/mypage/src/main/res/layout/item_habit_archived.xml @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/presentation/mypage/src/main/res/layout/snackbar_archived_habit_onboarding.xml b/presentation/mypage/src/main/res/layout/snackbar_archived_habit_onboarding.xml new file mode 100644 index 00000000..9b45cc36 --- /dev/null +++ b/presentation/mypage/src/main/res/layout/snackbar_archived_habit_onboarding.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + diff --git a/presentation/mypage/src/main/res/values/strings.xml b/presentation/mypage/src/main/res/values/strings.xml index 402d93f0..016acd03 100644 --- a/presentation/mypage/src/main/res/values/strings.xml +++ b/presentation/mypage/src/main/res/values/strings.xml @@ -1,4 +1,14 @@ - - Hello blank fragment + 닉네임 수정 + 취소 + 저장 + 🎯 + 실행 기록이 있거나 짝꿍과 연결된 습관은 홈에서 삭제시 보관함으로 이동돼요. + 버전 정보 + 이용 약관 + 개인정보처리방침 + 로그아웃 + 회원탈퇴 + 습관 보관함 + 편집 diff --git a/presentation/notification/src/main/java/com/depromeet/threedays/notification/NotificationActivity.kt b/presentation/notification/src/main/java/com/depromeet/threedays/notification/NotificationActivity.kt index 69a1a3d6..202c65b8 100644 --- a/presentation/notification/src/main/java/com/depromeet/threedays/notification/NotificationActivity.kt +++ b/presentation/notification/src/main/java/com/depromeet/threedays/notification/NotificationActivity.kt @@ -1,7 +1,5 @@ package com.depromeet.threedays.notification -import android.graphics.Rect -import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.View import androidx.activity.viewModels @@ -9,9 +7,7 @@ import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView import com.depromeet.threedays.core.BaseActivity -import com.depromeet.threedays.core.util.dpToPx import com.depromeet.threedays.notification.databinding.ActivityNotificationBinding import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch