From 7a352a3e83849880903eedbaa978a53bedd75433 Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Mon, 23 Feb 2026 22:01:34 +0900 Subject: [PATCH 1/6] =?UTF-8?q?chore:=20=EB=B2=84=EC=A0=84=EB=84=A4?= =?UTF-8?q?=EC=9E=84=200.0.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e086e1e0..79ecc4e0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,7 +22,7 @@ android { defaultConfig { applicationId = "com.sseotdabwa.buyornot" versionCode = 1 - versionName = "1.0.0" + versionName = "0.0.1" buildConfigField("String", "KAKAO_NATIVE_APP_KEY", "\"${localProperties.getProperty("kakao.nativeAppKey", "")}\"") manifestPlaceholders["NATIVE_APP_KEY"] = localProperties.getProperty("kakao.nativeAppKey", "") From 5374b726c0a4991bb90d8386fff209987fbf8bee Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Mon, 23 Feb 2026 22:11:16 +0900 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20=EB=B3=B8=EC=9D=B8=20=EA=B8=80=20?= =?UTF-8?q?=ED=88=AC=ED=91=9C=20=EB=B0=A9=EC=A7=80=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../buyornot/navigation/BuyOrNotNavHost.kt | 2 +- .../feature/home/navigation/HomeNavigation.kt | 2 +- .../home/{viewmodel => ui}/HomeContract.kt | 2 +- .../buyornot/feature/home/ui/HomeScreen.kt | 6 ------ .../buyornot/feature/home/ui/HomeViewModel.kt | 18 ++++++++++++------ 5 files changed, 15 insertions(+), 15 deletions(-) rename feature/home/src/main/java/com/sseotdabwa/buyornot/feature/home/{viewmodel => ui}/HomeContract.kt (98%) diff --git a/app/src/main/java/com/sseotdabwa/buyornot/navigation/BuyOrNotNavHost.kt b/app/src/main/java/com/sseotdabwa/buyornot/navigation/BuyOrNotNavHost.kt index 1dc892ba..e64547f1 100644 --- a/app/src/main/java/com/sseotdabwa/buyornot/navigation/BuyOrNotNavHost.kt +++ b/app/src/main/java/com/sseotdabwa/buyornot/navigation/BuyOrNotNavHost.kt @@ -20,7 +20,7 @@ import com.sseotdabwa.buyornot.feature.auth.navigation.splashScreen import com.sseotdabwa.buyornot.feature.home.navigation.homeScreen import com.sseotdabwa.buyornot.feature.home.navigation.navigateToHome import com.sseotdabwa.buyornot.feature.home.navigation.navigateToHomeWithTab -import com.sseotdabwa.buyornot.feature.home.viewmodel.HomeTab +import com.sseotdabwa.buyornot.feature.home.ui.HomeTab import com.sseotdabwa.buyornot.feature.mypage.navigation.myPageGraph import com.sseotdabwa.buyornot.feature.mypage.navigation.navigateToMyPage import com.sseotdabwa.buyornot.feature.notification.navigation.navigateToNotification diff --git a/feature/home/src/main/java/com/sseotdabwa/buyornot/feature/home/navigation/HomeNavigation.kt b/feature/home/src/main/java/com/sseotdabwa/buyornot/feature/home/navigation/HomeNavigation.kt index be401504..68187740 100644 --- a/feature/home/src/main/java/com/sseotdabwa/buyornot/feature/home/navigation/HomeNavigation.kt +++ b/feature/home/src/main/java/com/sseotdabwa/buyornot/feature/home/navigation/HomeNavigation.kt @@ -7,7 +7,7 @@ import androidx.navigation.NavType import androidx.navigation.compose.composable import androidx.navigation.navArgument import com.sseotdabwa.buyornot.feature.home.ui.HomeRoute -import com.sseotdabwa.buyornot.feature.home.viewmodel.HomeTab +import com.sseotdabwa.buyornot.feature.home.ui.HomeTab const val HOME_ROUTE = "home" const val HOME_ROUTE_WITH_TAB = "home?tab={tab}" diff --git a/feature/home/src/main/java/com/sseotdabwa/buyornot/feature/home/viewmodel/HomeContract.kt b/feature/home/src/main/java/com/sseotdabwa/buyornot/feature/home/ui/HomeContract.kt similarity index 98% rename from feature/home/src/main/java/com/sseotdabwa/buyornot/feature/home/viewmodel/HomeContract.kt rename to feature/home/src/main/java/com/sseotdabwa/buyornot/feature/home/ui/HomeContract.kt index 5f71b6f1..0ffac450 100644 --- a/feature/home/src/main/java/com/sseotdabwa/buyornot/feature/home/viewmodel/HomeContract.kt +++ b/feature/home/src/main/java/com/sseotdabwa/buyornot/feature/home/ui/HomeContract.kt @@ -1,4 +1,4 @@ -package com.sseotdabwa.buyornot.feature.home.viewmodel +package com.sseotdabwa.buyornot.feature.home.ui import androidx.compose.runtime.Immutable import com.sseotdabwa.buyornot.core.designsystem.components.ImageAspectRatio diff --git a/feature/home/src/main/java/com/sseotdabwa/buyornot/feature/home/ui/HomeScreen.kt b/feature/home/src/main/java/com/sseotdabwa/buyornot/feature/home/ui/HomeScreen.kt index 77465420..63df1895 100644 --- a/feature/home/src/main/java/com/sseotdabwa/buyornot/feature/home/ui/HomeScreen.kt +++ b/feature/home/src/main/java/com/sseotdabwa/buyornot/feature/home/ui/HomeScreen.kt @@ -63,12 +63,6 @@ import com.sseotdabwa.buyornot.core.designsystem.icon.BuyOrNotIcons import com.sseotdabwa.buyornot.core.designsystem.icon.asImageVector import com.sseotdabwa.buyornot.core.designsystem.theme.BuyOrNotTheme import com.sseotdabwa.buyornot.domain.model.UserType -import com.sseotdabwa.buyornot.feature.home.viewmodel.FeedItem -import com.sseotdabwa.buyornot.feature.home.viewmodel.FilterChip -import com.sseotdabwa.buyornot.feature.home.viewmodel.HomeIntent -import com.sseotdabwa.buyornot.feature.home.viewmodel.HomeSideEffect -import com.sseotdabwa.buyornot.feature.home.viewmodel.HomeTab -import com.sseotdabwa.buyornot.feature.home.viewmodel.HomeUiState import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlin.math.roundToInt diff --git a/feature/home/src/main/java/com/sseotdabwa/buyornot/feature/home/ui/HomeViewModel.kt b/feature/home/src/main/java/com/sseotdabwa/buyornot/feature/home/ui/HomeViewModel.kt index 6ebf3a19..ac648b8e 100644 --- a/feature/home/src/main/java/com/sseotdabwa/buyornot/feature/home/ui/HomeViewModel.kt +++ b/feature/home/src/main/java/com/sseotdabwa/buyornot/feature/home/ui/HomeViewModel.kt @@ -14,12 +14,6 @@ import com.sseotdabwa.buyornot.domain.model.VoteChoice import com.sseotdabwa.buyornot.domain.repository.FeedRepository import com.sseotdabwa.buyornot.domain.repository.UserPreferencesRepository import com.sseotdabwa.buyornot.domain.repository.UserRepository -import com.sseotdabwa.buyornot.feature.home.viewmodel.FeedItem -import com.sseotdabwa.buyornot.feature.home.viewmodel.FilterChip -import com.sseotdabwa.buyornot.feature.home.viewmodel.HomeIntent -import com.sseotdabwa.buyornot.feature.home.viewmodel.HomeSideEffect -import com.sseotdabwa.buyornot.feature.home.viewmodel.HomeTab -import com.sseotdabwa.buyornot.feature.home.viewmodel.HomeUiState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.stateIn @@ -210,6 +204,18 @@ class HomeViewModel @Inject constructor( val previousFeeds = uiState.value.feeds val previousCachedFeeds = cachedFeeds + // 본인 글 여부 확인 (투표 방지) + val targetFeed = cachedFeeds.find { it.id == feedId } + if (targetFeed?.isOwner == true) { + sendSideEffect( + HomeSideEffect.ShowSnackbar( + message = "자신의 글에는 투표할 수 없습니다.", + icon = null, + ), + ) + return + } + // 1. 낙관적 업데이트 (Optimistic Update) // API 호출 전 UI를 즉시 업데이트하여 사용자 경험 개선 val optimisticUpdate = { feeds: List -> From 230244316a8d722c1601e39500127c042673e376 Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Mon, 23 Feb 2026 22:16:15 +0900 Subject: [PATCH 3/6] =?UTF-8?q?feat:=20=EC=97=85=EB=A1=9C=EB=93=9C=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=EC=97=90=EC=84=9C=20=EB=92=A4=EB=A1=9C?= =?UTF-8?q?=EA=B0=80=EA=B8=B0=20=EC=8B=9C=20=EC=9E=85=EB=A0=A5=20=EB=82=B4?= =?UTF-8?q?=EC=9A=A9=EC=9D=B4=20=EC=97=86=EC=9C=BC=EB=A9=B4=20=EB=B0=94?= =?UTF-8?q?=EB=A1=9C=20=EC=A2=85=EB=A3=8C=EB=90=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../buyornot/feature/upload/ui/UploadContract.kt | 5 ++++- .../buyornot/feature/upload/ui/UploadScreen.kt | 12 ++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/feature/upload/src/main/java/com/sseotdabwa/buyornot/feature/upload/ui/UploadContract.kt b/feature/upload/src/main/java/com/sseotdabwa/buyornot/feature/upload/ui/UploadContract.kt index c04db261..51b2d2d4 100644 --- a/feature/upload/src/main/java/com/sseotdabwa/buyornot/feature/upload/ui/UploadContract.kt +++ b/feature/upload/src/main/java/com/sseotdabwa/buyornot/feature/upload/ui/UploadContract.kt @@ -15,7 +15,10 @@ data class UploadUiState( val showCategorySheet: Boolean = false, val showExitDialog: Boolean = false, val categories: List = FeedCategory.entries, -) +) { + val hasInput: Boolean + get() = selectedImageUri != null || category != null || price.isNotEmpty() || content.isNotEmpty() +} sealed interface UploadIntent { data class UpdateCategory( diff --git a/feature/upload/src/main/java/com/sseotdabwa/buyornot/feature/upload/ui/UploadScreen.kt b/feature/upload/src/main/java/com/sseotdabwa/buyornot/feature/upload/ui/UploadScreen.kt index 783e7692..665ae09b 100644 --- a/feature/upload/src/main/java/com/sseotdabwa/buyornot/feature/upload/ui/UploadScreen.kt +++ b/feature/upload/src/main/java/com/sseotdabwa/buyornot/feature/upload/ui/UploadScreen.kt @@ -119,7 +119,11 @@ fun UploadScreen( } BackHandler { - if (!uiState.showExitDialog) viewModel.handleIntent(UploadIntent.UpdateExitDialogVisibility(true)) + if (uiState.hasInput) { + if (!uiState.showExitDialog) viewModel.handleIntent(UploadIntent.UpdateExitDialogVisibility(true)) + } else { + onNavigateBack() + } } Column( @@ -131,7 +135,11 @@ fun UploadScreen( .windowInsetsPadding(WindowInsets.safeDrawing), ) { BackTopBar { - viewModel.handleIntent(UploadIntent.UpdateExitDialogVisibility(true)) + if (uiState.hasInput) { + viewModel.handleIntent(UploadIntent.UpdateExitDialogVisibility(true)) + } else { + onNavigateBack() + } } Column( From 0e1ab0ea71d2c804dfd16664872582c4417a3779 Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Mon, 23 Feb 2026 22:23:29 +0900 Subject: [PATCH 4/6] =?UTF-8?q?feat:=20Proguard=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20=EB=A6=B4=EB=A6=AC=EC=8A=A4=20=EB=B9=8C=EB=93=9C=20?= =?UTF-8?q?=EC=B5=9C=EC=A0=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 3 +- app/proguard-rules.pro | 81 +++++++++++++++++++++++++++++++----------- 2 files changed, 62 insertions(+), 22 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 79ecc4e0..d377cba2 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -59,7 +59,8 @@ android { signingConfig = signingConfigs.getByName("release") } release { - isMinifyEnabled = false + isMinifyEnabled = true + isShrinkResources = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro", diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 481bb434..b44e8339 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -1,21 +1,60 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file +# [Common] Android +-keepattributes SourceFile,LineNumberTable +-keepattributes *Annotation* +-keepattributes Signature +-keepattributes InnerClasses +-dontwarn sun.misc.** +-dontwarn javax.annotation.** + +# [Kotlin] +-keep class kotlin.Metadata { *; } + +# [Hilt / Dagger] +-keep class dagger.hilt.** { *; } +-keep class com.google.dagger.** { *; } +-keep @dagger.hilt.android.lifecycle.HiltViewModel class * +-keep interface * extends javax.inject.Provider + +# [Retrofit / OkHttp] +-keep class retrofit2.** { *; } +-dontwarn retrofit2.** +-keepattributes *Annotation* +-keepclassmembers class * { + @retrofit2.http.* ; +} +-keep class okhttp3.** { *; } +-dontwarn okhttp3.** +-dontwarn okio.** + +# [Kotlinx Serialization] +-keepattributes *Annotation*, InnerClasses +-keepclassmembers class * { + @kotlinx.serialization.Serializable *; +} +-keepclassmembers class * { + kotlinx.serialization.KSerializer serializer(...); +} + +# [Domain/Data Models] - API 통신 데이터 클래스 보존 +# 모든 모듈의 domain.model, network.model 하위의 클래스들을 보존합니다. +-keep class com.sseotdabwa.buyornot.domain.model.** { *; } +-keep class com.sseotdabwa.buyornot.core.network.model.** { *; } + +# [Coil] +-keep class coil.** { *; } +-dontwarn coil.** + +# [Firebase] +-keep class com.google.firebase.** { *; } +-dontwarn com.google.firebase.** + +# [Lottie] +-keep class com.airbnb.lottie.** { *; } + +# [Kakao SDK] +-keep class com.kakao.sdk.** { *; } +-dontwarn com.kakao.sdk.** + +# [Jetpack Compose] +-keep class androidx.compose.runtime.RecomposeScopeImpl { *; } +-keep class * implements androidx.compose.runtime.Parcelable { *; } From 0b480b4d10db97579403286b6dba9cd50b51dffd Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Mon, 23 Feb 2026 22:39:13 +0900 Subject: [PATCH 5/6] =?UTF-8?q?feat:=20Firebase=20Crashlytics=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=EC=84=B1=20=EB=B0=8F=20=EA=B4=80=EB=A0=A8=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 2 ++ app/src/main/AndroidManifest.xml | 1 + build.gradle.kts | 1 + gradle/libs.versions.toml | 5 ++++- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d377cba2..f2de374c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -6,6 +6,7 @@ plugins { alias(libs.plugins.hilt) alias(libs.plugins.ksp) alias(libs.plugins.google.services) + alias(libs.plugins.firebase.crashlytics) } val localProperties = @@ -105,6 +106,7 @@ dependencies { implementation(platform(libs.firebase.bom)) implementation(libs.firebase.messaging) + implementation(libs.firebase.crashlytics) ksp(libs.hilt.compiler) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2afd70c0..cf13dc03 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ + Date: Mon, 23 Feb 2026 22:51:22 +0900 Subject: [PATCH 6/6] =?UTF-8?q?chore:=20=EB=B2=84=EC=A0=84=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=201=20->=202?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f2de374c..0681f262 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,7 +22,7 @@ android { defaultConfig { applicationId = "com.sseotdabwa.buyornot" - versionCode = 1 + versionCode = 2 versionName = "0.0.1" buildConfigField("String", "KAKAO_NATIVE_APP_KEY", "\"${localProperties.getProperty("kakao.nativeAppKey", "")}\"")