From f73ba6ef253f573a119c9166e263da66614efee8 Mon Sep 17 00:00:00 2001 From: min486 Date: Sun, 24 Aug 2025 17:01:47 +0900 Subject: [PATCH 01/98] =?UTF-8?q?=EC=95=88=EB=93=9C=EB=A1=9C=EC=9D=B4?= =?UTF-8?q?=EB=93=9C=20=ED=94=84=EB=A1=9C=EC=A0=9D=ED=8A=B8=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 48 +++++ app/.gitignore | 1 + app/build.gradle.kts | 59 ++++++ app/proguard-rules.pro | 21 ++ .../com/min/dngo/ExampleInstrumentedTest.kt | 24 +++ app/src/main/AndroidManifest.xml | 27 +++ .../main/java/com/min/dngo/MainActivity.kt | 47 +++++ .../main/java/com/min/dngo/ui/theme/Color.kt | 11 ++ .../main/java/com/min/dngo/ui/theme/Theme.kt | 58 ++++++ .../main/java/com/min/dngo/ui/theme/Type.kt | 34 ++++ .../res/drawable/ic_launcher_background.xml | 170 ++++++++++++++++ .../res/drawable/ic_launcher_foreground.xml | 30 +++ .../main/res/mipmap-anydpi/ic_launcher.xml | 6 + .../res/mipmap-anydpi/ic_launcher_round.xml | 6 + app/src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1404 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2898 bytes app/src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 982 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1772 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1900 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3918 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2884 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5914 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3844 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 7778 bytes app/src/main/res/values/colors.xml | 10 + app/src/main/res/values/strings.xml | 3 + app/src/main/res/values/themes.xml | 5 + app/src/main/res/xml/backup_rules.xml | 13 ++ .../main/res/xml/data_extraction_rules.xml | 19 ++ .../test/java/com/min/dngo/ExampleUnitTest.kt | 17 ++ build.gradle.kts | 6 + gradle.properties | 23 +++ gradle/libs.versions.toml | 32 +++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 185 ++++++++++++++++++ gradlew.bat | 89 +++++++++ settings.gradle.kts | 24 +++ 38 files changed, 974 insertions(+) create mode 100644 .gitignore create mode 100644 app/.gitignore create mode 100644 app/build.gradle.kts create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/com/min/dngo/ExampleInstrumentedTest.kt create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/java/com/min/dngo/MainActivity.kt create mode 100644 app/src/main/java/com/min/dngo/ui/theme/Color.kt create mode 100644 app/src/main/java/com/min/dngo/ui/theme/Theme.kt create mode 100644 app/src/main/java/com/min/dngo/ui/theme/Type.kt create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 app/src/main/res/mipmap-anydpi/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/themes.xml create mode 100644 app/src/main/res/xml/backup_rules.xml create mode 100644 app/src/main/res/xml/data_extraction_rules.xml create mode 100644 app/src/test/java/com/min/dngo/ExampleUnitTest.kt create mode 100644 build.gradle.kts create mode 100644 gradle.properties create mode 100644 gradle/libs.versions.toml create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle.kts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ed88217 --- /dev/null +++ b/.gitignore @@ -0,0 +1,48 @@ +# Built application files +*.apk +*.aab +*.aar +*.ap_ + +# Files for the ART/Dalvik VM +*.dex + +# Gradle files +.gradle/ +build/ +local.properties +.idea/caches/ +.idea/libraries/ +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/misc.xml +.idea/modules.xml +.idea/vcs.xml + +# Kotlin files +*.kt.log +*.kt.test.log + +# Android Studio 4.x +.idea/runConfigurations.xml + +# Local configuration files (e.g., used by third-party tools) +.env +.env.local +.DS_Store + +# IDE specific files +.idea/ +*.iws +*.iml +*.ipr +.idea/codeStyles/ +.idea/gradle.xml +.idea/misc.xml +.idea/modules.xml +.idea/vcs.xml + +# Keystore files +*.jks +*.keystore diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..ff3d9eb --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,59 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) +} + +android { + namespace = "com.min.dngo" + compileSdk = 36 + + defaultConfig { + applicationId = "com.min.dngo" + minSdk = 30 + targetSdk = 36 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + buildFeatures { + compose = true + } +} + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.ui.test.junit4) + debugImplementation(libs.androidx.ui.tooling) + debugImplementation(libs.androidx.ui.test.manifest) +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/com/min/dngo/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/min/dngo/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..526856e --- /dev/null +++ b/app/src/androidTest/java/com/min/dngo/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.min.dngo + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.min.dngo", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..c5970f7 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/min/dngo/MainActivity.kt b/app/src/main/java/com/min/dngo/MainActivity.kt new file mode 100644 index 0000000..f846c9a --- /dev/null +++ b/app/src/main/java/com/min/dngo/MainActivity.kt @@ -0,0 +1,47 @@ +package com.min.dngo + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.min.dngo.ui.theme.DngoTheme + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + setContent { + DngoTheme { + Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> + Greeting( + name = "Android", + modifier = Modifier.padding(innerPadding) + ) + } + } + } + } +} + +@Composable +fun Greeting(name: String, modifier: Modifier = Modifier) { + Text( + text = "Hello $name!", + modifier = modifier + ) +} + +@Preview(showBackground = true) +@Composable +fun GreetingPreview() { + DngoTheme { + Greeting("Android") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/min/dngo/ui/theme/Color.kt b/app/src/main/java/com/min/dngo/ui/theme/Color.kt new file mode 100644 index 0000000..21e65fa --- /dev/null +++ b/app/src/main/java/com/min/dngo/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package com.min.dngo.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/app/src/main/java/com/min/dngo/ui/theme/Theme.kt b/app/src/main/java/com/min/dngo/ui/theme/Theme.kt new file mode 100644 index 0000000..67268a3 --- /dev/null +++ b/app/src/main/java/com/min/dngo/ui/theme/Theme.kt @@ -0,0 +1,58 @@ +package com.min.dngo.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun DngoTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/min/dngo/ui/theme/Type.kt b/app/src/main/java/com/min/dngo/ui/theme/Type.kt new file mode 100644 index 0000000..d36996a --- /dev/null +++ b/app/src/main/java/com/min/dngo/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package com.min.dngo.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/app/src/main/res/mipmap-anydpi/ic_launcher.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml new file mode 100644 index 0000000..6f3b755 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..c209e78ecd372343283f4157dcfd918ec5165bb3 GIT binary patch literal 1404 zcmV-?1%vuhNk&F=1pok7MM6+kP&il$0000G0000-002h-06|PpNX!5L00Dqw+t%{r zzW2vH!KF=w&cMnnN@{whkTw+#mAh0SV?YL=)3MimFYCWp#fpdtz~8$hD5VPuQgtcN zXl<@<#Cme5f5yr2h%@8TWh?)bSK`O z^Z@d={gn7J{iyxL_y_%J|L>ep{dUxUP8a{byupH&!UNR*OutO~0{*T4q5R6@ApLF! z5{w?Z150gC7#>(VHFJZ-^6O@PYp{t!jH(_Z*nzTK4 zkc{fLE4Q3|mA2`CWQ3{8;gxGizgM!zccbdQoOLZc8hThi-IhN90RFT|zlxh3Ty&VG z?Fe{#9RrRnxzsu|Lg2ddugg7k%>0JeD+{XZ7>Z~{=|M+sh1MF7~ zz>To~`~LVQe1nNoR-gEzkpe{Ak^7{{ZBk2i_<+`Bq<^GB!RYG+z)h;Y3+<{zlMUYd zrd*W4w&jZ0%kBuDZ1EW&KLpyR7r2=}fF2%0VwHM4pUs}ZI2egi#DRMYZPek*^H9YK zay4Iy3WXFG(F14xYsoDA|KXgGc5%2DhmQ1gFCkrgHBm!lXG8I5h*uf{rn48Z!_@ z4Bk6TJAB2CKYqPjiX&mWoW>OPFGd$wqroa($ne7EUK;#3VYkXaew%Kh^3OrMhtjYN?XEoY`tRPQsAkH-DSL^QqyN0>^ zmC>{#F14jz4GeW{pJoRpLFa_*GI{?T93^rX7SPQgT@LbLqpNA}<@2wH;q493)G=1Y z#-sCiRNX~qf3KgiFzB3I>4Z%AfS(3$`-aMIBU+6?gbgDb!)L~A)je+;fR0jWLL-Fu z4)P{c7{B4Hp91&%??2$v9iRSFnuckHUm}or9seH6 z>%NbT+5*@L5(I9j@06@(!{ZI?U0=pKn8uwIg&L{JV14+8s2hnvbRrU|hZCd}IJu7*;;ECgO%8_*W Kmw_-CKmY()leWbG literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..b2dfe3d1ba5cf3ee31b3ecc1ced89044a1f3b7a9 GIT binary patch literal 2898 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..4f0f1d64e58ba64d180ce43ee13bf9a17835fbca GIT binary patch literal 982 zcmV;{11bDcNk&G_0{{S5MM6+kP&il$0000G0000l001ul06|PpNU8t;00Dqo+t#w^ z^1csucXz7-Qrhzl9HuHB%l>&>1tG2^vb*E&k^T3$FG1eQZ51g$uv4V+kI`0<^1Z@N zk?Jjh$olyC%l>)Xq;7!>{iBj&BjJ`P&$fsCfpve_epJOBkTF?nu-B7D!hO=2ZR}

C%4 zc_9eOXvPbC4kzU8YowIA8cW~Uv|eB&yYwAObSwL2vY~UYI7NXPvf3b+c^?wcs~_t{ ze_m66-0)^{JdOMKPwjpQ@Sna!*?$wTZ~su*tNv7o!gXT!GRgivP}ec?5>l1!7<(rT zds|8x(qGc673zrvYIz;J23FG{9nHMnAuP}NpAED^laz3mAN1sy+NXK)!6v1FxQ;lh zOBLA>$~P3r4b*NcqR;y6pwyhZ3_PiDb|%n1gGjl3ZU}ujInlP{eks-#oA6>rh&g+!f`hv#_%JrgYPu z(U^&XLW^QX7F9Z*SRPpQl{B%x)_AMp^}_v~?j7 zapvHMKxSf*Mtyx8I}-<*UGn3)oHd(nn=)BZ`d$lDBwq_GL($_TPaS{UeevT(AJ`p0 z9%+hQb6z)U9qjbuXjg|dExCLjpS8$VKQ55VsIC%@{N5t{NsW)=hNGI`J=x97_kbz@ E0Of=7!TQj4N+cqN`nQhxvX7dAV-`K|Ub$-q+H-5I?Tx0g9jWxd@A|?POE8`3b8fO$T))xP* z(X?&brZw({`)WU&rdAs1iTa0x6F@PIxJ&&L|dpySV!ID|iUhjCcKz(@mE z!x@~W#3H<)4Ae(4eQJRk`Iz3<1)6^m)0b_4_TRZ+cz#eD3f8V;2r-1fE!F}W zEi0MEkTTx}8i1{`l_6vo0(Vuh0HD$I4SjZ=?^?k82R51bC)2D_{y8mi_?X^=U?2|F{Vr7s!k(AZC$O#ZMyavHhlQ7 zUR~QXuH~#o#>(b$u4?s~HLF*3IcF7023AlwAYudn0FV~|odGH^05AYPEfR)8p`i{n zwg3zPVp{+wOsxKc>)(pMupKF!Y2HoUqQ3|Yu|8lwR=?5zZuhG6J?H`bSNk_wPoM{u zSL{c@pY7+c2kck>`^q1^^gR0QB7Y?KUD{vz-uVX~;V-rW)PDcI)$_UjgVV?S?=oLR zf4}zz{#*R_{LkiJ#0RdQLNC^2Vp%JPEUvG9ra2BVZ92(p9h7Ka@!yf9(lj#}>+|u* z;^_?KWdzkM`6gqPo9;;r6&JEa)}R3X{(CWv?NvgLeOTq$cZXqf7|sPImi-7cS8DCN zGf;DVt3Am`>hH3{4-WzH43Ftx)SofNe^-#|0HdCo<+8Qs!}TZP{HH8~z5n`ExcHuT zDL1m&|DVpIy=xsLO>8k92HcmfSKhflQ0H~9=^-{#!I1g(;+44xw~=* zxvNz35vfsQE)@)Zsp*6_GjYD};Squ83<_?^SbALb{a`j<0Gn%6JY!zhp=Fg}Ga2|8 z52e1WU%^L1}15Ex0fF$e@eCT(()_P zvV?CA%#Sy08_U6VPt4EtmVQraWJX` zh=N|WQ>LgrvF~R&qOfB$!%D3cGv?;Xh_z$z7k&s4N)$WYf*k=|*jCEkO19{h_(%W4 zPuOqbCw`SeAX*R}UUsbVsgtuG?xs(#Ikx9`JZoQFz0n*7ZG@Fv@kZk`gzO$HoA9kN z8U5{-yY zvV{`&WKU2$mZeoBmiJrEdzUZAv1sRxpePdg1)F*X^Y)zp^Y*R;;z~vOv-z&)&G)JQ{m!C9cmziu1^nHA z`#`0c>@PnQ9CJKgC5NjJD8HM3|KC(g5nnCq$n0Gsu_DXk36@ql%npEye|?%RmG)

FJ$wK}0tWNB{uH;AM~i literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..948a3070fe34c611c42c0d3ad3013a0dce358be0 GIT binary patch literal 1900 zcmV-y2b1_xNk&Fw2LJ$9MM6+kP&il$0000G0001A003VA06|PpNH75a00DqwTbm-~ zullQTcXxO9ki!OCRx^i?oR|n!<8G0=kI^!JSjFi-LL*`V;ET0H2IXfU0*i>o6o6Gy zRq6Ap5(_{XLdXcL-MzlN`ugSdZY_`jXhcENAu)N_0?GhF))9R;E`!bo9p?g?SRgw_ zEXHhFG$0{qYOqhdX<(wE4N@es3VIo$%il%6xP9gjiBri+2pI6aY4 zJbgh-Ud|V%3O!IcHKQx1FQH(_*TK;1>FQWbt^$K1zNn^cczkBs=QHCYZ8b&l!UV{K z{L0$KCf_&KR^}&2Fe|L&?1I7~pBENnCtCuH3sjcx6$c zwqkNkru);ie``q+_QI;IYLD9OV0ZxkuyBz|5<$1BH|vtey$> z5oto4=l-R-Aaq`Dk0}o9N0VrkqW_#;!u{!bJLDq%0092{Ghe=F;(kn} z+sQ@1=UlX30+2nWjkL$B^b!H2^QYO@iFc0{(-~yXj2TWz?VG{v`Jg zg}WyYnwGgn>{HFaG7E~pt=)sOO}*yd(UU-D(E&x{xKEl6OcU?pl)K%#U$dn1mDF19 zSw@l8G!GNFB3c3VVK0?uyqN&utT-D5%NM4g-3@Sii9tSXKtwce~uF zS&Jn746EW^wV~8zdQ1XC28~kXu8+Yo9p!<8h&(Q({J*4DBglPdpe4M_mD8AguZFn~ ztiuO~{6Bx?SfO~_ZV(GIboeR9~hAym{{fV|VM=77MxDrbW6`ujX z<3HF(>Zr;#*uCvC*bpoSr~C$h?_%nXps@A)=l_;({Fo#6Y1+Zv`!T5HB+)#^-Ud_; zBwftPN=d8Vx)*O1Mj+0oO=mZ+NVH*ptNDC-&zZ7Hwho6UQ#l-yNvc0Cm+2$$6YUk2D2t#vdZX-u3>-Be1u9gtTBiMB^xwWQ_rgvGpZ6(C@e23c!^K=>ai-Rqu zhqT`ZQof;9Bu!AD(i^PCbYV%yha9zuoKMp`U^z;3!+&d@Hud&_iy!O-$b9ZLcSRh? z)R|826w}TU!J#X6P%@Zh=La$I6zXa#h!B;{qfug}O%z@K{EZECu6zl)7CiNi%xti0 zB{OKfAj83~iJvmpTU|&q1^?^cIMn2RQ?jeSB95l}{DrEPTW{_gmU_pqTc)h@4T>~& zluq3)GM=xa(#^VU5}@FNqpc$?#SbVsX!~RH*5p0p@w z;~v{QMX0^bFT1!cXGM8K9FP+=9~-d~#TK#ZE{4umGT=;dfvWi?rYj;^l_Zxywze`W z^Cr{55U@*BalS}K%Czii_80e0#0#Zkhlij4-~I@}`-JFJ7$5{>LnoJSs??J8kWVl6|8A}RCGAu9^rAsfCE=2}tHwl93t0C?#+jMpvr7O3`2=tr{Hg$=HlnjVG^ewm|Js0J*kfPa6*GhtB>`fN!m#9J(sU!?(OSfzY*zS(FJ<-Vb zfAIg+`U)YaXv#sY(c--|X zEB+TVyZ%Ie4L$gi#Fc++`h6%vzsS$pjz9aLt+ZL(g;n$Dzy5=m=_TV(3H8^C{r0xd zp#a%}ht55dOq?yhwYPrtp-m1xXp;4X;)NhxxUpgP%XTLmO zcjaFva^}dP3$&sfFTIR_jC=2pHh9kpI@2(6V*GQo7Ws)`j)hd+tr@P~gR*2gO@+1? zG<`_tB+LJuF|SZ9tIec;h%}}6WClT`L>HSW?E{Hp1h^+mlbf_$9zA>!ug>NALJsO{ mU%z=YwVD?}XMya)Bp;vlyE5&E_6!fzx9pwrdz474!~g(M6R?N? literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..1b9a6956b3acdc11f40ce2bb3f6efbd845cc243f GIT binary patch literal 3918 zcmV-U53%r4Nk&FS4*&pHMM6+kP&il$0000G0001A003VA06|PpNSy@$00HoY|G(*G z+qV7x14$dSO^Re!iqt-AAIE9iwr$(CZQJL$blA4B`>;C3fBY6Q8_YSjb2%a=fc}4E zrSzssacq<^nmW|Rs93PJni30R<8w<(bK_$LO4L?!_OxLl$}K$MUEllnMK|rg=f3;y z*?;3j|Nh>)p0JQ3A~rf(MibH2r+)3cyV1qF&;8m{w-S*y+0mM){KTK^M5}ksc`qX3 zy>rf^b>~l>SSHds8(I@hz3&PD@LmEs4&prkT=BjsBCXTMhN$_)+kvnl0bLKW5rEsj z*d#KXGDB4P&>etx0X+`R19yC=LS)j!mgs5M0L~+o-T~Jl!p!AJxnGAhV%~rhYUL4hlWhgES3Kb5oA&X z{}?3OBSS-{!v$nCIGj->(-TAG)8LR{htr41^gxsT8yqt2@DEG6Yl`Uma3Nd4;YUoW zTbkYl3CMU5ypMF3EIkYmWL|*BknM`0+Kq6CpvO(y$#j94e+q{vI{Zp8cV_6RK!`&C zob$*5Q|$IZ09dW=L!V zw@#2wviu|<#3lgGE8GEhcx+zBt`} zOwP8j9X%^f7i_bth4PiJ$LYtFJSCN$3xwDN;8mr*B;CJwBP2G0TMq0uNt7S^DO_wE zepk!Wrn#Z#03j{`c*Rf~y3o7?J}w?tEELRUR2cgxB*Y{LzA#pxHgf}q?u5idu>077 zd^=p)`nA}6e`|@`p?u}YU66PP_MA}Zqqe!c{nK&z%Jwq1N4e_q<#4g^xaz=ao;u|6 zwpRcW2Lax=ZGbx=Q*HhlJ`Ns#Y*r0*%!T?P*TTiX;rb)$CGLz=rSUum$)3Qyv{BL2 zO*=OI2|%(Yz~`pNEOnLp>+?T@glq-DujlIp?hdJeZ7ctP4_OKx|5@EOps3rr(pWzg zK4d3&oN-X2qN(d_MkfwB4I)_)!I_6nj2iA9u^pQ{;GckGLxBGrJUM2Wdda!k)Y>lq zmjws>dVQ*vW9lvEMkiN3wE-__6OWD0txS&Qn0n22cyj4Q*8(nG4!G{6OOwNvsrPIL zCl-$W9UwkEUVuLwyD%|inbOF*xMODZ4VMEVAq_zUxZ+K#Gdqf!DW$5f)?7UNOFMz! zrB~tuu=6X2FE(p^iqgxr+?ZK;=yz`e;C$#_@D9Lj-+TDVOrva>(#*PVbaHO>A)mhl z07OJWCqYC60518$!&c`eNBcBW%GnfaQ*$eazV^2_AW?j)h;J1nUjN(I9=0+!RVx~% z3@Tf!P0TE+98jA?WceK-}A1% zW!K)lyKcGqy#M~})315-A#2NXQ`?6NR#Apo=S!oF=JfpX>iR*49ec{7AN$xxpK{D$ z2d%Fz&rdfSqourN$~Y^NFIMV1CZ?J*bMx~H3k&meGtH@q9ra2vZxmA$S(#jaaj-g4 ztJmxG+DLV<*q<|sDXPp$X>E)#S}Vm&sRaO5P&goh2><}FEdZSXDqsL$06sAkh(e+v zAsBhKSRexgwg6tIy~GFJzaTxXD(}|+0eOwFDA%rn`X;MVwDHT9=4=g%OaJ9s%3b9>9EUTnnp0t;2Zpa{*>mk~hZqItE_!dQ zOtC>8`$l|mV43Jbudf0N6&&X;{=z}Zi}d1`2qmJ}i|0*GsulD3>GgQXHN)pkR6sf1 z?5ZU%&xtL}oH;YiAA)d*^Ndw2T$+Mjuzyzz@-SM`9df7LqTxLuIwC~S0092~+=qYv z@*ja;?Wt!T!{U?c*Z0YtGe)XbI&y-?B&G2$`JDM)(dIV9G`Sc#6?sI60de6kv+)Qb zUW~2|WjvJq3TA8`0+sWA3zRhY9a~ow)O~&StBkG2{*{TGiY~S8ep{V&Vo2l<6LWsu z^#p0-v*t2?3&aA1)ozu|%efSR=XnpX$lvTeRdKlvM!@|pM5p2w3u-6 zU>}t2xiYLS+{|%C65AzX+23Mtlq?BS&YdYcYsVjoiE&rT>;Necn6l^K)T^lmE`5u{ zm1i+-a-gc;Z&v-{;8r)z6NYfBUv+=_L}ef}qa9FX01)+Aaf+;xj(mL6|JUzGJR1|fnanb%?BPPIp>SCjP|8qE5qJ{=n5ZGw?81z3(k;pzH%1CtlX50{E7h)$h{qGKfzC`e2o`*IqA#tjA z`Fz&^%$b9F*N`)U-#6>a)Z`55`$Dd0cfcs0$d13^ONrdCu9xcv_=n#WQo8stcz3jP9|2EvdI-RhJM3%Q%oM&!OlShM|0 z?gz?wHZSnm45njLtsz8PVT1S&jAlbKg5kVam$p16=EK@Sj4EP0OtH zmJDmdc^v)x>56Qg_wmYHz6h)>kl_h$>0@J!ypv%APmjZTAQVLy6Fu50RGY&JAVNhx zrF_qG6`x9MkT;1SFWo$)l{M$;3qUDn9JwE}z zRl#E_bDRJFii61kPgBybIgp8dNW!Cc1b*^YYk-#oWLJvtM_v^hQx~9?8LD4VFFxBF z3MlrsSC%f9Oupn*ctPL0U1fwfX?`tRhPD{PSLFPQOmIt$mDy0SgpNVvHS+f#Do>h1Gn?LZU9(KaN>Q_=Y*_T zvtD7%_u^^+{g`0VGzg(VZrpVQ6Ub5M=tI_p7T93R8@3Zulu3|#{iNcu!oiHxZ4Rf*( zfmiN$$ru(*_Zqn=`Gq#OuHRTSwp7uH_SokR&|)RuW5yo=Z|_4?qU-JU+tpt>!B&Is z@N(=SG;bpVc;AO@zbmMM zScqq1)b-ZQIrs={oD}|?6y{$HNB1U0^LsBh8JI&3!GBZxOXI<}&5-$lgkAaYqhOTb z?2vEnZ$-kk;*M_17(upJF3%+iH*s0-r{vttXVB2OUwI1s^+G(Ft(U8gYFXC}#P&E^ z>T@C^tS`Z7{6HT4_nF~n>JlZtk5&qDBl6r|^kzQYe`wq!C)n@$c>WOPA61NDFj<<6 zGW71NMMhwAl!U-yqrq2xrSFqRCI8acw7?}3j;ynxo*-b7Co;g5r%^j=H@9({PXXBf z@r>U>>N;E)81wx`B4f%{PB~MHka_);%kBCb(d|Jy5!MqJ%2p`t&@L)4$T2j&-WHvG zv3(uyA_gwqNu(k?jQTtv3dgPKRZoH8prxe7>pQBW5L&dpumS&5Ld2?(sCpJjvc4L5 zEnh&?91WVm)ZdTj=fjJ$pPDdgAttLXuke+?KdKxu*;kTC(r!tQk6;gxj4h%FdHAt(^M3YvYj(!tOeN)+Hvj6+< zzyJRG?^lZfWuR#t!tUKP&(?%3v&Zd$R2YN>lB(Lq`OInY48%4%yTv2 zYe1{G`3)(PDEio5Y@-I5tUf`c%%OCJMtSW56g3iEg%3`$7XSJJHyA z<|7&N)5Xrlgv~%BO24eFd;Hd;uiK%D`EdK|quUeRZDqbh9l)%j%J#0lfrZumvA<_w zu&=AVvdChf6}eqh(bUz`(`Ue*p01{fBAcTgKyDYLs_I+YyJEk+rM@avU~>fB$n)HS zM7pfJydu`i%gfS<{PF94kZDv$t>06sAkheDzu40NJ$5CMW%n^Lls?8^p^QGWURbKu3ZduZQZ((s2? zzE`}<{;Zt7<$C|9R8A~DJ~@%x>TfP zF>TX8)@v|t)q4GjRt<}5s6hLHwRel7>V@&r-O|Av(yh;Q1A{E>Ir>p+%dHD|=l+lT zpr(Dg&>#Nu=!)6bCLr-ZS%|;h)Ij$+e@r8_{qO19QvDe=&1tmpY*0lcA^Cc-#{9fQ z<~$*<&P$Q<_jy#<$40PMofM7aQ}C=jphI`4kLg}Z7CIN#26D{-4v-_CA-LiE@(%{y!BzsU%gG`Q?sjLUf%qFSl0y)2#ae*+EI>s|i`d^V$Dn)qmzqRq6VJRY|{4ujsIU%#bnqU6MR&-1I_43=|5(6Jr;Jvert) zE?S|Tmn}Tv<-??sxV5@9t}3D=>YZ0JrQe$CO~|EY=Lj9RM&4svQHPQL6%pV5fPFiH zfXDx;l@~et{*{U*#c#Dvzu)|znDO7$#CRx)Z&yp-}SrD{&|(MQtfUz~n35@RLfUy=aqrhCX0M}J_r5QsK~NmRCR|Nm&L z41UdsLjWxSUlL41r^0K&nCCK>fdR-!MYjFg(z9_mF^C|#ZQw?`)f6uVzF^`bRnVY& zo}@M06J&_+>w9@jpaO4snmU;0t-(zYW1qVBHtuD!d?%?AtN7Plp><-1Y8Rqb20ZaP zTCgn*-Sri4Q8Xn>=gNaWQ57%!D35UkA@ksOlPB*Dvw}t02ENAqw|kFhn%ZyyW%+t{ zNdM!uqEM^;2}f+tECHbwLmH*!nZVrb$-az%t50Y2pg(HqhvY-^-lb}>^6l{$jOI6} zo_kBzj%8aX|6H5M0Y<)7pzz_wLkIpRm!;PzY)9+24wk2&TT{w--phDGDCOz{cN_ca zpnm7`$oDy=HX%0i-`769*0M6(e5j-?(?24%)<)&46y0e&6@HCDZAm9W6Ib#Y#BF6- z=30crHGg+RRTe%VBC>T00OV6F+gQDAK38Ne3N9bm|62tPccBJi)5{B z4zc^Db72XiBd}v$CF|yU{Z=M|DZ%-(XarYNclODlb1Kz1_EKLy(NSLCN`eUl(rBCL zT*jx@wNvze0|TSqgE(QArOZU)_?qH(sj#TwzElLs9q)(0u!_P|R%Cy_0JFQxgGV>1 zz4?_uq<8_gM0`c*Hh|;UMz~vrg1gQXp{ufg`hM_qU;U>+zmvc5blCLSq@PrEBSGR# z&8=2Z4uXN`F3p73ueD1l{s{k$WipAvSh5W7ABe?4)t;r@V?y`bNB5FvBuE|0VRTb< zM1Hn^?DSsJY+sX@T5xW=#>T9VEV|?<(=6|ge$X6Sb05!LFdjDcoq*gM(Zq=t;_)Le&jyt(&9jzR73noru`a# zN*<`KwGa^gZU3-)MSLF0aFag#f0<>E(bYTeHmtdbns#|I)-$)mJ`q9ctQ8g0=ET?| zdO}eZ*b_p>ygRTtR^5Ggdam=Zb5wmd{}np+Jn1d_=M`~P=M67jj})fH4ztb5yQqQW z^C|C&^LHAK-u+ooIK)yM)QM?t;|<{P;;{`p=BclzAN#JzL4jCwXkQB1Dy{=^KR`=~ zTrr)y7eiYBzSNs_DvO=4A6#EgGS-zY%Vi)N*Yb`U;6o}KR}dq{r9pT5wqZ@3NOE8- z9-(}D|Nc5732CSYQbL)!gPQ#RbD8BhK3dl{sUuPvei0tkvnJBxDEAYTesU8H$)g(Plra{VH(v3u^CO1~(+ zU0O7#)jaS4{NcwA+LuSm&VBcX2#Im3xg)W}ySNw%->orn1taZ&+d)}8gJTqA!u|5P z{yv?zol_3|(1(%M(EVU=cp?L`{Pi|ixk{U)*guFML3P!OSlz;zGA#T+E@8@cgQ_mv1o7RSU=Zo_82F?&&2r;WE z@wk}JHYEZ9nYUc(Vv~iTCa3u8e4q(yq<29VoNbKk|`mq%I6u)My=gPIDuUb&lzf4`MEA9^g8u z)vp8|$$HE9m_BTV?lOosIGa4jud=jIbw)O2eCMfyw2*S8?hjWw^nqws$O*M$3I1)x zR0PWFb3$ySOcGTe1dz%N0l;RPc`x%05FtT^f^j{YCP}*Q=lvp4$ZXrTZQHhO+w%wJn3c8j%+5C3UAFD&%8dBl_qi9D5g8fry}6Ev z2_Q~)5^N$!IU`BPh1O|=BxQ#*C5*}`lluC515$lxc-vNC)IgW=K|=z7o%cWFpndn= zX}f{`!VK02_kU+Q5a3m37J;c} zTzbxteE{GNf?yLt5X=Bzc-mio^Up0nunMCgp*ZJ;%MJvPM3QK)BryP(_v@ei4UvHr z6+sbCifQaOkL6-;5fL8$W($zZ_;CZp305C;~$hhRquZr-r)jjd1z z31%ZK{-(`P#|Um_Sivn@p$-vz46uqT>QG0B1w9znfS9A8PB2LaHdzA|_)yjXVR*l{ zkcu3@vEf7bxH0nkh`q?8FmoO_Ucui*>_a~P?qQrlZ9@+D7%MTpSnztpylXrt5!-k8_QPB?YL8Kx_On8WD zgT+111d(Op$^$&KLAN5+@?>f7F4~wFi(8TL8+szgVmcMDTp5l&k6~=rA{Dt}!gb^r zSWY<)M7D|Z2P0cEodj6E42PV>&>DFmQpgt)E-|#sSUU@uKed+F680H@<;-x{p|nuH4!_mn85rx>wz;0mPi2ZkL#k6;sznu?cXh!T0S>{w6 zL^gvR05NY64l*<+_L>On$rjx9!US;l;LX6@z}yi#2XHh)F@Oo+l)h%fq$v}DNmF2> zfs^_t0)3N-W<9-N?uedVv{)-J0W5mh#29QM5R5h&KuiRM=0Zvnf#lF=K#WlCgc#9c zS;qvh(P$!_a8JwyhI^ZJV2k+B6Z^64?w|1?5gyo6y{}923CRZfYVe1#?F% z7h2SUiNO3;T#JUOyovSs@@C1GtwipycA=*x5{BpIZ_#GCMuV8XK=x;qCNy{d7?wA~ zC+=vjls;ci&zW=6$H~4^K%v{p}Ab?U%C6Z4p%eC<3ExqU$XR<}LLF67A$Sr20DR_pJ3yeBa~ z^sw{V0FI5;UpwXsScYuhbqGQ`YQ25;6p6W^+tgL&;Ml;>S3CGpSZ>VrTn0m1$y$HU z&65)I!c?oREz};c=nLCliriqQX->4uivHTgd${GqeAlf*!P^B|jkU|*IdNP(&6C>4 zqOW$)Nw9nvjy^&`?E|gotDV{JmJ9Q~vuhy<`^C4XIUDt|j4o6rK^e8_(=YqC zuaR6TRVf@tUFHB079o4MBIh{M~4>WwnGgesQH*3?w(RA%hCZ*7)b!aNV=yOQ%o_Y=Lt0Sl*(9^jfRnC210Om$=y>*o|3z} zAR&vAdrB#mWoaB0fJSw9xw|Am$fzK>rx-~R#7IFSAwdu_EI|SRfB*yl0w8oX09H^q zAjl2?0I)v*odGJ40FVGaF&2qJq9Gv`>V>2r0|c`GX8h>CX8eHcOy>S0@<;M3<_6UM z7yCEpug5NZL!H_0>Hg_HasQGxR`rY&Z{geOy?N92Z z{lER^um|$*?*G63*njwc(R?NT)Bei*3jVzR>FWUDb^gKhtL4A=kE_1p-%Fo2`!8M} z(0AjuCiS;G{?*^1tB-uY%=)SRx&D)pK4u@>f6@KPe3}2j_har$>HqzH;UCR^ssFD0 z7h+VLO4o@_Yt>>AeaZKUxqyvxWCAjKB>qjQ30UA)#w z&=RmdwlT`7a8J8Yae=7*c8XL|{@%wA8uvCqfsNX^?UZsS>wX}QD{K}ad4y~iO*p%4 z_cS{u7Ek%?WV6em2(U9#d8(&JDirb^u~7wK4+xP$iiI6IlD|a&S)6o=kG;59N|>K1 zn(0mUqbG3YIY7dQd+*4~)`!S9m7H6HP6YcKHhBc#b%1L}VIisp%;TckEkcu0>lo@u995$<*Em;XNodjTiCdC%R+TX|_ZR#|1`RR|`^@Teh zl#w@8fI1FTx2Dy+{blUT{`^kY*V-AZUd?ZZqCS4gW(kY5?retkLbF=>p=59Nl|=sf zo1Pc|{{N4>5nt#627ylGF`3n>X%`w%bw-Y~zWM_{Si$dc82|=YhISal{N7OY?O`C4 zD|qb}6nLWJ`hUyL+E>-;ricg9J@ZNYP(x(Sct&OI$Y!QWr*=^VN;G3#i>^1n4e#Je zOVhbFbLpXVu*16enDM+ic;97@R~u&kh__kgP#!R`*rQEnA+_dLkNP~L`0alC|J;c; zeiK=s8;BsLE)KbG3BD&Br@(Ha@SBT&$?xX`=$;eeel=|R_dIr6-Ro?=HEjnsJ_b`1 zK6Yg^-6;^2aW!xeTK)A~3Rm|L^FCHB_I>jIju7ZGo&N_1*QHkxH2!!%@o4iZ?vntS;&zJdPe1dH#04YD93A44o-MpfD zP{rn_aq>U%RDvC2+bp;xPlsOzauIi3*Lf42`jVKKZCRuKdYhi>FDuL2l=v{$BCN#Q6796s%r-AG$Q^t(3c@ zD?w0UhYr11@feiyl9kY_@H8~|xlmO<8PfQmj1!$@WieW@VxR@Psxfe-v9WCi1+f>F4VL?0O~K7T?m4-u|pSkBpUJZZe*16_wAp zSYZ@;k`3;W3UHKUWc8QeI}0jH5Ly=cGWQPw(Kr2fm=-5L(d`lcXofy8tJY3@Tuadz zYWXR{mW7XT!RF#RVCe%}=tM*O6!AD3^(!8un~opNI%Uko7$5t@<8+?; zTxDys(MyyGsUjtSu9$+|_-t!U3fVb1dkK?l`17<+jfl=hrBHnDSV>^R1=TnQeyqbW z>ov#l%!1|S!1>8UUxIdhQq`_klcHVx0{?#>K3#$4GlXncwldt!g17TcvKq-jo_996 z>oA=tH9CqRl6Yw?Uc`am!V?lHJbizOJaVaScf1UP5e7Dbgabq=b!B~T&_F6?ooU>w%x0A zH~&MHJ=q`fCH{U<7MDXE4SD32cDZA)WJeWkllJ`UspWaS#eDe^kg^oU_A14UE9zG-a^g{xaXf$})Wik>gT zl#dkzGr(;h0JZDuFn(+k8wNq?PZ5grQ<+sM?wBGt@JnH6v0#or-5wBQWKU~(S_> zkE!tc*ZJ1Y&*p(xX84POb3cClRMd!^qJ#CAZfIepEj-<`VURS_yCz0(?*Ixcj4 z-!zV1_QZhpm=0<;*(nm+F>T=)o?ep@CK5I%g^VAA+RB25ab?7)A~z~egru=I1S|@v zH7tXV!0wmGS^qj#e+MY;C5eUjEAp$Y?LDkS^QPZ}8WN85?r$u<-Epi;yZ1|J2J`se z$D6DpH~2F=eI0B&=UFAUnJvZAmClJlK)sutJ?M>xpZiWV&0=G4MZP+x+p>EX=HbCz zxls%Mw?*u^;LbHWIWCyq+yi)`GmFn9J112CZda_u@YIP%i;srFg_paU02Ifij*7}l z&CF-(3|>*a|+vbNR`^RP=9G?ymEJ0Z~)d&c*UE$UMepZ zcITr{0WqhxkjUnM15js_gW=e3Uh|y6ZReaXHIz-=p`x5VvB&rH9y>Amv@^WmXFEw) zQXYrk3feir=a{jMQ+wDIkkFnZ$k{sJakHn*?u za%4b!00ev8NVLM1TY=cl?KB&55BY_MU-sg?c>=Dbz_W{(Z~c?HJi*XpYL)C6Bd8WH zt+v-#0&o~@t4qESi*)+eW%@VD0|o^yF)n0hME$UtXF$*Lvh}7sso{`|pn*JDIy5^Fm3s$5*zEE=?u5<=l8FJc3r%+H} zdfoNl2J0^~!-*mOL5o-x32|e0Im*E!yY7F7E5N)W3>+v_LBydlEx?4$RL5f2oYRD# zaR0wv(-p~wO0eLDl3K=%`{5+0Gd$ktO=W)gWlGZJ0`K z$_RNA=ckrfa;H0KA~dR^p�(p-{x$&=IACIfoAR!za)F-^da-t3#0Dycnp zwO~NVXwXCl;jE<}>%@xz|=8fIJAB?>+E{7)|4l${4ngA3G|=r z2Dyv;VVWSgZx9Wj>qUjleGl3Ei9K4>h!(lPS%8VOG>Xu0%6VDz^O=bjJmuP7>DeUv zrbI}MlHB^^d?{zv6d=@_ZD2lg1&G7UjnVN{1}9WkaM3H~btX0GtSzB+tZ^qRgWo4m z!GmimlG$=wgXCnr6j@m<1gAL46#T~5Bnm=2{^@>|t&`9mkEPddj zAvG~@Tv~TAm2i%VW}R-g(Z0)z-Y|szHr@rk>4MAyG*Ma*7Yh#H7(!-5>DZ@8r;_dx z{prSe<>~099F8vsYd2xff7uAS%7{S)f(|@me3t2$iy&NEc7OUEchp@9A|X;;IA>8!oX+y(BKJ$EzV* znR$z;!L$s7uy@{OT~nG#B!NRraT8(X##Ho!0r_o@gg0CA-9H^;-uE&?$2$nHv_00o z%cbuUc-tCx$Uh&EZ4Nf4Zgqv)Y6>usG3>GeQnxx_Z6+PcbX-+ysbt1hQ`K1LDpOE? zrAhIZhSN9yVIAOa22gn577tbc&i3|3V8NWy&!tw##`}9*x}gtI^h1DzZRA>UuaJG) zaZ7j)dq!O}{?#8Y7~7i6fHh4{`pL?>-18|p!S75Y#^DM>-S3)vuZG+Q7l@ek zQP~#cBpWgg#mApc_sPYjpw8odQuRokmTkzcNl`^CcKB7e&;zViV;{Y{o^Y$%7i0m# z62%#1Lq!RC?}lK>%mp}T!3Xv;L*0v*>USLm``N%>w>@fwC+#T&Tx2bN4w(20JB}oU zuSa6v^kXi0xPs?pbaOHnyiqq6By1EZY9OZ^^QA>{q-Hsd&m`pbQ%8121aWG-F5xf zlZ%;B{;C>X19|`^_?dVyCq>n+41w7|!tUS!{9rHlbhX=SZO5CQ^;!Du_E7*`GiR^Q w)2!4MKjfSAeNo!9>IaV6aUZ*?W>} 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

UmY2RIYtNPVDpE$%vda+HD#3m z&VuXJ{BK&Qe+rBa7eq}Q(bq|tn(RrJAk|ztj2(i{d>nmQnM?;HF2k&9sA6up5tmjl z7lySlzMbifH17-m-Lwa_F&e7nOH?ESi3#ckR3tsM+jsck3`oG!uMS}|eAwVXv>}qxwq?QY%QJ0}r@^;fhuUA9W z*BVl>TGo&N004@xSiwDUXUvp51sVmqO3m)=B55aPwf@0=e}cN+$-BdKxY`YrT_4)0 z_d10#i44Q*rFr8MC>*)v$EJvz``(pb{e&*6k+b zsMz%($|1+8hn8c2?P(l@;Rb&CsZeYoCI3?2!LqjbwPXW3z4G$Qfj=cT5Yb%vY0(AX oeb?AaKtwrnc|$|zzw9vfvn^aJJ!zd)XFXqqy0000001=f@-~a#s literal 0 HcmV?d00001 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..4e1b1ae --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Dngo + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..5ff8139 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ + + + + + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index f8c6127..3f4a0dc 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -7,4 +7,5 @@ #FF018786 #FF000000 #FFFFFFFF + #FFEDE2DA \ 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 5ff8139..0cba15e 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,5 +1,14 @@ + - + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 93ece85..3cbb928 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,6 +16,7 @@ nav = "2.9.3" hilt = "2.56.2" ksp = "2.2.0-2.0.2" hiltNavigationCompose = "1.2.0" +splash = "1.0.1" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -42,6 +43,7 @@ androidx-navigation-compose = { module = "androidx.navigation:navigation-compose hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" } hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hilt" } hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "hiltNavigationCompose" } +splash = { module = "androidx.core:core-splashscreen", version.ref = "splash" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } From 5c9b5bc0efd24a7f0ae783248d214ffac0f0c879 Mon Sep 17 00:00:00 2001 From: min486 Date: Tue, 7 Oct 2025 17:24:24 +0900 Subject: [PATCH 17/98] =?UTF-8?q?design:=20=EC=98=A8=EB=B3=B4=EB=94=A9=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20UI=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 8 +- .../onboarding/OnboardingScreen.kt | 57 ++++++ .../onboarding/OnboardingScreen2.kt | 85 ++++++++ .../onboarding/OnboardingScreen3.kt | 85 ++++++++ .../component/OnboardingButtonSection.kt | 93 +++++++++ .../dnapp/presentation/ui/icon/__AppIcons.kt | 3 +- .../presentation/ui/icon/appicons/Back.kt | 114 +++++++++++ app/src/main/res/drawable/logo_onboarding.xml | 137 +++++++++++++ .../main/res/drawable/logo_onboarding2.xml | 137 +++++++++++++ .../main/res/drawable/logo_onboarding3.xml | 185 ++++++++++++++++++ 10 files changed, 902 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen2.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen3.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/onboarding/component/OnboardingButtonSection.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Back.kt create mode 100644 app/src/main/res/drawable/logo_onboarding.xml create mode 100644 app/src/main/res/drawable/logo_onboarding2.xml create mode 100644 app/src/main/res/drawable/logo_onboarding3.xml diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index 00d504a..d360d38 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -19,6 +19,9 @@ import com.min.dnapp.presentation.AppStartViewModel import com.min.dnapp.presentation.home.HomeScreen import com.min.dnapp.presentation.login.LoginScreen import com.min.dnapp.presentation.login.LoginScreen2 +import com.min.dnapp.presentation.onboarding.OnboardingScreen +import com.min.dnapp.presentation.onboarding.OnboardingScreen2 +import com.min.dnapp.presentation.onboarding.OnboardingScreen3 import com.min.dnapp.presentation.ui.theme.DngoTheme import dagger.hilt.android.AndroidEntryPoint @@ -33,7 +36,10 @@ class MainActivity : ComponentActivity() { setContent { DngoTheme { // MomentoApp() - LoginScreen2() +// LoginScreen2() +// OnboardingScreen() +// OnboardingScreen2() + OnboardingScreen3() } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen.kt b/app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen.kt new file mode 100644 index 0000000..1c5b3d6 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen.kt @@ -0,0 +1,57 @@ +package com.min.dnapp.presentation.onboarding + +import androidx.compose.foundation.Image +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.height +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.R +import com.min.dnapp.presentation.onboarding.component.OnboardingButtonSection +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun OnboardingScreen() { + Surface( + modifier = Modifier.fillMaxSize(), + color = MomentoTheme.colors.brownW90 + ) { + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.SpaceBetween + ) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.End + ) { + Spacer(Modifier.height(144.dp)) + Image( + painter = painterResource(R.drawable.logo_onboarding), + contentDescription = null + ) + } + + OnboardingButtonSection( + title = "모멘토와 함께하는 따뜻하고 진솔한 공간. \n제목, 날짜, 장소, 감정을 \n입력하여 내 기록을 남겨보세요.", + onClick = {} + ) + } + } +} + +@Preview +@Composable +fun OnboardingScreenPreview() { + DngoTheme { + OnboardingScreen() + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen2.kt b/app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen2.kt new file mode 100644 index 0000000..cbf2c55 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen2.kt @@ -0,0 +1,85 @@ +package com.min.dnapp.presentation.onboarding + +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +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.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.R +import com.min.dnapp.presentation.onboarding.component.OnboardingButtonSection +import com.min.dnapp.presentation.ui.icon.AppIcons +import com.min.dnapp.presentation.ui.icon.appicons.Back +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun OnboardingScreen2() { + Scaffold( + containerColor = MomentoTheme.colors.brownW90, + topBar = { + CenterAlignedTopAppBar( + title = { Text("") }, + navigationIcon = { + Icon( + modifier = Modifier + .clickable { } + .padding(16.dp), + imageVector = AppIcons.Back, + contentDescription = null + ) + }, + colors = TopAppBarDefaults.centerAlignedTopAppBarColors( + containerColor = MomentoTheme.colors.brownW90 + ) + ) + } + ) { paddingValues -> + Column( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize(), + verticalArrangement = Arrangement.SpaceBetween + ) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.End + ) { + Spacer(Modifier.height(76.dp)) + Image( + painter = painterResource(R.drawable.logo_onboarding2), + contentDescription = null + ) + } + + OnboardingButtonSection( + title = "여행을 기록할 때마다 스탬프가 적립돼요. \n하나의 기록이 모여 나만의 컬렉션이 완성됩니다. \n", + onClick = {} + ) + } + } +} + +@Preview +@Composable +fun OnboardingScreen2Preview() { + DngoTheme { + OnboardingScreen2() + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen3.kt b/app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen3.kt new file mode 100644 index 0000000..9fad16c --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen3.kt @@ -0,0 +1,85 @@ +package com.min.dnapp.presentation.onboarding + +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +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.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.R +import com.min.dnapp.presentation.onboarding.component.OnboardingButtonSection +import com.min.dnapp.presentation.ui.icon.AppIcons +import com.min.dnapp.presentation.ui.icon.appicons.Back +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun OnboardingScreen3() { + Scaffold( + containerColor = MomentoTheme.colors.brownW90, + topBar = { + CenterAlignedTopAppBar( + title = { Text("") }, + navigationIcon = { + Icon( + modifier = Modifier + .clickable { } + .padding(16.dp), + imageVector = AppIcons.Back, + contentDescription = null + ) + }, + colors = TopAppBarDefaults.centerAlignedTopAppBarColors( + containerColor = MomentoTheme.colors.brownW90 + ) + ) + } + ) { paddingValues -> + Column( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize(), + verticalArrangement = Arrangement.SpaceBetween + ) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(Modifier.height(40.dp)) + Image( + painter = painterResource(R.drawable.logo_onboarding3), + contentDescription = null + ) + } + + OnboardingButtonSection( + title = "솔직한 기록을 다른 사람과 가볍게 나누기 \n공감과 영감을 주고받는 공간입니다. \n", + onClick = {} + ) + } + } +} + +@Preview +@Composable +fun OnboardingScreen3Preview() { + DngoTheme { + OnboardingScreen3() + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/onboarding/component/OnboardingButtonSection.kt b/app/src/main/java/com/min/dnapp/presentation/onboarding/component/OnboardingButtonSection.kt new file mode 100644 index 0000000..9ea1020 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/onboarding/component/OnboardingButtonSection.kt @@ -0,0 +1,93 @@ +package com.min.dnapp.presentation.onboarding.component + +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.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.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun OnboardingButtonSection( + title: String, + onClick: () -> Unit +) { + Box( + modifier = Modifier + .fillMaxWidth() + .background(color = MomentoTheme.colors.white, shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp)), + ) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(Modifier.height(40.dp)) + Text( +// text = "모멘토와 함께하는 따뜻하고 진솔한 공간. \n제목, 날짜, 장소, 감정을 \n입력하여 내 기록을 남겨보세요.", + text = title, + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.black, + textAlign = TextAlign.Center + ) + Spacer(Modifier.height(20.dp)) + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 20.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row { + Box( + modifier = Modifier + .width(16.dp) + .height(8.dp) + .background(color = MomentoTheme.colors.pinkBase, shape = RoundedCornerShape(20.dp)) + ) + Spacer(Modifier.width(4.dp)) + Box( + modifier = Modifier + .size(8.dp) + .background(color = MomentoTheme.colors.pinkW40, shape = CircleShape) + ) + Spacer(Modifier.width(4.dp)) + Box( + modifier = Modifier + .size(8.dp) + .background(color = MomentoTheme.colors.pinkW40, shape = CircleShape) + ) + } + Box( + modifier = Modifier + .clickable { onClick() } + .background(color = MomentoTheme.colors.pinkW80, shape = RoundedCornerShape(10.dp)) + .padding(horizontal = 20.dp, vertical = 12.dp) + ) { + Text( + text = "Next", + style = MomentoTheme.typography.label, + color = MomentoTheme.colors.black, + textAlign = TextAlign.Center + ) + } + } + Spacer(Modifier.height(20.dp)) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt index 6ec04d8..9002396 100644 --- a/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt @@ -1,6 +1,7 @@ package com.min.dnapp.presentation.ui.icon import androidx.compose.ui.graphics.vector.ImageVector +import com.min.dnapp.presentation.ui.icon.appicons.Back import com.min.dnapp.presentation.ui.icon.appicons.Kakao import kotlin.collections.List as ____KtList @@ -13,6 +14,6 @@ public val AppIcons.AllIcons: ____KtList if (__AllIcons != null) { return __AllIcons!! } - __AllIcons= listOf(Kakao) + __AllIcons= listOf(Back, Kakao) return __AllIcons!! } diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Back.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Back.kt new file mode 100644 index 0000000..6aa3841 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Back.kt @@ -0,0 +1,114 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.Back: ImageVector + get() { + if (_back != null) { + return _back!! + } + _back = Builder(name = "Back", defaultWidth = 16.0.dp, defaultHeight = 12.0.dp, + viewportWidth = 16.0f, viewportHeight = 12.0f).apply { + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(1.121f, 6.0f) + lineTo(0.708f, 5.587f) + lineTo(0.296f, 6.0f) + lineTo(0.708f, 6.413f) + lineTo(1.121f, 6.0f) + close() + moveTo(15.121f, 6.583f) + curveTo(15.276f, 6.583f, 15.424f, 6.522f, 15.533f, 6.413f) + curveTo(15.643f, 6.303f, 15.704f, 6.155f, 15.704f, 6.0f) + curveTo(15.704f, 5.845f, 15.643f, 5.697f, 15.533f, 5.588f) + curveTo(15.424f, 5.478f, 15.276f, 5.417f, 15.121f, 5.417f) + verticalLineTo(6.583f) + close() + moveTo(5.374f, 0.92f) + lineTo(0.708f, 5.587f) + lineTo(1.534f, 6.413f) + lineTo(6.2f, 1.746f) + lineTo(5.374f, 0.92f) + close() + moveTo(0.708f, 6.413f) + lineTo(5.374f, 11.08f) + lineTo(6.2f, 10.254f) + lineTo(1.534f, 5.587f) + lineTo(0.708f, 6.413f) + close() + moveTo(1.121f, 6.583f) + horizontalLineTo(15.121f) + verticalLineTo(5.417f) + horizontalLineTo(1.121f) + verticalLineTo(6.583f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.2f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(1.121f, 6.0f) + lineTo(0.708f, 5.587f) + lineTo(0.296f, 6.0f) + lineTo(0.708f, 6.413f) + lineTo(1.121f, 6.0f) + close() + moveTo(15.121f, 6.583f) + curveTo(15.276f, 6.583f, 15.424f, 6.522f, 15.533f, 6.413f) + curveTo(15.643f, 6.303f, 15.704f, 6.155f, 15.704f, 6.0f) + curveTo(15.704f, 5.845f, 15.643f, 5.697f, 15.533f, 5.588f) + curveTo(15.424f, 5.478f, 15.276f, 5.417f, 15.121f, 5.417f) + verticalLineTo(6.583f) + close() + moveTo(5.374f, 0.92f) + lineTo(0.708f, 5.587f) + lineTo(1.534f, 6.413f) + lineTo(6.2f, 1.746f) + lineTo(5.374f, 0.92f) + close() + moveTo(0.708f, 6.413f) + lineTo(5.374f, 11.08f) + lineTo(6.2f, 10.254f) + lineTo(1.534f, 5.587f) + lineTo(0.708f, 6.413f) + close() + moveTo(1.121f, 6.583f) + horizontalLineTo(15.121f) + verticalLineTo(5.417f) + horizontalLineTo(1.121f) + verticalLineTo(6.583f) + close() + } + } + .build() + return _back!! + } + +private var _back: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.Back, contentDescription = "") + } +} diff --git a/app/src/main/res/drawable/logo_onboarding.xml b/app/src/main/res/drawable/logo_onboarding.xml new file mode 100644 index 0000000..00ffcb3 --- /dev/null +++ b/app/src/main/res/drawable/logo_onboarding.xml @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/logo_onboarding2.xml b/app/src/main/res/drawable/logo_onboarding2.xml new file mode 100644 index 0000000..a3d99bc --- /dev/null +++ b/app/src/main/res/drawable/logo_onboarding2.xml @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/logo_onboarding3.xml b/app/src/main/res/drawable/logo_onboarding3.xml new file mode 100644 index 0000000..af4c493 --- /dev/null +++ b/app/src/main/res/drawable/logo_onboarding3.xml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 351058af6f385bb777e19ecd3357dfd20a1a6438 Mon Sep 17 00:00:00 2001 From: min486 Date: Tue, 7 Oct 2025 20:13:19 +0900 Subject: [PATCH 18/98] =?UTF-8?q?design:=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=ED=99=94=EB=A9=B4=20UI=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 4 +- .../profile/ProfileSetupScreen.kt | 171 +++++++++++++ app/src/main/res/drawable/logo_profile.xml | 63 +++++ app/src/main/res/drawable/logo_profile2.xml | 52 ++++ app/src/main/res/drawable/logo_profile3.xml | 35 +++ app/src/main/res/drawable/logo_profile4.xml | 162 ++++++++++++ app/src/main/res/drawable/logo_profile5.xml | 106 ++++++++ app/src/main/res/drawable/logo_profile6.xml | 80 ++++++ app/src/main/res/drawable/logo_profile7.xml | 241 ++++++++++++++++++ app/src/main/res/drawable/logo_profile8.xml | 46 ++++ 10 files changed, 959 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/profile/ProfileSetupScreen.kt create mode 100644 app/src/main/res/drawable/logo_profile.xml create mode 100644 app/src/main/res/drawable/logo_profile2.xml create mode 100644 app/src/main/res/drawable/logo_profile3.xml create mode 100644 app/src/main/res/drawable/logo_profile4.xml create mode 100644 app/src/main/res/drawable/logo_profile5.xml create mode 100644 app/src/main/res/drawable/logo_profile6.xml create mode 100644 app/src/main/res/drawable/logo_profile7.xml create mode 100644 app/src/main/res/drawable/logo_profile8.xml diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index d360d38..8765587 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -22,6 +22,7 @@ import com.min.dnapp.presentation.login.LoginScreen2 import com.min.dnapp.presentation.onboarding.OnboardingScreen import com.min.dnapp.presentation.onboarding.OnboardingScreen2 import com.min.dnapp.presentation.onboarding.OnboardingScreen3 +import com.min.dnapp.presentation.profile.ProfileSetupScreen import com.min.dnapp.presentation.ui.theme.DngoTheme import dagger.hilt.android.AndroidEntryPoint @@ -39,7 +40,8 @@ class MainActivity : ComponentActivity() { // LoginScreen2() // OnboardingScreen() // OnboardingScreen2() - OnboardingScreen3() +// OnboardingScreen3() + ProfileSetupScreen() } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/profile/ProfileSetupScreen.kt b/app/src/main/java/com/min/dnapp/presentation/profile/ProfileSetupScreen.kt new file mode 100644 index 0000000..cc89bdb --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/profile/ProfileSetupScreen.kt @@ -0,0 +1,171 @@ +package com.min.dnapp.presentation.profile + +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.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.shape.RoundedCornerShape +import androidx.compose.material3.Surface +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.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.R +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun ProfileSetupScreen() { + Surface( + modifier = Modifier.fillMaxSize(), + color = MomentoTheme.colors.white + ) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 20.dp), + verticalArrangement = Arrangement.SpaceBetween + ) { + ProfileSelectSection() + ProfileButtonSection( + onClick = {} + ) + } + } +} + +@Composable +fun ProfileSelectSection() { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(Modifier.height(20.dp)) + + Text( + text = "프로필 설정", + style = MomentoTheme.typography.title01, + color = MomentoTheme.colors.black + ) + + Spacer(Modifier.height(34.dp)) + + // 기본 프로필이미지 목록 (8개) + Column( + modifier = Modifier.fillMaxWidth() + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center + ) { + Image( + painter = painterResource(R.drawable.logo_profile), + contentDescription = null + ) + Spacer(Modifier.width(20.dp)) + Image( + painter = painterResource(R.drawable.logo_profile2), + contentDescription = null + ) + } + Spacer(Modifier.height(16.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center + ) { + Image( + painter = painterResource(R.drawable.logo_profile3), + contentDescription = null + ) + Spacer(Modifier.width(20.dp)) + Image( + painter = painterResource(R.drawable.logo_profile4), + contentDescription = null + ) + } + Spacer(Modifier.height(16.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center + ) { + Image( + painter = painterResource(R.drawable.logo_profile5), + contentDescription = null + ) + Spacer(Modifier.width(20.dp)) + Image( + painter = painterResource(R.drawable.logo_profile6), + contentDescription = null + ) + } + Spacer(Modifier.height(16.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center + ) { + Image( + painter = painterResource(R.drawable.logo_profile7), + contentDescription = null + ) + Spacer(Modifier.width(20.dp)) + Image( + painter = painterResource(R.drawable.logo_profile8), + contentDescription = null + ) + } + } + + Spacer(Modifier.height(20.dp)) + + Text( + text = "프로필을 설정해주세요!", + style = MomentoTheme.typography.title01, + color = MomentoTheme.colors.black + ) + } +} + +@Composable +fun ProfileButtonSection( + onClick: () -> Unit +) { + Column( + modifier = Modifier.fillMaxWidth() + ) { + Box( + modifier = Modifier + .clickable { onClick() } + .fillMaxWidth() + .background(color = MomentoTheme.colors.brownBase, shape = RoundedCornerShape(10.dp)) + .padding(vertical = 16.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "선택했어요", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.white + ) + } + Spacer(Modifier.height(16.dp)) + } +} + +@Preview +@Composable +fun ProfileSetupScreenPreview() { + DngoTheme { + ProfileSetupScreen() + } +} diff --git a/app/src/main/res/drawable/logo_profile.xml b/app/src/main/res/drawable/logo_profile.xml new file mode 100644 index 0000000..2294644 --- /dev/null +++ b/app/src/main/res/drawable/logo_profile.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/logo_profile2.xml b/app/src/main/res/drawable/logo_profile2.xml new file mode 100644 index 0000000..f1fd730 --- /dev/null +++ b/app/src/main/res/drawable/logo_profile2.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/logo_profile3.xml b/app/src/main/res/drawable/logo_profile3.xml new file mode 100644 index 0000000..eb43256 --- /dev/null +++ b/app/src/main/res/drawable/logo_profile3.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/logo_profile4.xml b/app/src/main/res/drawable/logo_profile4.xml new file mode 100644 index 0000000..08be0b3 --- /dev/null +++ b/app/src/main/res/drawable/logo_profile4.xml @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/logo_profile5.xml b/app/src/main/res/drawable/logo_profile5.xml new file mode 100644 index 0000000..d42ecc8 --- /dev/null +++ b/app/src/main/res/drawable/logo_profile5.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/logo_profile6.xml b/app/src/main/res/drawable/logo_profile6.xml new file mode 100644 index 0000000..e5307b7 --- /dev/null +++ b/app/src/main/res/drawable/logo_profile6.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/logo_profile7.xml b/app/src/main/res/drawable/logo_profile7.xml new file mode 100644 index 0000000..fc59bbc --- /dev/null +++ b/app/src/main/res/drawable/logo_profile7.xml @@ -0,0 +1,241 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/logo_profile8.xml b/app/src/main/res/drawable/logo_profile8.xml new file mode 100644 index 0000000..d774ddd --- /dev/null +++ b/app/src/main/res/drawable/logo_profile8.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + From 556554af7610357ddf7fc334210b67b4476c0997 Mon Sep 17 00:00:00 2001 From: min486 Date: Wed, 8 Oct 2025 13:27:19 +0900 Subject: [PATCH 19/98] =?UTF-8?q?design:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20UI=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 4 +- .../dnapp/presentation/mypage/MypageScreen.kt | 325 ++++++++++++++++++ .../dnapp/presentation/ui/icon/__AppIcons.kt | 4 +- .../presentation/ui/icon/appicons/Bell.kt | 218 ++++++++++++ .../presentation/ui/icon/appicons/PenSmall.kt | 220 ++++++++++++ app/src/main/res/drawable/badge_new.xml | 62 ++++ app/src/main/res/drawable/logo_momento.xml | 54 +++ app/src/main/res/drawable/my_record.xml | 16 + app/src/main/res/drawable/my_stamp.xml | 26 ++ 9 files changed, 927 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Bell.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/PenSmall.kt create mode 100644 app/src/main/res/drawable/badge_new.xml create mode 100644 app/src/main/res/drawable/logo_momento.xml create mode 100644 app/src/main/res/drawable/my_record.xml create mode 100644 app/src/main/res/drawable/my_stamp.xml diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index 8765587..926c9a0 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -19,6 +19,7 @@ import com.min.dnapp.presentation.AppStartViewModel import com.min.dnapp.presentation.home.HomeScreen import com.min.dnapp.presentation.login.LoginScreen import com.min.dnapp.presentation.login.LoginScreen2 +import com.min.dnapp.presentation.mypage.MypageScreen import com.min.dnapp.presentation.onboarding.OnboardingScreen import com.min.dnapp.presentation.onboarding.OnboardingScreen2 import com.min.dnapp.presentation.onboarding.OnboardingScreen3 @@ -41,7 +42,8 @@ class MainActivity : ComponentActivity() { // OnboardingScreen() // OnboardingScreen2() // OnboardingScreen3() - ProfileSetupScreen() +// ProfileSetupScreen() + MypageScreen() } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt new file mode 100644 index 0000000..cb37be6 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt @@ -0,0 +1,325 @@ +package com.min.dnapp.presentation.mypage + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.R +import com.min.dnapp.presentation.ui.icon.AppIcons +import com.min.dnapp.presentation.ui.icon.appicons.Bell +import com.min.dnapp.presentation.ui.icon.appicons.PenSmall +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun MypageScreen() { + Scaffold( + containerColor = MomentoTheme.colors.brownW90, + topBar = { + CenterAlignedTopAppBar( + title = { Text("") }, + colors = TopAppBarDefaults.centerAlignedTopAppBarColors( + containerColor = MomentoTheme.colors.brownW90 + ), + navigationIcon = { + Image( + modifier = Modifier + .clickable { } + .padding(16.dp), + painter = painterResource(R.drawable.logo_momento), + contentDescription = null + ) + }, + actions = { + Icon( + modifier = Modifier + .clickable { } + .padding(16.dp), + imageVector = AppIcons.Bell, + contentDescription = null, + tint = MomentoTheme.colors.grayW60 + ) + } + ) + } + ) { paddingValues -> + Column( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize() + ) { + Spacer(Modifier.height(20.dp)) + + MypageProfileSection() + + Spacer(Modifier.height(20.dp)) + + HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.brownW60) + + Spacer(Modifier.height(20.dp)) + + MypageMenuSection() + } + } +} + +@Composable +fun MypageProfileSection() { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + // 프로필 이미지 (수정 가능) + UserProfileImage( + onClick = {} + ) + + Spacer(Modifier.height(12.dp)) + + // 뱃지 + UserBadge() + + Spacer(Modifier.height(16.dp)) + + // 닉네임 + Text( + text = "성민", + style = MomentoTheme.typography.title01, + color = MomentoTheme.colors.grayW20 + ) + + Spacer(Modifier.height(28.dp)) + + // 기록/스탬프 개수 + RecordAndStampNum() + } +} + +@Composable +fun UserProfileImage(onClick: () -> Unit) { + Box( + modifier = Modifier + .clickable { onClick() } + .size(120.dp) + ) { + Box( + modifier = Modifier + .size(120.dp) + .border(width = 2.dp, color = MomentoTheme.colors.grayW80, shape = RoundedCornerShape(10.dp)) + ) { + Image( + painter = painterResource(R.drawable.logo_profile), + contentDescription = null + ) + } + + Box( + modifier = Modifier + .align(Alignment.BottomEnd) + .offset(x = 12.dp, y = 12.dp) + .size(28.dp) + .background(color = MomentoTheme.colors.grayW90, shape = CircleShape), + contentAlignment = Alignment.Center + ) { + Icon( + imageVector = AppIcons.PenSmall, + contentDescription = null, + tint = MomentoTheme.colors.grayW60 + ) + } + } +} + +@Composable +fun UserBadge() { + Row( + modifier = Modifier + .background(color = MomentoTheme.colors.white, shape = RoundedCornerShape(20.dp)) + .padding(horizontal = 12.dp, vertical = 6.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(R.drawable.badge_new), + contentDescription = null + ) + Spacer(Modifier.width(4.dp)) + Text( + text = "새내기", + style = MomentoTheme.typography.caption, + color = MomentoTheme.colors.grayW20 + ) + } +} + +@Composable +fun RecordAndStampNum() { + Row( + modifier = Modifier + .padding(horizontal = 20.dp) + .fillMaxWidth() + ) { + // 여행 기록 영역 + Box( + modifier = Modifier + .weight(1f) + .background(color = MomentoTheme.colors.pinkW60, shape = RoundedCornerShape(10.dp)) + ) { + Column( + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth() + ) { + Spacer(Modifier.height(12.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(R.drawable.my_record), + contentDescription = null + ) + Spacer(Modifier.width(8.dp)) + Text( + text = "여행 기록", + style = MomentoTheme.typography.label, + color = MomentoTheme.colors.grayW20 + ) + } + + Spacer(Modifier.height(12.dp)) + + Text( + modifier = Modifier.fillMaxWidth(), + text = "10개", + style = MomentoTheme.typography.label, + color = MomentoTheme.colors.grayW20, + textAlign = TextAlign.End + ) + + Spacer(Modifier.height(12.dp)) + } + } + + Spacer(Modifier.width(16.dp)) + + // 수집 스탬프 영역 + Box( + modifier = Modifier + .weight(1f) + .background(color = MomentoTheme.colors.pinkW60, shape = RoundedCornerShape(10.dp)) + ) { + Column( + modifier = Modifier + .padding(horizontal = 16.dp) + .fillMaxWidth() + ) { + Spacer(Modifier.height(12.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(R.drawable.my_stamp), + contentDescription = null + ) + Spacer(Modifier.width(8.dp)) + Text( + text = "수집 스탬프", + style = MomentoTheme.typography.label, + color = MomentoTheme.colors.grayW20 + ) + } + + Spacer(Modifier.height(12.dp)) + + Text( + modifier = Modifier.fillMaxWidth(), + text = "0개", + style = MomentoTheme.typography.label, + color = MomentoTheme.colors.grayW20, + textAlign = TextAlign.End + ) + + Spacer(Modifier.height(12.dp)) + } + } + } +} + +@Composable +fun MypageMenuSection() { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 20.dp) + ) { + MypageMenuItem( + text = "내 기록 모아보기", + onClick = {} + ) + Spacer(Modifier.height(28.dp)) + MypageMenuItem( + text = "북마크", + onClick = {} + ) + Spacer(Modifier.height(28.dp)) + MypageMenuItem( + text = "설정", + onClick = {} + ) + } +} + +@Composable +fun MypageMenuItem( + text: String, + onClick: () -> Unit +) { + Row( + modifier = Modifier + .fillMaxWidth() + .clickable { onClick() } + ) { + Text( + text = text, + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + } +} + +@Preview +@Composable +fun MypageScreenPreview() { + DngoTheme { + MypageScreen() + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt index 9002396..97e938f 100644 --- a/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt @@ -2,7 +2,9 @@ package com.min.dnapp.presentation.ui.icon import androidx.compose.ui.graphics.vector.ImageVector import com.min.dnapp.presentation.ui.icon.appicons.Back +import com.min.dnapp.presentation.ui.icon.appicons.Bell import com.min.dnapp.presentation.ui.icon.appicons.Kakao +import com.min.dnapp.presentation.ui.icon.appicons.PenSmall import kotlin.collections.List as ____KtList public object AppIcons @@ -14,6 +16,6 @@ public val AppIcons.AllIcons: ____KtList if (__AllIcons != null) { return __AllIcons!! } - __AllIcons= listOf(Back, Kakao) + __AllIcons= listOf(Back, Bell, Kakao, PenSmall) return __AllIcons!! } diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Bell.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Bell.kt new file mode 100644 index 0000000..222a2e0 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Bell.kt @@ -0,0 +1,218 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.Bell: ImageVector + get() { + if (_bell != null) { + return _bell!! + } + _bell = Builder(name = "Bell", defaultWidth = 16.0.dp, defaultHeight = 20.0.dp, + viewportWidth = 16.0f, viewportHeight = 20.0f).apply { + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(10.546f, 16.734f) + curveTo(10.812f, 16.806f, 10.971f, 17.083f, 10.899f, 17.352f) + curveTo(10.729f, 17.997f, 10.352f, 18.567f, 9.828f, 18.974f) + curveTo(9.304f, 19.38f, 8.661f, 19.6f, 8.001f, 19.6f) + curveTo(7.341f, 19.6f, 6.699f, 19.38f, 6.175f, 18.974f) + curveTo(5.651f, 18.567f, 5.274f, 17.997f, 5.103f, 17.352f) + curveTo(5.032f, 17.083f, 5.19f, 16.806f, 5.457f, 16.734f) + curveTo(5.724f, 16.662f, 5.998f, 16.821f, 6.069f, 17.091f) + curveTo(6.183f, 17.521f, 6.434f, 17.9f, 6.783f, 18.171f) + curveTo(7.132f, 18.442f, 7.561f, 18.59f, 8.001f, 18.59f) + curveTo(8.441f, 18.59f, 8.869f, 18.442f, 9.219f, 18.171f) + curveTo(9.568f, 17.9f, 9.82f, 17.521f, 9.934f, 17.091f) + curveTo(10.005f, 16.821f, 10.279f, 16.661f, 10.546f, 16.734f) + close() + moveTo(13.001f, 6.463f) + curveTo(13.001f, 5.123f, 12.474f, 3.838f, 11.537f, 2.891f) + curveTo(10.599f, 1.943f, 9.327f, 1.41f, 8.001f, 1.41f) + curveTo(6.675f, 1.41f, 5.403f, 1.943f, 4.466f, 2.891f) + curveTo(3.528f, 3.838f, 3.001f, 5.123f, 3.001f, 6.463f) + verticalLineTo(8.484f) + curveTo(3.001f, 10.233f, 2.44f, 11.935f, 1.401f, 13.334f) + lineTo(1.4f, 13.335f) + lineTo(1.188f, 13.617f) + curveTo(1.15f, 13.67f, 1.127f, 13.704f, 1.106f, 13.733f) + curveTo(1.097f, 13.746f, 1.09f, 13.755f, 1.085f, 13.762f) + curveTo(1.081f, 13.769f, 1.078f, 13.772f, 1.078f, 13.772f) + lineTo(1.077f, 13.771f) + curveTo(1.031f, 13.844f, 1.006f, 13.929f, 1.002f, 14.016f) + curveTo(0.998f, 14.103f, 1.015f, 14.19f, 1.054f, 14.267f) + curveTo(1.092f, 14.345f, 1.15f, 14.412f, 1.222f, 14.461f) + curveTo(1.293f, 14.509f, 1.375f, 14.538f, 1.46f, 14.545f) + curveTo(1.46f, 14.545f, 1.461f, 14.546f, 1.463f, 14.546f) + curveTo(1.465f, 14.546f, 1.469f, 14.546f, 1.473f, 14.546f) + curveTo(1.481f, 14.546f, 1.492f, 14.547f, 1.508f, 14.547f) + horizontalLineTo(14.493f) + curveTo(14.518f, 14.546f, 14.528f, 14.545f, 14.53f, 14.545f) + lineTo(14.54f, 14.544f) + curveTo(14.625f, 14.537f, 14.708f, 14.509f, 14.779f, 14.46f) + curveTo(14.851f, 14.411f, 14.908f, 14.344f, 14.946f, 14.267f) + curveTo(14.985f, 14.189f, 15.003f, 14.103f, 14.999f, 14.016f) + curveTo(14.995f, 13.931f, 14.968f, 13.848f, 14.924f, 13.775f) + curveTo(14.89f, 13.725f, 14.855f, 13.675f, 14.818f, 13.627f) + lineTo(14.814f, 13.623f) + lineTo(14.601f, 13.334f) + verticalLineTo(13.333f) + curveTo(13.563f, 11.934f, 13.001f, 10.233f, 13.001f, 8.484f) + verticalLineTo(6.463f) + close() + moveTo(14.001f, 8.484f) + curveTo(14.001f, 9.919f, 14.433f, 11.317f, 15.235f, 12.495f) + lineTo(15.401f, 12.728f) + lineTo(15.612f, 13.013f) + lineTo(15.759f, 13.218f) + lineTo(15.764f, 13.226f) + lineTo(15.769f, 13.232f) + curveTo(15.906f, 13.453f, 15.984f, 13.705f, 15.997f, 13.966f) + curveTo(16.01f, 14.226f, 15.956f, 14.485f, 15.841f, 14.719f) + curveTo(15.725f, 14.952f, 15.553f, 15.151f, 15.339f, 15.297f) + curveTo(15.127f, 15.441f, 14.883f, 15.527f, 14.629f, 15.549f) + lineTo(14.63f, 15.55f) + horizontalLineTo(14.627f) + curveTo(14.625f, 15.55f, 14.623f, 15.551f, 14.621f, 15.551f) + lineTo(14.62f, 15.55f) + curveTo(14.55f, 15.557f, 14.46f, 15.557f, 14.358f, 15.557f) + horizontalLineTo(1.644f) + curveTo(1.535f, 15.557f, 1.447f, 15.557f, 1.384f, 15.552f) + horizontalLineTo(1.383f) + curveTo(1.125f, 15.532f, 0.877f, 15.445f, 0.663f, 15.299f) + curveTo(0.449f, 15.153f, 0.275f, 14.953f, 0.159f, 14.719f) + curveTo(0.044f, 14.486f, -0.01f, 14.226f, 0.003f, 13.966f) + curveTo(0.016f, 13.705f, 0.095f, 13.451f, 0.233f, 13.23f) + lineTo(0.234f, 13.229f) + curveTo(0.267f, 13.177f, 0.321f, 13.104f, 0.383f, 13.02f) + lineTo(0.387f, 13.014f) + lineTo(0.602f, 12.727f) + curveTo(1.51f, 11.503f, 2.001f, 10.014f, 2.001f, 8.484f) + verticalLineTo(6.463f) + curveTo(2.001f, 4.855f, 2.634f, 3.313f, 3.759f, 2.176f) + curveTo(4.884f, 1.039f, 6.41f, 0.4f, 8.001f, 0.4f) + curveTo(9.592f, 0.4f, 11.119f, 1.039f, 12.244f, 2.176f) + curveTo(13.369f, 3.313f, 14.001f, 4.855f, 14.001f, 6.463f) + verticalLineTo(8.484f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(10.546f, 16.734f) + curveTo(10.812f, 16.806f, 10.971f, 17.083f, 10.899f, 17.352f) + curveTo(10.729f, 17.997f, 10.352f, 18.567f, 9.828f, 18.974f) + curveTo(9.304f, 19.38f, 8.661f, 19.6f, 8.001f, 19.6f) + curveTo(7.341f, 19.6f, 6.699f, 19.38f, 6.175f, 18.974f) + curveTo(5.651f, 18.567f, 5.274f, 17.997f, 5.103f, 17.352f) + curveTo(5.032f, 17.083f, 5.19f, 16.806f, 5.457f, 16.734f) + curveTo(5.724f, 16.662f, 5.998f, 16.821f, 6.069f, 17.091f) + curveTo(6.183f, 17.521f, 6.434f, 17.9f, 6.783f, 18.171f) + curveTo(7.132f, 18.442f, 7.561f, 18.59f, 8.001f, 18.59f) + curveTo(8.441f, 18.59f, 8.869f, 18.442f, 9.219f, 18.171f) + curveTo(9.568f, 17.9f, 9.82f, 17.521f, 9.934f, 17.091f) + curveTo(10.005f, 16.821f, 10.279f, 16.661f, 10.546f, 16.734f) + close() + moveTo(13.001f, 6.463f) + curveTo(13.001f, 5.123f, 12.474f, 3.838f, 11.537f, 2.891f) + curveTo(10.599f, 1.943f, 9.327f, 1.41f, 8.001f, 1.41f) + curveTo(6.675f, 1.41f, 5.403f, 1.943f, 4.466f, 2.891f) + curveTo(3.528f, 3.838f, 3.001f, 5.123f, 3.001f, 6.463f) + verticalLineTo(8.484f) + curveTo(3.001f, 10.233f, 2.44f, 11.935f, 1.401f, 13.334f) + lineTo(1.4f, 13.335f) + lineTo(1.188f, 13.617f) + curveTo(1.15f, 13.67f, 1.127f, 13.704f, 1.106f, 13.733f) + curveTo(1.097f, 13.746f, 1.09f, 13.755f, 1.085f, 13.762f) + curveTo(1.081f, 13.769f, 1.078f, 13.772f, 1.078f, 13.772f) + lineTo(1.077f, 13.771f) + curveTo(1.031f, 13.844f, 1.006f, 13.929f, 1.002f, 14.016f) + curveTo(0.998f, 14.103f, 1.015f, 14.19f, 1.054f, 14.267f) + curveTo(1.092f, 14.345f, 1.15f, 14.412f, 1.222f, 14.461f) + curveTo(1.293f, 14.509f, 1.375f, 14.538f, 1.46f, 14.545f) + curveTo(1.46f, 14.545f, 1.461f, 14.546f, 1.463f, 14.546f) + curveTo(1.465f, 14.546f, 1.469f, 14.546f, 1.473f, 14.546f) + curveTo(1.481f, 14.546f, 1.492f, 14.547f, 1.508f, 14.547f) + horizontalLineTo(14.493f) + curveTo(14.518f, 14.546f, 14.528f, 14.545f, 14.53f, 14.545f) + lineTo(14.54f, 14.544f) + curveTo(14.625f, 14.537f, 14.708f, 14.509f, 14.779f, 14.46f) + curveTo(14.851f, 14.411f, 14.908f, 14.344f, 14.946f, 14.267f) + curveTo(14.985f, 14.189f, 15.003f, 14.103f, 14.999f, 14.016f) + curveTo(14.995f, 13.931f, 14.968f, 13.848f, 14.924f, 13.775f) + curveTo(14.89f, 13.725f, 14.855f, 13.675f, 14.818f, 13.627f) + lineTo(14.814f, 13.623f) + lineTo(14.601f, 13.334f) + verticalLineTo(13.333f) + curveTo(13.563f, 11.934f, 13.001f, 10.233f, 13.001f, 8.484f) + verticalLineTo(6.463f) + close() + moveTo(14.001f, 8.484f) + curveTo(14.001f, 9.919f, 14.433f, 11.317f, 15.235f, 12.495f) + lineTo(15.401f, 12.728f) + lineTo(15.612f, 13.013f) + lineTo(15.759f, 13.218f) + lineTo(15.764f, 13.226f) + lineTo(15.769f, 13.232f) + curveTo(15.906f, 13.453f, 15.984f, 13.705f, 15.997f, 13.966f) + curveTo(16.01f, 14.226f, 15.956f, 14.485f, 15.841f, 14.719f) + curveTo(15.725f, 14.952f, 15.553f, 15.151f, 15.339f, 15.297f) + curveTo(15.127f, 15.441f, 14.883f, 15.527f, 14.629f, 15.549f) + lineTo(14.63f, 15.55f) + horizontalLineTo(14.627f) + curveTo(14.625f, 15.55f, 14.623f, 15.551f, 14.621f, 15.551f) + lineTo(14.62f, 15.55f) + curveTo(14.55f, 15.557f, 14.46f, 15.557f, 14.358f, 15.557f) + horizontalLineTo(1.644f) + curveTo(1.535f, 15.557f, 1.447f, 15.557f, 1.384f, 15.552f) + horizontalLineTo(1.383f) + curveTo(1.125f, 15.532f, 0.877f, 15.445f, 0.663f, 15.299f) + curveTo(0.449f, 15.153f, 0.275f, 14.953f, 0.159f, 14.719f) + curveTo(0.044f, 14.486f, -0.01f, 14.226f, 0.003f, 13.966f) + curveTo(0.016f, 13.705f, 0.095f, 13.451f, 0.233f, 13.23f) + lineTo(0.234f, 13.229f) + curveTo(0.267f, 13.177f, 0.321f, 13.104f, 0.383f, 13.02f) + lineTo(0.387f, 13.014f) + lineTo(0.602f, 12.727f) + curveTo(1.51f, 11.503f, 2.001f, 10.014f, 2.001f, 8.484f) + verticalLineTo(6.463f) + curveTo(2.001f, 4.855f, 2.634f, 3.313f, 3.759f, 2.176f) + curveTo(4.884f, 1.039f, 6.41f, 0.4f, 8.001f, 0.4f) + curveTo(9.592f, 0.4f, 11.119f, 1.039f, 12.244f, 2.176f) + curveTo(13.369f, 3.313f, 14.001f, 4.855f, 14.001f, 6.463f) + verticalLineTo(8.484f) + close() + } + } + .build() + return _bell!! + } + +private var _bell: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.Bell, contentDescription = "") + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/PenSmall.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/PenSmall.kt new file mode 100644 index 0000000..b7acab6 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/PenSmall.kt @@ -0,0 +1,220 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.PenSmall: ImageVector + get() { + if (_penSmall != null) { + return _penSmall!! + } + _penSmall = Builder(name = "PenSmall", defaultWidth = 10.0.dp, defaultHeight = 11.0.dp, + viewportWidth = 10.0f, viewportHeight = 11.0f).apply { + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(9.021f, 2.772f) + curveTo(9.021f, 2.635f, 8.965f, 2.51f, 8.853f, 2.364f) + curveTo(8.745f, 2.223f, 8.584f, 2.06f, 8.37f, 1.845f) + lineTo(8.353f, 1.83f) + lineTo(8.223f, 1.7f) + curveTo(8.009f, 1.486f, 7.847f, 1.324f, 7.706f, 1.216f) + lineTo(7.599f, 1.143f) + curveTo(7.496f, 1.08f, 7.4f, 1.049f, 7.297f, 1.048f) + curveTo(7.159f, 1.048f, 7.034f, 1.104f, 6.889f, 1.215f) + curveTo(6.747f, 1.323f, 6.584f, 1.485f, 6.37f, 1.7f) + lineTo(1.554f, 6.515f) + lineTo(1.532f, 6.537f) + curveTo(1.419f, 6.65f, 1.359f, 6.713f, 1.319f, 6.784f) + lineTo(1.318f, 6.785f) + curveTo(1.277f, 6.858f, 1.255f, 6.942f, 1.215f, 7.101f) + lineTo(1.207f, 7.131f) + lineTo(0.758f, 8.924f) + curveTo(0.736f, 9.009f, 0.717f, 9.096f, 0.704f, 9.183f) + curveTo(0.702f, 9.214f, 0.703f, 9.242f, 0.708f, 9.267f) + curveTo(0.713f, 9.29f, 0.723f, 9.31f, 0.741f, 9.328f) + curveTo(0.76f, 9.347f, 0.779f, 9.356f, 0.801f, 9.361f) + curveTo(0.826f, 9.367f, 0.854f, 9.367f, 0.885f, 9.364f) + curveTo(0.978f, 9.351f, 1.069f, 9.332f, 1.159f, 9.307f) + lineTo(1.172f, 9.303f) + lineTo(2.938f, 8.862f) + lineTo(2.947f, 8.86f) + lineTo(2.967f, 8.855f) + curveTo(3.125f, 8.815f, 3.211f, 8.792f, 3.284f, 8.751f) + curveTo(3.357f, 8.709f, 3.422f, 8.648f, 3.536f, 8.534f) + lineTo(3.557f, 8.511f) + lineTo(8.353f, 3.715f) + lineTo(8.37f, 3.7f) + curveTo(8.584f, 3.485f, 8.745f, 3.322f, 8.853f, 3.181f) + curveTo(8.965f, 3.034f, 9.021f, 2.91f, 9.021f, 2.772f) + close() + moveTo(9.687f, 2.772f) + curveTo(9.687f, 3.115f, 9.539f, 3.381f, 9.384f, 3.585f) + lineTo(9.383f, 3.586f) + curveTo(9.242f, 3.771f, 9.044f, 3.968f, 8.841f, 4.171f) + lineTo(4.007f, 9.005f) + curveTo(3.905f, 9.107f, 3.779f, 9.236f, 3.614f, 9.33f) + curveTo(3.448f, 9.425f, 3.269f, 9.467f, 3.13f, 9.502f) + lineTo(3.122f, 9.504f) + lineTo(3.1f, 9.508f) + lineTo(1.355f, 9.944f) + lineTo(1.342f, 9.948f) + curveTo(1.218f, 9.983f, 1.092f, 10.009f, 0.965f, 10.026f) + lineTo(0.956f, 10.027f) + curveTo(0.819f, 10.041f, 0.516f, 10.047f, 0.269f, 9.799f) + curveTo(0.023f, 9.553f, 0.028f, 9.251f, 0.042f, 9.114f) + lineTo(0.042f, 9.106f) + lineTo(0.044f, 9.099f) + curveTo(0.06f, 8.982f, 0.084f, 8.865f, 0.115f, 8.751f) + lineTo(0.561f, 6.969f) + lineTo(0.568f, 6.94f) + curveTo(0.603f, 6.8f, 0.644f, 6.623f, 0.738f, 6.456f) + curveTo(0.832f, 6.29f, 0.964f, 6.163f, 1.064f, 6.062f) + lineTo(1.068f, 6.058f) + lineTo(1.086f, 6.04f) + lineTo(5.882f, 1.244f) + lineTo(5.898f, 1.228f) + curveTo(6.101f, 1.025f, 6.299f, 0.826f, 6.484f, 0.685f) + curveTo(6.689f, 0.529f, 6.955f, 0.382f, 7.297f, 0.382f) + curveTo(7.597f, 0.382f, 7.838f, 0.496f, 8.03f, 0.628f) + lineTo(8.109f, 0.685f) + lineTo(8.251f, 0.801f) + curveTo(8.394f, 0.926f, 8.542f, 1.076f, 8.695f, 1.228f) + lineTo(8.711f, 1.244f) + lineTo(8.825f, 1.358f) + lineTo(8.841f, 1.374f) + curveTo(9.044f, 1.577f, 9.242f, 1.774f, 9.383f, 1.959f) + lineTo(9.441f, 2.039f) + curveTo(9.574f, 2.232f, 9.687f, 2.473f, 9.687f, 2.772f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(9.021f, 2.772f) + curveTo(9.021f, 2.635f, 8.965f, 2.51f, 8.853f, 2.364f) + curveTo(8.745f, 2.223f, 8.584f, 2.06f, 8.37f, 1.845f) + lineTo(8.353f, 1.83f) + lineTo(8.223f, 1.7f) + curveTo(8.009f, 1.486f, 7.847f, 1.324f, 7.706f, 1.216f) + lineTo(7.599f, 1.143f) + curveTo(7.496f, 1.08f, 7.4f, 1.049f, 7.297f, 1.048f) + curveTo(7.159f, 1.048f, 7.034f, 1.104f, 6.889f, 1.215f) + curveTo(6.747f, 1.323f, 6.584f, 1.485f, 6.37f, 1.7f) + lineTo(1.554f, 6.515f) + lineTo(1.532f, 6.537f) + curveTo(1.419f, 6.65f, 1.359f, 6.713f, 1.319f, 6.784f) + lineTo(1.318f, 6.785f) + curveTo(1.277f, 6.858f, 1.255f, 6.942f, 1.215f, 7.101f) + lineTo(1.207f, 7.131f) + lineTo(0.758f, 8.924f) + curveTo(0.736f, 9.009f, 0.717f, 9.096f, 0.704f, 9.183f) + curveTo(0.702f, 9.214f, 0.703f, 9.242f, 0.708f, 9.267f) + curveTo(0.713f, 9.29f, 0.723f, 9.31f, 0.741f, 9.328f) + curveTo(0.76f, 9.347f, 0.779f, 9.356f, 0.801f, 9.361f) + curveTo(0.826f, 9.367f, 0.854f, 9.367f, 0.885f, 9.364f) + curveTo(0.978f, 9.351f, 1.069f, 9.332f, 1.159f, 9.307f) + lineTo(1.172f, 9.303f) + lineTo(2.938f, 8.862f) + lineTo(2.947f, 8.86f) + lineTo(2.967f, 8.855f) + curveTo(3.125f, 8.815f, 3.211f, 8.792f, 3.284f, 8.751f) + curveTo(3.357f, 8.709f, 3.422f, 8.648f, 3.536f, 8.534f) + lineTo(3.557f, 8.511f) + lineTo(8.353f, 3.715f) + lineTo(8.37f, 3.7f) + curveTo(8.584f, 3.485f, 8.745f, 3.322f, 8.853f, 3.181f) + curveTo(8.965f, 3.034f, 9.021f, 2.91f, 9.021f, 2.772f) + close() + moveTo(9.687f, 2.772f) + curveTo(9.687f, 3.115f, 9.539f, 3.381f, 9.384f, 3.585f) + lineTo(9.383f, 3.586f) + curveTo(9.242f, 3.771f, 9.044f, 3.968f, 8.841f, 4.171f) + lineTo(4.007f, 9.005f) + curveTo(3.905f, 9.107f, 3.779f, 9.236f, 3.614f, 9.33f) + curveTo(3.448f, 9.425f, 3.269f, 9.467f, 3.13f, 9.502f) + lineTo(3.122f, 9.504f) + lineTo(3.1f, 9.508f) + lineTo(1.355f, 9.944f) + lineTo(1.342f, 9.948f) + curveTo(1.218f, 9.983f, 1.092f, 10.009f, 0.965f, 10.026f) + lineTo(0.956f, 10.027f) + curveTo(0.819f, 10.041f, 0.516f, 10.047f, 0.269f, 9.799f) + curveTo(0.023f, 9.553f, 0.028f, 9.251f, 0.042f, 9.114f) + lineTo(0.042f, 9.106f) + lineTo(0.044f, 9.099f) + curveTo(0.06f, 8.982f, 0.084f, 8.865f, 0.115f, 8.751f) + lineTo(0.561f, 6.969f) + lineTo(0.568f, 6.94f) + curveTo(0.603f, 6.8f, 0.644f, 6.623f, 0.738f, 6.456f) + curveTo(0.832f, 6.29f, 0.964f, 6.163f, 1.064f, 6.062f) + lineTo(1.068f, 6.058f) + lineTo(1.086f, 6.04f) + lineTo(5.882f, 1.244f) + lineTo(5.898f, 1.228f) + curveTo(6.101f, 1.025f, 6.299f, 0.826f, 6.484f, 0.685f) + curveTo(6.689f, 0.529f, 6.955f, 0.382f, 7.297f, 0.382f) + curveTo(7.597f, 0.382f, 7.838f, 0.496f, 8.03f, 0.628f) + lineTo(8.109f, 0.685f) + lineTo(8.251f, 0.801f) + curveTo(8.394f, 0.926f, 8.542f, 1.076f, 8.695f, 1.228f) + lineTo(8.711f, 1.244f) + lineTo(8.825f, 1.358f) + lineTo(8.841f, 1.374f) + curveTo(9.044f, 1.577f, 9.242f, 1.774f, 9.383f, 1.959f) + lineTo(9.441f, 2.039f) + curveTo(9.574f, 2.232f, 9.687f, 2.473f, 9.687f, 2.772f) + close() + } + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(5.63f, 1.773f) + lineTo(7.63f, 0.439f) + lineTo(9.63f, 2.439f) + lineTo(8.297f, 4.439f) + lineTo(5.63f, 1.773f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(5.63f, 1.773f) + lineTo(7.63f, 0.439f) + lineTo(9.63f, 2.439f) + lineTo(8.297f, 4.439f) + lineTo(5.63f, 1.773f) + close() + } + } + .build() + return _penSmall!! + } + +private var _penSmall: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.PenSmall, contentDescription = "") + } +} diff --git a/app/src/main/res/drawable/badge_new.xml b/app/src/main/res/drawable/badge_new.xml new file mode 100644 index 0000000..027c806 --- /dev/null +++ b/app/src/main/res/drawable/badge_new.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/logo_momento.xml b/app/src/main/res/drawable/logo_momento.xml new file mode 100644 index 0000000..0f08d1a --- /dev/null +++ b/app/src/main/res/drawable/logo_momento.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/my_record.xml b/app/src/main/res/drawable/my_record.xml new file mode 100644 index 0000000..57b8b4b --- /dev/null +++ b/app/src/main/res/drawable/my_record.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/main/res/drawable/my_stamp.xml b/app/src/main/res/drawable/my_stamp.xml new file mode 100644 index 0000000..d5d158b --- /dev/null +++ b/app/src/main/res/drawable/my_stamp.xml @@ -0,0 +1,26 @@ + + + + + + + + From d49ca0222662011e34c5b38ad492a0891f7fcc1d Mon Sep 17 00:00:00 2001 From: min486 Date: Wed, 8 Oct 2025 20:06:58 +0900 Subject: [PATCH 20/98] =?UTF-8?q?feat:=20MypageScreen=20-=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=AA=A8=EB=8B=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dnapp/presentation/mypage/MypageScreen.kt | 25 ++- .../mypage/component/ProfileImageDialog.kt | 163 ++++++++++++++++++ 2 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/mypage/component/ProfileImageDialog.kt diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt index cb37be6..b9ecb9c 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt @@ -25,6 +25,10 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults 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.painterResource @@ -32,6 +36,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.min.dnapp.R +import com.min.dnapp.presentation.mypage.component.ProfileImageDialog import com.min.dnapp.presentation.ui.icon.AppIcons import com.min.dnapp.presentation.ui.icon.appicons.Bell import com.min.dnapp.presentation.ui.icon.appicons.PenSmall @@ -41,6 +46,9 @@ import com.min.dnapp.presentation.ui.theme.MomentoTheme @OptIn(ExperimentalMaterial3Api::class) @Composable fun MypageScreen() { + + var showProfileImageDialog by remember { mutableStateOf(false) } + Scaffold( containerColor = MomentoTheme.colors.brownW90, topBar = { @@ -78,7 +86,9 @@ fun MypageScreen() { ) { Spacer(Modifier.height(20.dp)) - MypageProfileSection() + MypageProfileSection( + onClick = { showProfileImageDialog = true } + ) Spacer(Modifier.height(20.dp)) @@ -89,17 +99,26 @@ fun MypageScreen() { MypageMenuSection() } } + + // 프로필이미지 수정 모달창 + if (showProfileImageDialog) { + ProfileImageDialog( + onDismiss = { showProfileImageDialog = false }, + onCancel = { showProfileImageDialog = false }, + onConfirm = {} + ) + } } @Composable -fun MypageProfileSection() { +fun MypageProfileSection(onClick: () -> Unit) { Column( modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally ) { // 프로필 이미지 (수정 가능) UserProfileImage( - onClick = {} + onClick = { onClick() } ) Spacer(Modifier.height(12.dp)) diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/component/ProfileImageDialog.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/component/ProfileImageDialog.kt new file mode 100644 index 0000000..1e5fe36 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/component/ProfileImageDialog.kt @@ -0,0 +1,163 @@ +package com.min.dnapp.presentation.mypage.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +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.shape.RoundedCornerShape +import androidx.compose.material3.Surface +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.painterResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import com.min.dnapp.R +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun ProfileImageDialog( + onDismiss: () -> Unit, + onCancel: () -> Unit, + onConfirm: () -> Unit +) { + Dialog( + onDismissRequest = onDismiss + ) { + Surface( + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(16.dp), + color = MomentoTheme.colors.white + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 20.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "프로필을 선택해주세요!", + style = MomentoTheme.typography.title01, + color = MomentoTheme.colors.grayW20 + ) + + Spacer(Modifier.height(20.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center + ) { + Image( + painter = painterResource(R.drawable.logo_profile), + contentDescription = null + ) + Spacer(Modifier.width(20.dp)) + Image( + painter = painterResource(R.drawable.logo_profile2), + contentDescription = null + ) + } + Spacer(Modifier.height(16.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center + ) { + Image( + painter = painterResource(R.drawable.logo_profile3), + contentDescription = null + ) + Spacer(Modifier.width(20.dp)) + Image( + painter = painterResource(R.drawable.logo_profile4), + contentDescription = null + ) + } + Spacer(Modifier.height(16.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center + ) { + Image( + painter = painterResource(R.drawable.logo_profile5), + contentDescription = null + ) + Spacer(Modifier.width(20.dp)) + Box( + modifier = Modifier + .border(width = 3.dp, color = MomentoTheme.colors.pinkBase, shape = RoundedCornerShape(10.dp)) + ) { + Image( + painter = painterResource(R.drawable.logo_profile6), + contentDescription = null + ) + } + + } + Spacer(Modifier.height(16.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center + ) { + Image( + painter = painterResource(R.drawable.logo_profile7), + contentDescription = null + ) + Spacer(Modifier.width(20.dp)) + Image( + painter = painterResource(R.drawable.logo_profile8), + contentDescription = null + ) + } + + Spacer(Modifier.height(24.dp)) + + // 취소/확인 버튼 영역 + Row( + modifier = Modifier.fillMaxWidth() + ) { + Box( + modifier = Modifier + .clickable { onCancel() } + .weight(1f) + .background(color = MomentoTheme.colors.grayW80, shape = RoundedCornerShape(10.dp)) + .padding(16.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "취소", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.white + ) + } + + Spacer(Modifier.width(8.dp)) + + Box( + modifier = Modifier + .clickable { onConfirm() } + .weight(1f) + .background(color = MomentoTheme.colors.brownBase, shape = RoundedCornerShape(10.dp)) + .padding(16.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "확인", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.white + ) + } + } + } + } + } +} From b7d25639e824931218e9180e06012db07b96d21d Mon Sep 17 00:00:00 2001 From: min486 Date: Wed, 8 Oct 2025 21:43:01 +0900 Subject: [PATCH 21/98] =?UTF-8?q?design:=20=EC=84=A4=EC=A0=95=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20UI=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 4 +- .../presentation/mypage/SettingScreen.kt | 98 +++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/mypage/SettingScreen.kt diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index 926c9a0..bedd1ee 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -20,6 +20,7 @@ import com.min.dnapp.presentation.home.HomeScreen import com.min.dnapp.presentation.login.LoginScreen import com.min.dnapp.presentation.login.LoginScreen2 import com.min.dnapp.presentation.mypage.MypageScreen +import com.min.dnapp.presentation.mypage.SettingScreen import com.min.dnapp.presentation.onboarding.OnboardingScreen import com.min.dnapp.presentation.onboarding.OnboardingScreen2 import com.min.dnapp.presentation.onboarding.OnboardingScreen3 @@ -43,7 +44,8 @@ class MainActivity : ComponentActivity() { // OnboardingScreen2() // OnboardingScreen3() // ProfileSetupScreen() - MypageScreen() +// MypageScreen() + SettingScreen() } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/SettingScreen.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/SettingScreen.kt new file mode 100644 index 0000000..523d38d --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/SettingScreen.kt @@ -0,0 +1,98 @@ +package com.min.dnapp.presentation.mypage + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import com.min.dnapp.presentation.ui.icon.appicons.Back +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SettingScreen() { + Scaffold( + containerColor = MomentoTheme.colors.brownBg, + topBar = { + CenterAlignedTopAppBar( + title = { + Text( + text = "설정", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 + ) + }, + colors = TopAppBarDefaults.centerAlignedTopAppBarColors( + containerColor = MomentoTheme.colors.brownBg + ), + navigationIcon = { + Icon( + modifier = Modifier + .clickable { } + .padding(16.dp), + imageVector = AppIcons.Back, + contentDescription = null + ) + } + ) + } + ) { paddingValues -> + Column( + modifier = Modifier + .padding(paddingValues) + .padding(horizontal = 20.dp) + .fillMaxSize() + ) { + Spacer(Modifier.height(20.dp)) + + Row( + modifier = Modifier + .fillMaxWidth() + .clickable { } + ) { + Text( + text = "로그아웃", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + } + + Spacer(Modifier.height(28.dp)) + + Row( + modifier = Modifier + .fillMaxWidth() + .clickable { } + ) { + Text( + text = "계정 탈퇴", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + } + } + } +} + +@Preview +@Composable +fun SettingScreenPreview() { + DngoTheme { + SettingScreen() + } +} From a9d3c388517519deeca63074694955c2d73e27c4 Mon Sep 17 00:00:00 2001 From: min486 Date: Sun, 12 Oct 2025 13:29:40 +0900 Subject: [PATCH 22/98] =?UTF-8?q?design:=20=EA=B8=B0=EB=A1=9D=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=20=ED=99=94=EB=A9=B4=20UI=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 4 +- .../dnapp/presentation/ui/icon/__AppIcons.kt | 4 +- .../presentation/ui/icon/appicons/Calendar.kt | 100 ++++++ .../presentation/ui/icon/appicons/Gallery.kt | 305 ++++++++++++++++ .../min/dnapp/presentation/ui/theme/Color.kt | 6 + .../min/dnapp/presentation/ui/theme/Theme.kt | 12 + .../presentation/write/RecordWriteScreen.kt | 334 ++++++++++++++++++ app/src/main/res/drawable/emotion_angry.xml | 44 +++ app/src/main/res/drawable/emotion_check.xml | 9 + app/src/main/res/drawable/emotion_feel.xml | 36 ++ app/src/main/res/drawable/emotion_happy.xml | 30 ++ app/src/main/res/drawable/emotion_love.xml | 23 ++ app/src/main/res/drawable/emotion_sad.xml | 57 +++ app/src/main/res/drawable/emotion_shine.xml | 18 + .../main/res/drawable/emotion_surprise.xml | 44 +++ app/src/main/res/drawable/weather_check.xml | 9 + app/src/main/res/drawable/weather_cloud.xml | 33 ++ app/src/main/res/drawable/weather_moon.xml | 27 ++ app/src/main/res/drawable/weather_rain.xml | 57 +++ app/src/main/res/drawable/weather_snow.xml | 72 ++++ app/src/main/res/drawable/weather_sun.xml | 33 ++ app/src/main/res/drawable/weather_thunder.xml | 65 ++++ app/src/main/res/drawable/weather_wind.xml | 42 +++ app/src/main/res/drawable/write_place.xml | 24 ++ 24 files changed, 1386 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Calendar.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Gallery.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt create mode 100644 app/src/main/res/drawable/emotion_angry.xml create mode 100644 app/src/main/res/drawable/emotion_check.xml create mode 100644 app/src/main/res/drawable/emotion_feel.xml create mode 100644 app/src/main/res/drawable/emotion_happy.xml create mode 100644 app/src/main/res/drawable/emotion_love.xml create mode 100644 app/src/main/res/drawable/emotion_sad.xml create mode 100644 app/src/main/res/drawable/emotion_shine.xml create mode 100644 app/src/main/res/drawable/emotion_surprise.xml create mode 100644 app/src/main/res/drawable/weather_check.xml create mode 100644 app/src/main/res/drawable/weather_cloud.xml create mode 100644 app/src/main/res/drawable/weather_moon.xml create mode 100644 app/src/main/res/drawable/weather_rain.xml create mode 100644 app/src/main/res/drawable/weather_snow.xml create mode 100644 app/src/main/res/drawable/weather_sun.xml create mode 100644 app/src/main/res/drawable/weather_thunder.xml create mode 100644 app/src/main/res/drawable/weather_wind.xml create mode 100644 app/src/main/res/drawable/write_place.xml diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index bedd1ee..8f04a8c 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -26,6 +26,7 @@ import com.min.dnapp.presentation.onboarding.OnboardingScreen2 import com.min.dnapp.presentation.onboarding.OnboardingScreen3 import com.min.dnapp.presentation.profile.ProfileSetupScreen import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.write.RecordWriteScreen import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -45,7 +46,8 @@ class MainActivity : ComponentActivity() { // OnboardingScreen3() // ProfileSetupScreen() // MypageScreen() - SettingScreen() +// SettingScreen() + RecordWriteScreen() } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt index 97e938f..763d5ff 100644 --- a/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt @@ -3,6 +3,8 @@ package com.min.dnapp.presentation.ui.icon import androidx.compose.ui.graphics.vector.ImageVector import com.min.dnapp.presentation.ui.icon.appicons.Back import com.min.dnapp.presentation.ui.icon.appicons.Bell +import com.min.dnapp.presentation.ui.icon.appicons.Calendar +import com.min.dnapp.presentation.ui.icon.appicons.Gallery import com.min.dnapp.presentation.ui.icon.appicons.Kakao import com.min.dnapp.presentation.ui.icon.appicons.PenSmall import kotlin.collections.List as ____KtList @@ -16,6 +18,6 @@ public val AppIcons.AllIcons: ____KtList if (__AllIcons != null) { return __AllIcons!! } - __AllIcons= listOf(Back, Bell, Kakao, PenSmall) + __AllIcons= listOf(Back, Bell, Calendar, Gallery, Kakao, PenSmall) return __AllIcons!! } diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Calendar.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Calendar.kt new file mode 100644 index 0000000..9a59e01 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Calendar.kt @@ -0,0 +1,100 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.Calendar: ImageVector + get() { + if (_calendar != null) { + return _calendar!! + } + _calendar = Builder(name = "Calendar", defaultWidth = 20.0.dp, defaultHeight = 20.0.dp, + viewportWidth = 20.0f, viewportHeight = 20.0f).apply { + path(fill = SolidColor(Color(0xFFA56C48)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(18.0f, 6.0f) + curveTo(18.0f, 5.448f, 17.552f, 5.0f, 17.0f, 5.0f) + horizontalLineTo(3.0f) + curveTo(2.448f, 5.0f, 2.0f, 5.448f, 2.0f, 6.0f) + verticalLineTo(17.0f) + curveTo(2.0f, 17.552f, 2.448f, 18.0f, 3.0f, 18.0f) + horizontalLineTo(17.0f) + curveTo(17.552f, 18.0f, 18.0f, 17.552f, 18.0f, 17.0f) + verticalLineTo(6.0f) + close() + moveTo(20.0f, 17.0f) + curveTo(20.0f, 18.657f, 18.657f, 20.0f, 17.0f, 20.0f) + horizontalLineTo(3.0f) + curveTo(1.343f, 20.0f, 0.0f, 18.657f, 0.0f, 17.0f) + verticalLineTo(6.0f) + curveTo(0.0f, 4.343f, 1.343f, 3.0f, 3.0f, 3.0f) + horizontalLineTo(17.0f) + curveTo(18.657f, 3.0f, 20.0f, 4.343f, 20.0f, 6.0f) + verticalLineTo(17.0f) + close() + } + path(fill = SolidColor(Color(0xFFA56C48)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(1.0f, 8.0f) + curveTo(1.0f, 6.114f, 1.0f, 5.172f, 1.586f, 4.586f) + curveTo(2.172f, 4.0f, 3.114f, 4.0f, 5.0f, 4.0f) + horizontalLineTo(15.0f) + curveTo(16.886f, 4.0f, 17.828f, 4.0f, 18.414f, 4.586f) + curveTo(19.0f, 5.172f, 19.0f, 6.114f, 19.0f, 8.0f) + horizontalLineTo(1.0f) + close() + } + path(fill = SolidColor(Color(0xFFA56C48)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(4.0f, 4.0f) + verticalLineTo(1.0f) + curveTo(4.0f, 0.448f, 4.448f, 0.0f, 5.0f, 0.0f) + curveTo(5.552f, 0.0f, 6.0f, 0.448f, 6.0f, 1.0f) + verticalLineTo(4.0f) + curveTo(6.0f, 4.552f, 5.552f, 5.0f, 5.0f, 5.0f) + curveTo(4.448f, 5.0f, 4.0f, 4.552f, 4.0f, 4.0f) + close() + moveTo(14.0f, 4.0f) + verticalLineTo(1.0f) + curveTo(14.0f, 0.448f, 14.448f, 0.0f, 15.0f, 0.0f) + curveTo(15.552f, 0.0f, 16.0f, 0.448f, 16.0f, 1.0f) + verticalLineTo(4.0f) + curveTo(16.0f, 4.552f, 15.552f, 5.0f, 15.0f, 5.0f) + curveTo(14.448f, 5.0f, 14.0f, 4.552f, 14.0f, 4.0f) + close() + } + } + .build() + return _calendar!! + } + +private var _calendar: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.Calendar, contentDescription = "") + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Gallery.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Gallery.kt new file mode 100644 index 0000000..c11e911 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Gallery.kt @@ -0,0 +1,305 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.EvenOdd +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.Gallery: ImageVector + get() { + if (_gallery != null) { + return _gallery!! + } + _gallery = Builder(name = "Gallery", defaultWidth = 22.0.dp, defaultHeight = 22.0.dp, + viewportWidth = 22.0f, viewportHeight = 22.0f).apply { + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(11.25f, 0.75f) + curveTo(13.121f, 0.75f, 14.576f, 0.749f, 15.706f, 0.901f) + curveTo(16.851f, 1.055f, 17.738f, 1.374f, 18.432f, 2.068f) + curveTo(19.125f, 2.763f, 19.444f, 3.65f, 19.599f, 4.795f) + curveTo(19.751f, 5.925f, 19.75f, 7.379f, 19.75f, 9.25f) + verticalLineTo(11.25f) + curveTo(19.75f, 11.293f, 19.749f, 11.336f, 19.749f, 11.379f) + curveTo(19.434f, 11.153f, 19.1f, 10.958f, 18.75f, 10.797f) + verticalLineTo(9.25f) + curveTo(18.75f, 7.35f, 18.749f, 5.976f, 18.607f, 4.928f) + curveTo(18.468f, 3.894f, 18.202f, 3.253f, 17.725f, 2.775f) + curveTo(17.247f, 2.298f, 16.606f, 2.031f, 15.572f, 1.892f) + curveTo(14.524f, 1.751f, 13.15f, 1.75f, 11.25f, 1.75f) + horizontalLineTo(9.25f) + curveTo(7.35f, 1.75f, 5.976f, 1.751f, 4.928f, 1.893f) + curveTo(3.894f, 2.032f, 3.253f, 2.298f, 2.775f, 2.775f) + curveTo(2.298f, 3.252f, 2.031f, 3.894f, 1.892f, 4.928f) + curveTo(1.751f, 5.976f, 1.75f, 7.35f, 1.75f, 9.25f) + verticalLineTo(11.25f) + curveTo(1.75f, 13.15f, 1.751f, 14.524f, 1.893f, 15.572f) + curveTo(2.032f, 16.606f, 2.298f, 17.247f, 2.775f, 17.725f) + curveTo(3.252f, 18.202f, 3.894f, 18.469f, 4.928f, 18.608f) + curveTo(5.976f, 18.749f, 7.35f, 18.75f, 9.25f, 18.75f) + horizontalLineTo(10.797f) + curveTo(10.958f, 19.1f, 11.153f, 19.434f, 11.379f, 19.749f) + curveTo(11.336f, 19.749f, 11.293f, 19.75f, 11.25f, 19.75f) + horizontalLineTo(9.25f) + curveTo(7.379f, 19.75f, 5.924f, 19.751f, 4.794f, 19.599f) + curveTo(3.65f, 19.445f, 2.762f, 19.126f, 2.068f, 18.432f) + curveTo(1.375f, 17.737f, 1.055f, 16.85f, 0.901f, 15.705f) + curveTo(0.749f, 14.575f, 0.75f, 13.121f, 0.75f, 11.25f) + verticalLineTo(9.25f) + curveTo(0.75f, 7.379f, 0.749f, 5.924f, 0.901f, 4.794f) + curveTo(1.055f, 3.65f, 1.374f, 2.762f, 2.068f, 2.068f) + curveTo(2.763f, 1.375f, 3.65f, 1.055f, 4.795f, 0.901f) + curveTo(5.925f, 0.749f, 7.379f, 0.75f, 9.25f, 0.75f) + horizontalLineTo(11.25f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(11.25f, 0.75f) + curveTo(13.121f, 0.75f, 14.576f, 0.749f, 15.706f, 0.901f) + curveTo(16.851f, 1.055f, 17.738f, 1.374f, 18.432f, 2.068f) + curveTo(19.125f, 2.763f, 19.444f, 3.65f, 19.599f, 4.795f) + curveTo(19.751f, 5.925f, 19.75f, 7.379f, 19.75f, 9.25f) + verticalLineTo(11.25f) + curveTo(19.75f, 11.293f, 19.749f, 11.336f, 19.749f, 11.379f) + curveTo(19.434f, 11.153f, 19.1f, 10.958f, 18.75f, 10.797f) + verticalLineTo(9.25f) + curveTo(18.75f, 7.35f, 18.749f, 5.976f, 18.607f, 4.928f) + curveTo(18.468f, 3.894f, 18.202f, 3.253f, 17.725f, 2.775f) + curveTo(17.247f, 2.298f, 16.606f, 2.031f, 15.572f, 1.892f) + curveTo(14.524f, 1.751f, 13.15f, 1.75f, 11.25f, 1.75f) + horizontalLineTo(9.25f) + curveTo(7.35f, 1.75f, 5.976f, 1.751f, 4.928f, 1.893f) + curveTo(3.894f, 2.032f, 3.253f, 2.298f, 2.775f, 2.775f) + curveTo(2.298f, 3.252f, 2.031f, 3.894f, 1.892f, 4.928f) + curveTo(1.751f, 5.976f, 1.75f, 7.35f, 1.75f, 9.25f) + verticalLineTo(11.25f) + curveTo(1.75f, 13.15f, 1.751f, 14.524f, 1.893f, 15.572f) + curveTo(2.032f, 16.606f, 2.298f, 17.247f, 2.775f, 17.725f) + curveTo(3.252f, 18.202f, 3.894f, 18.469f, 4.928f, 18.608f) + curveTo(5.976f, 18.749f, 7.35f, 18.75f, 9.25f, 18.75f) + horizontalLineTo(10.797f) + curveTo(10.958f, 19.1f, 11.153f, 19.434f, 11.379f, 19.749f) + curveTo(11.336f, 19.749f, 11.293f, 19.75f, 11.25f, 19.75f) + horizontalLineTo(9.25f) + curveTo(7.379f, 19.75f, 5.924f, 19.751f, 4.794f, 19.599f) + curveTo(3.65f, 19.445f, 2.762f, 19.126f, 2.068f, 18.432f) + curveTo(1.375f, 17.737f, 1.055f, 16.85f, 0.901f, 15.705f) + curveTo(0.749f, 14.575f, 0.75f, 13.121f, 0.75f, 11.25f) + verticalLineTo(9.25f) + curveTo(0.75f, 7.379f, 0.749f, 5.924f, 0.901f, 4.794f) + curveTo(1.055f, 3.65f, 1.374f, 2.762f, 2.068f, 2.068f) + curveTo(2.763f, 1.375f, 3.65f, 1.055f, 4.795f, 0.901f) + curveTo(5.925f, 0.749f, 7.379f, 0.75f, 9.25f, 0.75f) + horizontalLineTo(11.25f) + close() + } + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(6.366f, 8.262f) + curveTo(6.825f, 8.223f, 7.285f, 8.312f, 7.696f, 8.518f) + curveTo(8.155f, 8.748f, 8.474f, 9.153f, 8.761f, 9.663f) + curveTo(9.043f, 10.164f, 9.333f, 10.841f, 9.697f, 11.691f) + lineTo(9.71f, 11.72f) + lineTo(9.763f, 11.844f) + curveTo(9.878f, 12.127f, 10.004f, 12.406f, 10.143f, 12.679f) + curveTo(10.243f, 12.862f, 10.3f, 12.908f, 10.324f, 12.924f) + curveTo(10.428f, 12.988f, 10.552f, 13.012f, 10.673f, 12.991f) + curveTo(10.702f, 12.986f, 10.772f, 12.964f, 10.933f, 12.831f) + curveTo(11.096f, 12.697f, 11.296f, 12.497f, 11.596f, 12.197f) + lineTo(11.611f, 12.181f) + curveTo(12.012f, 11.781f, 12.335f, 11.458f, 12.618f, 11.219f) + curveTo(12.911f, 10.973f, 13.195f, 10.785f, 13.528f, 10.685f) + curveTo(13.778f, 10.609f, 14.035f, 10.575f, 14.293f, 10.579f) + curveTo(13.441f, 10.873f, 12.658f, 11.358f, 12.008f, 12.008f) + curveTo(11.435f, 12.58f, 10.99f, 13.257f, 10.691f, 13.993f) + curveTo(10.379f, 14.015f, 10.066f, 13.941f, 9.798f, 13.774f) + curveTo(9.554f, 13.623f, 9.394f, 13.396f, 9.264f, 13.157f) + curveTo(9.138f, 12.925f, 9.008f, 12.621f, 8.854f, 12.261f) + lineTo(8.844f, 12.238f) + lineTo(8.79f, 12.113f) + curveTo(8.411f, 11.228f, 8.142f, 10.603f, 7.889f, 10.153f) + curveTo(7.638f, 9.706f, 7.442f, 9.509f, 7.248f, 9.412f) + curveTo(7.001f, 9.288f, 6.725f, 9.235f, 6.449f, 9.258f) + curveTo(6.233f, 9.277f, 5.978f, 9.387f, 5.578f, 9.708f) + curveTo(5.177f, 10.031f, 4.694f, 10.513f, 4.013f, 11.193f) + lineTo(3.25f, 11.957f) + verticalLineTo(10.543f) + lineTo(3.306f, 10.486f) + lineTo(3.328f, 10.465f) + curveTo(3.982f, 9.81f, 4.503f, 9.29f, 4.951f, 8.929f) + curveTo(5.407f, 8.562f, 5.853f, 8.305f, 6.366f, 8.262f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(6.366f, 8.262f) + curveTo(6.825f, 8.223f, 7.285f, 8.312f, 7.696f, 8.518f) + curveTo(8.155f, 8.748f, 8.474f, 9.153f, 8.761f, 9.663f) + curveTo(9.043f, 10.164f, 9.333f, 10.841f, 9.697f, 11.691f) + lineTo(9.71f, 11.72f) + lineTo(9.763f, 11.844f) + curveTo(9.878f, 12.127f, 10.004f, 12.406f, 10.143f, 12.679f) + curveTo(10.243f, 12.862f, 10.3f, 12.908f, 10.324f, 12.924f) + curveTo(10.428f, 12.988f, 10.552f, 13.012f, 10.673f, 12.991f) + curveTo(10.702f, 12.986f, 10.772f, 12.964f, 10.933f, 12.831f) + curveTo(11.096f, 12.697f, 11.296f, 12.497f, 11.596f, 12.197f) + lineTo(11.611f, 12.181f) + curveTo(12.012f, 11.781f, 12.335f, 11.458f, 12.618f, 11.219f) + curveTo(12.911f, 10.973f, 13.195f, 10.785f, 13.528f, 10.685f) + curveTo(13.778f, 10.609f, 14.035f, 10.575f, 14.293f, 10.579f) + curveTo(13.441f, 10.873f, 12.658f, 11.358f, 12.008f, 12.008f) + curveTo(11.435f, 12.58f, 10.99f, 13.257f, 10.691f, 13.993f) + curveTo(10.379f, 14.015f, 10.066f, 13.941f, 9.798f, 13.774f) + curveTo(9.554f, 13.623f, 9.394f, 13.396f, 9.264f, 13.157f) + curveTo(9.138f, 12.925f, 9.008f, 12.621f, 8.854f, 12.261f) + lineTo(8.844f, 12.238f) + lineTo(8.79f, 12.113f) + curveTo(8.411f, 11.228f, 8.142f, 10.603f, 7.889f, 10.153f) + curveTo(7.638f, 9.706f, 7.442f, 9.509f, 7.248f, 9.412f) + curveTo(7.001f, 9.288f, 6.725f, 9.235f, 6.449f, 9.258f) + curveTo(6.233f, 9.277f, 5.978f, 9.387f, 5.578f, 9.708f) + curveTo(5.177f, 10.031f, 4.694f, 10.513f, 4.013f, 11.193f) + lineTo(3.25f, 11.957f) + verticalLineTo(10.543f) + lineTo(3.306f, 10.486f) + lineTo(3.328f, 10.465f) + curveTo(3.982f, 9.81f, 4.503f, 9.29f, 4.951f, 8.929f) + curveTo(5.407f, 8.562f, 5.853f, 8.305f, 6.366f, 8.262f) + close() + } + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(14.75f, 4.25f) + curveTo(15.578f, 4.25f, 16.25f, 4.922f, 16.25f, 5.75f) + curveTo(16.25f, 6.578f, 15.578f, 7.25f, 14.75f, 7.25f) + curveTo(13.922f, 7.25f, 13.25f, 6.578f, 13.25f, 5.75f) + curveTo(13.25f, 4.922f, 13.922f, 4.25f, 14.75f, 4.25f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(14.75f, 4.25f) + curveTo(15.578f, 4.25f, 16.25f, 4.922f, 16.25f, 5.75f) + curveTo(16.25f, 6.578f, 15.578f, 7.25f, 14.75f, 7.25f) + curveTo(13.922f, 7.25f, 13.25f, 6.578f, 13.25f, 5.75f) + curveTo(13.25f, 4.922f, 13.922f, 4.25f, 14.75f, 4.25f) + close() + } + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = EvenOdd) { + moveTo(16.25f, 21.25f) + curveTo(17.576f, 21.25f, 18.848f, 20.723f, 19.785f, 19.785f) + curveTo(20.723f, 18.848f, 21.25f, 17.576f, 21.25f, 16.25f) + curveTo(21.25f, 14.924f, 20.723f, 13.652f, 19.785f, 12.715f) + curveTo(18.848f, 11.777f, 17.576f, 11.25f, 16.25f, 11.25f) + curveTo(14.924f, 11.25f, 13.652f, 11.777f, 12.715f, 12.715f) + curveTo(11.777f, 13.652f, 11.25f, 14.924f, 11.25f, 16.25f) + curveTo(11.25f, 17.576f, 11.777f, 18.848f, 12.715f, 19.785f) + curveTo(13.652f, 20.723f, 14.924f, 21.25f, 16.25f, 21.25f) + close() + moveTo(16.25f, 13.075f) + curveTo(16.371f, 13.075f, 16.486f, 13.122f, 16.571f, 13.208f) + curveTo(16.657f, 13.293f, 16.705f, 13.408f, 16.705f, 13.529f) + verticalLineTo(15.795f) + horizontalLineTo(18.971f) + curveTo(19.091f, 15.795f, 19.207f, 15.843f, 19.292f, 15.929f) + curveTo(19.378f, 16.014f, 19.426f, 16.129f, 19.426f, 16.25f) + curveTo(19.426f, 16.371f, 19.378f, 16.486f, 19.292f, 16.571f) + curveTo(19.207f, 16.657f, 19.091f, 16.705f, 18.971f, 16.705f) + horizontalLineTo(16.705f) + verticalLineTo(18.972f) + curveTo(16.705f, 19.092f, 16.657f, 19.208f, 16.571f, 19.293f) + curveTo(16.486f, 19.378f, 16.371f, 19.426f, 16.25f, 19.426f) + curveTo(16.129f, 19.426f, 16.014f, 19.378f, 15.929f, 19.293f) + curveTo(15.843f, 19.208f, 15.795f, 19.092f, 15.795f, 18.972f) + verticalLineTo(16.705f) + horizontalLineTo(13.529f) + curveTo(13.408f, 16.705f, 13.293f, 16.657f, 13.208f, 16.571f) + curveTo(13.122f, 16.486f, 13.075f, 16.371f, 13.075f, 16.25f) + curveTo(13.075f, 16.129f, 13.122f, 16.014f, 13.208f, 15.929f) + curveTo(13.293f, 15.843f, 13.408f, 15.795f, 13.529f, 15.795f) + horizontalLineTo(15.795f) + verticalLineTo(13.529f) + curveTo(15.795f, 13.408f, 15.843f, 13.293f, 15.929f, 13.208f) + curveTo(16.014f, 13.122f, 16.129f, 13.075f, 16.25f, 13.075f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = EvenOdd) { + moveTo(16.25f, 21.25f) + curveTo(17.576f, 21.25f, 18.848f, 20.723f, 19.785f, 19.785f) + curveTo(20.723f, 18.848f, 21.25f, 17.576f, 21.25f, 16.25f) + curveTo(21.25f, 14.924f, 20.723f, 13.652f, 19.785f, 12.715f) + curveTo(18.848f, 11.777f, 17.576f, 11.25f, 16.25f, 11.25f) + curveTo(14.924f, 11.25f, 13.652f, 11.777f, 12.715f, 12.715f) + curveTo(11.777f, 13.652f, 11.25f, 14.924f, 11.25f, 16.25f) + curveTo(11.25f, 17.576f, 11.777f, 18.848f, 12.715f, 19.785f) + curveTo(13.652f, 20.723f, 14.924f, 21.25f, 16.25f, 21.25f) + close() + moveTo(16.25f, 13.075f) + curveTo(16.371f, 13.075f, 16.486f, 13.122f, 16.571f, 13.208f) + curveTo(16.657f, 13.293f, 16.705f, 13.408f, 16.705f, 13.529f) + verticalLineTo(15.795f) + horizontalLineTo(18.971f) + curveTo(19.091f, 15.795f, 19.207f, 15.843f, 19.292f, 15.929f) + curveTo(19.378f, 16.014f, 19.426f, 16.129f, 19.426f, 16.25f) + curveTo(19.426f, 16.371f, 19.378f, 16.486f, 19.292f, 16.571f) + curveTo(19.207f, 16.657f, 19.091f, 16.705f, 18.971f, 16.705f) + horizontalLineTo(16.705f) + verticalLineTo(18.972f) + curveTo(16.705f, 19.092f, 16.657f, 19.208f, 16.571f, 19.293f) + curveTo(16.486f, 19.378f, 16.371f, 19.426f, 16.25f, 19.426f) + curveTo(16.129f, 19.426f, 16.014f, 19.378f, 15.929f, 19.293f) + curveTo(15.843f, 19.208f, 15.795f, 19.092f, 15.795f, 18.972f) + verticalLineTo(16.705f) + horizontalLineTo(13.529f) + curveTo(13.408f, 16.705f, 13.293f, 16.657f, 13.208f, 16.571f) + curveTo(13.122f, 16.486f, 13.075f, 16.371f, 13.075f, 16.25f) + curveTo(13.075f, 16.129f, 13.122f, 16.014f, 13.208f, 15.929f) + curveTo(13.293f, 15.843f, 13.408f, 15.795f, 13.529f, 15.795f) + horizontalLineTo(15.795f) + verticalLineTo(13.529f) + curveTo(15.795f, 13.408f, 15.843f, 13.293f, 15.929f, 13.208f) + curveTo(16.014f, 13.122f, 16.129f, 13.075f, 16.25f, 13.075f) + close() + } + } + .build() + return _gallery!! + } + +private var _gallery: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.Gallery, contentDescription = "") + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/theme/Color.kt b/app/src/main/java/com/min/dnapp/presentation/ui/theme/Color.kt index f259543..d3f66fc 100644 --- a/app/src/main/java/com/min/dnapp/presentation/ui/theme/Color.kt +++ b/app/src/main/java/com/min/dnapp/presentation/ui/theme/Color.kt @@ -28,6 +28,12 @@ val Pink_B40 = Color(0xFF8C6D64) val Pink_B60 = Color(0xFF5D4942) val Pink_B80 = Color(0xFF2F2421) +val Green_W80 = Color(0xFFE2E8E3) +val Green_W60 = Color(0xFFC5D1C7) +val Green_W40 = Color(0xFFA8B9AC) +val Green_W20 = Color(0xFF8BA290) +val Green_Base = Color(0xFF6E8B74) + // gray val Gray_W10 = Color(0xFF1B1D1F) val Gray_W20 = Color(0xFF333333) diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/theme/Theme.kt b/app/src/main/java/com/min/dnapp/presentation/ui/theme/Theme.kt index b6837f9..3422df4 100644 --- a/app/src/main/java/com/min/dnapp/presentation/ui/theme/Theme.kt +++ b/app/src/main/java/com/min/dnapp/presentation/ui/theme/Theme.kt @@ -38,6 +38,13 @@ data class MomentoColors( val pinkB60: Color, val pinkB80: Color, + // secondary (green) + val greenW80: Color, + val greenW60: Color, + val greenW40: Color, + val greenW20: Color, + val greenBase: Color, + // gray val grayW10: Color, val grayW20: Color, @@ -75,6 +82,11 @@ private val LightColorPalette = MomentoColors( pinkB40 = Pink_B40, pinkB60 = Pink_B60, pinkB80 = Pink_B80, + greenW80 = Green_W80, + greenW60 = Green_W60, + greenW40 = Green_W40, + greenW20 = Green_W20, + greenBase = Green_Base, grayW10 = Gray_W10, grayW20 = Gray_W20, grayW40 = Gray_W40, diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt new file mode 100644 index 0000000..94a28a4 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -0,0 +1,334 @@ +package com.min.dnapp.presentation.write + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.RadioButton +import androidx.compose.material3.RadioButtonDefaults +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Switch +import androidx.compose.material3.SwitchDefaults +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +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.draw.scale +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.R +import com.min.dnapp.presentation.ui.icon.AppIcons +import com.min.dnapp.presentation.ui.icon.appicons.Back +import com.min.dnapp.presentation.ui.icon.appicons.Calendar +import com.min.dnapp.presentation.ui.icon.appicons.Gallery +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun RecordWriteScreen() { + val radioOptions = listOf("국내", "해외 (직접 입력)") + var selectedPlace by remember { mutableStateOf("국내") } + var isChecked by remember { mutableStateOf(true) } + + Scaffold( + containerColor = MomentoTheme.colors.brownW90, + topBar = { + CenterAlignedTopAppBar( + title = { + Text( + text = "기록 작성하기", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 + ) + }, + colors = TopAppBarDefaults.centerAlignedTopAppBarColors( + containerColor = MomentoTheme.colors.brownW90 + ), + navigationIcon = { + Icon( + modifier = Modifier + .clickable { } + .padding(16.dp), + imageVector = AppIcons.Back, + contentDescription = null + ) + }, + actions = { + Text( + modifier = Modifier + .clickable { } + .padding(16.dp), + text = "완료", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 + ) + } + ) + } + ) { paddingValues -> + Column( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize(), + verticalArrangement = Arrangement.SpaceBetween + ) { + Column( + modifier = Modifier + .padding(horizontal = 20.dp) + .fillMaxWidth() + ) { + Spacer(Modifier.height(20.dp)) + + // 날짜 + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = AppIcons.Calendar, + contentDescription = null, + tint = MomentoTheme.colors.brownBase + ) + Spacer(Modifier.width(10.dp)) + Text( + text = "2025년 12월 12일 ~ 2025년 12월 13일", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 + ) + } + + Spacer(Modifier.height(20.dp)) + + // 감정 & 날씨 + Row { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "감정 태그", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + Spacer(Modifier.width(8.dp)) + Box( + modifier = Modifier + .size(32.dp) + .background(color = MomentoTheme.colors.white, shape = RoundedCornerShape(5.dp)) + .border(width = 1.dp, color = MomentoTheme.colors.pinkW60, shape = RoundedCornerShape(5.dp)) + .padding(6.dp) + ) { + Image( + painter = painterResource(R.drawable.emotion_love), + contentDescription = null + ) + } + } + Spacer(Modifier.width(20.dp)) + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "날씨", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + Spacer(Modifier.width(8.dp)) + Box( + modifier = Modifier + .size(32.dp) + .background(color = MomentoTheme.colors.white, shape = RoundedCornerShape(5.dp)) + .border(width = 1.dp, color = MomentoTheme.colors.pinkW60, shape = RoundedCornerShape(5.dp)), + contentAlignment = Alignment.Center + ) { + Image( + painter = painterResource(R.drawable.weather_cloud), + contentDescription = null + ) + } + } + } + + Spacer(Modifier.height(20.dp)) + + // 제목 + Box( + modifier = Modifier + .fillMaxWidth() + .height(40.dp) + .background(color = MomentoTheme.colors.brownBg, shape = RoundedCornerShape(5.dp)) + ) + + Spacer(Modifier.height(20.dp)) + + // 여행지 + Column( + modifier = Modifier.fillMaxWidth() + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "어디로 다녀오셨나요?", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + + // 라디오 버튼 + Row( + verticalAlignment = Alignment.CenterVertically + ) { + radioOptions.forEachIndexed { idx, text -> + RadioButton( + modifier = Modifier.size(24.dp), + selected = (text == selectedPlace), + onClick = { selectedPlace = text }, + colors = RadioButtonDefaults.colors( + selectedColor = MomentoTheme.colors.greenW20, + unselectedColor = MomentoTheme.colors.grayW80, + disabledSelectedColor = MomentoTheme.colors.white + ) + ) + Spacer(Modifier.width(4.dp)) + Text( + text = text, + style = MomentoTheme.typography.body03, + color = MomentoTheme.colors.grayW20 + ) + if (idx == 0) { + Spacer(Modifier.width(12.dp)) + } + } + } + } + + Spacer(Modifier.height(12.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(R.drawable.write_place), + contentDescription = null + ) + Spacer(Modifier.width(6.dp)) + Text( + text = "위치 추가", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW40 + ) + } + } + + Spacer(Modifier.height(40.dp)) + + // 내용 + Column( + modifier = Modifier.fillMaxWidth() + ) { + Text( + text = "이번 여행에 대해 소개해주세요.", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + Spacer(Modifier.height(12.dp)) + Box( + modifier = Modifier + .fillMaxWidth() + .height(310.dp) + .background(color = MomentoTheme.colors.brownBg) + ) + } + } + + Row( + modifier = Modifier + .fillMaxWidth() + .background(color = MomentoTheme.colors.white), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + modifier = Modifier + .clickable { } + .padding(20.dp), + imageVector = AppIcons.Gallery, + contentDescription = null, + tint = MomentoTheme.colors.grayW60 + ) + + Row( + modifier = Modifier.padding(end = 20.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "공유 여부", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + Spacer(Modifier.width(8.dp)) + Switch( + // 기본 크기의 80%로 축소 + modifier = Modifier.scale(0.8f), + checked = isChecked, + onCheckedChange = { newChecked -> + isChecked = newChecked + }, + thumbContent = { FixedSizeThumbBox() }, + colors = SwitchDefaults.colors( + // on - switch 배경 색 + checkedTrackColor = MomentoTheme.colors.greenW20, + // off - switch 배경 색 + uncheckedTrackColor = MomentoTheme.colors.grayW80, + // off - switch 테두리 색 + uncheckedBorderColor = Color.Transparent, + // off - thumb 테두리 색 + uncheckedThumbColor = MomentoTheme.colors.white + ) + ) + } + } + } + } +} + +@Composable +fun FixedSizeThumbBox() { + Box( + modifier = Modifier + .size(SwitchDefaults.IconSize) + .background(color = MomentoTheme.colors.white, shape = CircleShape) + ) +} + +@Preview +@Composable +fun RecordWriteScreenPreview() { + DngoTheme { + RecordWriteScreen() + } +} diff --git a/app/src/main/res/drawable/emotion_angry.xml b/app/src/main/res/drawable/emotion_angry.xml new file mode 100644 index 0000000..2ddcc99 --- /dev/null +++ b/app/src/main/res/drawable/emotion_angry.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/emotion_check.xml b/app/src/main/res/drawable/emotion_check.xml new file mode 100644 index 0000000..01c245c --- /dev/null +++ b/app/src/main/res/drawable/emotion_check.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/emotion_feel.xml b/app/src/main/res/drawable/emotion_feel.xml new file mode 100644 index 0000000..968bf77 --- /dev/null +++ b/app/src/main/res/drawable/emotion_feel.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/emotion_happy.xml b/app/src/main/res/drawable/emotion_happy.xml new file mode 100644 index 0000000..b7550cc --- /dev/null +++ b/app/src/main/res/drawable/emotion_happy.xml @@ -0,0 +1,30 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/emotion_love.xml b/app/src/main/res/drawable/emotion_love.xml new file mode 100644 index 0000000..0358c66 --- /dev/null +++ b/app/src/main/res/drawable/emotion_love.xml @@ -0,0 +1,23 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/emotion_sad.xml b/app/src/main/res/drawable/emotion_sad.xml new file mode 100644 index 0000000..10c9ab2 --- /dev/null +++ b/app/src/main/res/drawable/emotion_sad.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/emotion_shine.xml b/app/src/main/res/drawable/emotion_shine.xml new file mode 100644 index 0000000..227b21c --- /dev/null +++ b/app/src/main/res/drawable/emotion_shine.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/drawable/emotion_surprise.xml b/app/src/main/res/drawable/emotion_surprise.xml new file mode 100644 index 0000000..b117145 --- /dev/null +++ b/app/src/main/res/drawable/emotion_surprise.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/weather_check.xml b/app/src/main/res/drawable/weather_check.xml new file mode 100644 index 0000000..a0fb31b --- /dev/null +++ b/app/src/main/res/drawable/weather_check.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/weather_cloud.xml b/app/src/main/res/drawable/weather_cloud.xml new file mode 100644 index 0000000..bd48dfd --- /dev/null +++ b/app/src/main/res/drawable/weather_cloud.xml @@ -0,0 +1,33 @@ + + + + + + + + + + diff --git a/app/src/main/res/drawable/weather_moon.xml b/app/src/main/res/drawable/weather_moon.xml new file mode 100644 index 0000000..fb3bf6b --- /dev/null +++ b/app/src/main/res/drawable/weather_moon.xml @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/weather_rain.xml b/app/src/main/res/drawable/weather_rain.xml new file mode 100644 index 0000000..dafe185 --- /dev/null +++ b/app/src/main/res/drawable/weather_rain.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/weather_snow.xml b/app/src/main/res/drawable/weather_snow.xml new file mode 100644 index 0000000..f01f5c9 --- /dev/null +++ b/app/src/main/res/drawable/weather_snow.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/weather_sun.xml b/app/src/main/res/drawable/weather_sun.xml new file mode 100644 index 0000000..44fb0e2 --- /dev/null +++ b/app/src/main/res/drawable/weather_sun.xml @@ -0,0 +1,33 @@ + + + + + + + + + + diff --git a/app/src/main/res/drawable/weather_thunder.xml b/app/src/main/res/drawable/weather_thunder.xml new file mode 100644 index 0000000..cefca47 --- /dev/null +++ b/app/src/main/res/drawable/weather_thunder.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/weather_wind.xml b/app/src/main/res/drawable/weather_wind.xml new file mode 100644 index 0000000..ee9bfb7 --- /dev/null +++ b/app/src/main/res/drawable/weather_wind.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/write_place.xml b/app/src/main/res/drawable/write_place.xml new file mode 100644 index 0000000..f1a5275 --- /dev/null +++ b/app/src/main/res/drawable/write_place.xml @@ -0,0 +1,24 @@ + + + + + + From c0e43348b4241523da96351fccf0db8aabe85a38 Mon Sep 17 00:00:00 2001 From: min486 Date: Sun, 12 Oct 2025 13:55:08 +0900 Subject: [PATCH 23/98] =?UTF-8?q?design:=20=EC=9E=91=EC=84=B1=20=EC=99=84?= =?UTF-8?q?=EB=A3=8C=20=ED=99=94=EB=A9=B4=20UI=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 4 +- .../presentation/write/WriteFinishScreen.kt | 86 ++++++++ app/src/main/res/drawable/write_finish.xml | 200 ++++++++++++++++++ app/src/main/res/drawable/write_stamp.xml | 97 +++++++++ 4 files changed, 386 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt create mode 100644 app/src/main/res/drawable/write_finish.xml create mode 100644 app/src/main/res/drawable/write_stamp.xml diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index 8f04a8c..181ee34 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -27,6 +27,7 @@ import com.min.dnapp.presentation.onboarding.OnboardingScreen3 import com.min.dnapp.presentation.profile.ProfileSetupScreen import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.write.RecordWriteScreen +import com.min.dnapp.presentation.write.WriteFinishScreen import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -47,7 +48,8 @@ class MainActivity : ComponentActivity() { // ProfileSetupScreen() // MypageScreen() // SettingScreen() - RecordWriteScreen() +// RecordWriteScreen() + WriteFinishScreen() } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt new file mode 100644 index 0000000..949f116 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt @@ -0,0 +1,86 @@ +package com.min.dnapp.presentation.write + +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.Spacer +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.shape.RoundedCornerShape +import androidx.compose.material3.Surface +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.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.R +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun WriteFinishScreen() { + Surface( + modifier = Modifier.fillMaxSize(), + color = MomentoTheme.colors.white + ) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 20.dp), + verticalArrangement = Arrangement.SpaceBetween + ) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(Modifier.height(100.dp)) + Image( + painter = painterResource(R.drawable.write_finish), + contentDescription = null + ) + Spacer(Modifier.height(40.dp)) + Text( + text = "여행 기록 작성이 완료되었어요.", + style = MomentoTheme.typography.title01, + color = MomentoTheme.colors.grayW20 + ) + } + + // 버튼 영역 + Column( + modifier = Modifier.fillMaxWidth() + ) { + Box( + modifier = Modifier + .clickable { } + .fillMaxWidth() + .background(color = MomentoTheme.colors.brownBase, shape = RoundedCornerShape(10.dp)) + .padding(vertical = 16.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "홈으로", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.white + ) + } + Spacer(Modifier.height(16.dp)) + } + } + } +} + +@Preview +@Composable +fun WriteFinishScreenPreview() { + DngoTheme { + WriteFinishScreen() + } +} diff --git a/app/src/main/res/drawable/write_finish.xml b/app/src/main/res/drawable/write_finish.xml new file mode 100644 index 0000000..88b33a8 --- /dev/null +++ b/app/src/main/res/drawable/write_finish.xml @@ -0,0 +1,200 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/write_stamp.xml b/app/src/main/res/drawable/write_stamp.xml new file mode 100644 index 0000000..fa61a9c --- /dev/null +++ b/app/src/main/res/drawable/write_stamp.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From b274e3b063aaccec8b558b2a1b23e52cc7c1f45e Mon Sep 17 00:00:00 2001 From: min486 Date: Sun, 12 Oct 2025 15:20:03 +0900 Subject: [PATCH 24/98] =?UTF-8?q?feat:=20WriteFinishScreen=20-=20=EC=8A=A4?= =?UTF-8?q?=ED=83=AC=ED=94=84=20=EC=A7=80=EA=B8=89=20Dialog=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/write/WriteFinishScreen.kt | 16 +++++ .../write/component/WriteStampDialog.kt | 71 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 app/src/main/java/com/min/dnapp/presentation/write/component/WriteStampDialog.kt diff --git a/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt index 949f116..0403447 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt @@ -15,6 +15,10 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Surface 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.painterResource @@ -23,9 +27,13 @@ import androidx.compose.ui.unit.dp import com.min.dnapp.R import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.ui.theme.MomentoTheme +import com.min.dnapp.presentation.write.component.WriteStampDialog @Composable fun WriteFinishScreen() { + + var showStampDialog by remember { mutableStateOf(true) } + Surface( modifier = Modifier.fillMaxSize(), color = MomentoTheme.colors.white @@ -75,6 +83,14 @@ fun WriteFinishScreen() { } } } + + // 스탬프 지급 모달창 + if (showStampDialog) { + WriteStampDialog( + onDismiss = { showStampDialog = false }, + onConfirm = { showStampDialog = false } + ) + } } @Preview diff --git a/app/src/main/java/com/min/dnapp/presentation/write/component/WriteStampDialog.kt b/app/src/main/java/com/min/dnapp/presentation/write/component/WriteStampDialog.kt new file mode 100644 index 0000000..cd9b680 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/write/component/WriteStampDialog.kt @@ -0,0 +1,71 @@ +package com.min.dnapp.presentation.write.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Surface +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.painterResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import com.min.dnapp.R +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun WriteStampDialog( + onDismiss: () -> Unit, + onConfirm: () -> Unit +) { + Dialog( + onDismissRequest = onDismiss + ) { + Surface( + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(16.dp), + color = MomentoTheme.colors.white + ) { + Column( + modifier = Modifier.padding(horizontal = 20.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(Modifier.height(20.dp)) + Image( + painter = painterResource(R.drawable.write_stamp), + contentDescription = null + ) + Spacer(Modifier.height(20.dp)) + Text( + text = "스탬프 1개가 지급되었어요!", + style = MomentoTheme.typography.title01, + color = MomentoTheme.colors.grayW20 + ) + Spacer(Modifier.height(20.dp)) + Box( + modifier = Modifier + .clickable { onConfirm() } + .fillMaxWidth() + .background(color = MomentoTheme.colors.brownBase, shape = RoundedCornerShape(10.dp)) + .padding(vertical = 16.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "확인했어요", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.white + ) + } + Spacer(Modifier.height(20.dp)) + } + } + } +} From 7981f4a21d5a95816e9ca45146ec814449801364 Mon Sep 17 00:00:00 2001 From: min486 Date: Sun, 12 Oct 2025 16:28:23 +0900 Subject: [PATCH 25/98] =?UTF-8?q?feat:=20RecordWriteScreen=20-=20=EA=B0=90?= =?UTF-8?q?=EC=A0=95=20=EC=84=A0=ED=83=9D=20bottomSheet=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/write/RecordWriteScreen.kt | 19 +++ .../component/EmotionBottomSheetContent.kt | 127 ++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 app/src/main/java/com/min/dnapp/presentation/write/component/EmotionBottomSheetContent.kt diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index 94a28a4..2f1504f 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -20,6 +20,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon +import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.RadioButton import androidx.compose.material3.RadioButtonDefaults import androidx.compose.material3.Scaffold @@ -46,6 +47,7 @@ import com.min.dnapp.presentation.ui.icon.appicons.Calendar import com.min.dnapp.presentation.ui.icon.appicons.Gallery import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.ui.theme.MomentoTheme +import com.min.dnapp.presentation.write.component.EmotionBottomSheetContent @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -53,6 +55,8 @@ fun RecordWriteScreen() { val radioOptions = listOf("국내", "해외 (직접 입력)") var selectedPlace by remember { mutableStateOf("국내") } var isChecked by remember { mutableStateOf(true) } + var showEmotionBottomSheet by remember { mutableStateOf(false) } + var showWeatherBottomSheet by remember { mutableStateOf(false) } Scaffold( containerColor = MomentoTheme.colors.brownW90, @@ -125,6 +129,7 @@ fun RecordWriteScreen() { // 감정 & 날씨 Row { Row( + modifier = Modifier.clickable { showEmotionBottomSheet = true }, verticalAlignment = Alignment.CenterVertically ) { Text( @@ -314,6 +319,20 @@ fun RecordWriteScreen() { } } } + + // 감정 선택 바텀시트 + if (showEmotionBottomSheet) { + ModalBottomSheet( + onDismissRequest = { showEmotionBottomSheet = false }, + dragHandle = null, + containerColor = MomentoTheme.colors.white, + shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) + ) { + EmotionBottomSheetContent( + onConfirm = { showEmotionBottomSheet = false } + ) + } + } } @Composable diff --git a/app/src/main/java/com/min/dnapp/presentation/write/component/EmotionBottomSheetContent.kt b/app/src/main/java/com/min/dnapp/presentation/write/component/EmotionBottomSheetContent.kt new file mode 100644 index 0000000..8aba23f --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/write/component/EmotionBottomSheetContent.kt @@ -0,0 +1,127 @@ +package com.min.dnapp.presentation.write.component + +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.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.HorizontalDivider +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.painterResource +import androidx.compose.ui.unit.dp +import com.min.dnapp.R +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun EmotionBottomSheetContent( + onConfirm: () -> Unit +) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(Modifier.height(20.dp)) + + Text( + text = "기분은 어땠나요?", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 + ) + + Spacer(Modifier.height(20.dp)) + + HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW90) + + Spacer(Modifier.height(20.dp)) + + Column( + modifier = Modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(28.dp) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + Image( + modifier = Modifier.clickable { }, + painter = painterResource(R.drawable.emotion_happy), + contentDescription = null + ) + Image( + modifier = Modifier.clickable { }, + painter = painterResource(R.drawable.emotion_love), + contentDescription = null + ) + Image( + modifier = Modifier.clickable { }, + painter = painterResource(R.drawable.emotion_surprise), + contentDescription = null + ) + } + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + Image( + modifier = Modifier.clickable { }, + painter = painterResource(R.drawable.emotion_angry), + contentDescription = null + ) + Image( + modifier = Modifier.clickable { }, + painter = painterResource(R.drawable.emotion_feel), + contentDescription = null + ) + Image( + modifier = Modifier.clickable { }, + painter = painterResource(R.drawable.emotion_sad), + contentDescription = null + ) + } + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center + ) { + Image( + modifier = Modifier.clickable { }, + painter = painterResource(R.drawable.emotion_shine), + contentDescription = null + ) + } + } + + Spacer(Modifier.height(40.dp)) + + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 20.dp) + ) { + Box( + modifier = Modifier + .clickable { onConfirm() } + .fillMaxWidth() + .background(color = MomentoTheme.colors.brownBase, shape = RoundedCornerShape(10.dp)) + .padding(vertical = 16.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "선택했어요", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.white + ) + } + Spacer(Modifier.height(16.dp)) + } + } +} From ce81f2d0ee3bf7cfd77b5278dd0d526dcb436d68 Mon Sep 17 00:00:00 2001 From: min486 Date: Sun, 12 Oct 2025 17:06:45 +0900 Subject: [PATCH 26/98] =?UTF-8?q?feat:=20RecordWriteScreen=20-=20=EB=82=A0?= =?UTF-8?q?=EC=94=A8=20=EC=84=A0=ED=83=9D=20bottomSheet=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/write/RecordWriteScreen.kt | 16 +++ .../component/WeatherBottomSheetContent.kt | 127 ++++++++++++++++++ app/src/main/res/drawable/weather_cloud.xml | 24 ++-- app/src/main/res/drawable/weather_moon.xml | 22 +-- app/src/main/res/drawable/weather_rain.xml | 40 +++--- app/src/main/res/drawable/weather_snow.xml | 50 +++---- app/src/main/res/drawable/weather_sun.xml | 24 ++-- app/src/main/res/drawable/weather_thunder.xml | 44 +++--- app/src/main/res/drawable/weather_wind.xml | 30 ++--- 9 files changed, 260 insertions(+), 117 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/write/component/WeatherBottomSheetContent.kt diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index 2f1504f..e6c356d 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -48,6 +48,7 @@ import com.min.dnapp.presentation.ui.icon.appicons.Gallery import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.ui.theme.MomentoTheme import com.min.dnapp.presentation.write.component.EmotionBottomSheetContent +import com.min.dnapp.presentation.write.component.WeatherBottomSheetContent @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -153,6 +154,7 @@ fun RecordWriteScreen() { } Spacer(Modifier.width(20.dp)) Row( + modifier = Modifier.clickable { showWeatherBottomSheet = true }, verticalAlignment = Alignment.CenterVertically ) { Text( @@ -333,6 +335,20 @@ fun RecordWriteScreen() { ) } } + + // 날씨 선택 바텀시트 + if (showWeatherBottomSheet) { + ModalBottomSheet( + onDismissRequest = { showWeatherBottomSheet = false }, + dragHandle = null, + containerColor = MomentoTheme.colors.white, + shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) + ) { + WeatherBottomSheetContent ( + onConfirm = { showWeatherBottomSheet = false } + ) + } + } } @Composable diff --git a/app/src/main/java/com/min/dnapp/presentation/write/component/WeatherBottomSheetContent.kt b/app/src/main/java/com/min/dnapp/presentation/write/component/WeatherBottomSheetContent.kt new file mode 100644 index 0000000..a3fbd7b --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/write/component/WeatherBottomSheetContent.kt @@ -0,0 +1,127 @@ +package com.min.dnapp.presentation.write.component + +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.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.HorizontalDivider +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.painterResource +import androidx.compose.ui.unit.dp +import com.min.dnapp.R +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun WeatherBottomSheetContent( + onConfirm: () -> Unit +) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(Modifier.height(20.dp)) + + Text( + text = "날씨는 어땠나요?", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 + ) + + Spacer(Modifier.height(20.dp)) + + HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW90) + + Spacer(Modifier.height(12 .dp)) + + Column( + modifier = Modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(20.dp) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + Image( + modifier = Modifier.clickable { }, + painter = painterResource(R.drawable.weather_sun), + contentDescription = null + ) + Image( + modifier = Modifier.clickable { }, + painter = painterResource(R.drawable.weather_wind), + contentDescription = null + ) + Image( + modifier = Modifier.clickable { }, + painter = painterResource(R.drawable.weather_moon), + contentDescription = null + ) + } + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + Image( + modifier = Modifier.clickable { }, + painter = painterResource(R.drawable.weather_thunder), + contentDescription = null + ) + Image( + modifier = Modifier.clickable { }, + painter = painterResource(R.drawable.weather_rain), + contentDescription = null + ) + Image( + modifier = Modifier.clickable { }, + painter = painterResource(R.drawable.weather_cloud), + contentDescription = null + ) + } + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center + ) { + Image( + modifier = Modifier.clickable { }, + painter = painterResource(R.drawable.weather_snow), + contentDescription = null + ) + } + } + + Spacer(Modifier.height(32.dp)) + + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 20.dp) + ) { + Box( + modifier = Modifier + .clickable { onConfirm() } + .fillMaxWidth() + .background(color = MomentoTheme.colors.brownBase, shape = RoundedCornerShape(10.dp)) + .padding(vertical = 16.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "선택했어요", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.white + ) + } + Spacer(Modifier.height(16.dp)) + } + } +} diff --git a/app/src/main/res/drawable/weather_cloud.xml b/app/src/main/res/drawable/weather_cloud.xml index bd48dfd..dc5f758 100644 --- a/app/src/main/res/drawable/weather_cloud.xml +++ b/app/src/main/res/drawable/weather_cloud.xml @@ -1,33 +1,33 @@ + android:width="56dp" + android:height="56dp" + android:viewportWidth="56" + android:viewportHeight="56"> diff --git a/app/src/main/res/drawable/weather_moon.xml b/app/src/main/res/drawable/weather_moon.xml index fb3bf6b..d637baa 100644 --- a/app/src/main/res/drawable/weather_moon.xml +++ b/app/src/main/res/drawable/weather_moon.xml @@ -1,27 +1,27 @@ + android:width="56dp" + android:height="56dp" + android:viewportWidth="56" + android:viewportHeight="56"> diff --git a/app/src/main/res/drawable/weather_rain.xml b/app/src/main/res/drawable/weather_rain.xml index dafe185..524aa23 100644 --- a/app/src/main/res/drawable/weather_rain.xml +++ b/app/src/main/res/drawable/weather_rain.xml @@ -1,57 +1,57 @@ + android:width="56dp" + android:height="56dp" + android:viewportWidth="56" + android:viewportHeight="56"> diff --git a/app/src/main/res/drawable/weather_snow.xml b/app/src/main/res/drawable/weather_snow.xml index f01f5c9..208b6ac 100644 --- a/app/src/main/res/drawable/weather_snow.xml +++ b/app/src/main/res/drawable/weather_snow.xml @@ -1,72 +1,72 @@ + android:width="56dp" + android:height="56dp" + android:viewportWidth="56" + android:viewportHeight="56"> diff --git a/app/src/main/res/drawable/weather_sun.xml b/app/src/main/res/drawable/weather_sun.xml index 44fb0e2..07c0feb 100644 --- a/app/src/main/res/drawable/weather_sun.xml +++ b/app/src/main/res/drawable/weather_sun.xml @@ -1,33 +1,33 @@ + android:width="56dp" + android:height="56dp" + android:viewportWidth="56" + android:viewportHeight="56"> diff --git a/app/src/main/res/drawable/weather_thunder.xml b/app/src/main/res/drawable/weather_thunder.xml index cefca47..591c1f5 100644 --- a/app/src/main/res/drawable/weather_thunder.xml +++ b/app/src/main/res/drawable/weather_thunder.xml @@ -1,65 +1,65 @@ + android:width="56dp" + android:height="56dp" + android:viewportWidth="56" + android:viewportHeight="56"> diff --git a/app/src/main/res/drawable/weather_wind.xml b/app/src/main/res/drawable/weather_wind.xml index ee9bfb7..eb1bf98 100644 --- a/app/src/main/res/drawable/weather_wind.xml +++ b/app/src/main/res/drawable/weather_wind.xml @@ -1,42 +1,42 @@ + android:width="56dp" + android:height="56dp" + android:viewportWidth="56" + android:viewportHeight="56"> From 6634279e9d1394b3a0ec981c3e9115a2f716ed2b Mon Sep 17 00:00:00 2001 From: min486 Date: Mon, 13 Oct 2025 17:15:05 +0900 Subject: [PATCH 27/98] =?UTF-8?q?design:=20=EB=B0=9C=EA=B2=AC=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20UI=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 14 +- .../min/dnapp/presentation/find/FindScreen.kt | 94 +++++ .../find/component/FindReactionIconSection.kt | 121 ++++++ .../find/component/SharedRecordItem.kt | 205 ++++++++++ .../dnapp/presentation/ui/icon/__AppIcons.kt | 9 +- .../presentation/ui/icon/appicons/Delete.kt | 92 +++++ .../ui/icon/appicons/RecordBest.kt | 184 +++++++++ .../ui/icon/appicons/RecordBookmark.kt | 178 +++++++++ .../ui/icon/appicons/RecordComment.kt | 210 ++++++++++ .../ui/icon/appicons/RecordLike.kt | 148 +++++++ .../ui/icon/appicons/RecordSurprise.kt | 148 +++++++ app/src/main/res/drawable/badge_bronze.xml | 250 ++++++++++++ app/src/main/res/drawable/badge_gold.xml | 250 ++++++++++++ app/src/main/res/drawable/badge_silver.xml | 370 ++++++++++++++++++ app/src/main/res/drawable/beach.png | Bin 0 -> 99258 bytes 15 files changed, 2261 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/find/component/FindReactionIconSection.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Delete.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordBest.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordBookmark.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordComment.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordLike.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordSurprise.kt create mode 100644 app/src/main/res/drawable/badge_bronze.xml create mode 100644 app/src/main/res/drawable/badge_gold.xml create mode 100644 app/src/main/res/drawable/badge_silver.xml create mode 100644 app/src/main/res/drawable/beach.png diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index 181ee34..2d28724 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -3,7 +3,6 @@ package com.min.dnapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.Surface import androidx.compose.runtime.Composable @@ -16,18 +15,10 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import com.min.dnapp.presentation.AppStartViewModel +import com.min.dnapp.presentation.find.FindScreen import com.min.dnapp.presentation.home.HomeScreen import com.min.dnapp.presentation.login.LoginScreen -import com.min.dnapp.presentation.login.LoginScreen2 -import com.min.dnapp.presentation.mypage.MypageScreen -import com.min.dnapp.presentation.mypage.SettingScreen -import com.min.dnapp.presentation.onboarding.OnboardingScreen -import com.min.dnapp.presentation.onboarding.OnboardingScreen2 -import com.min.dnapp.presentation.onboarding.OnboardingScreen3 -import com.min.dnapp.presentation.profile.ProfileSetupScreen import com.min.dnapp.presentation.ui.theme.DngoTheme -import com.min.dnapp.presentation.write.RecordWriteScreen -import com.min.dnapp.presentation.write.WriteFinishScreen import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -49,7 +40,8 @@ class MainActivity : ComponentActivity() { // MypageScreen() // SettingScreen() // RecordWriteScreen() - WriteFinishScreen() +// WriteFinishScreen() + FindScreen() } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt b/app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt new file mode 100644 index 0000000..bd044db --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt @@ -0,0 +1,94 @@ +package com.min.dnapp.presentation.find + +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.R +import com.min.dnapp.presentation.find.component.SharedRecordItem +import com.min.dnapp.presentation.ui.icon.AppIcons +import com.min.dnapp.presentation.ui.icon.appicons.Bell +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun FindScreen() { + Scaffold( + containerColor = MomentoTheme.colors.brownBg, + topBar = { + CenterAlignedTopAppBar( + title = { Text("") }, + colors = TopAppBarDefaults.centerAlignedTopAppBarColors( + containerColor = MomentoTheme.colors.brownBg + ), + navigationIcon = { + Image( + modifier = Modifier + .clickable { } + .padding(16.dp), + painter = painterResource(R.drawable.logo_momento), + contentDescription = null + ) + }, + actions = { + Icon( + modifier = Modifier + .clickable { } + .padding(16.dp), + imageVector = AppIcons.Bell, + contentDescription = null, + tint = MomentoTheme.colors.grayW60 + ) + } + ) + } + ) { paddingValues -> + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + ) { + item { + HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW80) + } + + val itemCnt = 5 + + items(count = itemCnt) { idx -> + Box( + modifier = Modifier.padding(20.dp) + ) { + // 발견 탭에 공유된 여행기록 아이템 + SharedRecordItem() + } + + if (idx < itemCnt - 1) { + HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW80) + } + } + } + } +} + +@Preview +@Composable +fun FindScreenPreview() { + DngoTheme { + FindScreen() + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/find/component/FindReactionIconSection.kt b/app/src/main/java/com/min/dnapp/presentation/find/component/FindReactionIconSection.kt new file mode 100644 index 0000000..e578575 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/find/component/FindReactionIconSection.kt @@ -0,0 +1,121 @@ +package com.min.dnapp.presentation.find.component + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import com.min.dnapp.presentation.ui.icon.appicons.RecordBest +import com.min.dnapp.presentation.ui.icon.appicons.RecordBookmark +import com.min.dnapp.presentation.ui.icon.appicons.RecordComment +import com.min.dnapp.presentation.ui.icon.appicons.RecordLike +import com.min.dnapp.presentation.ui.icon.appicons.RecordSurprise +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun FindReactionIconSection( + bestNum: Int, + likeNum: Int, + surpriseNum: Int, + commentNum: Int +) { + Row( + modifier = Modifier + .fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = AppIcons.RecordBest, + contentDescription = null, + tint = MomentoTheme.colors.grayW60 + ) + Spacer(Modifier.width(2.dp)) + Text( + text = bestNum.toString(), + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + } + + Spacer(Modifier.width(4.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = AppIcons.RecordLike, + contentDescription = null, + tint = MomentoTheme.colors.grayW60 + ) + Spacer(Modifier.width(2.dp)) + Text( + text = likeNum.toString(), + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + } + + Spacer(Modifier.width(4.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = AppIcons.RecordSurprise, + contentDescription = null, + tint = MomentoTheme.colors.grayW60 + ) + Spacer(Modifier.width(2.dp)) + Text( + text = surpriseNum.toString(), + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + } + } + + Row( + modifier = Modifier.clickable { }, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = AppIcons.RecordComment, + contentDescription = null, + tint = MomentoTheme.colors.grayW60 + ) + Spacer(Modifier.width(2.dp)) + Text( + text = commentNum.toString(), + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + } + + Spacer(Modifier.width(12.dp)) + + Icon( + imageVector = AppIcons.RecordBookmark, + contentDescription = null, + tint = MomentoTheme.colors.grayW60 + ) + } + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt new file mode 100644 index 0000000..39fe001 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt @@ -0,0 +1,205 @@ +package com.min.dnapp.presentation.find.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +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.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.shape.CircleShape +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +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.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.R +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun SharedRecordItem() { + Row( + modifier = Modifier.fillMaxWidth() + ) { + // 프로필 이미지 + Box( + modifier = Modifier + .size(36.dp) + .clip(CircleShape) + .border(width = 2.dp, color = MomentoTheme.colors.grayW90, shape = CircleShape) + ) { + Image( + painter = painterResource(R.drawable.logo_profile), + contentDescription = null + ) + } + + Spacer(Modifier.width(8.dp)) + + Column( + modifier = Modifier.weight(1f) + ) { + // 닉네임 + 공유 안내 + SharedRecordHeaderSection() + + Spacer(Modifier.height(8.dp)) + + // 기록 내용 + SharedRecordContentSection() + + Spacer(Modifier.height(12.dp)) + + // 반응 이모지 영역 + FindReactionIconSection( + bestNum = 1, + likeNum = 2, + surpriseNum = 12, + commentNum = 2 + ) + } + } +} + +@Composable +fun SharedRecordHeaderSection() { + Column( + modifier = Modifier.fillMaxWidth() + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "시골청년", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + Image( + modifier = Modifier.size(20.dp), + painter = painterResource(R.drawable.badge_bronze), + contentDescription = null + ) + Spacer(Modifier.width(4.dp)) + Text( + text = "2분 전", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW20 + ) + } + + Spacer(Modifier.height(8.dp)) + + Text( + text = "시골청년님이 여행 기록을 공유했어요.", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + } +} + +@Composable +fun SharedRecordContentSection() { + Column( + modifier = Modifier + .fillMaxWidth() + .background(color = MomentoTheme.colors.brownW90) + .padding(horizontal = 16.dp) + ) { + Spacer(Modifier.height(16.dp)) + + Text( + text = "제주도 동쪽 투어!", + style = MomentoTheme.typography.label, + color = MomentoTheme.colors.grayW20 + ) + + Spacer(Modifier.height(6.dp)) + + HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.pinkBase) + + Spacer(Modifier.height(4.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "25.08.20 ~ 25.08.22", + style = MomentoTheme.typography.body03, + color = MomentoTheme.colors.grayW20 + ) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Image( + modifier = Modifier.size(28.dp), + painter = painterResource(R.drawable.weather_sun), + contentDescription = null + ) + Spacer(Modifier.width(4.dp)) + Image( + modifier = Modifier.size(28.dp), + painter = painterResource(R.drawable.emotion_feel), + contentDescription = null + ) + } + } + + Spacer(Modifier.height(4.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(R.drawable.write_place), + contentDescription = null + ) + Spacer(Modifier.width(6.dp)) + Text( + text = "제주특별자치도", + style = MomentoTheme.typography.body03 , + color = MomentoTheme.colors.grayW20 + ) + } + + Spacer(Modifier.height(6.dp)) + + Text( + text = "비 오는 날 이호해수욕장... 너무 좋았어요", + style = MomentoTheme.typography.body02 , + color = MomentoTheme.colors.grayW20 + ) + + Spacer(Modifier.height(6.dp)) + + Image( + modifier = Modifier.fillMaxWidth(), + painter = painterResource(R.drawable.beach ), + contentDescription = null, + contentScale = ContentScale.Crop + ) + + Spacer(Modifier.height(12.dp)) + } +} + +@Preview +@Composable +fun RecordItemPreview() { + DngoTheme { + SharedRecordItem() + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt index 763d5ff..2e1e93e 100644 --- a/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt @@ -4,9 +4,15 @@ import androidx.compose.ui.graphics.vector.ImageVector import com.min.dnapp.presentation.ui.icon.appicons.Back import com.min.dnapp.presentation.ui.icon.appicons.Bell import com.min.dnapp.presentation.ui.icon.appicons.Calendar +import com.min.dnapp.presentation.ui.icon.appicons.Delete import com.min.dnapp.presentation.ui.icon.appicons.Gallery import com.min.dnapp.presentation.ui.icon.appicons.Kakao import com.min.dnapp.presentation.ui.icon.appicons.PenSmall +import com.min.dnapp.presentation.ui.icon.appicons.RecordBest +import com.min.dnapp.presentation.ui.icon.appicons.RecordBookmark +import com.min.dnapp.presentation.ui.icon.appicons.RecordComment +import com.min.dnapp.presentation.ui.icon.appicons.RecordLike +import com.min.dnapp.presentation.ui.icon.appicons.RecordSurprise import kotlin.collections.List as ____KtList public object AppIcons @@ -18,6 +24,7 @@ public val AppIcons.AllIcons: ____KtList if (__AllIcons != null) { return __AllIcons!! } - __AllIcons= listOf(Back, Bell, Calendar, Gallery, Kakao, PenSmall) + __AllIcons= listOf(Back, Bell, Calendar, Delete, Gallery, Kakao, PenSmall, RecordBest, + RecordBookmark, RecordComment, RecordLike, RecordSurprise) return __AllIcons!! } diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Delete.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Delete.kt new file mode 100644 index 0000000..1835935 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Delete.kt @@ -0,0 +1,92 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.EvenOdd +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.Delete: ImageVector + get() { + if (_delete != null) { + return _delete!! + } + _delete = Builder(name = "Delete", defaultWidth = 18.0.dp, defaultHeight = 18.0.dp, + viewportWidth = 18.0f, viewportHeight = 18.0f).apply { + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = EvenOdd) { + moveTo(9.0f, 0.0f) + curveTo(13.971f, 0.0f, 18.0f, 4.029f, 18.0f, 9.0f) + curveTo(18.0f, 13.971f, 13.971f, 18.0f, 9.0f, 18.0f) + curveTo(4.029f, 18.0f, 0.0f, 13.971f, 0.0f, 9.0f) + curveTo(0.0f, 4.029f, 4.029f, 0.0f, 9.0f, 0.0f) + close() + moveTo(9.0f, 8.293f) + lineTo(6.0f, 5.293f) + lineTo(5.293f, 6.0f) + lineTo(8.293f, 9.0f) + lineTo(5.293f, 12.0f) + lineTo(6.0f, 12.707f) + lineTo(9.0f, 9.707f) + lineTo(12.0f, 12.707f) + lineTo(12.707f, 12.0f) + lineTo(9.707f, 9.0f) + lineTo(12.707f, 6.0f) + lineTo(12.0f, 5.293f) + lineTo(9.0f, 8.293f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = EvenOdd) { + moveTo(9.0f, 0.0f) + curveTo(13.971f, 0.0f, 18.0f, 4.029f, 18.0f, 9.0f) + curveTo(18.0f, 13.971f, 13.971f, 18.0f, 9.0f, 18.0f) + curveTo(4.029f, 18.0f, 0.0f, 13.971f, 0.0f, 9.0f) + curveTo(0.0f, 4.029f, 4.029f, 0.0f, 9.0f, 0.0f) + close() + moveTo(9.0f, 8.293f) + lineTo(6.0f, 5.293f) + lineTo(5.293f, 6.0f) + lineTo(8.293f, 9.0f) + lineTo(5.293f, 12.0f) + lineTo(6.0f, 12.707f) + lineTo(9.0f, 9.707f) + lineTo(12.0f, 12.707f) + lineTo(12.707f, 12.0f) + lineTo(9.707f, 9.0f) + lineTo(12.707f, 6.0f) + lineTo(12.0f, 5.293f) + lineTo(9.0f, 8.293f) + close() + } + } + .build() + return _delete!! + } + +private var _delete: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.Delete, contentDescription = "") + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordBest.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordBest.kt new file mode 100644 index 0000000..5cf69f7 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordBest.kt @@ -0,0 +1,184 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.RecordBest: ImageVector + get() { + if (_recordBest != null) { + return _recordBest!! + } + _recordBest = Builder(name = "RecordBest", defaultWidth = 20.0.dp, defaultHeight = 20.0.dp, + viewportWidth = 20.0f, viewportHeight = 20.0f).apply { + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(13.661f, 17.5f) + horizontalLineTo(4.128f) + curveTo(3.702f, 17.499f, 3.293f, 17.33f, 2.992f, 17.029f) + curveTo(2.69f, 16.728f, 2.521f, 16.319f, 2.52f, 15.893f) + verticalLineTo(10.536f) + curveTo(2.52f, 9.65f, 3.241f, 8.929f, 4.127f, 8.929f) + horizontalLineTo(6.0f) + curveTo(6.959f, 7.607f, 7.728f, 6.157f, 8.283f, 4.621f) + lineTo(8.78f, 3.242f) + curveTo(8.9f, 2.819f, 9.324f, 2.5f, 9.799f, 2.5f) + lineTo(9.935f, 2.504f) + curveTo(10.605f, 2.541f, 11.227f, 2.856f, 11.656f, 3.379f) + curveTo(11.853f, 3.619f, 12.001f, 3.894f, 12.093f, 4.19f) + lineTo(12.129f, 4.319f) + curveTo(12.215f, 4.663f, 12.223f, 5.022f, 12.153f, 5.37f) + lineTo(11.656f, 7.856f) + horizontalLineTo(15.336f) + lineTo(15.465f, 7.861f) + curveTo(16.101f, 7.898f, 16.68f, 8.209f, 17.061f, 8.73f) + curveTo(17.237f, 8.966f, 17.361f, 9.236f, 17.427f, 9.521f) + lineTo(17.451f, 9.645f) + curveTo(17.507f, 9.977f, 17.483f, 10.317f, 17.381f, 10.638f) + lineTo(15.708f, 15.995f) + curveTo(15.443f, 16.839f, 14.705f, 17.423f, 13.837f, 17.493f) + lineTo(13.661f, 17.5f) + close() + moveTo(13.664f, 16.428f) + curveTo(13.892f, 16.428f, 14.115f, 16.355f, 14.298f, 16.22f) + lineTo(14.365f, 16.166f) + curveTo(14.515f, 16.036f, 14.626f, 15.867f, 14.686f, 15.676f) + lineTo(16.36f, 10.319f) + curveTo(16.41f, 10.159f, 16.421f, 9.988f, 16.394f, 9.823f) + curveTo(16.366f, 9.657f, 16.3f, 9.5f, 16.201f, 9.364f) + curveTo(16.102f, 9.228f, 15.972f, 9.117f, 15.822f, 9.041f) + curveTo(15.672f, 8.965f, 15.506f, 8.926f, 15.337f, 8.927f) + horizontalLineTo(11.003f) + lineTo(10.944f, 8.923f) + curveTo(10.885f, 8.917f, 10.827f, 8.901f, 10.774f, 8.875f) + curveTo(10.702f, 8.841f, 10.638f, 8.793f, 10.588f, 8.731f) + curveTo(10.538f, 8.67f, 10.502f, 8.598f, 10.482f, 8.521f) + curveTo(10.463f, 8.444f, 10.461f, 8.364f, 10.477f, 8.286f) + lineTo(11.102f, 5.16f) + lineTo(11.124f, 5.014f) + curveTo(11.137f, 4.868f, 11.126f, 4.72f, 11.09f, 4.577f) + curveTo(11.043f, 4.386f, 10.953f, 4.207f, 10.828f, 4.055f) + curveTo(10.703f, 3.903f, 10.546f, 3.781f, 10.368f, 3.697f) + curveTo(10.19f, 3.613f, 9.996f, 3.57f, 9.799f, 3.57f) + lineTo(9.292f, 4.983f) + horizontalLineTo(9.296f) + curveTo(8.695f, 6.646f, 7.858f, 8.215f, 6.81f, 9.639f) + verticalLineTo(16.428f) + horizontalLineTo(13.664f) + close() + moveTo(5.735f, 16.428f) + verticalLineTo(9.999f) + horizontalLineTo(4.128f) + lineTo(4.023f, 10.01f) + curveTo(3.954f, 10.024f, 3.889f, 10.051f, 3.831f, 10.09f) + lineTo(3.75f, 10.156f) + curveTo(3.649f, 10.257f, 3.592f, 10.393f, 3.592f, 10.535f) + verticalLineTo(15.893f) + curveTo(3.592f, 16.035f, 3.649f, 16.171f, 3.75f, 16.272f) + curveTo(3.825f, 16.347f, 3.92f, 16.398f, 4.023f, 16.419f) + lineTo(4.128f, 16.428f) + horizontalLineTo(5.735f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(13.661f, 17.5f) + horizontalLineTo(4.128f) + curveTo(3.702f, 17.499f, 3.293f, 17.33f, 2.992f, 17.029f) + curveTo(2.69f, 16.728f, 2.521f, 16.319f, 2.52f, 15.893f) + verticalLineTo(10.536f) + curveTo(2.52f, 9.65f, 3.241f, 8.929f, 4.127f, 8.929f) + horizontalLineTo(6.0f) + curveTo(6.959f, 7.607f, 7.728f, 6.157f, 8.283f, 4.621f) + lineTo(8.78f, 3.242f) + curveTo(8.9f, 2.819f, 9.324f, 2.5f, 9.799f, 2.5f) + lineTo(9.935f, 2.504f) + curveTo(10.605f, 2.541f, 11.227f, 2.856f, 11.656f, 3.379f) + curveTo(11.853f, 3.619f, 12.001f, 3.894f, 12.093f, 4.19f) + lineTo(12.129f, 4.319f) + curveTo(12.215f, 4.663f, 12.223f, 5.022f, 12.153f, 5.37f) + lineTo(11.656f, 7.856f) + horizontalLineTo(15.336f) + lineTo(15.465f, 7.861f) + curveTo(16.101f, 7.898f, 16.68f, 8.209f, 17.061f, 8.73f) + curveTo(17.237f, 8.966f, 17.361f, 9.236f, 17.427f, 9.521f) + lineTo(17.451f, 9.645f) + curveTo(17.507f, 9.977f, 17.483f, 10.317f, 17.381f, 10.638f) + lineTo(15.708f, 15.995f) + curveTo(15.443f, 16.839f, 14.705f, 17.423f, 13.837f, 17.493f) + lineTo(13.661f, 17.5f) + close() + moveTo(13.664f, 16.428f) + curveTo(13.892f, 16.428f, 14.115f, 16.355f, 14.298f, 16.22f) + lineTo(14.365f, 16.166f) + curveTo(14.515f, 16.036f, 14.626f, 15.867f, 14.686f, 15.676f) + lineTo(16.36f, 10.319f) + curveTo(16.41f, 10.159f, 16.421f, 9.988f, 16.394f, 9.823f) + curveTo(16.366f, 9.657f, 16.3f, 9.5f, 16.201f, 9.364f) + curveTo(16.102f, 9.228f, 15.972f, 9.117f, 15.822f, 9.041f) + curveTo(15.672f, 8.965f, 15.506f, 8.926f, 15.337f, 8.927f) + horizontalLineTo(11.003f) + lineTo(10.944f, 8.923f) + curveTo(10.885f, 8.917f, 10.827f, 8.901f, 10.774f, 8.875f) + curveTo(10.702f, 8.841f, 10.638f, 8.793f, 10.588f, 8.731f) + curveTo(10.538f, 8.67f, 10.502f, 8.598f, 10.482f, 8.521f) + curveTo(10.463f, 8.444f, 10.461f, 8.364f, 10.477f, 8.286f) + lineTo(11.102f, 5.16f) + lineTo(11.124f, 5.014f) + curveTo(11.137f, 4.868f, 11.126f, 4.72f, 11.09f, 4.577f) + curveTo(11.043f, 4.386f, 10.953f, 4.207f, 10.828f, 4.055f) + curveTo(10.703f, 3.903f, 10.546f, 3.781f, 10.368f, 3.697f) + curveTo(10.19f, 3.613f, 9.996f, 3.57f, 9.799f, 3.57f) + lineTo(9.292f, 4.983f) + horizontalLineTo(9.296f) + curveTo(8.695f, 6.646f, 7.858f, 8.215f, 6.81f, 9.639f) + verticalLineTo(16.428f) + horizontalLineTo(13.664f) + close() + moveTo(5.735f, 16.428f) + verticalLineTo(9.999f) + horizontalLineTo(4.128f) + lineTo(4.023f, 10.01f) + curveTo(3.954f, 10.024f, 3.889f, 10.051f, 3.831f, 10.09f) + lineTo(3.75f, 10.156f) + curveTo(3.649f, 10.257f, 3.592f, 10.393f, 3.592f, 10.535f) + verticalLineTo(15.893f) + curveTo(3.592f, 16.035f, 3.649f, 16.171f, 3.75f, 16.272f) + curveTo(3.825f, 16.347f, 3.92f, 16.398f, 4.023f, 16.419f) + lineTo(4.128f, 16.428f) + horizontalLineTo(5.735f) + close() + } + } + .build() + return _recordBest!! + } + +private var _recordBest: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.RecordBest, contentDescription = "") + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordBookmark.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordBookmark.kt new file mode 100644 index 0000000..aafb923 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordBookmark.kt @@ -0,0 +1,178 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.RecordBookmark: ImageVector + get() { + if (_recordBookmark != null) { + return _recordBookmark!! + } + _recordBookmark = Builder(name = "RecordBookmark", defaultWidth = 20.0.dp, defaultHeight = + 20.0.dp, viewportWidth = 20.0f, viewportHeight = 20.0f).apply { + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(10.0f, 13.395f) + curveTo(10.391f, 13.395f, 10.733f, 13.532f, 11.086f, 13.748f) + curveTo(11.43f, 13.958f, 11.822f, 14.267f, 12.306f, 14.649f) + lineTo(12.866f, 15.092f) + lineTo(13.484f, 15.578f) + curveTo(14.057f, 16.025f, 14.503f, 16.356f, 14.872f, 16.569f) + curveTo(15.369f, 16.855f, 15.598f, 16.851f, 15.755f, 16.775f) + lineTo(15.812f, 16.741f) + curveTo(15.945f, 16.648f, 16.065f, 16.449f, 16.138f, 15.951f) + curveTo(16.22f, 15.387f, 16.221f, 14.586f, 16.221f, 13.454f) + verticalLineTo(7.764f) + curveTo(16.221f, 6.574f, 16.22f, 5.722f, 16.134f, 5.076f) + curveTo(16.059f, 4.521f, 15.927f, 4.164f, 15.712f, 3.899f) + lineTo(15.614f, 3.791f) + curveTo(15.34f, 3.515f, 14.966f, 3.354f, 14.335f, 3.268f) + curveTo(13.691f, 3.181f, 12.844f, 3.181f, 11.659f, 3.181f) + horizontalLineTo(8.341f) + curveTo(7.156f, 3.181f, 6.309f, 3.181f, 5.665f, 3.268f) + curveTo(5.113f, 3.343f, 4.758f, 3.476f, 4.494f, 3.692f) + lineTo(4.386f, 3.791f) + curveTo(4.112f, 4.066f, 3.951f, 4.441f, 3.866f, 5.076f) + curveTo(3.78f, 5.722f, 3.779f, 6.574f, 3.779f, 7.764f) + verticalLineTo(13.454f) + curveTo(3.779f, 14.585f, 3.78f, 15.387f, 3.862f, 15.951f) + curveTo(3.945f, 16.521f, 4.09f, 16.699f, 4.245f, 16.775f) + curveTo(4.401f, 16.851f, 4.631f, 16.855f, 5.127f, 16.569f) + curveTo(5.619f, 16.285f, 6.248f, 15.791f, 7.134f, 15.091f) + lineTo(7.694f, 14.649f) + curveTo(8.178f, 14.267f, 8.57f, 13.958f, 8.914f, 13.748f) + curveTo(9.267f, 13.532f, 9.609f, 13.395f, 10.0f, 13.395f) + close() + moveTo(17.051f, 13.454f) + curveTo(17.051f, 14.558f, 17.052f, 15.433f, 16.959f, 16.072f) + curveTo(16.867f, 16.706f, 16.662f, 17.258f, 16.118f, 17.525f) + horizontalLineTo(16.117f) + curveTo(15.572f, 17.79f, 15.014f, 17.611f, 14.46f, 17.292f) + curveTo(14.042f, 17.051f, 13.552f, 16.686f, 12.969f, 16.231f) + lineTo(12.353f, 15.747f) + lineTo(11.793f, 15.304f) + curveTo(11.294f, 14.91f, 10.947f, 14.638f, 10.655f, 14.46f) + curveTo(10.373f, 14.287f, 10.182f, 14.229f, 10.0f, 14.229f) + curveTo(9.818f, 14.229f, 9.627f, 14.287f, 9.345f, 14.46f) + curveTo(9.053f, 14.638f, 8.706f, 14.91f, 8.206f, 15.304f) + verticalLineTo(15.305f) + lineTo(7.646f, 15.746f) + curveTo(6.782f, 16.428f, 6.097f, 16.97f, 5.54f, 17.292f) + curveTo(4.986f, 17.611f, 4.428f, 17.79f, 3.883f, 17.525f) + curveTo(3.339f, 17.259f, 3.133f, 16.706f, 3.041f, 16.072f) + curveTo(2.948f, 15.433f, 2.949f, 14.557f, 2.949f, 13.454f) + verticalLineTo(7.764f) + curveTo(2.949f, 6.597f, 2.948f, 5.68f, 3.044f, 4.965f) + curveTo(3.141f, 4.238f, 3.345f, 3.658f, 3.8f, 3.202f) + lineTo(3.976f, 3.042f) + curveTo(4.4f, 2.696f, 4.922f, 2.528f, 5.555f, 2.442f) + curveTo(6.267f, 2.346f, 7.18f, 2.347f, 8.341f, 2.347f) + horizontalLineTo(11.659f) + curveTo(12.82f, 2.347f, 13.733f, 2.346f, 14.445f, 2.442f) + curveTo(15.168f, 2.54f, 15.746f, 2.745f, 16.2f, 3.202f) + lineTo(16.359f, 3.378f) + curveTo(16.704f, 3.805f, 16.871f, 4.329f, 16.956f, 4.965f) + curveTo(17.052f, 5.68f, 17.051f, 6.597f, 17.051f, 7.764f) + verticalLineTo(13.454f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(10.0f, 13.395f) + curveTo(10.391f, 13.395f, 10.733f, 13.532f, 11.086f, 13.748f) + curveTo(11.43f, 13.958f, 11.822f, 14.267f, 12.306f, 14.649f) + lineTo(12.866f, 15.092f) + lineTo(13.484f, 15.578f) + curveTo(14.057f, 16.025f, 14.503f, 16.356f, 14.872f, 16.569f) + curveTo(15.369f, 16.855f, 15.598f, 16.851f, 15.755f, 16.775f) + lineTo(15.812f, 16.741f) + curveTo(15.945f, 16.648f, 16.065f, 16.449f, 16.138f, 15.951f) + curveTo(16.22f, 15.387f, 16.221f, 14.586f, 16.221f, 13.454f) + verticalLineTo(7.764f) + curveTo(16.221f, 6.574f, 16.22f, 5.722f, 16.134f, 5.076f) + curveTo(16.059f, 4.521f, 15.927f, 4.164f, 15.712f, 3.899f) + lineTo(15.614f, 3.791f) + curveTo(15.34f, 3.515f, 14.966f, 3.354f, 14.335f, 3.268f) + curveTo(13.691f, 3.181f, 12.844f, 3.181f, 11.659f, 3.181f) + horizontalLineTo(8.341f) + curveTo(7.156f, 3.181f, 6.309f, 3.181f, 5.665f, 3.268f) + curveTo(5.113f, 3.343f, 4.758f, 3.476f, 4.494f, 3.692f) + lineTo(4.386f, 3.791f) + curveTo(4.112f, 4.066f, 3.951f, 4.441f, 3.866f, 5.076f) + curveTo(3.78f, 5.722f, 3.779f, 6.574f, 3.779f, 7.764f) + verticalLineTo(13.454f) + curveTo(3.779f, 14.585f, 3.78f, 15.387f, 3.862f, 15.951f) + curveTo(3.945f, 16.521f, 4.09f, 16.699f, 4.245f, 16.775f) + curveTo(4.401f, 16.851f, 4.631f, 16.855f, 5.127f, 16.569f) + curveTo(5.619f, 16.285f, 6.248f, 15.791f, 7.134f, 15.091f) + lineTo(7.694f, 14.649f) + curveTo(8.178f, 14.267f, 8.57f, 13.958f, 8.914f, 13.748f) + curveTo(9.267f, 13.532f, 9.609f, 13.395f, 10.0f, 13.395f) + close() + moveTo(17.051f, 13.454f) + curveTo(17.051f, 14.558f, 17.052f, 15.433f, 16.959f, 16.072f) + curveTo(16.867f, 16.706f, 16.662f, 17.258f, 16.118f, 17.525f) + horizontalLineTo(16.117f) + curveTo(15.572f, 17.79f, 15.014f, 17.611f, 14.46f, 17.292f) + curveTo(14.042f, 17.051f, 13.552f, 16.686f, 12.969f, 16.231f) + lineTo(12.353f, 15.747f) + lineTo(11.793f, 15.304f) + curveTo(11.294f, 14.91f, 10.947f, 14.638f, 10.655f, 14.46f) + curveTo(10.373f, 14.287f, 10.182f, 14.229f, 10.0f, 14.229f) + curveTo(9.818f, 14.229f, 9.627f, 14.287f, 9.345f, 14.46f) + curveTo(9.053f, 14.638f, 8.706f, 14.91f, 8.206f, 15.304f) + verticalLineTo(15.305f) + lineTo(7.646f, 15.746f) + curveTo(6.782f, 16.428f, 6.097f, 16.97f, 5.54f, 17.292f) + curveTo(4.986f, 17.611f, 4.428f, 17.79f, 3.883f, 17.525f) + curveTo(3.339f, 17.259f, 3.133f, 16.706f, 3.041f, 16.072f) + curveTo(2.948f, 15.433f, 2.949f, 14.557f, 2.949f, 13.454f) + verticalLineTo(7.764f) + curveTo(2.949f, 6.597f, 2.948f, 5.68f, 3.044f, 4.965f) + curveTo(3.141f, 4.238f, 3.345f, 3.658f, 3.8f, 3.202f) + lineTo(3.976f, 3.042f) + curveTo(4.4f, 2.696f, 4.922f, 2.528f, 5.555f, 2.442f) + curveTo(6.267f, 2.346f, 7.18f, 2.347f, 8.341f, 2.347f) + horizontalLineTo(11.659f) + curveTo(12.82f, 2.347f, 13.733f, 2.346f, 14.445f, 2.442f) + curveTo(15.168f, 2.54f, 15.746f, 2.745f, 16.2f, 3.202f) + lineTo(16.359f, 3.378f) + curveTo(16.704f, 3.805f, 16.871f, 4.329f, 16.956f, 4.965f) + curveTo(17.052f, 5.68f, 17.051f, 6.597f, 17.051f, 7.764f) + verticalLineTo(13.454f) + close() + } + } + .build() + return _recordBookmark!! + } + +private var _recordBookmark: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.RecordBookmark, contentDescription = "") + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordComment.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordComment.kt new file mode 100644 index 0000000..bbf3388 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordComment.kt @@ -0,0 +1,210 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.RecordComment: ImageVector + get() { + if (_recordComment != null) { + return _recordComment!! + } + _recordComment = Builder(name = "RecordComment", defaultWidth = 20.0.dp, defaultHeight = + 20.0.dp, viewportWidth = 20.0f, viewportHeight = 20.0f).apply { + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(16.25f, 9.23f) + curveTo(16.25f, 8.051f, 16.249f, 7.198f, 16.182f, 6.534f) + curveTo(16.115f, 5.877f, 15.986f, 5.45f, 15.759f, 5.11f) + curveTo(15.546f, 4.791f, 15.272f, 4.518f, 14.954f, 4.305f) + curveTo(14.613f, 4.077f, 14.187f, 3.949f, 13.53f, 3.882f) + curveTo(12.865f, 3.814f, 12.012f, 3.813f, 10.833f, 3.813f) + horizontalLineTo(9.167f) + curveTo(7.987f, 3.813f, 7.135f, 3.814f, 6.471f, 3.882f) + curveTo(5.814f, 3.949f, 5.387f, 4.077f, 5.046f, 4.305f) + curveTo(4.728f, 4.518f, 4.454f, 4.791f, 4.242f, 5.11f) + curveTo(4.014f, 5.45f, 3.885f, 5.877f, 3.818f, 6.534f) + curveTo(3.751f, 7.198f, 3.75f, 8.051f, 3.75f, 9.23f) + curveTo(3.75f, 10.409f, 3.751f, 11.262f, 3.818f, 11.926f) + curveTo(3.885f, 12.583f, 4.014f, 13.01f, 4.242f, 13.35f) + curveTo(4.454f, 13.669f, 4.728f, 13.942f, 5.046f, 14.155f) + curveTo(5.344f, 14.354f, 5.708f, 14.478f, 6.233f, 14.551f) + curveTo(6.765f, 14.624f, 7.434f, 14.642f, 8.335f, 14.647f) + curveTo(8.492f, 14.647f, 8.636f, 14.736f, 8.706f, 14.877f) + lineTo(9.627f, 16.719f) + lineTo(9.657f, 16.769f) + curveTo(9.689f, 16.816f, 9.732f, 16.857f, 9.781f, 16.887f) + curveTo(9.847f, 16.928f, 9.923f, 16.949f, 10.0f, 16.949f) + curveTo(10.077f, 16.949f, 10.153f, 16.928f, 10.219f, 16.887f) + curveTo(10.285f, 16.847f, 10.338f, 16.788f, 10.373f, 16.719f) + lineTo(11.294f, 14.876f) + curveTo(11.364f, 14.736f, 11.508f, 14.647f, 11.665f, 14.646f) + curveTo(12.566f, 14.642f, 13.236f, 14.624f, 13.768f, 14.551f) + curveTo(14.293f, 14.478f, 14.656f, 14.354f, 14.954f, 14.155f) + lineTo(15.071f, 14.073f) + curveTo(15.34f, 13.874f, 15.572f, 13.629f, 15.759f, 13.35f) + curveTo(15.986f, 13.01f, 16.115f, 12.583f, 16.182f, 11.926f) + curveTo(16.249f, 11.262f, 16.25f, 10.409f, 16.25f, 9.23f) + close() + moveTo(10.0f, 10.48f) + curveTo(10.23f, 10.48f, 10.417f, 10.667f, 10.417f, 10.897f) + curveTo(10.417f, 11.127f, 10.23f, 11.313f, 10.0f, 11.313f) + horizontalLineTo(7.5f) + curveTo(7.27f, 11.313f, 7.083f, 11.127f, 7.083f, 10.897f) + curveTo(7.083f, 10.667f, 7.27f, 10.48f, 7.5f, 10.48f) + horizontalLineTo(10.0f) + close() + moveTo(12.5f, 7.147f) + curveTo(12.73f, 7.147f, 12.917f, 7.333f, 12.917f, 7.563f) + curveTo(12.917f, 7.793f, 12.73f, 7.98f, 12.5f, 7.98f) + horizontalLineTo(7.5f) + curveTo(7.27f, 7.98f, 7.083f, 7.793f, 7.083f, 7.563f) + curveTo(7.083f, 7.333f, 7.27f, 7.147f, 7.5f, 7.147f) + horizontalLineTo(12.5f) + close() + moveTo(17.083f, 9.23f) + curveTo(17.083f, 10.392f, 17.084f, 11.295f, 17.011f, 12.011f) + curveTo(16.937f, 12.734f, 16.786f, 13.313f, 16.452f, 13.813f) + curveTo(16.178f, 14.223f, 15.826f, 14.575f, 15.417f, 14.849f) + lineTo(15.416f, 14.848f) + curveTo(14.979f, 15.14f, 14.483f, 15.293f, 13.882f, 15.376f) + curveTo(13.346f, 15.45f, 12.705f, 15.469f, 11.925f, 15.476f) + lineTo(11.117f, 17.092f) + curveTo(11.014f, 17.299f, 10.854f, 17.474f, 10.657f, 17.596f) + curveTo(10.46f, 17.718f, 10.232f, 17.782f, 10.0f, 17.782f) + curveTo(9.768f, 17.782f, 9.541f, 17.718f, 9.343f, 17.596f) + curveTo(9.146f, 17.474f, 8.987f, 17.299f, 8.883f, 17.092f) + lineTo(8.075f, 15.477f) + curveTo(7.295f, 15.47f, 6.655f, 15.45f, 6.118f, 15.376f) + curveTo(5.517f, 15.292f, 5.02f, 15.14f, 4.583f, 14.849f) + curveTo(4.174f, 14.575f, 3.822f, 14.223f, 3.548f, 13.813f) + curveTo(3.214f, 13.313f, 3.063f, 12.734f, 2.989f, 12.011f) + curveTo(2.916f, 11.295f, 2.917f, 10.392f, 2.917f, 9.23f) + curveTo(2.917f, 8.068f, 2.916f, 7.165f, 2.989f, 6.449f) + curveTo(3.063f, 5.726f, 3.214f, 5.147f, 3.548f, 4.647f) + curveTo(3.822f, 4.237f, 4.174f, 3.885f, 4.583f, 3.611f) + curveTo(5.084f, 3.277f, 5.663f, 3.126f, 6.386f, 3.052f) + curveTo(7.102f, 2.98f, 8.005f, 2.98f, 9.167f, 2.98f) + horizontalLineTo(10.833f) + curveTo(11.995f, 2.98f, 12.898f, 2.98f, 13.614f, 3.052f) + curveTo(14.337f, 3.126f, 14.917f, 3.277f, 15.417f, 3.611f) + curveTo(15.826f, 3.885f, 16.178f, 4.237f, 16.452f, 4.647f) + curveTo(16.786f, 5.147f, 16.937f, 5.726f, 17.011f, 6.449f) + curveTo(17.084f, 7.165f, 17.083f, 8.068f, 17.083f, 9.23f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(16.25f, 9.23f) + curveTo(16.25f, 8.051f, 16.249f, 7.198f, 16.182f, 6.534f) + curveTo(16.115f, 5.877f, 15.986f, 5.45f, 15.759f, 5.11f) + curveTo(15.546f, 4.791f, 15.272f, 4.518f, 14.954f, 4.305f) + curveTo(14.613f, 4.077f, 14.187f, 3.949f, 13.53f, 3.882f) + curveTo(12.865f, 3.814f, 12.012f, 3.813f, 10.833f, 3.813f) + horizontalLineTo(9.167f) + curveTo(7.987f, 3.813f, 7.135f, 3.814f, 6.471f, 3.882f) + curveTo(5.814f, 3.949f, 5.387f, 4.077f, 5.046f, 4.305f) + curveTo(4.728f, 4.518f, 4.454f, 4.791f, 4.242f, 5.11f) + curveTo(4.014f, 5.45f, 3.885f, 5.877f, 3.818f, 6.534f) + curveTo(3.751f, 7.198f, 3.75f, 8.051f, 3.75f, 9.23f) + curveTo(3.75f, 10.409f, 3.751f, 11.262f, 3.818f, 11.926f) + curveTo(3.885f, 12.583f, 4.014f, 13.01f, 4.242f, 13.35f) + curveTo(4.454f, 13.669f, 4.728f, 13.942f, 5.046f, 14.155f) + curveTo(5.344f, 14.354f, 5.708f, 14.478f, 6.233f, 14.551f) + curveTo(6.765f, 14.624f, 7.434f, 14.642f, 8.335f, 14.647f) + curveTo(8.492f, 14.647f, 8.636f, 14.736f, 8.706f, 14.877f) + lineTo(9.627f, 16.719f) + lineTo(9.657f, 16.769f) + curveTo(9.689f, 16.816f, 9.732f, 16.857f, 9.781f, 16.887f) + curveTo(9.847f, 16.928f, 9.923f, 16.949f, 10.0f, 16.949f) + curveTo(10.077f, 16.949f, 10.153f, 16.928f, 10.219f, 16.887f) + curveTo(10.285f, 16.847f, 10.338f, 16.788f, 10.373f, 16.719f) + lineTo(11.294f, 14.876f) + curveTo(11.364f, 14.736f, 11.508f, 14.647f, 11.665f, 14.646f) + curveTo(12.566f, 14.642f, 13.236f, 14.624f, 13.768f, 14.551f) + curveTo(14.293f, 14.478f, 14.656f, 14.354f, 14.954f, 14.155f) + lineTo(15.071f, 14.073f) + curveTo(15.34f, 13.874f, 15.572f, 13.629f, 15.759f, 13.35f) + curveTo(15.986f, 13.01f, 16.115f, 12.583f, 16.182f, 11.926f) + curveTo(16.249f, 11.262f, 16.25f, 10.409f, 16.25f, 9.23f) + close() + moveTo(10.0f, 10.48f) + curveTo(10.23f, 10.48f, 10.417f, 10.667f, 10.417f, 10.897f) + curveTo(10.417f, 11.127f, 10.23f, 11.313f, 10.0f, 11.313f) + horizontalLineTo(7.5f) + curveTo(7.27f, 11.313f, 7.083f, 11.127f, 7.083f, 10.897f) + curveTo(7.083f, 10.667f, 7.27f, 10.48f, 7.5f, 10.48f) + horizontalLineTo(10.0f) + close() + moveTo(12.5f, 7.147f) + curveTo(12.73f, 7.147f, 12.917f, 7.333f, 12.917f, 7.563f) + curveTo(12.917f, 7.793f, 12.73f, 7.98f, 12.5f, 7.98f) + horizontalLineTo(7.5f) + curveTo(7.27f, 7.98f, 7.083f, 7.793f, 7.083f, 7.563f) + curveTo(7.083f, 7.333f, 7.27f, 7.147f, 7.5f, 7.147f) + horizontalLineTo(12.5f) + close() + moveTo(17.083f, 9.23f) + curveTo(17.083f, 10.392f, 17.084f, 11.295f, 17.011f, 12.011f) + curveTo(16.937f, 12.734f, 16.786f, 13.313f, 16.452f, 13.813f) + curveTo(16.178f, 14.223f, 15.826f, 14.575f, 15.417f, 14.849f) + lineTo(15.416f, 14.848f) + curveTo(14.979f, 15.14f, 14.483f, 15.293f, 13.882f, 15.376f) + curveTo(13.346f, 15.45f, 12.705f, 15.469f, 11.925f, 15.476f) + lineTo(11.117f, 17.092f) + curveTo(11.014f, 17.299f, 10.854f, 17.474f, 10.657f, 17.596f) + curveTo(10.46f, 17.718f, 10.232f, 17.782f, 10.0f, 17.782f) + curveTo(9.768f, 17.782f, 9.541f, 17.718f, 9.343f, 17.596f) + curveTo(9.146f, 17.474f, 8.987f, 17.299f, 8.883f, 17.092f) + lineTo(8.075f, 15.477f) + curveTo(7.295f, 15.47f, 6.655f, 15.45f, 6.118f, 15.376f) + curveTo(5.517f, 15.292f, 5.02f, 15.14f, 4.583f, 14.849f) + curveTo(4.174f, 14.575f, 3.822f, 14.223f, 3.548f, 13.813f) + curveTo(3.214f, 13.313f, 3.063f, 12.734f, 2.989f, 12.011f) + curveTo(2.916f, 11.295f, 2.917f, 10.392f, 2.917f, 9.23f) + curveTo(2.917f, 8.068f, 2.916f, 7.165f, 2.989f, 6.449f) + curveTo(3.063f, 5.726f, 3.214f, 5.147f, 3.548f, 4.647f) + curveTo(3.822f, 4.237f, 4.174f, 3.885f, 4.583f, 3.611f) + curveTo(5.084f, 3.277f, 5.663f, 3.126f, 6.386f, 3.052f) + curveTo(7.102f, 2.98f, 8.005f, 2.98f, 9.167f, 2.98f) + horizontalLineTo(10.833f) + curveTo(11.995f, 2.98f, 12.898f, 2.98f, 13.614f, 3.052f) + curveTo(14.337f, 3.126f, 14.917f, 3.277f, 15.417f, 3.611f) + curveTo(15.826f, 3.885f, 16.178f, 4.237f, 16.452f, 4.647f) + curveTo(16.786f, 5.147f, 16.937f, 5.726f, 17.011f, 6.449f) + curveTo(17.084f, 7.165f, 17.083f, 8.068f, 17.083f, 9.23f) + close() + } + } + .build() + return _recordComment!! + } + +private var _recordComment: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.RecordComment, contentDescription = "") + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordLike.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordLike.kt new file mode 100644 index 0000000..46408e5 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordLike.kt @@ -0,0 +1,148 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.RecordLike: ImageVector + get() { + if (_recordLike != null) { + return _recordLike!! + } + _recordLike = Builder(name = "RecordLike", defaultWidth = 20.0.dp, defaultHeight = 20.0.dp, + viewportWidth = 20.0f, viewportHeight = 20.0f).apply { + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(3.127f, 4.487f) + curveTo(4.971f, 2.128f, 8.674f, 2.524f, 9.97f, 5.219f) + curveTo(9.973f, 5.225f, 9.976f, 5.23f, 9.981f, 5.233f) + curveTo(9.987f, 5.236f, 9.993f, 5.238f, 9.999f, 5.238f) + curveTo(10.006f, 5.238f, 10.012f, 5.236f, 10.017f, 5.233f) + curveTo(10.023f, 5.23f, 10.027f, 5.225f, 10.03f, 5.219f) + lineTo(10.158f, 4.973f) + curveTo(11.555f, 2.502f, 15.086f, 2.203f, 16.873f, 4.487f) + lineTo(17.133f, 4.819f) + curveTo(17.864f, 5.754f, 18.217f, 6.927f, 18.123f, 8.106f) + curveTo(18.03f, 9.286f, 17.497f, 10.388f, 16.627f, 11.198f) + lineTo(10.788f, 16.64f) + curveTo(10.693f, 16.728f, 10.601f, 16.816f, 10.516f, 16.881f) + curveTo(10.425f, 16.951f, 10.31f, 17.021f, 10.162f, 17.05f) + curveTo(10.055f, 17.071f, 9.944f, 17.071f, 9.837f, 17.05f) + horizontalLineTo(9.835f) + curveTo(9.687f, 17.021f, 9.572f, 16.949f, 9.483f, 16.88f) + curveTo(9.398f, 16.815f, 9.306f, 16.728f, 9.211f, 16.64f) + lineTo(2.598f, 10.477f) + horizontalLineTo(2.741f) + curveTo(2.247f, 9.783f, 1.944f, 8.965f, 1.876f, 8.106f) + curveTo(1.783f, 6.927f, 2.136f, 5.756f, 2.866f, 4.821f) + lineTo(3.127f, 4.487f) + close() + moveTo(9.211f, 5.578f) + curveTo(8.216f, 3.51f, 5.433f, 3.151f, 3.931f, 4.829f) + lineTo(3.79f, 4.998f) + lineTo(3.53f, 5.331f) + curveTo(2.928f, 6.102f, 2.637f, 7.068f, 2.714f, 8.04f) + curveTo(2.791f, 9.013f, 3.231f, 9.922f, 3.947f, 10.59f) + lineTo(4.72f, 11.31f) + lineTo(9.784f, 16.032f) + curveTo(9.891f, 16.132f, 9.951f, 16.186f, 9.996f, 16.221f) + curveTo(9.997f, 16.222f, 9.998f, 16.222f, 9.999f, 16.222f) + curveTo(10.0f, 16.222f, 10.002f, 16.222f, 10.003f, 16.221f) + curveTo(10.047f, 16.187f, 10.105f, 16.133f, 10.212f, 16.034f) + lineTo(10.213f, 16.033f) + lineTo(16.052f, 10.591f) + curveTo(16.769f, 9.923f, 17.21f, 9.014f, 17.287f, 8.041f) + curveTo(17.364f, 7.069f, 17.072f, 6.101f, 16.469f, 5.331f) + lineTo(16.209f, 4.998f) + curveTo(14.748f, 3.13f, 11.815f, 3.443f, 10.788f, 5.578f) + curveTo(10.716f, 5.725f, 10.604f, 5.851f, 10.465f, 5.938f) + curveTo(10.326f, 6.025f, 10.164f, 6.071f, 9.999f, 6.071f) + curveTo(9.835f, 6.071f, 9.674f, 6.025f, 9.534f, 5.938f) + curveTo(9.395f, 5.851f, 9.283f, 5.726f, 9.212f, 5.579f) + lineTo(9.211f, 5.578f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(3.127f, 4.487f) + curveTo(4.971f, 2.128f, 8.674f, 2.524f, 9.97f, 5.219f) + curveTo(9.973f, 5.225f, 9.976f, 5.23f, 9.981f, 5.233f) + curveTo(9.987f, 5.236f, 9.993f, 5.238f, 9.999f, 5.238f) + curveTo(10.006f, 5.238f, 10.012f, 5.236f, 10.017f, 5.233f) + curveTo(10.023f, 5.23f, 10.027f, 5.225f, 10.03f, 5.219f) + lineTo(10.158f, 4.973f) + curveTo(11.555f, 2.502f, 15.086f, 2.203f, 16.873f, 4.487f) + lineTo(17.133f, 4.819f) + curveTo(17.864f, 5.754f, 18.217f, 6.927f, 18.123f, 8.106f) + curveTo(18.03f, 9.286f, 17.497f, 10.388f, 16.627f, 11.198f) + lineTo(10.788f, 16.64f) + curveTo(10.693f, 16.728f, 10.601f, 16.816f, 10.516f, 16.881f) + curveTo(10.425f, 16.951f, 10.31f, 17.021f, 10.162f, 17.05f) + curveTo(10.055f, 17.071f, 9.944f, 17.071f, 9.837f, 17.05f) + horizontalLineTo(9.835f) + curveTo(9.687f, 17.021f, 9.572f, 16.949f, 9.483f, 16.88f) + curveTo(9.398f, 16.815f, 9.306f, 16.728f, 9.211f, 16.64f) + lineTo(2.598f, 10.477f) + horizontalLineTo(2.741f) + curveTo(2.247f, 9.783f, 1.944f, 8.965f, 1.876f, 8.106f) + curveTo(1.783f, 6.927f, 2.136f, 5.756f, 2.866f, 4.821f) + lineTo(3.127f, 4.487f) + close() + moveTo(9.211f, 5.578f) + curveTo(8.216f, 3.51f, 5.433f, 3.151f, 3.931f, 4.829f) + lineTo(3.79f, 4.998f) + lineTo(3.53f, 5.331f) + curveTo(2.928f, 6.102f, 2.637f, 7.068f, 2.714f, 8.04f) + curveTo(2.791f, 9.013f, 3.231f, 9.922f, 3.947f, 10.59f) + lineTo(4.72f, 11.31f) + lineTo(9.784f, 16.032f) + curveTo(9.891f, 16.132f, 9.951f, 16.186f, 9.996f, 16.221f) + curveTo(9.997f, 16.222f, 9.998f, 16.222f, 9.999f, 16.222f) + curveTo(10.0f, 16.222f, 10.002f, 16.222f, 10.003f, 16.221f) + curveTo(10.047f, 16.187f, 10.105f, 16.133f, 10.212f, 16.034f) + lineTo(10.213f, 16.033f) + lineTo(16.052f, 10.591f) + curveTo(16.769f, 9.923f, 17.21f, 9.014f, 17.287f, 8.041f) + curveTo(17.364f, 7.069f, 17.072f, 6.101f, 16.469f, 5.331f) + lineTo(16.209f, 4.998f) + curveTo(14.748f, 3.13f, 11.815f, 3.443f, 10.788f, 5.578f) + curveTo(10.716f, 5.725f, 10.604f, 5.851f, 10.465f, 5.938f) + curveTo(10.326f, 6.025f, 10.164f, 6.071f, 9.999f, 6.071f) + curveTo(9.835f, 6.071f, 9.674f, 6.025f, 9.534f, 5.938f) + curveTo(9.395f, 5.851f, 9.283f, 5.726f, 9.212f, 5.579f) + lineTo(9.211f, 5.578f) + close() + } + } + .build() + return _recordLike!! + } + +private var _recordLike: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.RecordLike, contentDescription = "") + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordSurprise.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordSurprise.kt new file mode 100644 index 0000000..1564609 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/RecordSurprise.kt @@ -0,0 +1,148 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.RecordSurprise: ImageVector + get() { + if (_recordSurprise != null) { + return _recordSurprise!! + } + _recordSurprise = Builder(name = "RecordSurprise", defaultWidth = 20.0.dp, defaultHeight = + 20.0.dp, viewportWidth = 20.0f, viewportHeight = 20.0f).apply { + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(17.2f, 10.0f) + curveTo(17.2f, 6.024f, 13.976f, 2.8f, 10.0f, 2.8f) + curveTo(6.024f, 2.8f, 2.8f, 6.024f, 2.8f, 10.0f) + curveTo(2.8f, 13.976f, 6.024f, 17.2f, 10.0f, 17.2f) + curveTo(13.976f, 17.2f, 17.2f, 13.976f, 17.2f, 10.0f) + close() + moveTo(18.0f, 10.0f) + curveTo(18.0f, 14.418f, 14.418f, 18.0f, 10.0f, 18.0f) + curveTo(5.582f, 18.0f, 2.0f, 14.418f, 2.0f, 10.0f) + curveTo(2.0f, 5.582f, 5.582f, 2.0f, 10.0f, 2.0f) + curveTo(14.418f, 2.0f, 18.0f, 5.582f, 18.0f, 10.0f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(17.2f, 10.0f) + curveTo(17.2f, 6.024f, 13.976f, 2.8f, 10.0f, 2.8f) + curveTo(6.024f, 2.8f, 2.8f, 6.024f, 2.8f, 10.0f) + curveTo(2.8f, 13.976f, 6.024f, 17.2f, 10.0f, 17.2f) + curveTo(13.976f, 17.2f, 17.2f, 13.976f, 17.2f, 10.0f) + close() + moveTo(18.0f, 10.0f) + curveTo(18.0f, 14.418f, 14.418f, 18.0f, 10.0f, 18.0f) + curveTo(5.582f, 18.0f, 2.0f, 14.418f, 2.0f, 10.0f) + curveTo(2.0f, 5.582f, 5.582f, 2.0f, 10.0f, 2.0f) + curveTo(14.418f, 2.0f, 18.0f, 5.582f, 18.0f, 10.0f) + close() + } + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(7.12f, 8.4f) + curveTo(7.562f, 8.4f, 7.92f, 8.042f, 7.92f, 7.6f) + curveTo(7.92f, 7.158f, 7.562f, 6.8f, 7.12f, 6.8f) + curveTo(6.678f, 6.8f, 6.32f, 7.158f, 6.32f, 7.6f) + curveTo(6.32f, 8.042f, 6.678f, 8.4f, 7.12f, 8.4f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(7.12f, 8.4f) + curveTo(7.562f, 8.4f, 7.92f, 8.042f, 7.92f, 7.6f) + curveTo(7.92f, 7.158f, 7.562f, 6.8f, 7.12f, 6.8f) + curveTo(6.678f, 6.8f, 6.32f, 7.158f, 6.32f, 7.6f) + curveTo(6.32f, 8.042f, 6.678f, 8.4f, 7.12f, 8.4f) + close() + } + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(12.88f, 8.4f) + curveTo(13.322f, 8.4f, 13.68f, 8.042f, 13.68f, 7.6f) + curveTo(13.68f, 7.158f, 13.322f, 6.8f, 12.88f, 6.8f) + curveTo(12.438f, 6.8f, 12.08f, 7.158f, 12.08f, 7.6f) + curveTo(12.08f, 8.042f, 12.438f, 8.4f, 12.88f, 8.4f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(12.88f, 8.4f) + curveTo(13.322f, 8.4f, 13.68f, 8.042f, 13.68f, 7.6f) + curveTo(13.68f, 7.158f, 13.322f, 6.8f, 12.88f, 6.8f) + curveTo(12.438f, 6.8f, 12.08f, 7.158f, 12.08f, 7.6f) + curveTo(12.08f, 8.042f, 12.438f, 8.4f, 12.88f, 8.4f) + close() + } + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(11.6f, 12.8f) + curveTo(11.6f, 12.268f, 11.026f, 11.6f, 10.0f, 11.6f) + curveTo(8.974f, 11.6f, 8.4f, 12.268f, 8.4f, 12.8f) + curveTo(8.4f, 13.332f, 8.974f, 14.0f, 10.0f, 14.0f) + verticalLineTo(14.8f) + curveTo(8.674f, 14.8f, 7.6f, 13.904f, 7.6f, 12.8f) + curveTo(7.6f, 11.696f, 8.674f, 10.8f, 10.0f, 10.8f) + curveTo(11.325f, 10.8f, 12.4f, 11.696f, 12.4f, 12.8f) + curveTo(12.4f, 13.904f, 11.325f, 14.8f, 10.0f, 14.8f) + verticalLineTo(14.0f) + curveTo(11.026f, 14.0f, 11.6f, 13.332f, 11.6f, 12.8f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(11.6f, 12.8f) + curveTo(11.6f, 12.268f, 11.026f, 11.6f, 10.0f, 11.6f) + curveTo(8.974f, 11.6f, 8.4f, 12.268f, 8.4f, 12.8f) + curveTo(8.4f, 13.332f, 8.974f, 14.0f, 10.0f, 14.0f) + verticalLineTo(14.8f) + curveTo(8.674f, 14.8f, 7.6f, 13.904f, 7.6f, 12.8f) + curveTo(7.6f, 11.696f, 8.674f, 10.8f, 10.0f, 10.8f) + curveTo(11.325f, 10.8f, 12.4f, 11.696f, 12.4f, 12.8f) + curveTo(12.4f, 13.904f, 11.325f, 14.8f, 10.0f, 14.8f) + verticalLineTo(14.0f) + curveTo(11.026f, 14.0f, 11.6f, 13.332f, 11.6f, 12.8f) + close() + } + } + .build() + return _recordSurprise!! + } + +private var _recordSurprise: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.RecordSurprise, contentDescription = "") + } +} diff --git a/app/src/main/res/drawable/badge_bronze.xml b/app/src/main/res/drawable/badge_bronze.xml new file mode 100644 index 0000000..e55da67 --- /dev/null +++ b/app/src/main/res/drawable/badge_bronze.xml @@ -0,0 +1,250 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/badge_gold.xml b/app/src/main/res/drawable/badge_gold.xml new file mode 100644 index 0000000..f95f729 --- /dev/null +++ b/app/src/main/res/drawable/badge_gold.xml @@ -0,0 +1,250 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/badge_silver.xml b/app/src/main/res/drawable/badge_silver.xml new file mode 100644 index 0000000..95c20e1 --- /dev/null +++ b/app/src/main/res/drawable/badge_silver.xml @@ -0,0 +1,370 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/beach.png b/app/src/main/res/drawable/beach.png new file mode 100644 index 0000000000000000000000000000000000000000..52c9aa09cc4cdf28ec8129656d655efdd1357b61 GIT binary patch literal 99258 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�gK-(?U9mz;Y(^di2e$P85MHJ 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 e(O`&5oBlh;B~ Date: Mon, 13 Oct 2025 20:04:15 +0900 Subject: [PATCH 28/98] =?UTF-8?q?design:=20=EB=B0=9C=EA=B2=AC=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=ED=99=94=EB=A9=B4=20UI=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 4 +- .../presentation/find/FindDetailScreen.kt | 323 ++++++++++++++++++ .../component/SharedRecordContentSection.kt | 111 ++++++ .../find/component/SharedRecordItem.kt | 162 +-------- .../find/component/SharedRecordTimeSection.kt | 39 +++ .../dnapp/presentation/ui/icon/__AppIcons.kt | 3 +- .../presentation/ui/icon/appicons/More.kt | 104 ++++++ .../ui/profile/ProfileImageCircle.kt | 29 ++ 8 files changed, 623 insertions(+), 152 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/find/FindDetailScreen.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordTimeSection.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/More.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/profile/ProfileImageCircle.kt diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index 2d28724..dcaf522 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -15,6 +15,7 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import com.min.dnapp.presentation.AppStartViewModel +import com.min.dnapp.presentation.find.FindDetailScreen import com.min.dnapp.presentation.find.FindScreen import com.min.dnapp.presentation.home.HomeScreen import com.min.dnapp.presentation.login.LoginScreen @@ -41,7 +42,8 @@ class MainActivity : ComponentActivity() { // SettingScreen() // RecordWriteScreen() // WriteFinishScreen() - FindScreen() +// FindScreen() + FindDetailScreen() } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/find/FindDetailScreen.kt b/app/src/main/java/com/min/dnapp/presentation/find/FindDetailScreen.kt new file mode 100644 index 0000000..3d2d78a --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/find/FindDetailScreen.kt @@ -0,0 +1,323 @@ +package com.min.dnapp.presentation.find + +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.R +import com.min.dnapp.presentation.find.component.SharedRecordContentSection +import com.min.dnapp.presentation.find.component.SharedRecordTimeSection +import com.min.dnapp.presentation.ui.icon.AppIcons +import com.min.dnapp.presentation.ui.icon.appicons.Back +import com.min.dnapp.presentation.ui.icon.appicons.More +import com.min.dnapp.presentation.ui.icon.appicons.RecordBest +import com.min.dnapp.presentation.ui.icon.appicons.RecordBookmark +import com.min.dnapp.presentation.ui.icon.appicons.RecordComment +import com.min.dnapp.presentation.ui.icon.appicons.RecordLike +import com.min.dnapp.presentation.ui.icon.appicons.RecordSurprise +import com.min.dnapp.presentation.ui.profile.ProfileImageCircle +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun FindDetailScreen() { + Scaffold( + containerColor = MomentoTheme.colors.brownBg, + topBar = { + CenterAlignedTopAppBar( + title = { + Text( + text = "상세 보기", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 + ) + }, + colors = TopAppBarDefaults.centerAlignedTopAppBarColors( + containerColor = MomentoTheme.colors.brownBg + ), + navigationIcon = { + Icon( + modifier = Modifier + .clickable { } + .padding(16.dp), + imageVector = AppIcons.Back, + contentDescription = null, + tint = MomentoTheme.colors.grayW20 + ) + } + ) + } + ) { paddingValues -> + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + ) { + // 기록 내용 영역 + item { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(20.dp) + ) { + // 프로필 이미지 + ProfileImageCircle(modifier = Modifier.size(36.dp)) + + Spacer(Modifier.width(8.dp)) + + Column( + modifier = Modifier.weight(1f) + ) { + // 공유 경과시간 + 더보기 아이콘 영역 + SharedRecordMoreSection() + + Spacer(Modifier.height(8.dp)) + + Text( + text = "시골청년님이 여행 기록을 공유했어요.", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + + Spacer(Modifier.height(8.dp)) + + // 기록 내용 + SharedRecordContentSection() + } + } + } + + // 반응 이모지 영역 + item { + HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW60) + FindDetailReactionSection( + bestNum = 1, + likeNum = 2, + surpriseNum = 12, + commentNum = 2 + ) + HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW60) + } + + // 댓글 목록 영역 + items(count = 5) { + CommentItem() + } + } + } +} + +@Composable +fun SharedRecordMoreSection() { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + SharedRecordTimeSection() + + Icon( + modifier = Modifier + .clickable { } + .padding(start = 16.dp), + imageVector = AppIcons.More, + contentDescription = null, + tint = MomentoTheme.colors.grayW20 + ) + } +} + +@Composable +fun FindDetailReactionSection( + bestNum: Int, + likeNum: Int, + surpriseNum: Int, + commentNum: Int +) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(start = 16.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = AppIcons.RecordComment, + contentDescription = null, + tint = MomentoTheme.colors.grayW60 + ) + Spacer(Modifier.width(2.dp)) + Text( + text = commentNum.toString(), + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + } + + Spacer(Modifier.width(20.dp)) + + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = AppIcons.RecordBest, + contentDescription = null, + tint = MomentoTheme.colors.grayW60 + ) + Spacer(Modifier.width(2.dp)) + Text( + text = bestNum.toString(), + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + } + + Spacer(Modifier.width(4.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = AppIcons.RecordLike, + contentDescription = null, + tint = MomentoTheme.colors.grayW60 + ) + Spacer(Modifier.width(2.dp)) + Text( + text = likeNum.toString(), + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + } + + Spacer(Modifier.width(4.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = AppIcons.RecordSurprise, + contentDescription = null, + tint = MomentoTheme.colors.grayW60 + ) + Spacer(Modifier.width(2.dp)) + Text( + text = surpriseNum.toString(), + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + } + } + + Icon( + modifier = Modifier + .clickable { } + .padding(16.dp), + imageVector = AppIcons.RecordBookmark, + contentDescription = null, + tint = MomentoTheme.colors.grayW60 + ) + } +} + +@Composable +fun CommentItem() { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 20.dp, vertical = 12.dp) + ) { + // 프로필 이미지 + ProfileImageCircle(modifier = Modifier.size(24.dp)) + + Spacer(Modifier.width(8.dp)) + + Column { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "성민", + style = MomentoTheme.typography.body03, + color = MomentoTheme.colors.grayW20 + ) + Spacer(Modifier.width(4.dp)) + Image( + modifier = Modifier.size(20.dp), + painter = painterResource(R.drawable.badge_bronze), + contentDescription = null + ) + } + + Spacer(Modifier.height(8.dp)) + + Text( + text = "너무 예쁜데요??", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW20 + ) + + Spacer(Modifier.height(6.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "1시간 전", + style = MomentoTheme.typography.label, + color = MomentoTheme.colors.grayW60 + ) + Spacer(Modifier.width(4.dp)) + Text( + text = "・", + style = MomentoTheme.typography.label, + color = MomentoTheme.colors.grayW60 + ) + Spacer(Modifier.width(4.dp)) + Text( + text = "신고", + style = MomentoTheme.typography.label, + color = MomentoTheme.colors.grayW60 + ) + } + } + } +} + +@Preview +@Composable +fun FindDetailScreenPreview() { + DngoTheme { + FindDetailScreen() + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt new file mode 100644 index 0000000..00fd194 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt @@ -0,0 +1,111 @@ +package com.min.dnapp.presentation.find.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +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.material3.HorizontalDivider +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import com.min.dnapp.R +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun SharedRecordContentSection() { + Column( + modifier = Modifier + .fillMaxWidth() + .background(color = MomentoTheme.colors.brownW90) + .padding(horizontal = 16.dp) + ) { + Spacer(Modifier.height(16.dp)) + + Text( + text = "제주도 동쪽 투어!", + style = MomentoTheme.typography.label, + color = MomentoTheme.colors.grayW20 + ) + + Spacer(Modifier.height(6.dp)) + + HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.pinkBase) + + Spacer(Modifier.height(4.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "25.08.20 ~ 25.08.22", + style = MomentoTheme.typography.body03, + color = MomentoTheme.colors.grayW20 + ) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Image( + modifier = Modifier.size(28.dp), + painter = painterResource(R.drawable.weather_sun), + contentDescription = null + ) + Spacer(Modifier.width(4.dp)) + Image( + modifier = Modifier.size(28.dp), + painter = painterResource(R.drawable.emotion_feel), + contentDescription = null + ) + } + } + + Spacer(Modifier.height(4.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(R.drawable.write_place), + contentDescription = null + ) + Spacer(Modifier.width(6.dp)) + Text( + text = "제주특별자치도", + style = MomentoTheme.typography.body03 , + color = MomentoTheme.colors.grayW20 + ) + } + + Spacer(Modifier.height(6.dp)) + + Text( + text = "비 오는 날 이호해수욕장... 너무 좋았어요", + style = MomentoTheme.typography.body02 , + color = MomentoTheme.colors.grayW20 + ) + + Spacer(Modifier.height(6.dp)) + + Image( + modifier = Modifier.fillMaxWidth(), + painter = painterResource(R.drawable.beach ), + contentDescription = null, + contentScale = ContentScale.Crop + ) + + Spacer(Modifier.height(12.dp)) + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt index 39fe001..6587986 100644 --- a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt +++ b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt @@ -1,30 +1,18 @@ package com.min.dnapp.presentation.find.component -import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.border -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.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.shape.CircleShape -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text import androidx.compose.runtime.Composable -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.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.min.dnapp.R +import com.min.dnapp.presentation.ui.profile.ProfileImageCircle import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.ui.theme.MomentoTheme @@ -34,25 +22,23 @@ fun SharedRecordItem() { modifier = Modifier.fillMaxWidth() ) { // 프로필 이미지 - Box( - modifier = Modifier - .size(36.dp) - .clip(CircleShape) - .border(width = 2.dp, color = MomentoTheme.colors.grayW90, shape = CircleShape) - ) { - Image( - painter = painterResource(R.drawable.logo_profile), - contentDescription = null - ) - } + ProfileImageCircle(modifier = Modifier.size(36.dp)) Spacer(Modifier.width(8.dp)) Column( modifier = Modifier.weight(1f) ) { - // 닉네임 + 공유 안내 - SharedRecordHeaderSection() + // 공유 경과시간 영역 + SharedRecordTimeSection() + + Spacer(Modifier.height(8.dp)) + + Text( + text = "시골청년님이 여행 기록을 공유했어요.", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) Spacer(Modifier.height(8.dp)) @@ -72,130 +58,6 @@ fun SharedRecordItem() { } } -@Composable -fun SharedRecordHeaderSection() { - Column( - modifier = Modifier.fillMaxWidth() - ) { - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = "시골청년", - style = MomentoTheme.typography.body01, - color = MomentoTheme.colors.grayW20 - ) - Image( - modifier = Modifier.size(20.dp), - painter = painterResource(R.drawable.badge_bronze), - contentDescription = null - ) - Spacer(Modifier.width(4.dp)) - Text( - text = "2분 전", - style = MomentoTheme.typography.body02, - color = MomentoTheme.colors.grayW20 - ) - } - - Spacer(Modifier.height(8.dp)) - - Text( - text = "시골청년님이 여행 기록을 공유했어요.", - style = MomentoTheme.typography.body01, - color = MomentoTheme.colors.grayW20 - ) - } -} - -@Composable -fun SharedRecordContentSection() { - Column( - modifier = Modifier - .fillMaxWidth() - .background(color = MomentoTheme.colors.brownW90) - .padding(horizontal = 16.dp) - ) { - Spacer(Modifier.height(16.dp)) - - Text( - text = "제주도 동쪽 투어!", - style = MomentoTheme.typography.label, - color = MomentoTheme.colors.grayW20 - ) - - Spacer(Modifier.height(6.dp)) - - HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.pinkBase) - - Spacer(Modifier.height(4.dp)) - - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = "25.08.20 ~ 25.08.22", - style = MomentoTheme.typography.body03, - color = MomentoTheme.colors.grayW20 - ) - - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Image( - modifier = Modifier.size(28.dp), - painter = painterResource(R.drawable.weather_sun), - contentDescription = null - ) - Spacer(Modifier.width(4.dp)) - Image( - modifier = Modifier.size(28.dp), - painter = painterResource(R.drawable.emotion_feel), - contentDescription = null - ) - } - } - - Spacer(Modifier.height(4.dp)) - - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Image( - painter = painterResource(R.drawable.write_place), - contentDescription = null - ) - Spacer(Modifier.width(6.dp)) - Text( - text = "제주특별자치도", - style = MomentoTheme.typography.body03 , - color = MomentoTheme.colors.grayW20 - ) - } - - Spacer(Modifier.height(6.dp)) - - Text( - text = "비 오는 날 이호해수욕장... 너무 좋았어요", - style = MomentoTheme.typography.body02 , - color = MomentoTheme.colors.grayW20 - ) - - Spacer(Modifier.height(6.dp)) - - Image( - modifier = Modifier.fillMaxWidth(), - painter = painterResource(R.drawable.beach ), - contentDescription = null, - contentScale = ContentScale.Crop - ) - - Spacer(Modifier.height(12.dp)) - } -} - @Preview @Composable fun RecordItemPreview() { diff --git a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordTimeSection.kt b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordTimeSection.kt new file mode 100644 index 0000000..dfab459 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordTimeSection.kt @@ -0,0 +1,39 @@ +package com.min.dnapp.presentation.find.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +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.painterResource +import androidx.compose.ui.unit.dp +import com.min.dnapp.R +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun SharedRecordTimeSection() { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "시골청년", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + Image( + modifier = Modifier.size(20.dp), + painter = painterResource(R.drawable.badge_bronze), + contentDescription = null + ) + Spacer(Modifier.width(4.dp)) + Text( + text = "2분 전", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW20 + ) + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt index 2e1e93e..77b48b8 100644 --- a/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt @@ -7,6 +7,7 @@ import com.min.dnapp.presentation.ui.icon.appicons.Calendar import com.min.dnapp.presentation.ui.icon.appicons.Delete import com.min.dnapp.presentation.ui.icon.appicons.Gallery import com.min.dnapp.presentation.ui.icon.appicons.Kakao +import com.min.dnapp.presentation.ui.icon.appicons.More import com.min.dnapp.presentation.ui.icon.appicons.PenSmall import com.min.dnapp.presentation.ui.icon.appicons.RecordBest import com.min.dnapp.presentation.ui.icon.appicons.RecordBookmark @@ -24,7 +25,7 @@ public val AppIcons.AllIcons: ____KtList if (__AllIcons != null) { return __AllIcons!! } - __AllIcons= listOf(Back, Bell, Calendar, Delete, Gallery, Kakao, PenSmall, RecordBest, + __AllIcons= listOf(Back, Bell, Calendar, Delete, Gallery, Kakao, More, PenSmall, RecordBest, RecordBookmark, RecordComment, RecordLike, RecordSurprise) return __AllIcons!! } diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/More.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/More.kt new file mode 100644 index 0000000..3af04d5 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/More.kt @@ -0,0 +1,104 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.More: ImageVector + get() { + if (_more != null) { + return _more!! + } + _more = Builder(name = "More", defaultWidth = 21.0.dp, defaultHeight = 20.0.dp, + viewportWidth = 21.0f, viewportHeight = 20.0f).apply { + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(5.11f, 10.0f) + curveTo(5.11f, 10.506f, 4.7f, 10.917f, 4.193f, 10.917f) + curveTo(3.687f, 10.917f, 3.277f, 10.506f, 3.277f, 10.0f) + curveTo(3.277f, 9.494f, 3.687f, 9.083f, 4.193f, 9.083f) + curveTo(4.7f, 9.083f, 5.11f, 9.494f, 5.11f, 10.0f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.2f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(5.11f, 10.0f) + curveTo(5.11f, 10.506f, 4.7f, 10.917f, 4.193f, 10.917f) + curveTo(3.687f, 10.917f, 3.277f, 10.506f, 3.277f, 10.0f) + curveTo(3.277f, 9.494f, 3.687f, 9.083f, 4.193f, 9.083f) + curveTo(4.7f, 9.083f, 5.11f, 9.494f, 5.11f, 10.0f) + close() + } + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(11.693f, 10.0f) + curveTo(11.693f, 10.506f, 11.283f, 10.917f, 10.777f, 10.917f) + curveTo(10.27f, 10.917f, 9.86f, 10.506f, 9.86f, 10.0f) + curveTo(9.86f, 9.494f, 10.27f, 9.083f, 10.777f, 9.083f) + curveTo(11.283f, 9.083f, 11.693f, 9.494f, 11.693f, 10.0f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.2f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(11.693f, 10.0f) + curveTo(11.693f, 10.506f, 11.283f, 10.917f, 10.777f, 10.917f) + curveTo(10.27f, 10.917f, 9.86f, 10.506f, 9.86f, 10.0f) + curveTo(9.86f, 9.494f, 10.27f, 9.083f, 10.777f, 9.083f) + curveTo(11.283f, 9.083f, 11.693f, 9.494f, 11.693f, 10.0f) + close() + } + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(18.277f, 10.0f) + curveTo(18.277f, 10.506f, 17.866f, 10.917f, 17.36f, 10.917f) + curveTo(16.854f, 10.917f, 16.443f, 10.506f, 16.443f, 10.0f) + curveTo(16.443f, 9.494f, 16.854f, 9.083f, 17.36f, 9.083f) + curveTo(17.866f, 9.083f, 18.277f, 9.494f, 18.277f, 10.0f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.2f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(18.277f, 10.0f) + curveTo(18.277f, 10.506f, 17.866f, 10.917f, 17.36f, 10.917f) + curveTo(16.854f, 10.917f, 16.443f, 10.506f, 16.443f, 10.0f) + curveTo(16.443f, 9.494f, 16.854f, 9.083f, 17.36f, 9.083f) + curveTo(17.866f, 9.083f, 18.277f, 9.494f, 18.277f, 10.0f) + close() + } + } + .build() + return _more!! + } + +private var _more: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.More, contentDescription = "") + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/profile/ProfileImageCircle.kt b/app/src/main/java/com/min/dnapp/presentation/ui/profile/ProfileImageCircle.kt new file mode 100644 index 0000000..df00263 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/profile/ProfileImageCircle.kt @@ -0,0 +1,29 @@ +package com.min.dnapp.presentation.ui.profile + +import androidx.compose.foundation.Image +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import com.min.dnapp.R +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun ProfileImageCircle( + modifier: Modifier = Modifier +) { + Box( + modifier = modifier + .clip(CircleShape) + .border(width = 2.dp, color = MomentoTheme.colors.grayW90, shape = CircleShape) + ) { + Image( + painter = painterResource(R.drawable.logo_profile), + contentDescription = null + ) + } +} From 808af115b9e4c82eda62cbe7d14c9288b6528b3a Mon Sep 17 00:00:00 2001 From: min486 Date: Thu, 16 Oct 2025 20:04:34 +0900 Subject: [PATCH 29/98] =?UTF-8?q?design:=20=ED=99=88=20=ED=99=94=EB=A9=B4?= =?UTF-8?q?=20UI=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 4 +- .../dnapp/presentation/home/HomeScreen2.kt | 402 ++++++++++++++++++ .../dnapp/presentation/ui/icon/__AppIcons.kt | 6 +- .../ui/icon/appicons/ArrowRight.kt | 114 +++++ .../presentation/ui/icon/appicons/Year.kt | 100 +++++ app/src/main/res/drawable/image_basic.xml | 70 +++ app/src/main/res/drawable/trip.png | Bin 0 -> 21004 bytes app/src/main/res/drawable/trip2.png | Bin 0 -> 17143 bytes app/src/main/res/drawable/trip3.png | Bin 0 -> 18232 bytes 9 files changed, 693 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/ArrowRight.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Year.kt create mode 100644 app/src/main/res/drawable/image_basic.xml create mode 100644 app/src/main/res/drawable/trip.png create mode 100644 app/src/main/res/drawable/trip2.png create mode 100644 app/src/main/res/drawable/trip3.png diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index dcaf522..fb75f69 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -18,6 +18,7 @@ import com.min.dnapp.presentation.AppStartViewModel import com.min.dnapp.presentation.find.FindDetailScreen import com.min.dnapp.presentation.find.FindScreen import com.min.dnapp.presentation.home.HomeScreen +import com.min.dnapp.presentation.home.HomeScreen2 import com.min.dnapp.presentation.login.LoginScreen import com.min.dnapp.presentation.ui.theme.DngoTheme import dagger.hilt.android.AndroidEntryPoint @@ -43,7 +44,8 @@ class MainActivity : ComponentActivity() { // RecordWriteScreen() // WriteFinishScreen() // FindScreen() - FindDetailScreen() +// FindDetailScreen() + HomeScreen2() } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt new file mode 100644 index 0000000..960c670 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt @@ -0,0 +1,402 @@ +package com.min.dnapp.presentation.home + +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.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.lazy.LazyColumn +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.VerticalDivider +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.R +import com.min.dnapp.presentation.mypage.UserBadge +import com.min.dnapp.presentation.ui.icon.AppIcons +import com.min.dnapp.presentation.ui.icon.appicons.ArrowRight +import com.min.dnapp.presentation.ui.icon.appicons.Bell +import com.min.dnapp.presentation.ui.icon.appicons.Year +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun HomeScreen2() { + Scaffold( + containerColor = MomentoTheme.colors.brownW90, + topBar = { + CenterAlignedTopAppBar( + title = { Text("") }, + colors = TopAppBarDefaults.centerAlignedTopAppBarColors( + MomentoTheme.colors.brownW90 + ), + navigationIcon = { + Image( + modifier = Modifier + .clickable { } + .padding(16.dp), + painter = painterResource(R.drawable.logo_momento), + contentDescription = null + ) + }, + actions = { + Icon( + modifier = Modifier + .clickable { } + .padding(16.dp), + imageVector = AppIcons.Bell, + contentDescription = null, + tint = MomentoTheme.colors.grayW60 + ) + } + ) + } + ) { paddingValues -> + Column( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize() + ) { + Spacer(Modifier.height(20.dp)) + + HomeHeaderSection() + + Spacer(Modifier.height(20.dp)) + + // 여행 기록 영역 + Column( + modifier = Modifier + .fillMaxWidth() + .background(color = MomentoTheme.colors.brownBg, shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp)) + .padding(horizontal = 20.dp) + ) { + Spacer(Modifier.height(20.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "내 여행 기록", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 + ) + Icon( + modifier = Modifier.clickable { }, + imageVector = AppIcons.ArrowRight, + contentDescription = null, + tint = MomentoTheme.colors.grayW20 + ) + } + + Spacer(Modifier.height(12.dp)) + + // 카드형 영역 + HomeCardSection() + + Spacer(Modifier.height(20.dp)) + + // 타임라인형 영역 + TimelineSection() + } + } + } +} + +@Composable +fun HomeHeaderSection() { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 20.dp) + ) { + UserBadge() + + Spacer(Modifier.height(12.dp)) + + Text( + text = "성민 님,", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 + ) + Spacer(Modifier.height(4.dp)) + Text( + text = "이번 달엔 총2번 여행을 다녀왔어요!", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + + Spacer(Modifier.height(12.dp)) + + // 스탬프 영역 + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(R.drawable.my_stamp), + contentDescription = null + ) + Spacer(Modifier.width(4.dp)) + Text( + text = "모은 스탬프 12개", + style = MomentoTheme.typography.label, + color = MomentoTheme.colors.grayW20 + ) + } + } +} + +@Composable +fun HomeCardSection() { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + HomeCardImage( + image = painterResource(R.drawable.trip), + text = "제주특별자치도" + ) + HomeCardNoImage() + HomeCardImage( + image = painterResource(R.drawable.trip2), + text = "일본 도쿄" + ) + } +} + +@Composable +fun HomeCardImage( + image: Painter, + text: String +) { + Box( + modifier = Modifier, + contentAlignment = Alignment.CenterStart + ) { + Image( + modifier = Modifier.size(100.dp), + painter = image, + contentDescription = null + ) + // 이미지 어둡게 처리 + Box( + modifier = Modifier + .matchParentSize() + .background(color = Color.Black.copy(alpha = 0.3f)) + ) + Text( + modifier = Modifier + .width(88.dp) + .padding(start = 12.dp), + text = text, + style = MomentoTheme.typography.label, + color = MomentoTheme.colors.white, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } +} + +@Composable +fun HomeCardNoImage() { + Box( + modifier = Modifier + .size(100.dp) + .background(color = MomentoTheme.colors.greenW80) + .padding(horizontal = 12.dp), + contentAlignment = Alignment.Center + ) { + Image( + painter = painterResource(R.drawable.image_basic), + contentDescription = null + ) + Text( + text = "제주특별자치도", + style = MomentoTheme.typography.label, + color = MomentoTheme.colors.grayW20, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } +} + +@Composable +fun TimelineSection() { + LazyColumn( + modifier = Modifier + .fillMaxWidth() + .padding(top = 20.dp), + verticalArrangement = Arrangement.spacedBy(20.dp) + ) { + item { + TimelineYear(year = 2024) + } + item { + TimelineYear(year = 2023) + } + } +} + +@Composable +fun TimelineYear( + year: Int +) { + Column( + modifier = Modifier.fillMaxWidth() + ) { + Row { + Icon( + imageVector = AppIcons.Year, + contentDescription = null, + tint = MomentoTheme.colors.brownBase + ) + Spacer(Modifier.width(6.dp)) + Text( + text = "${year}년", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 + ) + } + + Spacer(Modifier.height(12.dp)) + + // 타임라인형 아이템 + TimelineItem( + idx = 0, + image = painterResource(R.drawable.trip), + startDate = "07.25", + endDate = "07.28", + title = "제주도 동쪽 투어!", + place = "제주특별자치도" + ) + TimelineItem( + idx = 1, + image = painterResource(R.drawable.trip3), + startDate = "03.05", + endDate = "03.08", + title = "너와 함께 한 시간 속", + place = "부산광역시 수영구" + ) + TimelineItem( + idx = 2, + image = painterResource(R.drawable.trip3), + startDate = "01.05", + endDate = "01.07", + title = "신년맞이", + place = "부산광역시 수영구" + ) + } +} + +@Composable +fun TimelineItem( + idx: Int, + image: Painter, + startDate: String, + endDate: String, + title: String, + place: String +) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row { + HomeGrayLine(idx = idx) + + Spacer(Modifier.width(12.dp)) + + Column( + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + Spacer(Modifier.height(4.dp)) + Text( + text = "${startDate} ~ ${endDate}", + style = MomentoTheme.typography.body03, + color = MomentoTheme.colors.grayW20 + ) + Text( + text = title, + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW20 + ) + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(R.drawable.write_place), + contentDescription = null + ) + Spacer(Modifier.width(6.dp)) + Text( + text = place, + style = MomentoTheme.typography.body03, + color = MomentoTheme.colors.grayW20 + ) + } + } + } + + Image( + modifier = Modifier.size(90.dp), + painter = image, + contentDescription = null + ) + } +} + +@Composable +fun HomeGrayLine( + idx: Int +) { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + if (idx == 0) { + Box( + modifier = Modifier + .size(8.dp) + .background(color = MomentoTheme.colors.grayW60, shape = CircleShape) + ) + } + VerticalDivider(modifier = Modifier.height(100.dp), thickness = 1.dp, color = MomentoTheme.colors.grayW60) + Box( + modifier = Modifier + .size(8.dp) + .background(color = MomentoTheme.colors.grayW60, shape = CircleShape) + ) + } +} + +@Preview +@Composable +fun HomeScreen2Preview() { + DngoTheme { + HomeScreen2() + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt index 77b48b8..2914353 100644 --- a/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt @@ -1,6 +1,7 @@ package com.min.dnapp.presentation.ui.icon import androidx.compose.ui.graphics.vector.ImageVector +import com.min.dnapp.presentation.ui.icon.appicons.ArrowRight import com.min.dnapp.presentation.ui.icon.appicons.Back import com.min.dnapp.presentation.ui.icon.appicons.Bell import com.min.dnapp.presentation.ui.icon.appicons.Calendar @@ -14,6 +15,7 @@ import com.min.dnapp.presentation.ui.icon.appicons.RecordBookmark import com.min.dnapp.presentation.ui.icon.appicons.RecordComment import com.min.dnapp.presentation.ui.icon.appicons.RecordLike import com.min.dnapp.presentation.ui.icon.appicons.RecordSurprise +import com.min.dnapp.presentation.ui.icon.appicons.Year import kotlin.collections.List as ____KtList public object AppIcons @@ -25,7 +27,7 @@ public val AppIcons.AllIcons: ____KtList if (__AllIcons != null) { return __AllIcons!! } - __AllIcons= listOf(Back, Bell, Calendar, Delete, Gallery, Kakao, More, PenSmall, RecordBest, - RecordBookmark, RecordComment, RecordLike, RecordSurprise) + __AllIcons= listOf(ArrowRight, Back, Bell, Calendar, Delete, Gallery, Kakao, More, PenSmall, + RecordBest, RecordBookmark, RecordComment, RecordLike, RecordSurprise, Year) return __AllIcons!! } diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/ArrowRight.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/ArrowRight.kt new file mode 100644 index 0000000..ee0192f --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/ArrowRight.kt @@ -0,0 +1,114 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.ArrowRight: ImageVector + get() { + if (_arrowRight != null) { + return _arrowRight!! + } + _arrowRight = Builder(name = "ArrowRight", defaultWidth = 25.0.dp, defaultHeight = 24.0.dp, + viewportWidth = 25.0f, viewportHeight = 24.0f).apply { + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(18.546f, 12.0f) + lineTo(18.9f, 11.646f) + lineTo(19.253f, 12.0f) + lineTo(18.9f, 12.354f) + lineTo(18.546f, 12.0f) + close() + moveTo(6.547f, 12.5f) + curveTo(6.414f, 12.5f, 6.287f, 12.447f, 6.193f, 12.354f) + curveTo(6.099f, 12.26f, 6.047f, 12.133f, 6.047f, 12.0f) + curveTo(6.047f, 11.867f, 6.099f, 11.74f, 6.193f, 11.646f) + curveTo(6.287f, 11.553f, 6.414f, 11.5f, 6.547f, 11.5f) + verticalLineTo(12.5f) + close() + moveTo(14.901f, 7.646f) + lineTo(18.9f, 11.646f) + lineTo(18.192f, 12.354f) + lineTo(14.193f, 8.354f) + lineTo(14.901f, 7.646f) + close() + moveTo(18.9f, 12.354f) + lineTo(14.901f, 16.354f) + lineTo(14.193f, 15.646f) + lineTo(18.192f, 11.646f) + lineTo(18.9f, 12.354f) + close() + moveTo(18.546f, 12.5f) + horizontalLineTo(6.547f) + verticalLineTo(11.5f) + horizontalLineTo(18.546f) + verticalLineTo(12.5f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.2f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(18.546f, 12.0f) + lineTo(18.9f, 11.646f) + lineTo(19.253f, 12.0f) + lineTo(18.9f, 12.354f) + lineTo(18.546f, 12.0f) + close() + moveTo(6.547f, 12.5f) + curveTo(6.414f, 12.5f, 6.287f, 12.447f, 6.193f, 12.354f) + curveTo(6.099f, 12.26f, 6.047f, 12.133f, 6.047f, 12.0f) + curveTo(6.047f, 11.867f, 6.099f, 11.74f, 6.193f, 11.646f) + curveTo(6.287f, 11.553f, 6.414f, 11.5f, 6.547f, 11.5f) + verticalLineTo(12.5f) + close() + moveTo(14.901f, 7.646f) + lineTo(18.9f, 11.646f) + lineTo(18.192f, 12.354f) + lineTo(14.193f, 8.354f) + lineTo(14.901f, 7.646f) + close() + moveTo(18.9f, 12.354f) + lineTo(14.901f, 16.354f) + lineTo(14.193f, 15.646f) + lineTo(18.192f, 11.646f) + lineTo(18.9f, 12.354f) + close() + moveTo(18.546f, 12.5f) + horizontalLineTo(6.547f) + verticalLineTo(11.5f) + horizontalLineTo(18.546f) + verticalLineTo(12.5f) + close() + } + } + .build() + return _arrowRight!! + } + +private var _arrowRight: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.ArrowRight, contentDescription = "") + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Year.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Year.kt new file mode 100644 index 0000000..7908cf6 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Year.kt @@ -0,0 +1,100 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.Year: ImageVector + get() { + if (_year != null) { + return _year!! + } + _year = Builder(name = "Year", defaultWidth = 15.0.dp, defaultHeight = 18.0.dp, + viewportWidth = 15.0f, viewportHeight = 18.0f).apply { + path(fill = SolidColor(Color(0xFFA56C48)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(12.983f, 7.833f) + curveTo(12.983f, 7.465f, 12.685f, 7.167f, 12.317f, 7.167f) + horizontalLineTo(2.983f) + curveTo(2.615f, 7.167f, 2.317f, 7.465f, 2.317f, 7.833f) + verticalLineTo(15.167f) + curveTo(2.317f, 15.535f, 2.615f, 15.833f, 2.983f, 15.833f) + horizontalLineTo(12.317f) + curveTo(12.685f, 15.833f, 12.983f, 15.535f, 12.983f, 15.167f) + verticalLineTo(7.833f) + close() + moveTo(14.317f, 15.167f) + curveTo(14.317f, 16.271f, 13.421f, 17.167f, 12.317f, 17.167f) + horizontalLineTo(2.983f) + curveTo(1.879f, 17.167f, 0.983f, 16.271f, 0.983f, 15.167f) + verticalLineTo(7.833f) + curveTo(0.983f, 6.729f, 1.879f, 5.833f, 2.983f, 5.833f) + horizontalLineTo(12.317f) + curveTo(13.421f, 5.833f, 14.317f, 6.729f, 14.317f, 7.833f) + verticalLineTo(15.167f) + close() + } + path(fill = SolidColor(Color(0xFFA56C48)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(1.65f, 7.333f) + curveTo(1.65f, 6.076f, 1.65f, 5.448f, 2.041f, 5.057f) + curveTo(2.431f, 4.667f, 3.059f, 4.667f, 4.317f, 4.667f) + horizontalLineTo(10.983f) + curveTo(12.241f, 4.667f, 12.869f, 4.667f, 13.259f, 5.057f) + curveTo(13.65f, 5.448f, 13.65f, 6.076f, 13.65f, 7.333f) + horizontalLineTo(1.65f) + close() + } + path(fill = SolidColor(Color(0xFFA56C48)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(3.65f, 3.5f) + verticalLineTo(1.5f) + curveTo(3.65f, 1.132f, 3.948f, 0.833f, 4.317f, 0.833f) + curveTo(4.685f, 0.833f, 4.983f, 1.132f, 4.983f, 1.5f) + verticalLineTo(3.5f) + curveTo(4.983f, 3.868f, 4.685f, 4.167f, 4.317f, 4.167f) + curveTo(3.948f, 4.167f, 3.65f, 3.868f, 3.65f, 3.5f) + close() + moveTo(10.317f, 3.5f) + verticalLineTo(1.5f) + curveTo(10.317f, 1.132f, 10.615f, 0.833f, 10.983f, 0.833f) + curveTo(11.351f, 0.833f, 11.65f, 1.132f, 11.65f, 1.5f) + verticalLineTo(3.5f) + curveTo(11.65f, 3.868f, 11.351f, 4.167f, 10.983f, 4.167f) + curveTo(10.615f, 4.167f, 10.317f, 3.868f, 10.317f, 3.5f) + close() + } + } + .build() + return _year!! + } + +private var _year: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.Year, contentDescription = "") + } +} diff --git a/app/src/main/res/drawable/image_basic.xml b/app/src/main/res/drawable/image_basic.xml new file mode 100644 index 0000000..600ee09 --- /dev/null +++ b/app/src/main/res/drawable/image_basic.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/trip.png b/app/src/main/res/drawable/trip.png new file mode 100644 index 0000000000000000000000000000000000000000..f75814c922357170c80d58fedc66fd78228442e2 GIT binary patch literal 21004 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 LNkvXXu0mjfbN&Cc literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/trip2.png b/app/src/main/res/drawable/trip2.png new file mode 100644 index 0000000000000000000000000000000000000000..f218399a79eef02c11554b99c09c89237a156fad GIT binary patch literal 17143 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 v1MGzzzZFW%6s8cPn1SX2#|M*!2Gjorbr Date: Thu, 16 Oct 2025 20:51:05 +0900 Subject: [PATCH 30/98] =?UTF-8?q?design:=20=EC=95=8C=EB=A6=BC=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20UI=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 4 +- .../min/dnapp/presentation/bell/BellScreen.kt | 147 ++++++++++++++++++ app/src/main/res/drawable/bell_comment.xml | 22 +++ 3 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/bell/BellScreen.kt create mode 100644 app/src/main/res/drawable/bell_comment.xml diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index fb75f69..4f0b6c8 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -15,6 +15,7 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import com.min.dnapp.presentation.AppStartViewModel +import com.min.dnapp.presentation.bell.BellScreen import com.min.dnapp.presentation.find.FindDetailScreen import com.min.dnapp.presentation.find.FindScreen import com.min.dnapp.presentation.home.HomeScreen @@ -45,7 +46,8 @@ class MainActivity : ComponentActivity() { // WriteFinishScreen() // FindScreen() // FindDetailScreen() - HomeScreen2() +// HomeScreen2() + BellScreen() } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/bell/BellScreen.kt b/app/src/main/java/com/min/dnapp/presentation/bell/BellScreen.kt new file mode 100644 index 0000000..c98ea31 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/bell/BellScreen.kt @@ -0,0 +1,147 @@ +package com.min.dnapp.presentation.bell + +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +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.size +import androidx.compose.foundation.layout.width +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.R +import com.min.dnapp.presentation.ui.icon.AppIcons +import com.min.dnapp.presentation.ui.icon.appicons.Back +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun BellScreen() { + Scaffold( + containerColor = MomentoTheme.colors.brownBg, + topBar = { + CenterAlignedTopAppBar( + title = { + Text( + text = "알림", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 + ) + }, + colors = TopAppBarDefaults.centerAlignedTopAppBarColors( + MomentoTheme.colors.brownBg + ), + navigationIcon = { + Icon( + modifier = Modifier + .clickable { } + .padding(16.dp), + imageVector = AppIcons.Back, + contentDescription = null + ) + } + ) + } + ) { paddingValues -> + Column( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize() + ) { + HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW80) + + BellCommentItem( + image = painterResource(R.drawable.trip), + nickname = "안녕하세요안녕하세요" + ) + + for (i in 0 until 3) { + BellCommentItem( + image = painterResource(R.drawable.trip3), + nickname = "박사과" + ) + } + } + } +} + +@Composable +fun BellCommentItem( + image: Painter, + nickname: String +) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 20.dp, vertical = 12.dp ), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Row { + Image( + painter = painterResource(R.drawable.bell_comment), + contentDescription = null + ) + + Spacer(Modifier.width(8.dp)) + + Column( + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + Text( + text = "2분 전", + style = MomentoTheme.typography.label, + color = MomentoTheme.colors.grayW20 + ) + + Text( + text = "$nickname 님이", + style = MomentoTheme.typography.body02 , + color = MomentoTheme.colors.grayW20 + ) + Text( + text = "내 여행기록에 댓글을 달았어요.", + style = MomentoTheme.typography.body02 , + color = MomentoTheme.colors.grayW20 + ) + + Text( + text = "제주도 동쪽 투어!", + style = MomentoTheme.typography.caption, + color = MomentoTheme.colors.grayW40 + ) + } + } + + Image( + modifier = Modifier.size(56.dp), + painter = image, + contentDescription = null + ) + } + + HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW80) +} + +@Preview +@Composable +fun BellScreenPreview() { + DngoTheme { + BellScreen() + } +} diff --git a/app/src/main/res/drawable/bell_comment.xml b/app/src/main/res/drawable/bell_comment.xml new file mode 100644 index 0000000..9c3e3ea --- /dev/null +++ b/app/src/main/res/drawable/bell_comment.xml @@ -0,0 +1,22 @@ + + + + + From 8676c61f018ba18fbe967b1f00afe7c7ae0b1c8f Mon Sep 17 00:00:00 2001 From: min486 Date: Fri, 17 Oct 2025 01:29:03 +0900 Subject: [PATCH 31/98] 251017 --- README.assets/architecture.png | Bin 0 -> 31406 bytes README.assets/momento.png | Bin 0 -> 6876 bytes README.assets/play.png | Bin 0 -> 4698 bytes README.md | 22 +++++++++++++++++++++- 4 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 README.assets/architecture.png create mode 100644 README.assets/momento.png create mode 100644 README.assets/play.png diff --git a/README.assets/architecture.png b/README.assets/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..f60f3f0a1a4e55816238c1a872e449421c9b4359 GIT binary patch literal 31406 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 Kwc?w$q5lO*d}Koa literal 0 HcmV?d00001 diff --git a/README.assets/play.png b/README.assets/play.png new file mode 100644 index 0000000000000000000000000000000000000000..7a06997a57236e18b5bd2a152435911b72371a89 GIT binary patch literal 4698 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 + momento + + play + +

+ +## 🏝️ 여행을 기록하는 가장 감성적인 방법, 모멘토 + +- 자신의 여행 이야기를 간단하게 기록할 수 있어요 +- 행복했던 순간들을 한눈에 모아 관리해보세요 +- 원한다면 여행기록을 다른 사용자와 공유할 수도 있어요 +- 공유된 여행은 새로운 여행지를 찾는 사람들에게 영감을 줍니다 + +
+ +## Android 앱 아키텍처 (MVVM + Clean Architecture) + +play \ No newline at end of file From fef5bbf2c2f55bbca5fc98ae7adef035a64c19c6 Mon Sep 17 00:00:00 2001 From: min486 Date: Fri, 17 Oct 2025 19:58:51 +0900 Subject: [PATCH 32/98] =?UTF-8?q?feat:=20BottomBar=20=EA=B5=AC=EC=84=B1=20?= =?UTF-8?q?=EB=B0=8F=20navigation=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- .../main/java/com/min/dnapp/MainActivity.kt | 56 +-- .../ui/component/MomentoBottomNav.kt | 112 ++++++ .../dnapp/presentation/ui/icon/__AppIcons.kt | 8 +- .../presentation/ui/icon/appicons/Explore.kt | 350 ++++++++++++++++++ .../presentation/ui/icon/appicons/Home.kt | 216 +++++++++++ .../dnapp/presentation/ui/icon/appicons/My.kt | 144 +++++++ app/src/main/res/drawable/ic_explore.xml | 22 ++ app/src/main/res/drawable/ic_home.xml | 16 + app/src/main/res/drawable/ic_my.xml | 20 + 10 files changed, 920 insertions(+), 28 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/component/MomentoBottomNav.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Explore.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Home.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/My.kt create mode 100644 app/src/main/res/drawable/ic_explore.xml create mode 100644 app/src/main/res/drawable/ic_home.xml create mode 100644 app/src/main/res/drawable/ic_my.xml diff --git a/README.md b/README.md index 3b670fd..2e18e31 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ # 모멘토

- momento + momento +   play

+ ## 🏝️ 여행을 기록하는 가장 감성적인 방법, 모멘토 - 자신의 여행 이야기를 간단하게 기록할 수 있어요 diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index 4f0b6c8..c97751f 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -3,8 +3,8 @@ package com.min.dnapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.Surface +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier @@ -13,14 +13,14 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable +import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import com.min.dnapp.presentation.AppStartViewModel -import com.min.dnapp.presentation.bell.BellScreen -import com.min.dnapp.presentation.find.FindDetailScreen import com.min.dnapp.presentation.find.FindScreen -import com.min.dnapp.presentation.home.HomeScreen import com.min.dnapp.presentation.home.HomeScreen2 import com.min.dnapp.presentation.login.LoginScreen +import com.min.dnapp.presentation.mypage.MypageScreen +import com.min.dnapp.presentation.ui.component.MomentoBottomNav import com.min.dnapp.presentation.ui.theme.DngoTheme import dagger.hilt.android.AndroidEntryPoint @@ -34,20 +34,7 @@ class MainActivity : ComponentActivity() { // enableEdgeToEdge() setContent { DngoTheme { -// MomentoApp() -// LoginScreen2() -// OnboardingScreen() -// OnboardingScreen2() -// OnboardingScreen3() -// ProfileSetupScreen() -// MypageScreen() -// SettingScreen() -// RecordWriteScreen() -// WriteFinishScreen() -// FindScreen() -// FindDetailScreen() -// HomeScreen2() - BellScreen() + MomentoApp() } } } @@ -61,20 +48,39 @@ fun MomentoApp( val startDestination = if (isLogin) "home" else "login" val navController = rememberNavController() + val navBackStackEntry by navController.currentBackStackEntryAsState() + val currentRoute = navBackStackEntry?.destination?.route ?: "home" - Surface( - modifier = Modifier.fillMaxSize() - ) { + Scaffold( + bottomBar = { + MomentoBottomNav( + currentRoute = currentRoute, + onNavItemClick = { route -> + // 현재 경로와 다를때만 navigate 호출 + if (navController.currentDestination?.route != route) { + navController.navigate(route) + } + } + ) + } + ) { paddingValues -> NavHost( + modifier = Modifier.padding(paddingValues), navController = navController, - startDestination = startDestination +// startDestination = startDestination + startDestination = "home" ) { composable("login") { LoginScreen(navController = navController) } - composable("home") { - HomeScreen(navController = navController) + HomeScreen2() + } + composable("explore") { + FindScreen() + } + composable("my") { + MypageScreen() } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/component/MomentoBottomNav.kt b/app/src/main/java/com/min/dnapp/presentation/ui/component/MomentoBottomNav.kt new file mode 100644 index 0000000..48c6c81 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/component/MomentoBottomNav.kt @@ -0,0 +1,112 @@ +package com.min.dnapp.presentation.ui.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement +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.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.R +import com.min.dnapp.presentation.ui.icon.AppIcons +import com.min.dnapp.presentation.ui.icon.appicons.Explore +import com.min.dnapp.presentation.ui.icon.appicons.Home +import com.min.dnapp.presentation.ui.icon.appicons.My +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +data class BottonNavItem( + val icon: ImageVector, + val selectedIcon: Int, + val label: String, + val route: String +) + +@Composable +fun MomentoBottomNav( + currentRoute: String, + onNavItemClick: (String) -> Unit +) { + val items = listOf( + BottonNavItem(AppIcons.Home, R.drawable.ic_home, "Home", "home"), + BottonNavItem(AppIcons.Explore, R.drawable.ic_explore, "Explore", "explore"), + BottonNavItem(AppIcons.My, R.drawable.ic_my, "My", "my") + ) + + Column( + modifier = Modifier.fillMaxWidth() + ) { + Row( + modifier = Modifier + .fillMaxWidth() +// .height(56.dp) + .height(58.dp) + .background(color = MomentoTheme.colors.white), + horizontalArrangement = Arrangement.SpaceAround + ) { + items.forEach { item -> + val selected = currentRoute == item.route + + Column( + modifier = Modifier + .weight(1f) + .fillMaxHeight() + .clickable( + // 리플효과 제거 + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { + onNavItemClick(item.route) + }, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(Modifier.height(6.dp)) + + // bottomBar 아이콘 + if (selected) { + Image( + painter = painterResource(item.selectedIcon), + contentDescription = null + ) + } else { + Icon( + imageVector = item.icon, + contentDescription = null, + tint = if (selected) MomentoTheme.colors.brownBase else MomentoTheme.colors.grayW60 + ) + } + + Text( + text = item.label, + style = MomentoTheme.typography.label, + color = if (selected) MomentoTheme.colors.brownB40 else MomentoTheme.colors.grayW60 + ) + } + } + } + } +} + +@Preview +@Composable +fun MomentoBottomNavPreview() { + DngoTheme { + MomentoBottomNav( + currentRoute = "home" + ) { } + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt index 2914353..c4995e6 100644 --- a/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt @@ -6,9 +6,12 @@ import com.min.dnapp.presentation.ui.icon.appicons.Back import com.min.dnapp.presentation.ui.icon.appicons.Bell import com.min.dnapp.presentation.ui.icon.appicons.Calendar import com.min.dnapp.presentation.ui.icon.appicons.Delete +import com.min.dnapp.presentation.ui.icon.appicons.Explore import com.min.dnapp.presentation.ui.icon.appicons.Gallery +import com.min.dnapp.presentation.ui.icon.appicons.Home import com.min.dnapp.presentation.ui.icon.appicons.Kakao import com.min.dnapp.presentation.ui.icon.appicons.More +import com.min.dnapp.presentation.ui.icon.appicons.My import com.min.dnapp.presentation.ui.icon.appicons.PenSmall import com.min.dnapp.presentation.ui.icon.appicons.RecordBest import com.min.dnapp.presentation.ui.icon.appicons.RecordBookmark @@ -27,7 +30,8 @@ public val AppIcons.AllIcons: ____KtList if (__AllIcons != null) { return __AllIcons!! } - __AllIcons= listOf(ArrowRight, Back, Bell, Calendar, Delete, Gallery, Kakao, More, PenSmall, - RecordBest, RecordBookmark, RecordComment, RecordLike, RecordSurprise, Year) + __AllIcons= listOf(ArrowRight, Back, Bell, Calendar, Delete, Explore, Gallery, Home, Kakao, + More, My, PenSmall, RecordBest, RecordBookmark, RecordComment, RecordLike, RecordSurprise, + Year) return __AllIcons!! } diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Explore.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Explore.kt new file mode 100644 index 0000000..1f15b2a --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Explore.kt @@ -0,0 +1,350 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.Explore: ImageVector + get() { + if (_explore != null) { + return _explore!! + } + _explore = Builder(name = "Explore", defaultWidth = 28.0.dp, defaultHeight = 29.0.dp, + viewportWidth = 28.0f, viewportHeight = 29.0f).apply { + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(16.941f, 9.833f) + curveTo(16.941f, 8.222f, 15.635f, 6.917f, 14.024f, 6.917f) + curveTo(12.413f, 6.917f, 11.107f, 8.222f, 11.107f, 9.833f) + curveTo(11.107f, 11.444f, 12.413f, 12.75f, 14.024f, 12.75f) + curveTo(15.635f, 12.75f, 16.941f, 11.444f, 16.941f, 9.833f) + close() + moveTo(18.107f, 9.833f) + curveTo(18.107f, 12.089f, 16.279f, 13.917f, 14.024f, 13.917f) + curveTo(11.769f, 13.917f, 9.941f, 12.089f, 9.941f, 9.833f) + curveTo(9.941f, 7.578f, 11.769f, 5.75f, 14.024f, 5.75f) + curveTo(16.279f, 5.75f, 18.107f, 7.578f, 18.107f, 9.833f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(16.941f, 9.833f) + curveTo(16.941f, 8.222f, 15.635f, 6.917f, 14.024f, 6.917f) + curveTo(12.413f, 6.917f, 11.107f, 8.222f, 11.107f, 9.833f) + curveTo(11.107f, 11.444f, 12.413f, 12.75f, 14.024f, 12.75f) + curveTo(15.635f, 12.75f, 16.941f, 11.444f, 16.941f, 9.833f) + close() + moveTo(18.107f, 9.833f) + curveTo(18.107f, 12.089f, 16.279f, 13.917f, 14.024f, 13.917f) + curveTo(11.769f, 13.917f, 9.941f, 12.089f, 9.941f, 9.833f) + curveTo(9.941f, 7.578f, 11.769f, 5.75f, 14.024f, 5.75f) + curveTo(16.279f, 5.75f, 18.107f, 7.578f, 18.107f, 9.833f) + close() + } + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(8.573f, 8.094f) + curveTo(8.955f, 8.143f, 9.322f, 8.268f, 9.656f, 8.461f) + curveTo(9.989f, 8.653f, 10.281f, 8.909f, 10.514f, 9.215f) + curveTo(10.748f, 9.52f, 10.919f, 9.87f, 11.017f, 10.241f) + curveTo(11.115f, 10.613f, 11.139f, 11.001f, 11.087f, 11.382f) + curveTo(11.034f, 11.763f, 10.907f, 12.13f, 10.713f, 12.462f) + curveTo(10.323f, 13.126f, 9.687f, 13.609f, 8.942f, 13.806f) + curveTo(8.198f, 14.003f, 7.406f, 13.897f, 6.739f, 13.512f) + curveTo(6.072f, 13.127f, 5.584f, 12.494f, 5.382f, 11.751f) + curveTo(5.18f, 11.008f, 5.282f, 10.215f, 5.662f, 9.545f) + curveTo(5.852f, 9.211f, 6.107f, 8.917f, 6.411f, 8.682f) + curveTo(6.715f, 8.446f, 7.062f, 8.272f, 7.433f, 8.171f) + curveTo(7.804f, 8.07f, 8.192f, 8.044f, 8.573f, 8.094f) + close() + moveTo(20.24f, 8.094f) + curveTo(20.621f, 8.143f, 20.989f, 8.268f, 21.322f, 8.461f) + curveTo(21.655f, 8.653f, 21.948f, 8.909f, 22.181f, 9.215f) + curveTo(22.415f, 9.52f, 22.585f, 9.87f, 22.684f, 10.241f) + curveTo(22.782f, 10.613f, 22.805f, 11.001f, 22.753f, 11.382f) + curveTo(22.701f, 11.763f, 22.574f, 12.13f, 22.379f, 12.462f) + curveTo(21.99f, 13.126f, 21.353f, 13.609f, 20.609f, 13.806f) + curveTo(19.865f, 14.003f, 19.072f, 13.897f, 18.406f, 13.512f) + curveTo(17.739f, 13.127f, 17.25f, 12.494f, 17.049f, 11.751f) + curveTo(16.847f, 11.008f, 16.948f, 10.215f, 17.329f, 9.545f) + curveTo(17.519f, 9.211f, 17.773f, 8.917f, 18.077f, 8.682f) + curveTo(18.381f, 8.446f, 18.728f, 8.272f, 19.099f, 8.171f) + curveTo(19.471f, 8.07f, 19.858f, 8.044f, 20.24f, 8.094f) + close() + moveTo(8.423f, 9.251f) + curveTo(8.194f, 9.222f, 7.962f, 9.238f, 7.739f, 9.298f) + curveTo(7.516f, 9.358f, 7.307f, 9.462f, 7.125f, 9.603f) + curveTo(6.943f, 9.745f, 6.79f, 9.921f, 6.676f, 10.122f) + curveTo(6.448f, 10.523f, 6.388f, 10.999f, 6.509f, 11.444f) + curveTo(6.63f, 11.89f, 6.922f, 12.271f, 7.322f, 12.502f) + curveTo(7.722f, 12.733f, 8.198f, 12.796f, 8.645f, 12.678f) + curveTo(9.091f, 12.56f, 9.473f, 12.27f, 9.707f, 11.872f) + curveTo(9.823f, 11.673f, 9.9f, 11.452f, 9.931f, 11.223f) + curveTo(9.962f, 10.995f, 9.948f, 10.762f, 9.889f, 10.539f) + curveTo(9.83f, 10.316f, 9.727f, 10.107f, 9.587f, 9.923f) + curveTo(9.447f, 9.74f, 9.272f, 9.587f, 9.072f, 9.471f) + curveTo(8.872f, 9.356f, 8.652f, 9.281f, 8.423f, 9.251f) + close() + moveTo(20.089f, 9.251f) + curveTo(19.861f, 9.222f, 19.628f, 9.238f, 19.406f, 9.298f) + curveTo(19.183f, 9.358f, 18.974f, 9.462f, 18.792f, 9.603f) + curveTo(18.609f, 9.745f, 18.457f, 9.921f, 18.343f, 10.122f) + curveTo(18.115f, 10.523f, 18.054f, 10.999f, 18.175f, 11.444f) + curveTo(18.296f, 11.89f, 18.589f, 12.271f, 18.989f, 12.502f) + curveTo(19.389f, 12.733f, 19.865f, 12.796f, 20.312f, 12.678f) + curveTo(20.758f, 12.56f, 21.14f, 12.27f, 21.373f, 11.872f) + curveTo(21.49f, 11.673f, 21.567f, 11.452f, 21.598f, 11.223f) + curveTo(21.629f, 10.995f, 21.615f, 10.762f, 21.556f, 10.539f) + curveTo(21.497f, 10.316f, 21.394f, 10.107f, 21.254f, 9.923f) + curveTo(21.114f, 9.74f, 20.939f, 9.587f, 20.739f, 9.471f) + curveTo(20.539f, 9.356f, 20.318f, 9.281f, 20.089f, 9.251f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(8.573f, 8.094f) + curveTo(8.955f, 8.143f, 9.322f, 8.268f, 9.656f, 8.461f) + curveTo(9.989f, 8.653f, 10.281f, 8.909f, 10.514f, 9.215f) + curveTo(10.748f, 9.52f, 10.919f, 9.87f, 11.017f, 10.241f) + curveTo(11.115f, 10.613f, 11.139f, 11.001f, 11.087f, 11.382f) + curveTo(11.034f, 11.763f, 10.907f, 12.13f, 10.713f, 12.462f) + curveTo(10.323f, 13.126f, 9.687f, 13.609f, 8.942f, 13.806f) + curveTo(8.198f, 14.003f, 7.406f, 13.897f, 6.739f, 13.512f) + curveTo(6.072f, 13.127f, 5.584f, 12.494f, 5.382f, 11.751f) + curveTo(5.18f, 11.008f, 5.282f, 10.215f, 5.662f, 9.545f) + curveTo(5.852f, 9.211f, 6.107f, 8.917f, 6.411f, 8.682f) + curveTo(6.715f, 8.446f, 7.062f, 8.272f, 7.433f, 8.171f) + curveTo(7.804f, 8.07f, 8.192f, 8.044f, 8.573f, 8.094f) + close() + moveTo(20.24f, 8.094f) + curveTo(20.621f, 8.143f, 20.989f, 8.268f, 21.322f, 8.461f) + curveTo(21.655f, 8.653f, 21.948f, 8.909f, 22.181f, 9.215f) + curveTo(22.415f, 9.52f, 22.585f, 9.87f, 22.684f, 10.241f) + curveTo(22.782f, 10.613f, 22.805f, 11.001f, 22.753f, 11.382f) + curveTo(22.701f, 11.763f, 22.574f, 12.13f, 22.379f, 12.462f) + curveTo(21.99f, 13.126f, 21.353f, 13.609f, 20.609f, 13.806f) + curveTo(19.865f, 14.003f, 19.072f, 13.897f, 18.406f, 13.512f) + curveTo(17.739f, 13.127f, 17.25f, 12.494f, 17.049f, 11.751f) + curveTo(16.847f, 11.008f, 16.948f, 10.215f, 17.329f, 9.545f) + curveTo(17.519f, 9.211f, 17.773f, 8.917f, 18.077f, 8.682f) + curveTo(18.381f, 8.446f, 18.728f, 8.272f, 19.099f, 8.171f) + curveTo(19.471f, 8.07f, 19.858f, 8.044f, 20.24f, 8.094f) + close() + moveTo(8.423f, 9.251f) + curveTo(8.194f, 9.222f, 7.962f, 9.238f, 7.739f, 9.298f) + curveTo(7.516f, 9.358f, 7.307f, 9.462f, 7.125f, 9.603f) + curveTo(6.943f, 9.745f, 6.79f, 9.921f, 6.676f, 10.122f) + curveTo(6.448f, 10.523f, 6.388f, 10.999f, 6.509f, 11.444f) + curveTo(6.63f, 11.89f, 6.922f, 12.271f, 7.322f, 12.502f) + curveTo(7.722f, 12.733f, 8.198f, 12.796f, 8.645f, 12.678f) + curveTo(9.091f, 12.56f, 9.473f, 12.27f, 9.707f, 11.872f) + curveTo(9.823f, 11.673f, 9.9f, 11.452f, 9.931f, 11.223f) + curveTo(9.962f, 10.995f, 9.948f, 10.762f, 9.889f, 10.539f) + curveTo(9.83f, 10.316f, 9.727f, 10.107f, 9.587f, 9.923f) + curveTo(9.447f, 9.74f, 9.272f, 9.587f, 9.072f, 9.471f) + curveTo(8.872f, 9.356f, 8.652f, 9.281f, 8.423f, 9.251f) + close() + moveTo(20.089f, 9.251f) + curveTo(19.861f, 9.222f, 19.628f, 9.238f, 19.406f, 9.298f) + curveTo(19.183f, 9.358f, 18.974f, 9.462f, 18.792f, 9.603f) + curveTo(18.609f, 9.745f, 18.457f, 9.921f, 18.343f, 10.122f) + curveTo(18.115f, 10.523f, 18.054f, 10.999f, 18.175f, 11.444f) + curveTo(18.296f, 11.89f, 18.589f, 12.271f, 18.989f, 12.502f) + curveTo(19.389f, 12.733f, 19.865f, 12.796f, 20.312f, 12.678f) + curveTo(20.758f, 12.56f, 21.14f, 12.27f, 21.373f, 11.872f) + curveTo(21.49f, 11.673f, 21.567f, 11.452f, 21.598f, 11.223f) + curveTo(21.629f, 10.995f, 21.615f, 10.762f, 21.556f, 10.539f) + curveTo(21.497f, 10.316f, 21.394f, 10.107f, 21.254f, 9.923f) + curveTo(21.114f, 9.74f, 20.939f, 9.587f, 20.739f, 9.471f) + curveTo(20.539f, 9.356f, 20.318f, 9.281f, 20.089f, 9.251f) + close() + } + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(14.024f, 16.25f) + curveTo(16.265f, 16.25f, 17.765f, 17.058f, 18.742f, 18.144f) + curveTo(19.7f, 19.208f, 20.113f, 20.492f, 20.293f, 21.396f) + horizontalLineTo(20.292f) + curveTo(20.505f, 22.455f, 19.633f, 23.25f, 18.69f, 23.25f) + horizontalLineTo(9.357f) + curveTo(8.416f, 23.25f, 7.542f, 22.454f, 7.755f, 21.395f) + curveTo(7.936f, 20.49f, 8.349f, 19.208f, 9.307f, 18.144f) + curveTo(10.283f, 17.059f, 11.783f, 16.25f, 14.024f, 16.25f) + close() + moveTo(14.024f, 17.417f) + curveTo(12.098f, 17.417f, 10.919f, 18.096f, 10.174f, 18.924f) + curveTo(9.41f, 19.772f, 9.058f, 20.827f, 8.899f, 21.624f) + verticalLineTo(21.625f) + curveTo(8.874f, 21.748f, 8.909f, 21.85f, 8.983f, 21.931f) + curveTo(9.062f, 22.017f, 9.193f, 22.083f, 9.357f, 22.083f) + horizontalLineTo(18.69f) + curveTo(18.855f, 22.083f, 18.986f, 22.016f, 19.065f, 21.931f) + curveTo(19.139f, 21.85f, 19.174f, 21.748f, 19.149f, 21.625f) + lineTo(19.148f, 21.624f) + curveTo(18.989f, 20.828f, 18.638f, 19.772f, 17.875f, 18.924f) + curveTo(17.129f, 18.096f, 15.95f, 17.417f, 14.024f, 17.417f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(14.024f, 16.25f) + curveTo(16.265f, 16.25f, 17.765f, 17.058f, 18.742f, 18.144f) + curveTo(19.7f, 19.208f, 20.113f, 20.492f, 20.293f, 21.396f) + horizontalLineTo(20.292f) + curveTo(20.505f, 22.455f, 19.633f, 23.25f, 18.69f, 23.25f) + horizontalLineTo(9.357f) + curveTo(8.416f, 23.25f, 7.542f, 22.454f, 7.755f, 21.395f) + curveTo(7.936f, 20.49f, 8.349f, 19.208f, 9.307f, 18.144f) + curveTo(10.283f, 17.059f, 11.783f, 16.25f, 14.024f, 16.25f) + close() + moveTo(14.024f, 17.417f) + curveTo(12.098f, 17.417f, 10.919f, 18.096f, 10.174f, 18.924f) + curveTo(9.41f, 19.772f, 9.058f, 20.827f, 8.899f, 21.624f) + verticalLineTo(21.625f) + curveTo(8.874f, 21.748f, 8.909f, 21.85f, 8.983f, 21.931f) + curveTo(9.062f, 22.017f, 9.193f, 22.083f, 9.357f, 22.083f) + horizontalLineTo(18.69f) + curveTo(18.855f, 22.083f, 18.986f, 22.016f, 19.065f, 21.931f) + curveTo(19.139f, 21.85f, 19.174f, 21.748f, 19.149f, 21.625f) + lineTo(19.148f, 21.624f) + curveTo(18.989f, 20.828f, 18.638f, 19.772f, 17.875f, 18.924f) + curveTo(17.129f, 18.096f, 15.95f, 17.417f, 14.024f, 17.417f) + close() + } + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(8.166f, 15.551f) + curveTo(9.224f, 15.538f, 10.249f, 15.925f, 11.034f, 16.634f) + lineTo(11.597f, 17.144f) + lineTo(10.96f, 17.556f) + curveTo(9.382f, 18.579f, 8.524f, 20.406f, 8.067f, 22.117f) + lineTo(7.952f, 22.55f) + horizontalLineTo(4.789f) + curveTo(3.772f, 22.55f, 2.9f, 21.649f, 3.17f, 20.562f) + lineTo(3.172f, 20.56f) + curveTo(3.395f, 19.67f, 3.812f, 18.441f, 4.576f, 17.424f) + curveTo(5.351f, 16.392f, 6.506f, 15.554f, 8.158f, 15.551f) + curveTo(8.16f, 15.551f, 8.162f, 15.551f, 8.164f, 15.551f) + lineTo(8.166f, 15.55f) + verticalLineTo(15.551f) + close() + moveTo(19.833f, 15.55f) + curveTo(21.49f, 15.55f, 22.648f, 16.39f, 23.424f, 17.424f) + curveTo(24.093f, 18.314f, 24.496f, 19.367f, 24.736f, 20.212f) + lineTo(24.829f, 20.56f) + verticalLineTo(20.562f) + curveTo(25.1f, 21.649f, 24.228f, 22.55f, 23.211f, 22.55f) + horizontalLineTo(20.049f) + lineTo(19.933f, 22.117f) + curveTo(19.477f, 20.407f, 18.619f, 18.579f, 17.041f, 17.556f) + lineTo(16.397f, 17.139f) + lineTo(16.971f, 16.63f) + curveTo(17.7f, 15.985f, 18.644f, 15.55f, 19.833f, 15.55f) + close() + moveTo(8.166f, 16.716f) + curveTo(6.967f, 16.717f, 6.125f, 17.303f, 5.508f, 18.125f) + curveTo(4.879f, 18.963f, 4.51f, 20.019f, 4.303f, 20.844f) + curveTo(4.241f, 21.096f, 4.426f, 21.383f, 4.789f, 21.383f) + horizontalLineTo(7.065f) + curveTo(7.513f, 19.898f, 8.29f, 18.249f, 9.652f, 17.081f) + curveTo(9.201f, 16.839f, 8.694f, 16.709f, 8.174f, 16.716f) + horizontalLineTo(8.166f) + close() + moveTo(19.833f, 16.716f) + curveTo(19.256f, 16.716f, 18.767f, 16.854f, 18.347f, 17.081f) + curveTo(19.71f, 18.249f, 20.488f, 19.897f, 20.937f, 21.383f) + horizontalLineTo(23.211f) + curveTo(23.575f, 21.383f, 23.76f, 21.096f, 23.698f, 20.844f) + lineTo(23.612f, 20.525f) + curveTo(23.394f, 19.759f, 23.042f, 18.858f, 22.491f, 18.125f) + curveTo(21.874f, 17.303f, 21.032f, 16.716f, 19.833f, 16.716f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(8.166f, 15.551f) + curveTo(9.224f, 15.538f, 10.249f, 15.925f, 11.034f, 16.634f) + lineTo(11.597f, 17.144f) + lineTo(10.96f, 17.556f) + curveTo(9.382f, 18.579f, 8.524f, 20.406f, 8.067f, 22.117f) + lineTo(7.952f, 22.55f) + horizontalLineTo(4.789f) + curveTo(3.772f, 22.55f, 2.9f, 21.649f, 3.17f, 20.562f) + lineTo(3.172f, 20.56f) + curveTo(3.395f, 19.67f, 3.812f, 18.441f, 4.576f, 17.424f) + curveTo(5.351f, 16.392f, 6.506f, 15.554f, 8.158f, 15.551f) + curveTo(8.16f, 15.551f, 8.162f, 15.551f, 8.164f, 15.551f) + lineTo(8.166f, 15.55f) + verticalLineTo(15.551f) + close() + moveTo(19.833f, 15.55f) + curveTo(21.49f, 15.55f, 22.648f, 16.39f, 23.424f, 17.424f) + curveTo(24.093f, 18.314f, 24.496f, 19.367f, 24.736f, 20.212f) + lineTo(24.829f, 20.56f) + verticalLineTo(20.562f) + curveTo(25.1f, 21.649f, 24.228f, 22.55f, 23.211f, 22.55f) + horizontalLineTo(20.049f) + lineTo(19.933f, 22.117f) + curveTo(19.477f, 20.407f, 18.619f, 18.579f, 17.041f, 17.556f) + lineTo(16.397f, 17.139f) + lineTo(16.971f, 16.63f) + curveTo(17.7f, 15.985f, 18.644f, 15.55f, 19.833f, 15.55f) + close() + moveTo(8.166f, 16.716f) + curveTo(6.967f, 16.717f, 6.125f, 17.303f, 5.508f, 18.125f) + curveTo(4.879f, 18.963f, 4.51f, 20.019f, 4.303f, 20.844f) + curveTo(4.241f, 21.096f, 4.426f, 21.383f, 4.789f, 21.383f) + horizontalLineTo(7.065f) + curveTo(7.513f, 19.898f, 8.29f, 18.249f, 9.652f, 17.081f) + curveTo(9.201f, 16.839f, 8.694f, 16.709f, 8.174f, 16.716f) + horizontalLineTo(8.166f) + close() + moveTo(19.833f, 16.716f) + curveTo(19.256f, 16.716f, 18.767f, 16.854f, 18.347f, 17.081f) + curveTo(19.71f, 18.249f, 20.488f, 19.897f, 20.937f, 21.383f) + horizontalLineTo(23.211f) + curveTo(23.575f, 21.383f, 23.76f, 21.096f, 23.698f, 20.844f) + lineTo(23.612f, 20.525f) + curveTo(23.394f, 19.759f, 23.042f, 18.858f, 22.491f, 18.125f) + curveTo(21.874f, 17.303f, 21.032f, 16.716f, 19.833f, 16.716f) + close() + } + } + .build() + return _explore!! + } + +private var _explore: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.Explore, contentDescription = "") + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Home.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Home.kt new file mode 100644 index 0000000..c4779e5 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Home.kt @@ -0,0 +1,216 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.Home: ImageVector + get() { + if (_home != null) { + return _home!! + } + _home = Builder(name = "Home", defaultWidth = 29.0.dp, defaultHeight = 29.0.dp, + viewportWidth = 29.0f, viewportHeight = 29.0f).apply { + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(23.25f, 12.167f) + curveTo(23.25f, 12.012f, 23.189f, 11.864f, 23.079f, 11.755f) + curveTo(22.97f, 11.645f, 22.822f, 11.584f, 22.667f, 11.584f) + curveTo(22.512f, 11.584f, 22.364f, 11.645f, 22.254f, 11.755f) + curveTo(22.145f, 11.864f, 22.083f, 12.012f, 22.083f, 12.167f) + horizontalLineTo(23.25f) + close() + moveTo(6.917f, 12.167f) + curveTo(6.917f, 12.012f, 6.855f, 11.864f, 6.746f, 11.755f) + curveTo(6.636f, 11.645f, 6.488f, 11.584f, 6.333f, 11.584f) + curveTo(6.179f, 11.584f, 6.03f, 11.645f, 5.921f, 11.755f) + curveTo(5.812f, 11.864f, 5.75f, 12.012f, 5.75f, 12.167f) + horizontalLineTo(6.917f) + close() + moveTo(24.587f, 14.913f) + curveTo(24.697f, 15.023f, 24.845f, 15.085f, 25.0f, 15.085f) + curveTo(25.155f, 15.085f, 25.304f, 15.023f, 25.413f, 14.913f) + curveTo(25.523f, 14.804f, 25.584f, 14.655f, 25.584f, 14.5f) + curveTo(25.584f, 14.345f, 25.523f, 14.197f, 25.413f, 14.087f) + lineTo(24.587f, 14.913f) + close() + moveTo(14.5f, 4.0f) + lineTo(14.913f, 3.587f) + curveTo(14.859f, 3.533f, 14.795f, 3.49f, 14.724f, 3.461f) + curveTo(14.653f, 3.431f, 14.577f, 3.416f, 14.5f, 3.416f) + curveTo(14.423f, 3.416f, 14.347f, 3.431f, 14.276f, 3.461f) + curveTo(14.206f, 3.49f, 14.141f, 3.533f, 14.087f, 3.587f) + lineTo(14.5f, 4.0f) + close() + moveTo(3.587f, 14.087f) + curveTo(3.478f, 14.197f, 3.416f, 14.345f, 3.416f, 14.5f) + curveTo(3.416f, 14.655f, 3.478f, 14.804f, 3.587f, 14.913f) + curveTo(3.697f, 15.023f, 3.845f, 15.085f, 4.0f, 15.085f) + curveTo(4.155f, 15.085f, 4.304f, 15.023f, 4.413f, 14.913f) + lineTo(3.587f, 14.087f) + close() + moveTo(8.667f, 25.584f) + horizontalLineTo(20.333f) + verticalLineTo(24.417f) + horizontalLineTo(8.667f) + verticalLineTo(25.584f) + close() + moveTo(23.25f, 22.667f) + verticalLineTo(12.167f) + horizontalLineTo(22.083f) + verticalLineTo(22.667f) + horizontalLineTo(23.25f) + close() + moveTo(6.917f, 22.667f) + verticalLineTo(12.167f) + horizontalLineTo(5.75f) + verticalLineTo(22.667f) + horizontalLineTo(6.917f) + close() + moveTo(25.413f, 14.087f) + lineTo(14.913f, 3.587f) + lineTo(14.087f, 4.413f) + lineTo(24.587f, 14.913f) + lineTo(25.413f, 14.087f) + close() + moveTo(14.087f, 3.587f) + lineTo(3.587f, 14.087f) + lineTo(4.413f, 14.913f) + lineTo(14.913f, 4.413f) + lineTo(14.087f, 3.587f) + close() + moveTo(20.333f, 25.584f) + curveTo(21.107f, 25.584f, 21.849f, 25.276f, 22.396f, 24.729f) + curveTo(22.943f, 24.183f, 23.25f, 23.441f, 23.25f, 22.667f) + horizontalLineTo(22.083f) + curveTo(22.083f, 23.131f, 21.899f, 23.576f, 21.571f, 23.904f) + curveTo(21.243f, 24.233f, 20.798f, 24.417f, 20.333f, 24.417f) + verticalLineTo(25.584f) + close() + moveTo(8.667f, 24.417f) + curveTo(8.203f, 24.417f, 7.758f, 24.233f, 7.429f, 23.904f) + curveTo(7.101f, 23.576f, 6.917f, 23.131f, 6.917f, 22.667f) + horizontalLineTo(5.75f) + curveTo(5.75f, 23.441f, 6.057f, 24.183f, 6.604f, 24.729f) + curveTo(7.151f, 25.276f, 7.893f, 25.584f, 8.667f, 25.584f) + verticalLineTo(24.417f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(23.25f, 12.167f) + curveTo(23.25f, 12.012f, 23.189f, 11.864f, 23.079f, 11.755f) + curveTo(22.97f, 11.645f, 22.822f, 11.584f, 22.667f, 11.584f) + curveTo(22.512f, 11.584f, 22.364f, 11.645f, 22.254f, 11.755f) + curveTo(22.145f, 11.864f, 22.083f, 12.012f, 22.083f, 12.167f) + horizontalLineTo(23.25f) + close() + moveTo(6.917f, 12.167f) + curveTo(6.917f, 12.012f, 6.855f, 11.864f, 6.746f, 11.755f) + curveTo(6.636f, 11.645f, 6.488f, 11.584f, 6.333f, 11.584f) + curveTo(6.179f, 11.584f, 6.03f, 11.645f, 5.921f, 11.755f) + curveTo(5.812f, 11.864f, 5.75f, 12.012f, 5.75f, 12.167f) + horizontalLineTo(6.917f) + close() + moveTo(24.587f, 14.913f) + curveTo(24.697f, 15.023f, 24.845f, 15.085f, 25.0f, 15.085f) + curveTo(25.155f, 15.085f, 25.304f, 15.023f, 25.413f, 14.913f) + curveTo(25.523f, 14.804f, 25.584f, 14.655f, 25.584f, 14.5f) + curveTo(25.584f, 14.345f, 25.523f, 14.197f, 25.413f, 14.087f) + lineTo(24.587f, 14.913f) + close() + moveTo(14.5f, 4.0f) + lineTo(14.913f, 3.587f) + curveTo(14.859f, 3.533f, 14.795f, 3.49f, 14.724f, 3.461f) + curveTo(14.653f, 3.431f, 14.577f, 3.416f, 14.5f, 3.416f) + curveTo(14.423f, 3.416f, 14.347f, 3.431f, 14.276f, 3.461f) + curveTo(14.206f, 3.49f, 14.141f, 3.533f, 14.087f, 3.587f) + lineTo(14.5f, 4.0f) + close() + moveTo(3.587f, 14.087f) + curveTo(3.478f, 14.197f, 3.416f, 14.345f, 3.416f, 14.5f) + curveTo(3.416f, 14.655f, 3.478f, 14.804f, 3.587f, 14.913f) + curveTo(3.697f, 15.023f, 3.845f, 15.085f, 4.0f, 15.085f) + curveTo(4.155f, 15.085f, 4.304f, 15.023f, 4.413f, 14.913f) + lineTo(3.587f, 14.087f) + close() + moveTo(8.667f, 25.584f) + horizontalLineTo(20.333f) + verticalLineTo(24.417f) + horizontalLineTo(8.667f) + verticalLineTo(25.584f) + close() + moveTo(23.25f, 22.667f) + verticalLineTo(12.167f) + horizontalLineTo(22.083f) + verticalLineTo(22.667f) + horizontalLineTo(23.25f) + close() + moveTo(6.917f, 22.667f) + verticalLineTo(12.167f) + horizontalLineTo(5.75f) + verticalLineTo(22.667f) + horizontalLineTo(6.917f) + close() + moveTo(25.413f, 14.087f) + lineTo(14.913f, 3.587f) + lineTo(14.087f, 4.413f) + lineTo(24.587f, 14.913f) + lineTo(25.413f, 14.087f) + close() + moveTo(14.087f, 3.587f) + lineTo(3.587f, 14.087f) + lineTo(4.413f, 14.913f) + lineTo(14.913f, 4.413f) + lineTo(14.087f, 3.587f) + close() + moveTo(20.333f, 25.584f) + curveTo(21.107f, 25.584f, 21.849f, 25.276f, 22.396f, 24.729f) + curveTo(22.943f, 24.183f, 23.25f, 23.441f, 23.25f, 22.667f) + horizontalLineTo(22.083f) + curveTo(22.083f, 23.131f, 21.899f, 23.576f, 21.571f, 23.904f) + curveTo(21.243f, 24.233f, 20.798f, 24.417f, 20.333f, 24.417f) + verticalLineTo(25.584f) + close() + moveTo(8.667f, 24.417f) + curveTo(8.203f, 24.417f, 7.758f, 24.233f, 7.429f, 23.904f) + curveTo(7.101f, 23.576f, 6.917f, 23.131f, 6.917f, 22.667f) + horizontalLineTo(5.75f) + curveTo(5.75f, 23.441f, 6.057f, 24.183f, 6.604f, 24.729f) + curveTo(7.151f, 25.276f, 7.893f, 25.584f, 8.667f, 25.584f) + verticalLineTo(24.417f) + close() + } + } + .build() + return _home!! + } + +private var _home: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.Home, contentDescription = "") + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/My.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/My.kt new file mode 100644 index 0000000..f5fb11f --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/My.kt @@ -0,0 +1,144 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.My: ImageVector + get() { + if (_my != null) { + return _my!! + } + _my = Builder(name = "My", defaultWidth = 29.0.dp, defaultHeight = 29.0.dp, viewportWidth = + 29.0f, viewportHeight = 29.0f).apply { + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(17.417f, 12.166f) + curveTo(17.417f, 10.556f, 16.111f, 9.25f, 14.5f, 9.25f) + curveTo(12.889f, 9.25f, 11.583f, 10.556f, 11.583f, 12.166f) + curveTo(11.583f, 13.777f, 12.889f, 15.083f, 14.5f, 15.083f) + curveTo(16.111f, 15.083f, 17.417f, 13.777f, 17.417f, 12.166f) + close() + moveTo(18.583f, 12.166f) + curveTo(18.583f, 14.422f, 16.755f, 16.25f, 14.5f, 16.25f) + curveTo(12.245f, 16.25f, 10.417f, 14.422f, 10.417f, 12.166f) + curveTo(10.417f, 9.911f, 12.245f, 8.083f, 14.5f, 8.083f) + curveTo(16.755f, 8.083f, 18.583f, 9.911f, 18.583f, 12.166f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(17.417f, 12.166f) + curveTo(17.417f, 10.556f, 16.111f, 9.25f, 14.5f, 9.25f) + curveTo(12.889f, 9.25f, 11.583f, 10.556f, 11.583f, 12.166f) + curveTo(11.583f, 13.777f, 12.889f, 15.083f, 14.5f, 15.083f) + curveTo(16.111f, 15.083f, 17.417f, 13.777f, 17.417f, 12.166f) + close() + moveTo(18.583f, 12.166f) + curveTo(18.583f, 14.422f, 16.755f, 16.25f, 14.5f, 16.25f) + curveTo(12.245f, 16.25f, 10.417f, 14.422f, 10.417f, 12.166f) + curveTo(10.417f, 9.911f, 12.245f, 8.083f, 14.5f, 8.083f) + curveTo(16.755f, 8.083f, 18.583f, 9.911f, 18.583f, 12.166f) + close() + } + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(24.417f, 14.5f) + curveTo(24.417f, 9.023f, 19.977f, 4.583f, 14.5f, 4.583f) + curveTo(9.023f, 4.583f, 4.583f, 9.023f, 4.583f, 14.5f) + curveTo(4.583f, 19.977f, 9.023f, 24.417f, 14.5f, 24.417f) + curveTo(19.977f, 24.417f, 24.417f, 19.977f, 24.417f, 14.5f) + close() + moveTo(25.583f, 14.5f) + curveTo(25.583f, 20.621f, 20.621f, 25.583f, 14.5f, 25.583f) + curveTo(8.379f, 25.583f, 3.417f, 20.621f, 3.417f, 14.5f) + curveTo(3.417f, 8.379f, 8.379f, 3.417f, 14.5f, 3.417f) + curveTo(20.621f, 3.417f, 25.583f, 8.379f, 25.583f, 14.5f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(24.417f, 14.5f) + curveTo(24.417f, 9.023f, 19.977f, 4.583f, 14.5f, 4.583f) + curveTo(9.023f, 4.583f, 4.583f, 9.023f, 4.583f, 14.5f) + curveTo(4.583f, 19.977f, 9.023f, 24.417f, 14.5f, 24.417f) + curveTo(19.977f, 24.417f, 24.417f, 19.977f, 24.417f, 14.5f) + close() + moveTo(25.583f, 14.5f) + curveTo(25.583f, 20.621f, 20.621f, 25.583f, 14.5f, 25.583f) + curveTo(8.379f, 25.583f, 3.417f, 20.621f, 3.417f, 14.5f) + curveTo(3.417f, 8.379f, 8.379f, 3.417f, 14.5f, 3.417f) + curveTo(20.621f, 3.417f, 25.583f, 8.379f, 25.583f, 14.5f) + close() + } + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(14.5f, 17.417f) + curveTo(16.195f, 17.417f, 17.853f, 17.866f, 19.218f, 18.708f) + curveTo(20.583f, 19.552f, 21.592f, 20.751f, 22.054f, 22.139f) + curveTo(22.156f, 22.445f, 21.99f, 22.775f, 21.685f, 22.877f) + curveTo(21.379f, 22.979f, 21.048f, 22.814f, 20.946f, 22.508f) + curveTo(20.582f, 21.415f, 19.771f, 20.421f, 18.605f, 19.701f) + curveTo(17.438f, 18.98f, 15.995f, 18.583f, 14.5f, 18.583f) + curveTo(13.005f, 18.583f, 11.561f, 18.98f, 10.395f, 19.701f) + curveTo(9.23f, 20.421f, 8.418f, 21.416f, 8.054f, 22.508f) + curveTo(7.952f, 22.814f, 7.621f, 22.979f, 7.315f, 22.877f) + curveTo(7.01f, 22.775f, 6.845f, 22.445f, 6.946f, 22.139f) + curveTo(7.408f, 20.751f, 8.418f, 19.551f, 9.782f, 18.708f) + curveTo(11.146f, 17.866f, 12.805f, 17.417f, 14.5f, 17.417f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(14.5f, 17.417f) + curveTo(16.195f, 17.417f, 17.853f, 17.866f, 19.218f, 18.708f) + curveTo(20.583f, 19.552f, 21.592f, 20.751f, 22.054f, 22.139f) + curveTo(22.156f, 22.445f, 21.99f, 22.775f, 21.685f, 22.877f) + curveTo(21.379f, 22.979f, 21.048f, 22.814f, 20.946f, 22.508f) + curveTo(20.582f, 21.415f, 19.771f, 20.421f, 18.605f, 19.701f) + curveTo(17.438f, 18.98f, 15.995f, 18.583f, 14.5f, 18.583f) + curveTo(13.005f, 18.583f, 11.561f, 18.98f, 10.395f, 19.701f) + curveTo(9.23f, 20.421f, 8.418f, 21.416f, 8.054f, 22.508f) + curveTo(7.952f, 22.814f, 7.621f, 22.979f, 7.315f, 22.877f) + curveTo(7.01f, 22.775f, 6.845f, 22.445f, 6.946f, 22.139f) + curveTo(7.408f, 20.751f, 8.418f, 19.551f, 9.782f, 18.708f) + curveTo(11.146f, 17.866f, 12.805f, 17.417f, 14.5f, 17.417f) + close() + } + } + .build() + return _my!! + } + +private var _my: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.My, contentDescription = "") + } +} diff --git a/app/src/main/res/drawable/ic_explore.xml b/app/src/main/res/drawable/ic_explore.xml new file mode 100644 index 0000000..4c647e3 --- /dev/null +++ b/app/src/main/res/drawable/ic_explore.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_home.xml b/app/src/main/res/drawable/ic_home.xml new file mode 100644 index 0000000..bb80386 --- /dev/null +++ b/app/src/main/res/drawable/ic_home.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_my.xml b/app/src/main/res/drawable/ic_my.xml new file mode 100644 index 0000000..0691659 --- /dev/null +++ b/app/src/main/res/drawable/ic_my.xml @@ -0,0 +1,20 @@ + + + + + + From b2608a780dede43e1ca9982e001012786a008bd4 Mon Sep 17 00:00:00 2001 From: min486 Date: Fri, 17 Oct 2025 20:23:29 +0900 Subject: [PATCH 33/98] =?UTF-8?q?feat:=20=ED=99=94=EB=A9=B4=EB=B3=84=20nav?= =?UTF-8?q?igation=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 42 +++++++++++++------ .../min/dnapp/presentation/bell/BellScreen.kt | 7 ++-- .../presentation/find/FindDetailScreen.kt | 7 ++-- .../min/dnapp/presentation/find/FindScreen.kt | 9 ++-- .../find/component/SharedRecordItem.kt | 11 +++-- .../dnapp/presentation/home/HomeScreen2.kt | 7 ++-- .../dnapp/presentation/login/LoginScreen2.kt | 9 ++-- 7 files changed, 61 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index c97751f..7d304f4 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -16,9 +16,11 @@ import androidx.navigation.compose.composable import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import com.min.dnapp.presentation.AppStartViewModel +import com.min.dnapp.presentation.bell.BellScreen +import com.min.dnapp.presentation.find.FindDetailScreen import com.min.dnapp.presentation.find.FindScreen import com.min.dnapp.presentation.home.HomeScreen2 -import com.min.dnapp.presentation.login.LoginScreen +import com.min.dnapp.presentation.login.LoginScreen2 import com.min.dnapp.presentation.mypage.MypageScreen import com.min.dnapp.presentation.ui.component.MomentoBottomNav import com.min.dnapp.presentation.ui.theme.DngoTheme @@ -51,37 +53,51 @@ fun MomentoApp( val navBackStackEntry by navController.currentBackStackEntryAsState() val currentRoute = navBackStackEntry?.destination?.route ?: "home" + val showBottomBar = when (currentRoute) { + "login", "bell", "explore_detail" -> false + else -> true + } + Scaffold( bottomBar = { - MomentoBottomNav( - currentRoute = currentRoute, - onNavItemClick = { route -> - // 현재 경로와 다를때만 navigate 호출 - if (navController.currentDestination?.route != route) { - navController.navigate(route) + if (showBottomBar) { + MomentoBottomNav( + currentRoute = currentRoute, + onNavItemClick = { route -> + // 현재 경로와 다를때만 navigate 호출 + if (navController.currentDestination?.route != route) { + navController.navigate(route) + } } - } - ) + ) + } } ) { paddingValues -> NavHost( modifier = Modifier.padding(paddingValues), navController = navController, // startDestination = startDestination - startDestination = "home" +// startDestination = "home" + startDestination = "login" ) { composable("login") { - LoginScreen(navController = navController) + LoginScreen2(navController = navController) } composable("home") { - HomeScreen2() + HomeScreen2(navController = navController) } composable("explore") { - FindScreen() + FindScreen(navController = navController) } composable("my") { MypageScreen() } + composable("bell") { + BellScreen(navController = navController) + } + composable("explore_detail") { + FindDetailScreen(navController = navController) + } } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/bell/BellScreen.kt b/app/src/main/java/com/min/dnapp/presentation/bell/BellScreen.kt index c98ea31..bef42fc 100644 --- a/app/src/main/java/com/min/dnapp/presentation/bell/BellScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/bell/BellScreen.kt @@ -24,6 +24,7 @@ import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController import com.min.dnapp.R import com.min.dnapp.presentation.ui.icon.AppIcons import com.min.dnapp.presentation.ui.icon.appicons.Back @@ -32,7 +33,7 @@ import com.min.dnapp.presentation.ui.theme.MomentoTheme @OptIn(ExperimentalMaterial3Api::class) @Composable -fun BellScreen() { +fun BellScreen(navController: NavHostController) { Scaffold( containerColor = MomentoTheme.colors.brownBg, topBar = { @@ -50,7 +51,7 @@ fun BellScreen() { navigationIcon = { Icon( modifier = Modifier - .clickable { } + .clickable { navController.popBackStack() } .padding(16.dp), imageVector = AppIcons.Back, contentDescription = null @@ -142,6 +143,6 @@ fun BellCommentItem( @Composable fun BellScreenPreview() { DngoTheme { - BellScreen() +// BellScreen() } } diff --git a/app/src/main/java/com/min/dnapp/presentation/find/FindDetailScreen.kt b/app/src/main/java/com/min/dnapp/presentation/find/FindDetailScreen.kt index 3d2d78a..017c8a0 100644 --- a/app/src/main/java/com/min/dnapp/presentation/find/FindDetailScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/find/FindDetailScreen.kt @@ -26,6 +26,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController import com.min.dnapp.R import com.min.dnapp.presentation.find.component.SharedRecordContentSection import com.min.dnapp.presentation.find.component.SharedRecordTimeSection @@ -43,7 +44,7 @@ import com.min.dnapp.presentation.ui.theme.MomentoTheme @OptIn(ExperimentalMaterial3Api::class) @Composable -fun FindDetailScreen() { +fun FindDetailScreen(navController: NavHostController) { Scaffold( containerColor = MomentoTheme.colors.brownBg, topBar = { @@ -61,7 +62,7 @@ fun FindDetailScreen() { navigationIcon = { Icon( modifier = Modifier - .clickable { } + .clickable { navController.popBackStack() } .padding(16.dp), imageVector = AppIcons.Back, contentDescription = null, @@ -318,6 +319,6 @@ fun CommentItem() { @Composable fun FindDetailScreenPreview() { DngoTheme { - FindDetailScreen() +// FindDetailScreen() } } diff --git a/app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt b/app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt index bd044db..1692a9f 100644 --- a/app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt @@ -18,6 +18,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController import com.min.dnapp.R import com.min.dnapp.presentation.find.component.SharedRecordItem import com.min.dnapp.presentation.ui.icon.AppIcons @@ -27,7 +28,7 @@ import com.min.dnapp.presentation.ui.theme.MomentoTheme @OptIn(ExperimentalMaterial3Api::class) @Composable -fun FindScreen() { +fun FindScreen(navController: NavHostController) { Scaffold( containerColor = MomentoTheme.colors.brownBg, topBar = { @@ -74,7 +75,9 @@ fun FindScreen() { modifier = Modifier.padding(20.dp) ) { // 발견 탭에 공유된 여행기록 아이템 - SharedRecordItem() + SharedRecordItem( + onClick = { navController.navigate("explore_detail") } + ) } if (idx < itemCnt - 1) { @@ -89,6 +92,6 @@ fun FindScreen() { @Composable fun FindScreenPreview() { DngoTheme { - FindScreen() +// FindScreen() } } diff --git a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt index 6587986..38865d2 100644 --- a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt +++ b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt @@ -1,5 +1,6 @@ package com.min.dnapp.presentation.find.component +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -17,9 +18,13 @@ import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.ui.theme.MomentoTheme @Composable -fun SharedRecordItem() { +fun SharedRecordItem( + onClick: () -> Unit +) { Row( - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .clickable { onClick() } + .fillMaxWidth() ) { // 프로필 이미지 ProfileImageCircle(modifier = Modifier.size(36.dp)) @@ -62,6 +67,6 @@ fun SharedRecordItem() { @Composable fun RecordItemPreview() { DngoTheme { - SharedRecordItem() +// SharedRecordItem() } } diff --git a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt index 960c670..80ed293 100644 --- a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt +++ b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt @@ -33,6 +33,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController import com.min.dnapp.R import com.min.dnapp.presentation.mypage.UserBadge import com.min.dnapp.presentation.ui.icon.AppIcons @@ -44,7 +45,7 @@ import com.min.dnapp.presentation.ui.theme.MomentoTheme @OptIn(ExperimentalMaterial3Api::class) @Composable -fun HomeScreen2() { +fun HomeScreen2(navController: NavHostController) { Scaffold( containerColor = MomentoTheme.colors.brownW90, topBar = { @@ -65,7 +66,7 @@ fun HomeScreen2() { actions = { Icon( modifier = Modifier - .clickable { } + .clickable { navController.navigate("bell") } .padding(16.dp), imageVector = AppIcons.Bell, contentDescription = null, @@ -397,6 +398,6 @@ fun HomeGrayLine( @Composable fun HomeScreen2Preview() { DngoTheme { - HomeScreen2() +// HomeScreen2() } } diff --git a/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt b/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt index 2525a02..29943f4 100644 --- a/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt +++ b/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt @@ -25,6 +25,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController import com.min.dnapp.R import com.min.dnapp.presentation.ui.icon.AppIcons import com.min.dnapp.presentation.ui.icon.appicons.Kakao @@ -33,7 +34,7 @@ import com.min.dnapp.presentation.ui.theme.KakaoYellow import com.min.dnapp.presentation.ui.theme.MomentoTheme @Composable -fun LoginScreen2() { +fun LoginScreen2(navController: NavHostController) { Surface( modifier = Modifier.fillMaxSize(), color = MomentoTheme.colors.brownW80 @@ -44,7 +45,9 @@ fun LoginScreen2() { ) { LoginHeaderSection() LoginButtonSection( - onClick = {} + onClick = { + navController.navigate("home") + } ) } } @@ -137,6 +140,6 @@ fun LoginButtonSection( @Composable fun LoginScreen2Preview() { DngoTheme { - LoginScreen2() +// LoginScreen2() } } From 220a00b7d6e5a423cb1d4b21e9e2b3ee870dc69c Mon Sep 17 00:00:00 2001 From: min486 Date: Fri, 17 Oct 2025 21:01:10 +0900 Subject: [PATCH 34/98] =?UTF-8?q?chore:=20=EC=95=B1=20=EC=9D=B4=EB=A6=84?= =?UTF-8?q?=20=EB=B0=8F=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- app/src/main/AndroidManifest.xml | 4 +-- app/src/main/ic_momento-playstore.png | Bin 0 -> 16238 bytes app/src/main/res/drawable/ic_momento.xml | 29 ++++++++++++++++++ .../res/drawable/ic_momento_foreground.xml | 29 ++++++++++++++++++ .../main/res/mipmap-anydpi-v26/ic_momento.xml | 5 +++ .../mipmap-anydpi-v26/ic_momento_round.xml | 5 +++ app/src/main/res/mipmap-hdpi/ic_momento.webp | Bin 0 -> 1148 bytes .../res/mipmap-hdpi/ic_momento_round.webp | Bin 0 -> 2722 bytes app/src/main/res/mipmap-mdpi/ic_momento.webp | Bin 0 -> 902 bytes .../res/mipmap-mdpi/ic_momento_round.webp | Bin 0 -> 1736 bytes app/src/main/res/mipmap-xhdpi/ic_momento.webp | Bin 0 -> 1516 bytes .../res/mipmap-xhdpi/ic_momento_round.webp | Bin 0 -> 3882 bytes .../main/res/mipmap-xxhdpi/ic_momento.webp | Bin 0 -> 2176 bytes .../res/mipmap-xxhdpi/ic_momento_round.webp | Bin 0 -> 5962 bytes .../main/res/mipmap-xxxhdpi/ic_momento.webp | Bin 0 -> 2982 bytes .../res/mipmap-xxxhdpi/ic_momento_round.webp | Bin 0 -> 8424 bytes .../main/res/values/ic_momento_background.xml | 4 +++ app/src/main/res/values/strings.xml | 2 +- 19 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 app/src/main/ic_momento-playstore.png create mode 100644 app/src/main/res/drawable/ic_momento.xml create mode 100644 app/src/main/res/drawable/ic_momento_foreground.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_momento.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_momento_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_momento.webp create mode 100644 app/src/main/res/mipmap-hdpi/ic_momento_round.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_momento.webp create mode 100644 app/src/main/res/mipmap-mdpi/ic_momento_round.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_momento.webp create mode 100644 app/src/main/res/mipmap-xhdpi/ic_momento_round.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_momento.webp create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_momento_round.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_momento.webp create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_momento_round.webp create mode 100644 app/src/main/res/values/ic_momento_background.xml diff --git a/README.md b/README.md index 2e18e31..3e07c5f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

momento -   +    play diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 293cbfb..bed265b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,9 +11,9 @@ android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" - android:icon="@mipmap/ic_launcher" + android:icon="@mipmap/ic_momento" android:label="@string/app_name" - android:roundIcon="@mipmap/ic_launcher_round" + android:roundIcon="@mipmap/ic_momento_round" android:supportsRtl="true" android:theme="@style/Theme.Dngo"> l!%CwbeHr{5<{m-mjXkV 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

M%6_}#7=w%98Q@Pku7_37{B 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 + + + + + + + diff --git a/app/src/main/res/drawable/ic_momento_foreground.xml b/app/src/main/res/drawable/ic_momento_foreground.xml new file mode 100644 index 0000000..b181568 --- /dev/null +++ b/app/src/main/res/drawable/ic_momento_foreground.xml @@ -0,0 +1,29 @@ + + + + + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_momento.xml b/app/src/main/res/mipmap-anydpi-v26/ic_momento.xml new file mode 100644 index 0000000..7f9f2eb --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_momento.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_momento_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_momento_round.xml new file mode 100644 index 0000000..7f9f2eb --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_momento_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_momento.webp b/app/src/main/res/mipmap-hdpi/ic_momento.webp new file mode 100644 index 0000000000000000000000000000000000000000..14206db88da45072d6c569c21454664e44966143 GIT binary patch literal 1148 zcmV-?1cUohNk&F=1ONb6MM6+kP&iCz1ONapN5Byf)rNw$ZJ3rn?6-p;A|?Rq6h6cv z+}gHPE2knfBJ;j}5mZ3L`w{Mtk-7VmZ*AcBym2=c9^5l`cXz&x;jnERNzUp1M9Mj8 zBT15iKdK=xT+ZE!%nlC2ZD0A)Kjv3dLigIf^Xw$Tc0zw)`#kslUz=GQBKCO+JNy4Y3U}p=fRqiDAr4vw z`&YvUPmp}hr!P@+t;vEC0nw8!6yN?orlQV_-qcPzo$(XMfmu+uu1?hm=oT}1LLK{6 z({-HDVy8G&(+#KD%y260b_Q{!yKZu`77*gHqc347)C#jk$;r6@Fz+VZ>Mx(}?P)yeCUben*Or#{YYhFr-9zCBDlV`41D;XT2oA~OKm}>?& zLM@2MN|JZhZhV(Q*3quhp7SqU*gEg6&VW0EWv8APw*kUib#1_REWMdX${D|^+D1vs zXe+!`!v?~w9+puaUFsP(yJZoO)&0w8BYUd`7%MkE5IlHlteX%00!pJrV9T2Q8U|qf zzA<+VP}$ybZOi)2_-msT812Cr{cO#K$?}a4)Wyj;Nu@2oUq7+uUbV0VR6tjIQbe^l z0!pHj_4cI2N*Ew(*NL=h6J`N5?Ua~3>MH~+N3532yUFL83W{IShZvWuy8YJV@$rts_pYx zKs(f37{}`Eil|mHKvov;@mkN08rVfm09V?IOv@H++?H)*M=db6>`S^+tzkP*+1$-a zIy|xP9$v7ifJ&n>r~$;}Bx%b@fl<=zo|mMAXk94yRsmjlD=m7jdZGVvHz6iR&h(FY zZU#+Z?DLuWw3uTK@wtnq7y2WrKLY2!^m#$Enc`G#H=I^yhP$s-uUk%I8RG7bg{~Q= zV62afa*A;3b3R=KxxX~x4V;Y15D)|uLA1W!%>tkExdpUu7L;yY1c|K;QRM}SK+k#a zLPdRbC zzhVHl!z>uHg5~pLg8XJ02*MyBQb8n$5F`mw1ZnNPZ4-D2AQ2G4mI_Qdm!8UNC-8H% Ow|ccNu6hF`v#11R95SB( literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-hdpi/ic_momento_round.webp b/app/src/main/res/mipmap-hdpi/ic_momento_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..c2337e9c5be53a4a3c9e811380a21d35eaf62465 GIT binary patch literal 2722 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_momento.webp b/app/src/main/res/mipmap-xhdpi/ic_momento.webp new file mode 100644 index 0000000000000000000000000000000000000000..9dd5fd33ccd741efa4ab643da22da589588d30a9 GIT binary patch literal 1516 zcmVHn0!`CTH+tfTk@%sMhxh+`SW%uy&A%gl@m(|f#fx3jB?Ki4XDY?wS~? z-+KdLmo9%5b=pJbyNlTAj5TD2UzJJiWEr~4s7jv&*tSzC%lv`Aw@SsY-*|(#LsCDI8wRTd zUhCZMdA#v>eWmoaSHE80+>ZTHb|7m_tQqkLECP+7!?&~XH%u-C?or)% z#wM`Cxw8||+2MsvL5HJ5xsj}ER77L|XD>0cAE`fHbh54+lV%BR`;}IO6{*)%m?rh26Jyo3wZu5@csizOQPqxo*8jw@j8dBDl?yRf(+PFbSr9XeWwxB{!#++mDHPi=XSgSOCIR*k5 z$A2Jz(9^o~XJBU)U8A^%5tW)S%)IvRBOu*@=K6xbW+Wd)5~xfkfRBzgl^7B@)+Gzv zWAB0Qh%6!9GFjJv8&<$d2Mg>mQc|al(jMU7F%VZ0O5UO<2YA4+Vuh4xSfCGhJ%Uw4 zm4KDizMhnIna99V>hNB%1UO04F;b*-8*t0qom_Pmtt1YlP?7#X-SQP%_i3>5_2z>BU;6XH z@{YlU5m|+_eYvT&YaK`;KoFrPnTkd-$Cw?hiW9*#JN6QqvqE5BHl)qWzk9H{5?9P% zFwDS=DqhjSY|e4wC8~&bWEeNEe<-Ri3F$x7wg0aD&%7~1~?+6JnPWP zyEJW3M!{MWu_v9(-aRKR>lQNrW%?HGs!WeX_^ylZZ+kRjZy`2o0WE@sfCZp;spYi^ zu=q`qe?1WUe|~8Km3u3DU!WKOC1l1kEuF8maGvY@93=Kn`GbAuA2#`41}y{ts40LG z13<>}QUJt>%T0G=mrE>+?9<@er52jpRl<7nKO*?3kHruG;|&}DO)x}@wp3f3*;MB` zOTK1lo_CafbZ44!`-iIT)1z@wD35RpzaqG>*tT(Orm0qib z$p2eck3W`y765`9@NGZ|pan1jn3V6meEQu-3(9>AfCV5s0NWJ=E+BLQk>Y=^jUFC< SjM5*Q0GM&*|C*0+!%_fPa_m9? literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_momento_round.webp b/app/src/main/res/mipmap-xhdpi/ic_momento_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..673c3297465637cc1932d692a7c6469e529fcf62 GIT binary patch literal 3882 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 CxH`Q6 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_momento_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_momento_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..c3213c3c9d8440785b66dde0e9b48536d378abd2 GIT binary patch literal 5962 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 KWXO3eSyKTcF?uin literal 0 HcmV?d00001 diff --git a/app/src/main/res/values/ic_momento_background.xml b/app/src/main/res/values/ic_momento_background.xml new file mode 100644 index 0000000..d08fd9e --- /dev/null +++ b/app/src/main/res/values/ic_momento_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ 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 4e1b1ae..60fb829 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,3 @@ - Dngo + 모멘토 \ No newline at end of file From fced1e078377a852886a897a4914913de63a315c Mon Sep 17 00:00:00 2001 From: min486 Date: Sat, 18 Oct 2025 23:18:29 +0900 Subject: [PATCH 35/98] README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e07c5f..2713196 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,13 @@

momento    - + play

+ ## 🏝️ 여행을 기록하는 가장 감성적인 방법, 모멘토 - 자신의 여행 이야기를 간단하게 기록할 수 있어요 From afc39ce817f960edc0cacc73c8aac24e049e864b Mon Sep 17 00:00:00 2001 From: min486 Date: Tue, 21 Oct 2025 01:00:28 +0900 Subject: [PATCH 36/98] =?UTF-8?q?feat:=20=EC=97=AC=ED=96=89=20=EB=82=A0?= =?UTF-8?q?=EC=A7=9C=20=EC=84=A0=ED=83=9D=20=EA=B5=AC=ED=98=84=20(DateRang?= =?UTF-8?q?ePicker=20=ED=99=9C=EC=9A=A9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/write/RecordWriteScreen.kt | 191 ++++++++++++++++-- .../java/com/min/dnapp/util/DateTimeExt.kt | 18 ++ 2 files changed, 193 insertions(+), 16 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/util/DateTimeExt.kt diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index e6c356d..7c2145b 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -18,6 +18,9 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.DatePickerDefaults +import androidx.compose.material3.DatePickerDialog +import androidx.compose.material3.DateRangePicker import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.ModalBottomSheet @@ -27,7 +30,9 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.Switch import androidx.compose.material3.SwitchDefaults import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.rememberDateRangePickerState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -49,6 +54,7 @@ import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.ui.theme.MomentoTheme import com.min.dnapp.presentation.write.component.EmotionBottomSheetContent import com.min.dnapp.presentation.write.component.WeatherBottomSheetContent +import com.min.dnapp.util.toLocalDate @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -59,6 +65,10 @@ fun RecordWriteScreen() { var showEmotionBottomSheet by remember { mutableStateOf(false) } var showWeatherBottomSheet by remember { mutableStateOf(false) } + // 캘린더 + var showDatePicker by remember { mutableStateOf(false) } + val dateRangePickerState = rememberDateRangePickerState() + Scaffold( containerColor = MomentoTheme.colors.brownW90, topBar = { @@ -108,22 +118,12 @@ fun RecordWriteScreen() { ) { Spacer(Modifier.height(20.dp)) - // 날짜 - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Icon( - imageVector = AppIcons.Calendar, - contentDescription = null, - tint = MomentoTheme.colors.brownBase - ) - Spacer(Modifier.width(10.dp)) - Text( - text = "2025년 12월 12일 ~ 2025년 12월 13일", - style = MomentoTheme.typography.title02, - color = MomentoTheme.colors.grayW20 - ) - } + // 날짜 영역 + WriteDateSection( + startMillis = dateRangePickerState.selectedStartDateMillis, + endMillis = dateRangePickerState.selectedEndDateMillis, + onClick = { showDatePicker = true } + ) Spacer(Modifier.height(20.dp)) @@ -349,6 +349,165 @@ fun RecordWriteScreen() { ) } } + + // 캘린더(날짜 선택) 모달 + if (showDatePicker) { + DatePickerDialog( + onDismissRequest = { showDatePicker = false }, + confirmButton = { + TextButton( + onClick = { showDatePicker = false } + ) { + Text( + text = "확인", + ) + } + }, + dismissButton = { + TextButton( + onClick = { showDatePicker = false } + ) { + Text( + text = "취소" + ) + } + }, + colors = DatePickerDefaults.colors( + containerColor = MomentoTheme.colors.white + ) + ) { + DateRangePicker( + state = dateRangePickerState, + colors = DatePickerDefaults.colors( + containerColor = MomentoTheme.colors.white, + // 기간(시작일과 종료일 사이 공간)의 배경색 + dayInSelectionRangeContainerColor = MomentoTheme.colors.brownW80 + ), + // 펜 아이콘 숨기기 (캘린더 뷰와 텍스트 입력 뷰 전환 역할) + showModeToggle = false, + title = { + Box( + modifier = Modifier.padding(start = 16.dp, top = 16.dp) + ) { + Text( + text = "여행 날짜 선택", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 + ) + } + }, + headline = { + Box( + modifier = Modifier.padding(16.dp) + ) { + CustomDateRangeHeadline( + startDateMillis = dateRangePickerState.selectedStartDateMillis, + endDateMillis = dateRangePickerState.selectedEndDateMillis + ) + } + } + ) + } + } +} + +@Composable +fun WriteDateSection( + startMillis: Long?, + endMillis: Long?, + onClick: () -> Unit +) { + Row( + modifier = Modifier.clickable { onClick() }, + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = AppIcons.Calendar, + contentDescription = null, + tint = MomentoTheme.colors.brownBase + ) + Spacer(Modifier.width(10.dp)) + + when { + // 날짜 선택되지 않은 경우 + startMillis == null -> { + Text( + text = "날짜 선택", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW40 + ) + } + + // 시작일만 선택된 경우 or 시작일과 종료일이 같은 날짜에 선택된 경우 + endMillis == null || startMillis == endMillis -> { + val startDate = startMillis.toLocalDate() + + Text( + text = "${startDate?.year}년 ${startDate?.monthValue}월 ${startDate?.dayOfMonth}일", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 + ) + } + + // 시작일과 종료일 모두 선택된 경우 (다른 날짜) + else -> { + val startDate = startMillis.toLocalDate() + val endDate = endMillis.toLocalDate() + + Text( + text = "${startDate?.year}년 ${startDate?.monthValue}월 ${startDate?.dayOfMonth}일 ~ ${endDate?.year}년 ${endDate?.monthValue}월 ${endDate?.dayOfMonth}일", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 + ) + } + } + } +} + +@Composable +fun CustomDateRangeHeadline( + startDateMillis: Long?, + endDateMillis: Long? +) { + if (startDateMillis == null) { + Text( + text = "날짜를 선택해주세요", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW40 + ) + } else { + val startDate = startDateMillis.toLocalDate() + + if (endDateMillis == null || startDateMillis == endDateMillis) { + // 시작일만 선택된 경우 or 시작일과 종료일이 같은 날짜에 선택된 경우 + Text( + text = "${startDate?.year}년 ${startDate?.monthValue}월 ${startDate?.dayOfMonth}일", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW20 + ) + } else { + // 시작일과 종료일 모두 선택된 경우 (다른 날짜) + val endDate = endDateMillis.toLocalDate() + + Row { + Text( + text = "${startDate?.year}년 ${startDate?.monthValue}월 ${startDate?.dayOfMonth}일", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW20 + ) + Text( + text = " ~ ", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW20 + ) + Text( + text = "${endDate?.year}년 ${endDate?.monthValue}월 ${endDate?.dayOfMonth}일", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW20 + ) + } + } + } } @Composable diff --git a/app/src/main/java/com/min/dnapp/util/DateTimeExt.kt b/app/src/main/java/com/min/dnapp/util/DateTimeExt.kt new file mode 100644 index 0000000..37e3a79 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/util/DateTimeExt.kt @@ -0,0 +1,18 @@ +package com.min.dnapp.util + +import java.time.Instant +import java.time.LocalDate +import java.time.ZoneId + +/** + * Long(밀리초) 값을 시스템 기본 시간대를 기준으로 LocalDate로 변환 + */ +fun Long?.toLocalDate(): LocalDate? { + if (this == null || this == 0L) { + return null + } + + return Instant.ofEpochMilli(this) + .atZone(ZoneId.systemDefault()) + .toLocalDate() +} From 1f0f5ff35f3b234b4cc410947937b6ddcac3f662 Mon Sep 17 00:00:00 2001 From: min486 Date: Tue, 21 Oct 2025 23:52:15 +0900 Subject: [PATCH 37/98] =?UTF-8?q?feat:=20Naver=20=EC=A7=80=EC=97=AD=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20API=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 13 +++ .../main/java/com/min/dnapp/MainActivity.kt | 4 +- .../com/min/dnapp/data/di/NetworkModule.kt | 90 +++++++++++++++++++ .../com/min/dnapp/data/di/RepositoryModule.kt | 8 ++ .../dnapp/data/remote/LocalSearchResponse.kt | 16 ++++ .../dnapp/data/remote/LocalSearchService.kt | 16 ++++ .../repository/LocalSearchRepositoryImpl.kt | 45 ++++++++++ .../com/min/dnapp/domain/model/LocalPlace.kt | 7 ++ .../repository/LocalSearchRepository.kt | 9 ++ .../presentation/write/RecordWriteScreen.kt | 5 +- .../presentation/write/SearchViewModel.kt | 41 +++++++++ .../main/java/com/min/dnapp/util/Resource.kt | 7 ++ gradle/libs.versions.toml | 8 ++ 13 files changed, 267 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/data/di/NetworkModule.kt create mode 100644 app/src/main/java/com/min/dnapp/data/remote/LocalSearchResponse.kt create mode 100644 app/src/main/java/com/min/dnapp/data/remote/LocalSearchService.kt create mode 100644 app/src/main/java/com/min/dnapp/data/repository/LocalSearchRepositoryImpl.kt create mode 100644 app/src/main/java/com/min/dnapp/domain/model/LocalPlace.kt create mode 100644 app/src/main/java/com/min/dnapp/domain/repository/LocalSearchRepository.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt create mode 100644 app/src/main/java/com/min/dnapp/util/Resource.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index dbf5fbf..b78655f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -18,6 +18,7 @@ plugins { alias(libs.plugins.google.services) alias(libs.plugins.ksp) alias(libs.plugins.hilt) + alias(libs.plugins.kotlin.serialization) } android { @@ -34,11 +35,17 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" val kakaoNativeAppKey = properties.getProperty("kakao.native.app.key") + val naverClientId = properties.getProperty("naver.client.id") + val naverClientSecret = properties.getProperty("naver.client.secret") // 네이티브 앱 키를 BuildConfig에 필드로 추가 buildConfigField("String", "KAKAO_NATIVE_APP_KEY", "\"${kakaoNativeAppKey}\"") // AndroidManifest.xml에 전달할 플레이스홀더 정의 manifestPlaceholders["kakaoNativeAppKey"] = kakaoNativeAppKey + + // 네이버 + buildConfigField("String", "NAVER_CLIENT_ID", "\"${naverClientId}\"") + buildConfigField("String", "NAVER_CLIENT_SECRET", "\"${naverClientSecret}\"") } buildTypes { @@ -92,6 +99,12 @@ dependencies { implementation(libs.hilt.navigation.compose) // splash screen implementation(libs.splash) + // retrofit2 & kotlin serialization + implementation(libs.retrofit) + implementation(libs.retrofit.converter.kotlinx.serialization) + implementation(libs.kotlinx.serialization.json) + // okhttp (logging interceptor) + implementation(libs.okhttp.logging) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index 7d304f4..2e7c720 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -24,6 +24,7 @@ import com.min.dnapp.presentation.login.LoginScreen2 import com.min.dnapp.presentation.mypage.MypageScreen import com.min.dnapp.presentation.ui.component.MomentoBottomNav import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.write.RecordWriteScreen import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -36,7 +37,8 @@ class MainActivity : ComponentActivity() { // enableEdgeToEdge() setContent { DngoTheme { - MomentoApp() +// MomentoApp() + RecordWriteScreen() } } } diff --git a/app/src/main/java/com/min/dnapp/data/di/NetworkModule.kt b/app/src/main/java/com/min/dnapp/data/di/NetworkModule.kt new file mode 100644 index 0000000..8186e63 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/data/di/NetworkModule.kt @@ -0,0 +1,90 @@ +package com.min.dnapp.data.di + +import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory +import com.min.dnapp.BuildConfig +import com.min.dnapp.data.remote.LocalSearchService +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import kotlinx.serialization.json.Json +import okhttp3.Interceptor +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Retrofit +import javax.inject.Qualifier +import javax.inject.Singleton + +@Qualifier +@Retention(AnnotationRetention.BINARY) +annotation class NaverApiKey + +@Module +@InstallIn(SingletonComponent::class) +object NetworkModule { + + private const val BASE_URL = "https://openapi.naver.com/" + + @Provides + @Singleton + fun provideJson(): Json { + return Json { + // API 응답에서 사용하지 않는 필드는 무시하도록 설정 + ignoreUnknownKeys = true + // 기본값이 있는 필드에 null이 오면 기본값 사용 + coerceInputValues = true + } + } + + @NaverApiKey + @Provides + fun provideNaverApiKey(): Pair { + val clientId = BuildConfig.NAVER_CLIENT_ID + val clientSecret = BuildConfig.NAVER_CLIENT_SECRET + return clientId to clientSecret + } + + @Provides + @Singleton + fun provideAuthInterceptor(@NaverApiKey naverApiKey: Pair): Interceptor { + val (clientId, clientSecret) = naverApiKey + return Interceptor { chain -> + val request = chain.request().newBuilder() + .header("X-Naver-Client-Id", clientId) + .header("X-Naver-Client-Secret", clientSecret) + .build() + chain.proceed(request) + } + } + + @Provides + @Singleton + fun provideOkHttpClient(authInterceptor: Interceptor): OkHttpClient { + val loggingInterceptor = HttpLoggingInterceptor().apply { + level = HttpLoggingInterceptor.Level.BODY + } + return OkHttpClient.Builder() + .addInterceptor(authInterceptor) + .addInterceptor(loggingInterceptor) + .build() + } + + @Provides + @Singleton + fun provideRetrofit(okHttpClient: OkHttpClient, json: Json): Retrofit { + val contentType = "application/json".toMediaType() + + return Retrofit.Builder() + .baseUrl(BASE_URL) + .client(okHttpClient) + .addConverterFactory(json.asConverterFactory(contentType)) + .build() + } + + @Provides + @Singleton + fun provideLocalSearchService(retrofit: Retrofit): LocalSearchService { + return retrofit.create(LocalSearchService::class.java) + } +} diff --git a/app/src/main/java/com/min/dnapp/data/di/RepositoryModule.kt b/app/src/main/java/com/min/dnapp/data/di/RepositoryModule.kt index ca3621b..8cf545f 100644 --- a/app/src/main/java/com/min/dnapp/data/di/RepositoryModule.kt +++ b/app/src/main/java/com/min/dnapp/data/di/RepositoryModule.kt @@ -1,7 +1,9 @@ package com.min.dnapp.data.di import com.min.dnapp.data.repository.AuthRepositoryImpl +import com.min.dnapp.data.repository.LocalSearchRepositoryImpl import com.min.dnapp.domain.repository.AuthRepository +import com.min.dnapp.domain.repository.LocalSearchRepository import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -17,4 +19,10 @@ abstract class RepositoryModule { abstract fun bindAuthRepository( authRepositoryImpl: AuthRepositoryImpl ): AuthRepository + + @Binds + @Singleton + abstract fun bindLocalSearchRepository( + localSearchRepositoryImpl: LocalSearchRepositoryImpl + ): LocalSearchRepository } diff --git a/app/src/main/java/com/min/dnapp/data/remote/LocalSearchResponse.kt b/app/src/main/java/com/min/dnapp/data/remote/LocalSearchResponse.kt new file mode 100644 index 0000000..d12d4c8 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/data/remote/LocalSearchResponse.kt @@ -0,0 +1,16 @@ +package com.min.dnapp.data.remote + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class LocalSearchResponse( + @SerialName("items") val items: List +) + +@Serializable +data class SearchItem( + @SerialName("title") val title: String, + @SerialName("category") val category: String, + @SerialName("roadAddress") val roadAddress: String +) diff --git a/app/src/main/java/com/min/dnapp/data/remote/LocalSearchService.kt b/app/src/main/java/com/min/dnapp/data/remote/LocalSearchService.kt new file mode 100644 index 0000000..ac01086 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/data/remote/LocalSearchService.kt @@ -0,0 +1,16 @@ +package com.min.dnapp.data.remote + +import retrofit2.http.GET +import retrofit2.http.Header +import retrofit2.http.Query + +interface LocalSearchService { + @GET("v1/search/local.json") + suspend fun search( +// @Header("X-Naver-Client-Id") clientId: String, +// @Header("X-Naver-Client-Secret") clientSecret: String, + @Query("query") query: String, + @Query("display") display: Int = 5, + @Query("sort") sort: String = "random" + ): LocalSearchResponse +} diff --git a/app/src/main/java/com/min/dnapp/data/repository/LocalSearchRepositoryImpl.kt b/app/src/main/java/com/min/dnapp/data/repository/LocalSearchRepositoryImpl.kt new file mode 100644 index 0000000..e683167 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/data/repository/LocalSearchRepositoryImpl.kt @@ -0,0 +1,45 @@ +package com.min.dnapp.data.repository + +import android.net.http.HttpEngine +import android.util.Log +import com.min.dnapp.data.remote.LocalSearchResponse +import com.min.dnapp.data.remote.LocalSearchService +import com.min.dnapp.domain.model.LocalPlace +import com.min.dnapp.domain.repository.LocalSearchRepository +import com.min.dnapp.util.Resource +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import retrofit2.HttpException +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class LocalSearchRepositoryImpl @Inject constructor( + private val api: LocalSearchService +) : LocalSearchRepository { + override fun searchPlaces(query: String): Flow>> = flow { + emit(Resource.Loading()) + + try { + val response: LocalSearchResponse = api.search( + query = query + ) + + val places = response.items.map { searchItem -> + LocalPlace( + title = searchItem.title, + category = searchItem.category, + roadAddress = searchItem.roadAddress + ) + } + + emit(Resource.Success(places)) + } catch (e: HttpException) { + emit(Resource.Error("서버 오류 발생")) + } catch (e: java.io.IOException) { + emit(Resource.Error("네트워크 연결 문제")) + } catch (e: Exception) { + emit(Resource.Error("알 수 없는 오류 발생")) + } + } +} diff --git a/app/src/main/java/com/min/dnapp/domain/model/LocalPlace.kt b/app/src/main/java/com/min/dnapp/domain/model/LocalPlace.kt new file mode 100644 index 0000000..b8f92b4 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/model/LocalPlace.kt @@ -0,0 +1,7 @@ +package com.min.dnapp.domain.model + +data class LocalPlace( + val title: String, + val category: String, + val roadAddress: String +) diff --git a/app/src/main/java/com/min/dnapp/domain/repository/LocalSearchRepository.kt b/app/src/main/java/com/min/dnapp/domain/repository/LocalSearchRepository.kt new file mode 100644 index 0000000..a04d76a --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/repository/LocalSearchRepository.kt @@ -0,0 +1,9 @@ +package com.min.dnapp.domain.repository + +import com.min.dnapp.domain.model.LocalPlace +import com.min.dnapp.util.Resource +import kotlinx.coroutines.flow.Flow + +interface LocalSearchRepository { + fun searchPlaces(query: String): Flow>> +} diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index 7c2145b..5e5d28f 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -45,6 +45,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel import com.min.dnapp.R import com.min.dnapp.presentation.ui.icon.AppIcons import com.min.dnapp.presentation.ui.icon.appicons.Back @@ -58,7 +59,9 @@ import com.min.dnapp.util.toLocalDate @OptIn(ExperimentalMaterial3Api::class) @Composable -fun RecordWriteScreen() { +fun RecordWriteScreen( + searchViewModel: SearchViewModel = hiltViewModel() +) { val radioOptions = listOf("국내", "해외 (직접 입력)") var selectedPlace by remember { mutableStateOf("국내") } var isChecked by remember { mutableStateOf(true) } diff --git a/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt new file mode 100644 index 0000000..39ffa89 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt @@ -0,0 +1,41 @@ +package com.min.dnapp.presentation.write + +import android.util.Log +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.min.dnapp.domain.repository.LocalSearchRepository +import com.min.dnapp.util.Resource +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class SearchViewModel @Inject constructor( + private val repository: LocalSearchRepository +) : ViewModel() { + + init { + searchTest("광안리해수욕장") + } + + fun searchTest(query: String) { + viewModelScope.launch { + repository.searchPlaces(query = query).collect { result -> + when (result ) { + is Resource.Loading -> { + Log.e("naver", "로딩 중...") + } + is Resource.Success -> { + val data = result.data + data?.forEach { place -> + Log.e("naver", "place : ${place.title}") + } + } + is Resource.Error -> { + Log.e("naver", "search error : ${result.message}") + } + } + } + } + } +} diff --git a/app/src/main/java/com/min/dnapp/util/Resource.kt b/app/src/main/java/com/min/dnapp/util/Resource.kt new file mode 100644 index 0000000..6404418 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/util/Resource.kt @@ -0,0 +1,7 @@ +package com.min.dnapp.util + +sealed class Resource(val data: T? = null, val message: String? = null) { + class Success(data: T) : Resource(data) + class Error(message: String, data: T? = null) : Resource(data, message) + class Loading(data: T? = null) : Resource(data) +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3cbb928..284b9cb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,6 +17,9 @@ hilt = "2.56.2" ksp = "2.2.0-2.0.2" hiltNavigationCompose = "1.2.0" splash = "1.0.1" +retrofit = "3.0.0" +kotlinSerialization = "1.9.0" +okhttp = "5.0.0" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -44,6 +47,10 @@ hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hilt" } hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "hiltNavigationCompose" } splash = { module = "androidx.core:core-splashscreen", version.ref = "splash" } +retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" } +retrofit-converter-kotlinx-serialization = { module = "com.squareup.retrofit2:converter-kotlinx-serialization", version.ref = "retrofit" } +kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinSerialization" } +okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } @@ -52,3 +59,4 @@ kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "ko google-services = { id = "com.google.gms.google-services", version.ref = "google" } hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } +kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } From e25fef7fd5f3a5ccbccab94e293d8d471a1704dc Mon Sep 17 00:00:00 2001 From: min486 Date: Thu, 23 Oct 2025 23:10:11 +0900 Subject: [PATCH 38/98] =?UTF-8?q?feat:=20Naver=20=EC=A7=80=EC=97=AD=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 4 +- .../repository/LocalSearchRepositoryImpl.kt | 8 +- .../domain/usecase/LocalSearchUseCase.kt | 15 ++++ .../dnapp/presentation/write/SearchState.kt | 10 +++ .../presentation/write/SearchTestScreen.kt | 20 +++++ .../presentation/write/SearchViewModel.kt | 79 +++++++++++++++---- .../main/java/com/min/dnapp/util/StringExt.kt | 17 ++++ 7 files changed, 136 insertions(+), 17 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/domain/usecase/LocalSearchUseCase.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/write/SearchState.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/write/SearchTestScreen.kt create mode 100644 app/src/main/java/com/min/dnapp/util/StringExt.kt diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index 2e7c720..ccb82e5 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -25,6 +25,7 @@ import com.min.dnapp.presentation.mypage.MypageScreen import com.min.dnapp.presentation.ui.component.MomentoBottomNav import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.write.RecordWriteScreen +import com.min.dnapp.presentation.write.SearchTestScreen import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -38,7 +39,8 @@ class MainActivity : ComponentActivity() { setContent { DngoTheme { // MomentoApp() - RecordWriteScreen() +// RecordWriteScreen() + SearchTestScreen() } } } diff --git a/app/src/main/java/com/min/dnapp/data/repository/LocalSearchRepositoryImpl.kt b/app/src/main/java/com/min/dnapp/data/repository/LocalSearchRepositoryImpl.kt index e683167..6dc6d19 100644 --- a/app/src/main/java/com/min/dnapp/data/repository/LocalSearchRepositoryImpl.kt +++ b/app/src/main/java/com/min/dnapp/data/repository/LocalSearchRepositoryImpl.kt @@ -7,6 +7,8 @@ import com.min.dnapp.data.remote.LocalSearchService import com.min.dnapp.domain.model.LocalPlace import com.min.dnapp.domain.repository.LocalSearchRepository import com.min.dnapp.util.Resource +import com.min.dnapp.util.extractLastCategory +import com.min.dnapp.util.removeTag import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import retrofit2.HttpException @@ -18,6 +20,7 @@ class LocalSearchRepositoryImpl @Inject constructor( private val api: LocalSearchService ) : LocalSearchRepository { override fun searchPlaces(query: String): Flow>> = flow { + // 로딩 상태 방출 emit(Resource.Loading()) try { @@ -27,12 +30,13 @@ class LocalSearchRepositoryImpl @Inject constructor( val places = response.items.map { searchItem -> LocalPlace( - title = searchItem.title, - category = searchItem.category, + title = searchItem.title.removeTag(), + category = searchItem.category.extractLastCategory(), roadAddress = searchItem.roadAddress ) } + // 성공 상태 방출 emit(Resource.Success(places)) } catch (e: HttpException) { emit(Resource.Error("서버 오류 발생")) diff --git a/app/src/main/java/com/min/dnapp/domain/usecase/LocalSearchUseCase.kt b/app/src/main/java/com/min/dnapp/domain/usecase/LocalSearchUseCase.kt new file mode 100644 index 0000000..e33e229 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/usecase/LocalSearchUseCase.kt @@ -0,0 +1,15 @@ +package com.min.dnapp.domain.usecase + +import com.min.dnapp.domain.model.LocalPlace +import com.min.dnapp.domain.repository.LocalSearchRepository +import com.min.dnapp.util.Resource +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class LocalSearchUseCase @Inject constructor( + private val repository: LocalSearchRepository +) { + operator fun invoke(query: String): Flow>> { + return repository.searchPlaces(query) + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/write/SearchState.kt b/app/src/main/java/com/min/dnapp/presentation/write/SearchState.kt new file mode 100644 index 0000000..8951eb0 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/write/SearchState.kt @@ -0,0 +1,10 @@ +package com.min.dnapp.presentation.write + +import com.min.dnapp.domain.model.LocalPlace + +data class SearchState( + val isLoading: Boolean = false, + val places: List = emptyList(), + val error: String? = null, + val query: String = "" +) diff --git a/app/src/main/java/com/min/dnapp/presentation/write/SearchTestScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/SearchTestScreen.kt new file mode 100644 index 0000000..484994b --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/write/SearchTestScreen.kt @@ -0,0 +1,20 @@ +package com.min.dnapp.presentation.write + +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.runtime.Composable +import androidx.hilt.navigation.compose.hiltViewModel + +@Composable +fun SearchTestScreen( + searchViewModel: SearchViewModel = hiltViewModel() +) { + val searchState = searchViewModel.searchState.value + + BasicTextField( + value = searchState.query, + onValueChange = { newValue -> + searchViewModel.searchPlace(newValue) + }, + singleLine = false + ) +} diff --git a/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt index 39ffa89..25fa2f6 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt @@ -1,41 +1,92 @@ package com.min.dnapp.presentation.write import android.util.Log +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.min.dnapp.domain.repository.LocalSearchRepository +import com.min.dnapp.domain.usecase.LocalSearchUseCase import com.min.dnapp.util.Resource import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import javax.inject.Inject @HiltViewModel class SearchViewModel @Inject constructor( - private val repository: LocalSearchRepository + private val localSearchUseCase: LocalSearchUseCase ) : ViewModel() { + private val _searchState = mutableStateOf(SearchState()) + val searchState: State = _searchState + + // 이전 검색 작업을 취소하기 위한 Job + private var searchJob: Job? = null + init { - searchTest("광안리해수욕장") + searchPlace("광안리해수욕장") } - fun searchTest(query: String) { - viewModelScope.launch { - repository.searchPlaces(query = query).collect { result -> - when (result ) { + fun searchPlace(query: String) { + val currentQuery = _searchState.value.query + + // 검색어 상태 업데이트 (textField 값과 viewModel 상태를 동기화) + _searchState.value = _searchState.value.copy(query = query) + + // 검색어가 이전과 같으면 API 호출 막음 + if (query == currentQuery) return + + // 검색어가 비어있을 경우 (사용자가 모두 지웠을 경우) + if (query.isBlank()) { + searchJob?.cancel() + _searchState.value = _searchState.value.copy( + isLoading = false, + places = emptyList(), + error = null + ) + Log.d("naver", "search query blank") + return + } + + // 진행중인(이전 검색) 작업이 있으면 취소 + searchJob?.cancel() + + // Flow 수집 및 상태 업데이트 시작 + searchJob = localSearchUseCase(query) + .onEach { result -> + when (result) { is Resource.Loading -> { - Log.e("naver", "로딩 중...") + // 로딩 시작 + _searchState.value = _searchState.value.copy( + isLoading = true, + places = result.data ?: emptyList(), + error = null + ) + Log.d("naver", "search for $query : Loading...") + } is Resource.Success -> { - val data = result.data - data?.forEach { place -> - Log.e("naver", "place : ${place.title}") - } + // 성공 + _searchState.value = _searchState.value.copy( + isLoading = false, + places = result.data ?: emptyList(), + error = null + ) + Log.d("naver", "search success : ${result.data?.size} 개") } is Resource.Error -> { + // 에러 + _searchState.value = _searchState.value.copy( + isLoading = false, + places = result.data ?: emptyList(), + error = result.message ?: "알 수 없는 에러 발생" + ) Log.e("naver", "search error : ${result.message}") } } } - } + // viewModelScope에서 flow를 실행 + .launchIn(viewModelScope) } } diff --git a/app/src/main/java/com/min/dnapp/util/StringExt.kt b/app/src/main/java/com/min/dnapp/util/StringExt.kt new file mode 100644 index 0000000..1cb89b7 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/util/StringExt.kt @@ -0,0 +1,17 @@ +package com.min.dnapp.util + +/** + * 문자열에서 태그를 제거하는 확장함수 + * 네이버 검색 API의 title 필드에 포함된 태그를 제거하는데 사용 + */ +fun String.removeTag(): String { + return this.replace(Regex("<(/)?b>"), "") +} + +/** + * 카테고리 문자열에서 가장 마지막 카테고리를 추출하는 확장함수 + * 예: "음식점>일식>돈가스" -> "돈가스" + */ +fun String.extractLastCategory(): String { + return this.split(">").lastOrNull() ?: this +} From c1963e9a4fc7143167156e03ca04f7f278c48ffc Mon Sep 17 00:00:00 2001 From: min486 Date: Fri, 24 Oct 2025 23:52:09 +0900 Subject: [PATCH 39/98] =?UTF-8?q?fix:=20ModalBottomSheet=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=ED=94=8C=EB=A1=9C=EC=9A=B0=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 4 +- .../presentation/ui/component/SelectButton.kt | 41 +++++ .../presentation/write/RecordWriteScreen.kt | 37 ++++ .../presentation/write/SearchTestScreen.kt | 20 --- .../presentation/write/SearchViewModel.kt | 69 ++++--- .../component/PlaceBottomSheetContent.kt | 168 ++++++++++++++++++ 6 files changed, 292 insertions(+), 47 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/component/SelectButton.kt delete mode 100644 app/src/main/java/com/min/dnapp/presentation/write/SearchTestScreen.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/write/component/PlaceBottomSheetContent.kt diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index ccb82e5..2e7c720 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -25,7 +25,6 @@ import com.min.dnapp.presentation.mypage.MypageScreen import com.min.dnapp.presentation.ui.component.MomentoBottomNav import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.write.RecordWriteScreen -import com.min.dnapp.presentation.write.SearchTestScreen import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -39,8 +38,7 @@ class MainActivity : ComponentActivity() { setContent { DngoTheme { // MomentoApp() -// RecordWriteScreen() - SearchTestScreen() + RecordWriteScreen() } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/component/SelectButton.kt b/app/src/main/java/com/min/dnapp/presentation/ui/component/SelectButton.kt new file mode 100644 index 0000000..de34924 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/component/SelectButton.kt @@ -0,0 +1,41 @@ +package com.min.dnapp.presentation.ui.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun SelectButton( + enabled: Boolean, + onConfirm: () -> Unit +) { + val buttonColor = if (enabled) { + MomentoTheme.colors.brownBase + } else { + MomentoTheme.colors.grayW80 + } + + Box( + modifier = Modifier + .clickable(enabled = enabled, onClick = onConfirm) + .fillMaxWidth() + .background(color = buttonColor, shape = RoundedCornerShape(10.dp)) + .padding(vertical = 16.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "선택했어요", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.white + ) + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index 5e5d28f..a3a8496 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -1,5 +1,6 @@ package com.min.dnapp.presentation.write +import android.util.Log import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -33,6 +34,7 @@ import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberDateRangePickerState +import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -46,6 +48,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.min.dnapp.R import com.min.dnapp.presentation.ui.icon.AppIcons import com.min.dnapp.presentation.ui.icon.appicons.Back @@ -54,6 +57,7 @@ import com.min.dnapp.presentation.ui.icon.appicons.Gallery import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.ui.theme.MomentoTheme import com.min.dnapp.presentation.write.component.EmotionBottomSheetContent +import com.min.dnapp.presentation.write.component.PlaceBottomSheetContent import com.min.dnapp.presentation.write.component.WeatherBottomSheetContent import com.min.dnapp.util.toLocalDate @@ -62,6 +66,8 @@ import com.min.dnapp.util.toLocalDate fun RecordWriteScreen( searchViewModel: SearchViewModel = hiltViewModel() ) { + val searchState by searchViewModel.searchState.collectAsStateWithLifecycle() + val radioOptions = listOf("국내", "해외 (직접 입력)") var selectedPlace by remember { mutableStateOf("국내") } var isChecked by remember { mutableStateOf(true) } @@ -72,6 +78,13 @@ fun RecordWriteScreen( var showDatePicker by remember { mutableStateOf(false) } val dateRangePickerState = rememberDateRangePickerState() + // 여행지 - 위치 추가 + var showPlaceBottomSheet by remember { mutableStateOf(false) } + val sheetState = rememberModalBottomSheetState( + // halfExpanded 상태 건너뛰기 + skipPartiallyExpanded = true + ) + Scaffold( containerColor = MomentoTheme.colors.brownW90, topBar = { @@ -239,6 +252,7 @@ fun RecordWriteScreen( Spacer(Modifier.height(12.dp)) Row( + modifier = Modifier.clickable { showPlaceBottomSheet = true }, verticalAlignment = Alignment.CenterVertically ) { Image( @@ -412,6 +426,29 @@ fun RecordWriteScreen( ) } } + + // 위치 추가 바텀시트 + if (showPlaceBottomSheet) { + ModalBottomSheet( + onDismissRequest = { showPlaceBottomSheet = false }, + sheetState = sheetState, + dragHandle = null, + containerColor = MomentoTheme.colors.white, + shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) + ) { + PlaceBottomSheetContent ( + value = searchState.query, + places = searchState.places, + onValueChange = { newValue -> + Log.e("naver", "newValue : $newValue") + searchViewModel.updateQuery(newValue) + }, + onSearch = { searchViewModel.searchPlace() }, + onConfirm = { showPlaceBottomSheet = false }, + onClear = { searchViewModel.clearSearchResult() } + ) + } + } } @Composable diff --git a/app/src/main/java/com/min/dnapp/presentation/write/SearchTestScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/SearchTestScreen.kt deleted file mode 100644 index 484994b..0000000 --- a/app/src/main/java/com/min/dnapp/presentation/write/SearchTestScreen.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.min.dnapp.presentation.write - -import androidx.compose.foundation.text.BasicTextField -import androidx.compose.runtime.Composable -import androidx.hilt.navigation.compose.hiltViewModel - -@Composable -fun SearchTestScreen( - searchViewModel: SearchViewModel = hiltViewModel() -) { - val searchState = searchViewModel.searchState.value - - BasicTextField( - value = searchState.query, - onValueChange = { newValue -> - searchViewModel.searchPlace(newValue) - }, - singleLine = false - ) -} diff --git a/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt index 25fa2f6..f44fa2e 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt @@ -1,14 +1,15 @@ package com.min.dnapp.presentation.write import android.util.Log -import androidx.compose.runtime.State -import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.min.dnapp.domain.usecase.LocalSearchUseCase import com.min.dnapp.util.Resource import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import javax.inject.Inject @@ -18,34 +19,55 @@ class SearchViewModel @Inject constructor( private val localSearchUseCase: LocalSearchUseCase ) : ViewModel() { - private val _searchState = mutableStateOf(SearchState()) - val searchState: State = _searchState + private val _searchState = MutableStateFlow(SearchState()) + val searchState: StateFlow = _searchState.asStateFlow() // 이전 검색 작업을 취소하기 위한 Job private var searchJob: Job? = null - init { - searchPlace("광안리해수욕장") +// init { +// searchPlace("광안리해수욕장") +// } + + /** + * textField의 입력 값만 업데이트하고, 검색 API 호출은 생략 + */ + fun updateQuery(newQuery: String) { + _searchState.value = _searchState.value.copy(query = newQuery) + + // 검색어가 빈 경우 목록 지우기 + if (newQuery.isBlank()) { + // 진행중인 검색 작업 취소 + searchJob?.cancel() + Log.d("naver", "updateQuery - newQuery blank") + } } - fun searchPlace(query: String) { - val currentQuery = _searchState.value.query + /** + * 검색 결과 목록 초기화 + * (textField에 포커스가 잡히거나, 새 검색 시작할 때 사용) + */ + fun clearSearchResult() { + searchJob?.cancel() - // 검색어 상태 업데이트 (textField 값과 viewModel 상태를 동기화) - _searchState.value = _searchState.value.copy(query = query) + // query는 그대로 유지, 결과 목록만 초기화 + _searchState.value = _searchState.value.copy( + isLoading = false, + places = emptyList(), + error = null + ) + Log.d("naver", "result cleared") + } - // 검색어가 이전과 같으면 API 호출 막음 - if (query == currentQuery) return + /** + * 검색 버튼 클릭 시, 검색 API 호출 + */ + fun searchPlace() { + val currentQuery = _searchState.value.query - // 검색어가 비어있을 경우 (사용자가 모두 지웠을 경우) - if (query.isBlank()) { - searchJob?.cancel() - _searchState.value = _searchState.value.copy( - isLoading = false, - places = emptyList(), - error = null - ) - Log.d("naver", "search query blank") + // 검색어가 빈 경우 + if (currentQuery.isBlank()) { + Log.d("naver", "searchPlace - newQuery blank") return } @@ -53,7 +75,7 @@ class SearchViewModel @Inject constructor( searchJob?.cancel() // Flow 수집 및 상태 업데이트 시작 - searchJob = localSearchUseCase(query) + searchJob = localSearchUseCase(currentQuery) .onEach { result -> when (result) { is Resource.Loading -> { @@ -63,8 +85,7 @@ class SearchViewModel @Inject constructor( places = result.data ?: emptyList(), error = null ) - Log.d("naver", "search for $query : Loading...") - + Log.d("naver", "search for $currentQuery : Loading...") } is Resource.Success -> { // 성공 diff --git a/app/src/main/java/com/min/dnapp/presentation/write/component/PlaceBottomSheetContent.kt b/app/src/main/java/com/min/dnapp/presentation/write/component/PlaceBottomSheetContent.kt new file mode 100644 index 0000000..cd8db9b --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/write/component/PlaceBottomSheetContent.kt @@ -0,0 +1,168 @@ +package com.min.dnapp.presentation.write.component + +import androidx.compose.foundation.border +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.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.onFocusChanged +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.platform.LocalSoftwareKeyboardController +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.domain.model.LocalPlace +import com.min.dnapp.presentation.ui.component.SelectButton +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun PlaceBottomSheetContent( + value: String, + places: List, + onValueChange: (String) -> Unit, + onSearch: () -> Unit, + onConfirm: () -> Unit, + onClear: () -> Unit +) { + val keyboardController = LocalSoftwareKeyboardController.current + val focusManager = LocalFocusManager.current + + val onSearchAction = { + // 여행지 검색 실행 + onSearch() + // 키보드 숨기기 + keyboardController?.hide() + // 포커스 해제 + focusManager.clearFocus() + } + + Column( + modifier = Modifier.fillMaxWidth(), +// .padding(horizontal = 20.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(Modifier.height(20.dp)) + + Box( + modifier = Modifier + .padding(horizontal = 20.dp) + .fillMaxWidth() + .border(width = 1.dp, color = MomentoTheme.colors.grayW80, shape = RoundedCornerShape(6.dp)) + .padding(horizontal = 16.dp, vertical = 12.dp) + ) { + if (value.isEmpty()) { + Text( + text = "여행지를 입력해주세요", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW60 + ) + } + BasicTextField( + modifier = Modifier + .fillMaxWidth() + .onFocusChanged { focusState -> + if (focusState.isFocused) { + onClear() + } + }, + value = value, + onValueChange = onValueChange, + textStyle = MomentoTheme.typography.body01, + singleLine = true, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search), + keyboardActions = KeyboardActions( + onSearch = { onSearchAction() } + ) + ) + } + + // 검색 결과 목록 + Column( + modifier = Modifier.fillMaxWidth() + ) { + places.forEach { item -> + PlaceItem( + placeName = item.title, + placeCategory = item.category, + placeRoadAddress = item.roadAddress + ) + } + } + + Spacer(Modifier.height(20.dp)) + + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 20.dp) + ) { + SelectButton( + enabled = false, + onConfirm = {} + ) + Spacer(Modifier.height(16.dp)) + } + } +} + +@Composable +fun PlaceItem( + placeName: String, + placeCategory: String, + placeRoadAddress: String +) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(20.dp), + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = placeName, + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + Text( + text = placeCategory, + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW40 + ) + } + Spacer(Modifier.height(4.dp)) + Text( + text = placeRoadAddress, + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW60 + ) + } + HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW80) +} + +@Preview(showBackground = true) +@Composable +fun PlaceBottomSheetContentPreview() { + DngoTheme { +// PlaceBottomSheetContent( +// value = "", +// onValueChange = {}, +// onConfirm = {} +// ) + } +} From 00baa807ffe340d7bc03a10719d43e9ede544464 Mon Sep 17 00:00:00 2001 From: min486 Date: Sat, 25 Oct 2025 14:37:37 +0900 Subject: [PATCH 40/98] =?UTF-8?q?feat:=20=EC=97=AC=ED=96=89=EC=A7=80=20?= =?UTF-8?q?=EA=B5=AD=EB=82=B4/=ED=95=B4=EC=99=B8=20=EC=84=A0=ED=83=9D=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/write/RecordWriteScreen.kt | 192 ++++++++++++------ .../presentation/write/SearchViewModel.kt | 54 +++-- .../component/PlaceBottomSheetContent.kt | 38 +++- 3 files changed, 195 insertions(+), 89 deletions(-) diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index a3a8496..934c265 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -18,6 +18,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicTextField import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.DatePickerDefaults import androidx.compose.material3.DatePickerDialog @@ -50,6 +51,7 @@ import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.min.dnapp.R +import com.min.dnapp.domain.model.LocalPlace import com.min.dnapp.presentation.ui.icon.AppIcons import com.min.dnapp.presentation.ui.icon.appicons.Back import com.min.dnapp.presentation.ui.icon.appicons.Calendar @@ -67,9 +69,9 @@ fun RecordWriteScreen( searchViewModel: SearchViewModel = hiltViewModel() ) { val searchState by searchViewModel.searchState.collectAsStateWithLifecycle() + val selectedPlace by searchViewModel.selectedPlace.collectAsStateWithLifecycle() + val overseasPlace by searchViewModel.overseasPlace.collectAsStateWithLifecycle() - val radioOptions = listOf("국내", "해외 (직접 입력)") - var selectedPlace by remember { mutableStateOf("국내") } var isChecked by remember { mutableStateOf(true) } var showEmotionBottomSheet by remember { mutableStateOf(false) } var showWeatherBottomSheet by remember { mutableStateOf(false) } @@ -206,67 +208,15 @@ fun RecordWriteScreen( Spacer(Modifier.height(20.dp)) - // 여행지 - Column( - modifier = Modifier.fillMaxWidth() - ) { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = "어디로 다녀오셨나요?", - style = MomentoTheme.typography.body01, - color = MomentoTheme.colors.grayW20 - ) - - // 라디오 버튼 - Row( - verticalAlignment = Alignment.CenterVertically - ) { - radioOptions.forEachIndexed { idx, text -> - RadioButton( - modifier = Modifier.size(24.dp), - selected = (text == selectedPlace), - onClick = { selectedPlace = text }, - colors = RadioButtonDefaults.colors( - selectedColor = MomentoTheme.colors.greenW20, - unselectedColor = MomentoTheme.colors.grayW80, - disabledSelectedColor = MomentoTheme.colors.white - ) - ) - Spacer(Modifier.width(4.dp)) - Text( - text = text, - style = MomentoTheme.typography.body03, - color = MomentoTheme.colors.grayW20 - ) - if (idx == 0) { - Spacer(Modifier.width(12.dp)) - } - } - } - } - - Spacer(Modifier.height(12.dp)) - - Row( - modifier = Modifier.clickable { showPlaceBottomSheet = true }, - verticalAlignment = Alignment.CenterVertically - ) { - Image( - painter = painterResource(R.drawable.write_place), - contentDescription = null - ) - Spacer(Modifier.width(6.dp)) - Text( - text = "위치 추가", - style = MomentoTheme.typography.body02, - color = MomentoTheme.colors.grayW40 - ) - } - } + // 여행지 선택 영역 + PlaceSelectSection( + selectedPlace = selectedPlace, + overseasPlace = overseasPlace, + onValueChange = { newValue -> + searchViewModel.updateOverseas(newValue) + }, + onClick = { showPlaceBottomSheet = true } + ) Spacer(Modifier.height(40.dp)) @@ -436,7 +386,7 @@ fun RecordWriteScreen( containerColor = MomentoTheme.colors.white, shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) ) { - PlaceBottomSheetContent ( + PlaceBottomSheetContent( value = searchState.query, places = searchState.places, onValueChange = { newValue -> @@ -444,8 +394,11 @@ fun RecordWriteScreen( searchViewModel.updateQuery(newValue) }, onSearch = { searchViewModel.searchPlace() }, - onConfirm = { showPlaceBottomSheet = false }, - onClear = { searchViewModel.clearSearchResult() } + onClear = { searchViewModel.clearSearchResult() }, + onConfirm = { place -> + searchViewModel.selectPlace(place) + showPlaceBottomSheet = false + }, ) } } @@ -550,6 +503,113 @@ fun CustomDateRangeHeadline( } } +@Composable +fun PlaceSelectSection( + selectedPlace: LocalPlace?, + overseasPlace: String, + onValueChange: (String) -> Unit, + onClick: () -> Unit, +) { + val radioOptions = listOf("국내", "해외 (직접 입력)") + var selectedCountry by remember { mutableStateOf("국내") } + + Column( + modifier = Modifier.fillMaxWidth() + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "어디로 다녀오셨나요?", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + + // 라디오 버튼 + Row( + verticalAlignment = Alignment.CenterVertically + ) { + radioOptions.forEachIndexed { idx, text -> + RadioButton( + modifier = Modifier.size(24.dp), + selected = (text == selectedCountry), + onClick = { selectedCountry = text }, + colors = RadioButtonDefaults.colors( + selectedColor = MomentoTheme.colors.greenW20, + unselectedColor = MomentoTheme.colors.grayW80, + disabledSelectedColor = MomentoTheme.colors.white + ) + ) + Spacer(Modifier.width(4.dp)) + Text( + text = text, + style = MomentoTheme.typography.body03, + color = MomentoTheme.colors.grayW20 + ) + if (idx == 0) { + Spacer(Modifier.width(12.dp)) + } + } + } + } + + Spacer(Modifier.height(12.dp)) + + if (selectedCountry == "국내") { + Row( + modifier = Modifier.clickable { onClick() }, + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(R.drawable.write_place), + contentDescription = null + ) + Spacer(Modifier.width(6.dp)) + if (selectedPlace == null) { + Text( + text = "위치 추가", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW40 + ) + } else { + Text( + text = selectedPlace.title, + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW20 + ) + } + } + } else { + // 해외 + Box( + modifier = Modifier + .fillMaxWidth() + .height(40.dp) + .background(color = MomentoTheme.colors.brownBg, shape = RoundedCornerShape(5.dp)) + .padding(start = 12.dp), + contentAlignment = Alignment.CenterStart + ) { + if (overseasPlace.isEmpty()) { + Text( + text = "예) 도쿄, 발리", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW60 + ) + } + BasicTextField( + modifier = Modifier.fillMaxWidth(), + value = overseasPlace, + onValueChange = onValueChange, + textStyle = MomentoTheme.typography.body02, + singleLine = true + ) + } + } + } +} + @Composable fun FixedSizeThumbBox() { Box( diff --git a/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt index f44fa2e..12e9cc6 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt @@ -3,6 +3,7 @@ package com.min.dnapp.presentation.write import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.min.dnapp.domain.model.LocalPlace import com.min.dnapp.domain.usecase.LocalSearchUseCase import com.min.dnapp.util.Resource import dagger.hilt.android.lifecycle.HiltViewModel @@ -22,6 +23,12 @@ class SearchViewModel @Inject constructor( private val _searchState = MutableStateFlow(SearchState()) val searchState: StateFlow = _searchState.asStateFlow() + private val _selectedPlace = MutableStateFlow(null) + val selectedPlace: StateFlow = _selectedPlace.asStateFlow() + + private val _overseasPlace = MutableStateFlow("") + val overseasPlace: StateFlow = _overseasPlace.asStateFlow() + // 이전 검색 작업을 취소하기 위한 Job private var searchJob: Job? = null @@ -43,22 +50,6 @@ class SearchViewModel @Inject constructor( } } - /** - * 검색 결과 목록 초기화 - * (textField에 포커스가 잡히거나, 새 검색 시작할 때 사용) - */ - fun clearSearchResult() { - searchJob?.cancel() - - // query는 그대로 유지, 결과 목록만 초기화 - _searchState.value = _searchState.value.copy( - isLoading = false, - places = emptyList(), - error = null - ) - Log.d("naver", "result cleared") - } - /** * 검색 버튼 클릭 시, 검색 API 호출 */ @@ -110,4 +101,35 @@ class SearchViewModel @Inject constructor( // viewModelScope에서 flow를 실행 .launchIn(viewModelScope) } + + /** + * 검색 결과 목록 초기화 + * (textField에 포커스가 잡히거나, 새 검색 시작할 때 사용) + */ + fun clearSearchResult() { + searchJob?.cancel() + + // query는 그대로 유지, 결과 목록만 초기화 + _searchState.value = _searchState.value.copy( + isLoading = false, + places = emptyList(), + error = null + ) + Log.d("naver", "result cleared") + } + + /** + * 국내 - 선택된 장소 저장 + */ + fun selectPlace(place: LocalPlace) { + _selectedPlace.value = place + } + + /** + * 해외 - textField의 입력 값 업데이트 + */ + fun updateOverseas(newPlace: String) { + _overseasPlace.value = newPlace + Log.d("write", "updateOverseas - newPlace : $newPlace") + } } diff --git a/app/src/main/java/com/min/dnapp/presentation/write/component/PlaceBottomSheetContent.kt b/app/src/main/java/com/min/dnapp/presentation/write/component/PlaceBottomSheetContent.kt index cd8db9b..353ce0d 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/component/PlaceBottomSheetContent.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/component/PlaceBottomSheetContent.kt @@ -1,6 +1,8 @@ package com.min.dnapp.presentation.write.component +import androidx.compose.foundation.background import androidx.compose.foundation.border +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -16,9 +18,14 @@ import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.HorizontalDivider 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.focus.onFocusChanged +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.text.input.ImeAction @@ -35,9 +42,13 @@ fun PlaceBottomSheetContent( places: List, onValueChange: (String) -> Unit, onSearch: () -> Unit, - onConfirm: () -> Unit, - onClear: () -> Unit + onClear: () -> Unit, + onConfirm: (LocalPlace) -> Unit, ) { + // 검색 결과 목록에서 선택된 아이템 + var selectedPlace by remember { mutableStateOf(null) } + + // UI 컨트롤러 val keyboardController = LocalSoftwareKeyboardController.current val focusManager = LocalFocusManager.current @@ -52,7 +63,6 @@ fun PlaceBottomSheetContent( Column( modifier = Modifier.fillMaxWidth(), -// .padding(horizontal = 20.dp), horizontalAlignment = Alignment.CenterHorizontally ) { Spacer(Modifier.height(20.dp)) @@ -76,6 +86,7 @@ fun PlaceBottomSheetContent( .fillMaxWidth() .onFocusChanged { focusState -> if (focusState.isFocused) { + selectedPlace = null onClear() } }, @@ -90,6 +101,8 @@ fun PlaceBottomSheetContent( ) } + Spacer(Modifier.height(20.dp)) + // 검색 결과 목록 Column( modifier = Modifier.fillMaxWidth() @@ -98,7 +111,9 @@ fun PlaceBottomSheetContent( PlaceItem( placeName = item.title, placeCategory = item.category, - placeRoadAddress = item.roadAddress + placeRoadAddress = item.roadAddress, + isSelected = selectedPlace == item, + onClick = { selectedPlace = item } ) } } @@ -111,8 +126,11 @@ fun PlaceBottomSheetContent( .padding(horizontal = 20.dp) ) { SelectButton( - enabled = false, - onConfirm = {} + enabled = selectedPlace != null, + onConfirm = { + // 콜백으로 이벤트 전달 + selectedPlace?.let(onConfirm) + } ) Spacer(Modifier.height(16.dp)) } @@ -123,11 +141,17 @@ fun PlaceBottomSheetContent( fun PlaceItem( placeName: String, placeCategory: String, - placeRoadAddress: String + placeRoadAddress: String, + isSelected: Boolean = false, + onClick: () -> Unit ) { Column( modifier = Modifier + .clickable { onClick() } .fillMaxWidth() + .background( + if (isSelected) MomentoTheme.colors.brownW80 else Color.Transparent + ) .padding(20.dp), ) { Row( From be7f64aef782af04eec4ec759114e7ad6a926941 Mon Sep 17 00:00:00 2001 From: min486 Date: Sat, 25 Oct 2025 15:52:22 +0900 Subject: [PATCH 41/98] =?UTF-8?q?feat:=20=EC=A0=9C=EB=AA=A9=20=EB=B0=8F=20?= =?UTF-8?q?=EB=82=B4=EC=9A=A9=20=EC=9E=85=EB=A0=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/write/RecordWriteScreen.kt | 107 ++++++++++++++---- .../presentation/write/SearchViewModel.kt | 28 ++++- 2 files changed, 109 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index 934c265..9799821 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -71,6 +71,8 @@ fun RecordWriteScreen( val searchState by searchViewModel.searchState.collectAsStateWithLifecycle() val selectedPlace by searchViewModel.selectedPlace.collectAsStateWithLifecycle() val overseasPlace by searchViewModel.overseasPlace.collectAsStateWithLifecycle() + val recordTitle by searchViewModel.recordTitle.collectAsStateWithLifecycle() + val recordContent by searchViewModel.recordContent.collectAsStateWithLifecycle() var isChecked by remember { mutableStateOf(true) } var showEmotionBottomSheet by remember { mutableStateOf(false) } @@ -198,12 +200,12 @@ fun RecordWriteScreen( Spacer(Modifier.height(20.dp)) - // 제목 - Box( - modifier = Modifier - .fillMaxWidth() - .height(40.dp) - .background(color = MomentoTheme.colors.brownBg, shape = RoundedCornerShape(5.dp)) + // 제목 영역 + RecordTitleSection( + recordTitle = recordTitle, + onValueChange = { newValue -> + searchViewModel.updateTitle(newValue) + } ) Spacer(Modifier.height(20.dp)) @@ -220,23 +222,13 @@ fun RecordWriteScreen( Spacer(Modifier.height(40.dp)) - // 내용 - Column( - modifier = Modifier.fillMaxWidth() - ) { - Text( - text = "이번 여행에 대해 소개해주세요.", - style = MomentoTheme.typography.body01, - color = MomentoTheme.colors.grayW20 - ) - Spacer(Modifier.height(12.dp)) - Box( - modifier = Modifier - .fillMaxWidth() - .height(310.dp) - .background(color = MomentoTheme.colors.brownBg) - ) - } + // 내용 영역 + RecordContentSection( + recordContent = recordContent, + onValueChange = { newValue -> + searchViewModel.updateContent(newValue) + } + ) } Row( @@ -610,6 +602,75 @@ fun PlaceSelectSection( } } +@Composable +fun RecordTitleSection( + recordTitle: String, + onValueChange: (String) -> Unit +) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(40.dp) + .background(color = MomentoTheme.colors.brownBg, shape = RoundedCornerShape(5.dp)) + .padding(start = 12.dp), + contentAlignment = Alignment.CenterStart + ) { + if (recordTitle.isEmpty()) { + Text( + text = "제목", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW60 + ) + } + BasicTextField( + modifier = Modifier.fillMaxWidth(), + value = recordTitle, + onValueChange = onValueChange, + textStyle = MomentoTheme.typography.body02, + singleLine = true + ) + } +} + +@Composable +fun RecordContentSection( + recordContent: String, + onValueChange: (String) -> Unit +) { + Column( + modifier = Modifier.fillMaxWidth() + ) { + Text( + text = "이번 여행에 대해 소개해주세요.", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + Spacer(Modifier.height(12.dp)) + Box( + modifier = Modifier + .fillMaxWidth() + .height(310.dp) + .background(color = MomentoTheme.colors.brownBg, shape = RoundedCornerShape(5.dp)) + .padding(12.dp) + ) { + if (recordContent.isEmpty()) { + Text( + text = "내용", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW60 + ) + } + BasicTextField( + modifier = Modifier.fillMaxSize(), + value = recordContent, + onValueChange = onValueChange, + textStyle = MomentoTheme.typography.body02, + singleLine = false + ) + } + } +} + @Composable fun FixedSizeThumbBox() { Box( diff --git a/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt index 12e9cc6..c01a40f 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt @@ -29,6 +29,12 @@ class SearchViewModel @Inject constructor( private val _overseasPlace = MutableStateFlow("") val overseasPlace: StateFlow = _overseasPlace.asStateFlow() + private val _recordTitle = MutableStateFlow("") + val recordTitle: StateFlow = _recordTitle.asStateFlow() + + private val _recordContent = MutableStateFlow("") + val recordContent: StateFlow = _recordContent.asStateFlow() + // 이전 검색 작업을 취소하기 위한 Job private var searchJob: Job? = null @@ -128,8 +134,24 @@ class SearchViewModel @Inject constructor( /** * 해외 - textField의 입력 값 업데이트 */ - fun updateOverseas(newPlace: String) { - _overseasPlace.value = newPlace - Log.d("write", "updateOverseas - newPlace : $newPlace") + fun updateOverseas(newText: String) { + _overseasPlace.value = newText + Log.d("write", "updateOverseas - newText : $newText") + } + + /** + * 제목 - textField의 입력 값 업데이트 + */ + fun updateTitle(newText: String) { + _recordTitle.value = newText + Log.d("write", "updateTitle - newText : $newText") + } + + /** + * 내용 - textField의 입력 값 업데이트 + */ + fun updateContent(newText: String) { + _recordContent.value = newText + Log.d("write", "updateContent - newText : $newText") } } From d44a4e73314ac6fee9f4c7de907e45783c55fcc4 Mon Sep 17 00:00:00 2001 From: min486 Date: Sat, 25 Oct 2025 21:06:11 +0900 Subject: [PATCH 42/98] =?UTF-8?q?feat:=20=EA=B0=90=EC=A0=95=20=EB=B0=8F=20?= =?UTF-8?q?=EB=82=A0=EC=94=A8=20=EC=84=A0=ED=83=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/min/dnapp/domain/model/EmotionType.kt | 17 +++ .../com/min/dnapp/domain/model/WeatherType.kt | 17 +++ .../presentation/write/RecordWriteScreen.kt | 133 +++++++++++------- .../presentation/write/SearchViewModel.kt | 24 ++++ .../component/EmotionBottomSheetContent.kt | 130 ++++++++++------- .../component/WeatherBottomSheetContent.kt | 126 +++++++++++------ app/src/main/res/drawable/emotion_angry.xml | 30 ++-- app/src/main/res/drawable/emotion_check.xml | 9 -- app/src/main/res/drawable/emotion_feel.xml | 26 ++-- app/src/main/res/drawable/emotion_happy.xml | 22 +-- app/src/main/res/drawable/emotion_love.xml | 43 +++--- app/src/main/res/drawable/emotion_sad.xml | 38 ++--- app/src/main/res/drawable/emotion_shine.xml | 16 +-- .../main/res/drawable/emotion_surprise.xml | 30 ++-- .../{weather_check.xml => ew_check.xml} | 0 15 files changed, 403 insertions(+), 258 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/domain/model/EmotionType.kt create mode 100644 app/src/main/java/com/min/dnapp/domain/model/WeatherType.kt delete mode 100644 app/src/main/res/drawable/emotion_check.xml rename app/src/main/res/drawable/{weather_check.xml => ew_check.xml} (100%) diff --git a/app/src/main/java/com/min/dnapp/domain/model/EmotionType.kt b/app/src/main/java/com/min/dnapp/domain/model/EmotionType.kt new file mode 100644 index 0000000..bda48e1 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/model/EmotionType.kt @@ -0,0 +1,17 @@ +package com.min.dnapp.domain.model + +import androidx.annotation.DrawableRes +import com.min.dnapp.R + +enum class EmotionType( + val key: String, + @DrawableRes val resId: Int +) { + HAPPY("happy", R.drawable.emotion_happy), + LOVE("love", R.drawable.emotion_love), + SURPRISE("surprise", R.drawable.emotion_surprise), + ANGRY("angry", R.drawable.emotion_angry), + FEEL("feel", R.drawable.emotion_feel), + SAD("sad", R.drawable.emotion_sad), + SHINE("shine", R.drawable.emotion_shine) +} diff --git a/app/src/main/java/com/min/dnapp/domain/model/WeatherType.kt b/app/src/main/java/com/min/dnapp/domain/model/WeatherType.kt new file mode 100644 index 0000000..74e6d81 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/model/WeatherType.kt @@ -0,0 +1,17 @@ +package com.min.dnapp.domain.model + +import androidx.annotation.DrawableRes +import com.min.dnapp.R + +enum class WeatherType( + val key: String, + @DrawableRes val resId: Int +) { + SUN("sun", R.drawable.weather_sun), + WIND("wind", R.drawable.weather_wind), + MOON("moon", R.drawable.weather_moon), + THUNDER("thunder", R.drawable.weather_thunder), + RAIN("rain", R.drawable.weather_rain), + CLOUD("cloud", R.drawable.weather_cloud), + SNOW("snow", R.drawable.weather_snow) +} diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index 9799821..de9b275 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -51,7 +51,9 @@ import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.min.dnapp.R +import com.min.dnapp.domain.model.EmotionType import com.min.dnapp.domain.model.LocalPlace +import com.min.dnapp.domain.model.WeatherType import com.min.dnapp.presentation.ui.icon.AppIcons import com.min.dnapp.presentation.ui.icon.appicons.Back import com.min.dnapp.presentation.ui.icon.appicons.Calendar @@ -73,6 +75,8 @@ fun RecordWriteScreen( val overseasPlace by searchViewModel.overseasPlace.collectAsStateWithLifecycle() val recordTitle by searchViewModel.recordTitle.collectAsStateWithLifecycle() val recordContent by searchViewModel.recordContent.collectAsStateWithLifecycle() + val selectedEmotion by searchViewModel.selectedEmotion.collectAsStateWithLifecycle() + val selectedWeather by searchViewModel.selectedWeather.collectAsStateWithLifecycle() var isChecked by remember { mutableStateOf(true) } var showEmotionBottomSheet by remember { mutableStateOf(false) } @@ -147,56 +151,13 @@ fun RecordWriteScreen( Spacer(Modifier.height(20.dp)) - // 감정 & 날씨 - Row { - Row( - modifier = Modifier.clickable { showEmotionBottomSheet = true }, - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = "감정 태그", - style = MomentoTheme.typography.body01, - color = MomentoTheme.colors.grayW20 - ) - Spacer(Modifier.width(8.dp)) - Box( - modifier = Modifier - .size(32.dp) - .background(color = MomentoTheme.colors.white, shape = RoundedCornerShape(5.dp)) - .border(width = 1.dp, color = MomentoTheme.colors.pinkW60, shape = RoundedCornerShape(5.dp)) - .padding(6.dp) - ) { - Image( - painter = painterResource(R.drawable.emotion_love), - contentDescription = null - ) - } - } - Spacer(Modifier.width(20.dp)) - Row( - modifier = Modifier.clickable { showWeatherBottomSheet = true }, - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = "날씨", - style = MomentoTheme.typography.body01, - color = MomentoTheme.colors.grayW20 - ) - Spacer(Modifier.width(8.dp)) - Box( - modifier = Modifier - .size(32.dp) - .background(color = MomentoTheme.colors.white, shape = RoundedCornerShape(5.dp)) - .border(width = 1.dp, color = MomentoTheme.colors.pinkW60, shape = RoundedCornerShape(5.dp)), - contentAlignment = Alignment.Center - ) { - Image( - painter = painterResource(R.drawable.weather_cloud), - contentDescription = null - ) - } - } - } + // 감정 & 날씨 영역 + EmotionAndWeatherSection( + selectedEmotion = selectedEmotion, + selectedWeather = selectedWeather, + onClickEmotion = { showEmotionBottomSheet = true }, + onClickWeather = { showWeatherBottomSheet = true } + ) Spacer(Modifier.height(20.dp)) @@ -290,7 +251,10 @@ fun RecordWriteScreen( shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) ) { EmotionBottomSheetContent( - onConfirm = { showEmotionBottomSheet = false } + onConfirm = { emotionType -> + searchViewModel.selectEmotion(emotionType) + showEmotionBottomSheet = false + } ) } } @@ -304,7 +268,10 @@ fun RecordWriteScreen( shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) ) { WeatherBottomSheetContent ( - onConfirm = { showWeatherBottomSheet = false } + onConfirm = { weatherType -> + searchViewModel.selectWeather(weatherType) + showWeatherBottomSheet = false + } ) } } @@ -495,6 +462,68 @@ fun CustomDateRangeHeadline( } } +@Composable +fun EmotionAndWeatherSection( + selectedEmotion: EmotionType?, + selectedWeather: WeatherType?, + onClickEmotion: () -> Unit, + onClickWeather: () -> Unit +) { + Row { + Row( + modifier = Modifier.clickable { onClickEmotion() }, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "감정 태그", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + Spacer(Modifier.width(8.dp)) + Box( + modifier = Modifier + .size(32.dp) + .background(color = MomentoTheme.colors.white, shape = RoundedCornerShape(5.dp)) + .border(width = 1.dp, color = MomentoTheme.colors.pinkW60, shape = RoundedCornerShape(5.dp)), + contentAlignment = Alignment.Center + ) { + selectedEmotion?.let { emotionType -> + Image( + painter = painterResource(emotionType.resId), + contentDescription = null + ) + } + } + } + Spacer(Modifier.width(20.dp)) + Row( + modifier = Modifier.clickable { onClickWeather() }, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "날씨", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + Spacer(Modifier.width(8.dp)) + Box( + modifier = Modifier + .size(32.dp) + .background(color = MomentoTheme.colors.white, shape = RoundedCornerShape(5.dp)) + .border(width = 1.dp, color = MomentoTheme.colors.pinkW60, shape = RoundedCornerShape(5.dp)), + contentAlignment = Alignment.Center + ) { + selectedWeather?.let { weatherType -> + Image( + painter = painterResource(weatherType.resId), + contentDescription = null + ) + } + } + } + } +} + @Composable fun PlaceSelectSection( selectedPlace: LocalPlace?, diff --git a/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt index c01a40f..ef23148 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt @@ -3,7 +3,9 @@ package com.min.dnapp.presentation.write import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.min.dnapp.domain.model.EmotionType import com.min.dnapp.domain.model.LocalPlace +import com.min.dnapp.domain.model.WeatherType import com.min.dnapp.domain.usecase.LocalSearchUseCase import com.min.dnapp.util.Resource import dagger.hilt.android.lifecycle.HiltViewModel @@ -35,6 +37,12 @@ class SearchViewModel @Inject constructor( private val _recordContent = MutableStateFlow("") val recordContent: StateFlow = _recordContent.asStateFlow() + private val _selectedEmotion = MutableStateFlow(null) + val selectedEmotion: StateFlow = _selectedEmotion.asStateFlow() + + private val _selectedWeather = MutableStateFlow(null) + val selectedWeather: StateFlow = _selectedWeather.asStateFlow() + // 이전 검색 작업을 취소하기 위한 Job private var searchJob: Job? = null @@ -154,4 +162,20 @@ class SearchViewModel @Inject constructor( _recordContent.value = newText Log.d("write", "updateContent - newText : $newText") } + + /** + * 선택된 감정 저장 + */ + fun selectEmotion(emotionType: EmotionType) { + _selectedEmotion.value = emotionType + Log.d("write", "selectEmotion - emotionType : $emotionType") + } + + /** + * 선택된 날씨 저장 + */ + fun selectWeather(weatherType: WeatherType) { + _selectedWeather.value = weatherType + Log.d("write", "selectWeather - weatherType : $weatherType") + } } diff --git a/app/src/main/java/com/min/dnapp/presentation/write/component/EmotionBottomSheetContent.kt b/app/src/main/java/com/min/dnapp/presentation/write/component/EmotionBottomSheetContent.kt index 8aba23f..8ed1817 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/component/EmotionBottomSheetContent.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/component/EmotionBottomSheetContent.kt @@ -1,7 +1,6 @@ package com.min.dnapp.presentation.write.component 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 @@ -11,21 +10,32 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.layout.size import androidx.compose.material3.HorizontalDivider 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.painterResource import androidx.compose.ui.unit.dp import com.min.dnapp.R +import com.min.dnapp.domain.model.EmotionType +import com.min.dnapp.presentation.ui.component.SelectButton import com.min.dnapp.presentation.ui.theme.MomentoTheme @Composable fun EmotionBottomSheetContent( - onConfirm: () -> Unit + onConfirm: (EmotionType) -> Unit ) { + // 선택된 EmotionType 객체 저장 + var selectedEmotion by remember { mutableStateOf(null) } + // emotion 선택 시 버튼 활성화 + val isButtonEnabled = selectedEmotion != null + Column( modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally @@ -42,86 +52,110 @@ fun EmotionBottomSheetContent( HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW90) - Spacer(Modifier.height(20.dp)) + Spacer(Modifier.height(12.dp)) Column( modifier = Modifier.fillMaxWidth(), - verticalArrangement = Arrangement.spacedBy(28.dp) + verticalArrangement = Arrangement.spacedBy(20.dp) ) { + // happy / love / surprise Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly ) { - Image( - modifier = Modifier.clickable { }, - painter = painterResource(R.drawable.emotion_happy), - contentDescription = null + EmotionItem( + emotionType = EmotionType.HAPPY, + isSelected = selectedEmotion == EmotionType.HAPPY, + onSelect = { emotionType -> selectedEmotion = emotionType } ) - Image( - modifier = Modifier.clickable { }, - painter = painterResource(R.drawable.emotion_love), - contentDescription = null + EmotionItem( + emotionType = EmotionType.LOVE, + isSelected = selectedEmotion == EmotionType.LOVE, + onSelect = { emotionType -> selectedEmotion = emotionType } ) - Image( - modifier = Modifier.clickable { }, - painter = painterResource(R.drawable.emotion_surprise), - contentDescription = null + EmotionItem( + emotionType = EmotionType.SURPRISE, + isSelected = selectedEmotion == EmotionType.SURPRISE, + onSelect = { emotionType -> selectedEmotion = emotionType } ) } + + // angry / feel / sad Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly ) { - Image( - modifier = Modifier.clickable { }, - painter = painterResource(R.drawable.emotion_angry), - contentDescription = null + EmotionItem( + emotionType = EmotionType.ANGRY, + isSelected = selectedEmotion == EmotionType.ANGRY, + onSelect = { emotionType -> selectedEmotion = emotionType } ) - Image( - modifier = Modifier.clickable { }, - painter = painterResource(R.drawable.emotion_feel), - contentDescription = null + EmotionItem( + emotionType = EmotionType.FEEL, + isSelected = selectedEmotion == EmotionType.FEEL, + onSelect = { emotionType -> selectedEmotion = emotionType } ) - Image( - modifier = Modifier.clickable { }, - painter = painterResource(R.drawable.emotion_sad), - contentDescription = null + EmotionItem( + emotionType = EmotionType.SAD, + isSelected = selectedEmotion == EmotionType.SAD, + onSelect = { emotionType -> selectedEmotion = emotionType } ) } + + // shine Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center ) { - Image( - modifier = Modifier.clickable { }, - painter = painterResource(R.drawable.emotion_shine), - contentDescription = null + EmotionItem( + emotionType = EmotionType.SHINE, + isSelected = selectedEmotion == EmotionType.SHINE, + onSelect = { emotionType -> selectedEmotion = emotionType } ) } } - Spacer(Modifier.height(40.dp)) + Spacer(Modifier.height(32.dp)) + // 선택 버튼 Column( modifier = Modifier .fillMaxWidth() .padding(horizontal = 20.dp) ) { - Box( - modifier = Modifier - .clickable { onConfirm() } - .fillMaxWidth() - .background(color = MomentoTheme.colors.brownBase, shape = RoundedCornerShape(10.dp)) - .padding(vertical = 16.dp), - contentAlignment = Alignment.Center - ) { - Text( - text = "선택했어요", - style = MomentoTheme.typography.body01, - color = MomentoTheme.colors.white - ) - } + SelectButton( + enabled = isButtonEnabled, + onConfirm = { + selectedEmotion?.let(onConfirm) + } + ) Spacer(Modifier.height(16.dp)) } } } + +@Composable +fun EmotionItem( + emotionType: EmotionType, + isSelected: Boolean, + onSelect: (EmotionType) -> Unit +) { + Box( + contentAlignment = Alignment.Center + ) { + Image( + modifier = Modifier.clickable { + onSelect(emotionType) + }, + painter = painterResource(emotionType.resId), + contentDescription = null + ) + if (isSelected) { + Image( + modifier = Modifier.size(52.dp), + painter = painterResource(R.drawable.ew_check), + contentDescription = null + ) + } + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/write/component/WeatherBottomSheetContent.kt b/app/src/main/java/com/min/dnapp/presentation/write/component/WeatherBottomSheetContent.kt index a3fbd7b..e85502f 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/component/WeatherBottomSheetContent.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/component/WeatherBottomSheetContent.kt @@ -1,7 +1,6 @@ package com.min.dnapp.presentation.write.component 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 @@ -11,21 +10,32 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.layout.size import androidx.compose.material3.HorizontalDivider 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.painterResource import androidx.compose.ui.unit.dp import com.min.dnapp.R +import com.min.dnapp.domain.model.WeatherType +import com.min.dnapp.presentation.ui.component.SelectButton import com.min.dnapp.presentation.ui.theme.MomentoTheme @Composable fun WeatherBottomSheetContent( - onConfirm: () -> Unit + onConfirm: (WeatherType) -> Unit ) { + // 선택된 WeatherType 객체 저장 + var selectedWeather by remember { mutableStateOf(null) } + // weather 선택 시 버튼 활성화 + val isButtonEnabled = selectedWeather != null + Column( modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally @@ -42,86 +52,110 @@ fun WeatherBottomSheetContent( HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW90) - Spacer(Modifier.height(12 .dp)) + Spacer(Modifier.height(12.dp)) Column( modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(20.dp) ) { + // sun / wind / moon Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly ) { - Image( - modifier = Modifier.clickable { }, - painter = painterResource(R.drawable.weather_sun), - contentDescription = null + WeatherItem( + weatherType = WeatherType.SUN, + isSelected = selectedWeather == WeatherType.SUN, + onSelect = { weatherType -> selectedWeather = weatherType } ) - Image( - modifier = Modifier.clickable { }, - painter = painterResource(R.drawable.weather_wind), - contentDescription = null + WeatherItem( + weatherType = WeatherType.WIND, + isSelected = selectedWeather == WeatherType.WIND, + onSelect = { weatherType -> selectedWeather = weatherType } ) - Image( - modifier = Modifier.clickable { }, - painter = painterResource(R.drawable.weather_moon), - contentDescription = null + WeatherItem( + weatherType = WeatherType.MOON, + isSelected = selectedWeather == WeatherType.MOON, + onSelect = { weatherType -> selectedWeather = weatherType } ) } + + // thunder / rain / cloud Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly ) { - Image( - modifier = Modifier.clickable { }, - painter = painterResource(R.drawable.weather_thunder), - contentDescription = null + WeatherItem( + weatherType = WeatherType.THUNDER, + isSelected = selectedWeather == WeatherType.THUNDER, + onSelect = { weatherType -> selectedWeather = weatherType } ) - Image( - modifier = Modifier.clickable { }, - painter = painterResource(R.drawable.weather_rain), - contentDescription = null + WeatherItem( + weatherType = WeatherType.RAIN, + isSelected = selectedWeather == WeatherType.RAIN, + onSelect = { weatherType -> selectedWeather = weatherType } ) - Image( - modifier = Modifier.clickable { }, - painter = painterResource(R.drawable.weather_cloud), - contentDescription = null + WeatherItem( + weatherType = WeatherType.CLOUD, + isSelected = selectedWeather == WeatherType.CLOUD, + onSelect = { weatherType -> selectedWeather = weatherType } ) } + + // snow Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center ) { - Image( - modifier = Modifier.clickable { }, - painter = painterResource(R.drawable.weather_snow), - contentDescription = null + WeatherItem( + weatherType = WeatherType.SNOW, + isSelected = selectedWeather == WeatherType.SNOW, + onSelect = { weatherType -> selectedWeather = weatherType } ) } } Spacer(Modifier.height(32.dp)) + // 선택 버튼 Column( modifier = Modifier .fillMaxWidth() .padding(horizontal = 20.dp) ) { - Box( - modifier = Modifier - .clickable { onConfirm() } - .fillMaxWidth() - .background(color = MomentoTheme.colors.brownBase, shape = RoundedCornerShape(10.dp)) - .padding(vertical = 16.dp), - contentAlignment = Alignment.Center - ) { - Text( - text = "선택했어요", - style = MomentoTheme.typography.body01, - color = MomentoTheme.colors.white - ) - } + SelectButton( + enabled = isButtonEnabled, + onConfirm = { + selectedWeather?.let(onConfirm) + } + ) Spacer(Modifier.height(16.dp)) } } } + +@Composable +fun WeatherItem( + weatherType: WeatherType, + isSelected: Boolean, + onSelect: (WeatherType) -> Unit +) { + Box( + contentAlignment = Alignment.Center + ) { + Image( + modifier = Modifier.clickable { + onSelect(weatherType) + }, + painter = painterResource(weatherType.resId), + contentDescription = null + ) + if (isSelected) { + Image( + modifier = Modifier.size(48.dp), + painter = painterResource(R.drawable.ew_check), + contentDescription = null + ) + } + } +} diff --git a/app/src/main/res/drawable/emotion_angry.xml b/app/src/main/res/drawable/emotion_angry.xml index 2ddcc99..ccabfb6 100644 --- a/app/src/main/res/drawable/emotion_angry.xml +++ b/app/src/main/res/drawable/emotion_angry.xml @@ -1,44 +1,44 @@ + android:width="56dp" + android:height="56dp" + android:viewportWidth="56" + android:viewportHeight="56"> diff --git a/app/src/main/res/drawable/emotion_check.xml b/app/src/main/res/drawable/emotion_check.xml deleted file mode 100644 index 01c245c..0000000 --- a/app/src/main/res/drawable/emotion_check.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/emotion_feel.xml b/app/src/main/res/drawable/emotion_feel.xml index 968bf77..cee3641 100644 --- a/app/src/main/res/drawable/emotion_feel.xml +++ b/app/src/main/res/drawable/emotion_feel.xml @@ -1,36 +1,36 @@ + android:width="56dp" + android:height="56dp" + android:viewportWidth="56" + android:viewportHeight="56"> diff --git a/app/src/main/res/drawable/emotion_happy.xml b/app/src/main/res/drawable/emotion_happy.xml index b7550cc..9883e53 100644 --- a/app/src/main/res/drawable/emotion_happy.xml +++ b/app/src/main/res/drawable/emotion_happy.xml @@ -1,30 +1,30 @@ + android:width="56dp" + android:height="56dp" + android:viewportWidth="56" + android:viewportHeight="56"> diff --git a/app/src/main/res/drawable/emotion_love.xml b/app/src/main/res/drawable/emotion_love.xml index 0358c66..a5a35a8 100644 --- a/app/src/main/res/drawable/emotion_love.xml +++ b/app/src/main/res/drawable/emotion_love.xml @@ -1,23 +1,22 @@ - - - - - - - \ No newline at end of file + android:width="56dp" + android:height="56dp" + android:viewportWidth="56" + android:viewportHeight="56"> + + + + + + diff --git a/app/src/main/res/drawable/emotion_sad.xml b/app/src/main/res/drawable/emotion_sad.xml index 10c9ab2..e3a6ef7 100644 --- a/app/src/main/res/drawable/emotion_sad.xml +++ b/app/src/main/res/drawable/emotion_sad.xml @@ -1,57 +1,57 @@ + android:width="56dp" + android:height="56dp" + android:viewportWidth="56" + android:viewportHeight="56"> diff --git a/app/src/main/res/drawable/emotion_shine.xml b/app/src/main/res/drawable/emotion_shine.xml index 227b21c..86c8197 100644 --- a/app/src/main/res/drawable/emotion_shine.xml +++ b/app/src/main/res/drawable/emotion_shine.xml @@ -1,18 +1,18 @@ + android:width="56dp" + android:height="56dp" + android:viewportWidth="56" + android:viewportHeight="56"> diff --git a/app/src/main/res/drawable/emotion_surprise.xml b/app/src/main/res/drawable/emotion_surprise.xml index b117145..0672f65 100644 --- a/app/src/main/res/drawable/emotion_surprise.xml +++ b/app/src/main/res/drawable/emotion_surprise.xml @@ -1,44 +1,44 @@ + android:width="56dp" + android:height="56dp" + android:viewportWidth="56" + android:viewportHeight="56"> diff --git a/app/src/main/res/drawable/weather_check.xml b/app/src/main/res/drawable/ew_check.xml similarity index 100% rename from app/src/main/res/drawable/weather_check.xml rename to app/src/main/res/drawable/ew_check.xml From 029fd71f12015f269ee8354547a9b93e007b85bb Mon Sep 17 00:00:00 2001 From: min486 Date: Sat, 25 Oct 2025 23:49:26 +0900 Subject: [PATCH 43/98] =?UTF-8?q?feat:=20=EA=B3=B5=EC=9C=A0=EC=97=AC?= =?UTF-8?q?=EB=B6=80=20=EC=84=A4=EC=A0=95=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/write/RecordWriteScreen.kt | 192 ++++++++++-------- .../presentation/write/SearchViewModel.kt | 11 + 2 files changed, 113 insertions(+), 90 deletions(-) diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index de9b275..91c09cd 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -77,15 +77,15 @@ fun RecordWriteScreen( val recordContent by searchViewModel.recordContent.collectAsStateWithLifecycle() val selectedEmotion by searchViewModel.selectedEmotion.collectAsStateWithLifecycle() val selectedWeather by searchViewModel.selectedWeather.collectAsStateWithLifecycle() - - var isChecked by remember { mutableStateOf(true) } - var showEmotionBottomSheet by remember { mutableStateOf(false) } - var showWeatherBottomSheet by remember { mutableStateOf(false) } + val isChecked by searchViewModel.isChecked.collectAsStateWithLifecycle() // 캘린더 var showDatePicker by remember { mutableStateOf(false) } val dateRangePickerState = rememberDateRangePickerState() + var showEmotionBottomSheet by remember { mutableStateOf(false) } + var showWeatherBottomSheet by remember { mutableStateOf(false) } + // 여행지 - 위치 추가 var showPlaceBottomSheet by remember { mutableStateOf(false) } val sheetState = rememberModalBottomSheetState( @@ -162,7 +162,7 @@ fun RecordWriteScreen( Spacer(Modifier.height(20.dp)) // 제목 영역 - RecordTitleSection( + WriteTitleSection( recordTitle = recordTitle, onValueChange = { newValue -> searchViewModel.updateTitle(newValue) @@ -171,8 +171,8 @@ fun RecordWriteScreen( Spacer(Modifier.height(20.dp)) - // 여행지 선택 영역 - PlaceSelectSection( + // 여행지 영역 + WritePlaceSection( selectedPlace = selectedPlace, overseasPlace = overseasPlace, onValueChange = { newValue -> @@ -184,7 +184,7 @@ fun RecordWriteScreen( Spacer(Modifier.height(40.dp)) // 내용 영역 - RecordContentSection( + WriteContentSection( recordContent = recordContent, onValueChange = { newValue -> searchViewModel.updateContent(newValue) @@ -192,85 +192,11 @@ fun RecordWriteScreen( ) } - Row( - modifier = Modifier - .fillMaxWidth() - .background(color = MomentoTheme.colors.white), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Icon( - modifier = Modifier - .clickable { } - .padding(20.dp), - imageVector = AppIcons.Gallery, - contentDescription = null, - tint = MomentoTheme.colors.grayW60 - ) - - Row( - modifier = Modifier.padding(end = 20.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = "공유 여부", - style = MomentoTheme.typography.body01, - color = MomentoTheme.colors.grayW20 - ) - Spacer(Modifier.width(8.dp)) - Switch( - // 기본 크기의 80%로 축소 - modifier = Modifier.scale(0.8f), - checked = isChecked, - onCheckedChange = { newChecked -> - isChecked = newChecked - }, - thumbContent = { FixedSizeThumbBox() }, - colors = SwitchDefaults.colors( - // on - switch 배경 색 - checkedTrackColor = MomentoTheme.colors.greenW20, - // off - switch 배경 색 - uncheckedTrackColor = MomentoTheme.colors.grayW80, - // off - switch 테두리 색 - uncheckedBorderColor = Color.Transparent, - // off - thumb 테두리 색 - uncheckedThumbColor = MomentoTheme.colors.white - ) - ) - } - } - } - } - - // 감정 선택 바텀시트 - if (showEmotionBottomSheet) { - ModalBottomSheet( - onDismissRequest = { showEmotionBottomSheet = false }, - dragHandle = null, - containerColor = MomentoTheme.colors.white, - shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) - ) { - EmotionBottomSheetContent( - onConfirm = { emotionType -> - searchViewModel.selectEmotion(emotionType) - showEmotionBottomSheet = false - } - ) - } - } - - // 날씨 선택 바텀시트 - if (showWeatherBottomSheet) { - ModalBottomSheet( - onDismissRequest = { showWeatherBottomSheet = false }, - dragHandle = null, - containerColor = MomentoTheme.colors.white, - shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) - ) { - WeatherBottomSheetContent ( - onConfirm = { weatherType -> - searchViewModel.selectWeather(weatherType) - showWeatherBottomSheet = false + // 이미지 아이콘 & 공유여부 스위치 영역 + ImageAndShareSection( + isChecked = isChecked, + onCheckedChange = { newChecked -> + searchViewModel.updateShare(newChecked) } ) } @@ -336,6 +262,40 @@ fun RecordWriteScreen( } } + // 감정 선택 바텀시트 + if (showEmotionBottomSheet) { + ModalBottomSheet( + onDismissRequest = { showEmotionBottomSheet = false }, + dragHandle = null, + containerColor = MomentoTheme.colors.white, + shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) + ) { + EmotionBottomSheetContent( + onConfirm = { emotionType -> + searchViewModel.selectEmotion(emotionType) + showEmotionBottomSheet = false + } + ) + } + } + + // 날씨 선택 바텀시트 + if (showWeatherBottomSheet) { + ModalBottomSheet( + onDismissRequest = { showWeatherBottomSheet = false }, + dragHandle = null, + containerColor = MomentoTheme.colors.white, + shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) + ) { + WeatherBottomSheetContent ( + onConfirm = { weatherType -> + searchViewModel.selectWeather(weatherType) + showWeatherBottomSheet = false + } + ) + } + } + // 위치 추가 바텀시트 if (showPlaceBottomSheet) { ModalBottomSheet( @@ -525,7 +485,7 @@ fun EmotionAndWeatherSection( } @Composable -fun PlaceSelectSection( +fun WritePlaceSection( selectedPlace: LocalPlace?, overseasPlace: String, onValueChange: (String) -> Unit, @@ -632,7 +592,7 @@ fun PlaceSelectSection( } @Composable -fun RecordTitleSection( +fun WriteTitleSection( recordTitle: String, onValueChange: (String) -> Unit ) { @@ -662,7 +622,7 @@ fun RecordTitleSection( } @Composable -fun RecordContentSection( +fun WriteContentSection( recordContent: String, onValueChange: (String) -> Unit ) { @@ -700,6 +660,58 @@ fun RecordContentSection( } } +@Composable +fun ImageAndShareSection( + isChecked: Boolean, + onCheckedChange: (Boolean) -> Unit +) { + Row( + modifier = Modifier + .fillMaxWidth() + .background(color = MomentoTheme.colors.white), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + modifier = Modifier + .clickable { } + .padding(20.dp), + imageVector = AppIcons.Gallery, + contentDescription = null, + tint = MomentoTheme.colors.grayW60 + ) + + Row( + modifier = Modifier.padding(end = 20.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "공유 여부", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + Spacer(Modifier.width(8.dp)) + Switch( + // 기본 크기의 80%로 축소 + modifier = Modifier.scale(0.8f), + checked = isChecked, + onCheckedChange = onCheckedChange, + thumbContent = { FixedSizeThumbBox() }, + colors = SwitchDefaults.colors( + // on - switch 배경 색 + checkedTrackColor = MomentoTheme.colors.greenW20, + // off - switch 배경 색 + uncheckedTrackColor = MomentoTheme.colors.grayW80, + // off - switch 테두리 색 + uncheckedBorderColor = Color.Transparent, + // off - thumb 테두리 색 + uncheckedThumbColor = MomentoTheme.colors.white + ) + ) + } + } +} + @Composable fun FixedSizeThumbBox() { Box( diff --git a/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt index ef23148..fbbdd48 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt @@ -43,6 +43,9 @@ class SearchViewModel @Inject constructor( private val _selectedWeather = MutableStateFlow(null) val selectedWeather: StateFlow = _selectedWeather.asStateFlow() + private val _isChecked = MutableStateFlow(true) + val isChecked: StateFlow = _isChecked.asStateFlow() + // 이전 검색 작업을 취소하기 위한 Job private var searchJob: Job? = null @@ -178,4 +181,12 @@ class SearchViewModel @Inject constructor( _selectedWeather.value = weatherType Log.d("write", "selectWeather - weatherType : $weatherType") } + + /** + * 공유여부 설정 상태 업데이트 + */ + fun updateShare(newChecked: Boolean) { + _isChecked.value = newChecked + Log.d("write", "updateShare - newChecked : $newChecked") + } } From 502fd67aed427146b1c2ec4a37dc652cb0ce83f9 Mon Sep 17 00:00:00 2001 From: min486 Date: Mon, 27 Oct 2025 21:30:59 +0900 Subject: [PATCH 44/98] =?UTF-8?q?feat:=20=EC=BB=A4=EC=8A=A4=ED=85=80=20flo?= =?UTF-8?q?atingActionButton=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 10 +- .../dnapp/presentation/home/HomeScreen2.kt | 13 +- .../component/CustomFloatingActionButton.kt | 45 ++++++ .../dnapp/presentation/ui/icon/__AppIcons.kt | 5 +- .../presentation/ui/icon/appicons/Pen.kt | 132 ++++++++++++++++++ .../presentation/write/RecordWriteScreen.kt | 6 +- 6 files changed, 202 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/component/CustomFloatingActionButton.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Pen.kt diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index 2e7c720..60db65a 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -37,8 +37,7 @@ class MainActivity : ComponentActivity() { // enableEdgeToEdge() setContent { DngoTheme { -// MomentoApp() - RecordWriteScreen() + MomentoApp() } } } @@ -79,8 +78,8 @@ fun MomentoApp( modifier = Modifier.padding(paddingValues), navController = navController, // startDestination = startDestination -// startDestination = "home" - startDestination = "login" + startDestination = "home" +// startDestination = "login" ) { composable("login") { LoginScreen2(navController = navController) @@ -100,6 +99,9 @@ fun MomentoApp( composable("explore_detail") { FindDetailScreen(navController = navController) } + composable("record_write") { + RecordWriteScreen(navController = navController) + } } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt index 80ed293..0f8447d 100644 --- a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt +++ b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt @@ -34,8 +34,10 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.navigation.NavHostController +import androidx.navigation.compose.rememberNavController import com.min.dnapp.R import com.min.dnapp.presentation.mypage.UserBadge +import com.min.dnapp.presentation.ui.component.CustomFloatingActionButton import com.min.dnapp.presentation.ui.icon.AppIcons import com.min.dnapp.presentation.ui.icon.appicons.ArrowRight import com.min.dnapp.presentation.ui.icon.appicons.Bell @@ -74,6 +76,13 @@ fun HomeScreen2(navController: NavHostController) { ) } ) + }, + floatingActionButton = { + CustomFloatingActionButton( + onClick = { + navController.navigate("record_write") + } + ) } ) { paddingValues -> Column( @@ -398,6 +407,8 @@ fun HomeGrayLine( @Composable fun HomeScreen2Preview() { DngoTheme { -// HomeScreen2() + HomeScreen2( + navController = rememberNavController() + ) } } diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/component/CustomFloatingActionButton.kt b/app/src/main/java/com/min/dnapp/presentation/ui/component/CustomFloatingActionButton.kt new file mode 100644 index 0000000..fade4ca --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/component/CustomFloatingActionButton.kt @@ -0,0 +1,45 @@ +package com.min.dnapp.presentation.ui.component + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import com.min.dnapp.presentation.ui.icon.appicons.Pen +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun CustomFloatingActionButton( + onClick: () -> Unit +) { + Surface( + onClick = { onClick() }, + color = MomentoTheme.colors.pinkB20, + shape = RoundedCornerShape(50.dp) + ) { + Row( + modifier = Modifier.padding(horizontal = 12.dp, vertical = 10.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = AppIcons.Pen, + contentDescription = null, + tint = MomentoTheme.colors.white + ) + Spacer(Modifier.width(4.dp)) + Text( + text = "기록 남기기", + style = MomentoTheme.typography.label, + color = MomentoTheme.colors.white + ) + } + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt index c4995e6..034c738 100644 --- a/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt @@ -12,6 +12,7 @@ import com.min.dnapp.presentation.ui.icon.appicons.Home import com.min.dnapp.presentation.ui.icon.appicons.Kakao import com.min.dnapp.presentation.ui.icon.appicons.More import com.min.dnapp.presentation.ui.icon.appicons.My +import com.min.dnapp.presentation.ui.icon.appicons.Pen import com.min.dnapp.presentation.ui.icon.appicons.PenSmall import com.min.dnapp.presentation.ui.icon.appicons.RecordBest import com.min.dnapp.presentation.ui.icon.appicons.RecordBookmark @@ -31,7 +32,7 @@ public val AppIcons.AllIcons: ____KtList return __AllIcons!! } __AllIcons= listOf(ArrowRight, Back, Bell, Calendar, Delete, Explore, Gallery, Home, Kakao, - More, My, PenSmall, RecordBest, RecordBookmark, RecordComment, RecordLike, RecordSurprise, - Year) + More, My, Pen, PenSmall, RecordBest, RecordBookmark, RecordComment, RecordLike, + RecordSurprise, Year) return __AllIcons!! } diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Pen.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Pen.kt new file mode 100644 index 0000000..8299864 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/Pen.kt @@ -0,0 +1,132 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.Pen: ImageVector + get() { + if (_pen != null) { + return _pen!! + } + _pen = Builder(name = "Pen", defaultWidth = 20.0.dp, defaultHeight = 20.0.dp, viewportWidth + = 20.0f, viewportHeight = 20.0f).apply { + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(15.026f, 7.164f) + curveTo(15.026f, 6.992f, 14.956f, 6.835f, 14.817f, 6.653f) + curveTo(14.682f, 6.476f, 14.48f, 6.273f, 14.212f, 6.005f) + lineTo(14.192f, 5.985f) + lineTo(14.029f, 5.822f) + curveTo(13.762f, 5.555f, 13.559f, 5.353f, 13.382f, 5.218f) + lineTo(13.249f, 5.127f) + curveTo(13.12f, 5.048f, 13.0f, 5.009f, 12.871f, 5.009f) + curveTo(12.699f, 5.009f, 12.543f, 5.078f, 12.361f, 5.217f) + curveTo(12.184f, 5.352f, 11.98f, 5.555f, 11.712f, 5.822f) + lineTo(5.693f, 11.842f) + lineTo(5.665f, 11.869f) + curveTo(5.524f, 12.011f, 5.45f, 12.089f, 5.399f, 12.178f) + lineTo(5.398f, 12.179f) + curveTo(5.346f, 12.271f, 5.318f, 12.376f, 5.269f, 12.575f) + lineTo(5.259f, 12.611f) + lineTo(4.698f, 14.852f) + curveTo(4.67f, 14.959f, 4.647f, 15.068f, 4.631f, 15.177f) + curveTo(4.627f, 15.215f, 4.629f, 15.251f, 4.636f, 15.282f) + curveTo(4.642f, 15.311f, 4.654f, 15.335f, 4.677f, 15.359f) + curveTo(4.7f, 15.382f, 4.724f, 15.393f, 4.751f, 15.399f) + curveTo(4.782f, 15.406f, 4.818f, 15.406f, 4.857f, 15.403f) + curveTo(4.972f, 15.387f, 5.087f, 15.363f, 5.199f, 15.332f) + lineTo(5.216f, 15.327f) + lineTo(7.423f, 14.775f) + lineTo(7.434f, 14.773f) + lineTo(7.459f, 14.767f) + curveTo(7.657f, 14.717f, 7.764f, 14.688f, 7.855f, 14.637f) + curveTo(7.947f, 14.584f, 8.027f, 14.507f, 8.17f, 14.365f) + lineTo(8.197f, 14.337f) + lineTo(14.192f, 8.342f) + lineTo(14.212f, 8.322f) + curveTo(14.48f, 8.055f, 14.682f, 7.851f, 14.817f, 7.674f) + curveTo(14.956f, 7.491f, 15.026f, 7.335f, 15.026f, 7.164f) + close() + moveTo(15.859f, 7.164f) + curveTo(15.859f, 7.592f, 15.674f, 7.924f, 15.48f, 8.179f) + lineTo(15.479f, 8.18f) + curveTo(15.303f, 8.411f, 15.055f, 8.658f, 14.802f, 8.912f) + lineTo(8.759f, 14.954f) + curveTo(8.632f, 15.081f, 8.474f, 15.243f, 8.268f, 15.361f) + curveTo(8.06f, 15.479f, 7.837f, 15.531f, 7.663f, 15.575f) + lineTo(7.652f, 15.578f) + lineTo(7.625f, 15.583f) + lineTo(5.444f, 16.128f) + lineTo(5.427f, 16.133f) + curveTo(5.273f, 16.177f, 5.115f, 16.21f, 4.956f, 16.23f) + lineTo(4.946f, 16.232f) + curveTo(4.774f, 16.25f, 4.395f, 16.257f, 4.086f, 15.947f) + curveTo(3.779f, 15.639f, 3.786f, 15.262f, 3.802f, 15.091f) + lineTo(3.803f, 15.081f) + lineTo(3.805f, 15.072f) + curveTo(3.826f, 14.925f, 3.855f, 14.78f, 3.893f, 14.637f) + lineTo(4.451f, 12.409f) + lineTo(4.46f, 12.373f) + curveTo(4.503f, 12.198f, 4.555f, 11.976f, 4.673f, 11.768f) + curveTo(4.79f, 11.561f, 4.955f, 11.402f, 5.08f, 11.276f) + lineTo(5.085f, 11.27f) + lineTo(5.108f, 11.248f) + lineTo(11.103f, 5.253f) + lineTo(11.123f, 5.233f) + curveTo(11.377f, 4.98f, 11.624f, 4.731f, 11.855f, 4.555f) + curveTo(12.111f, 4.359f, 12.443f, 4.175f, 12.871f, 4.175f) + curveTo(13.246f, 4.175f, 13.547f, 4.317f, 13.788f, 4.483f) + lineTo(13.887f, 4.555f) + lineTo(14.064f, 4.699f) + curveTo(14.242f, 4.855f, 14.428f, 5.043f, 14.618f, 5.233f) + lineTo(14.639f, 5.253f) + lineTo(14.781f, 5.396f) + lineTo(14.802f, 5.416f) + curveTo(15.055f, 5.669f, 15.303f, 5.916f, 15.479f, 6.147f) + lineTo(15.552f, 6.247f) + curveTo(15.718f, 6.488f, 15.859f, 6.789f, 15.859f, 7.164f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(10.788f, 5.914f) + lineTo(13.288f, 4.247f) + lineTo(15.788f, 6.747f) + lineTo(14.121f, 9.247f) + lineTo(10.788f, 5.914f) + close() + } + } + .build() + return _pen!! + } + +private var _pen: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.Pen, contentDescription = "") + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index 91c09cd..9e10c18 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -50,6 +50,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.NavHostController import com.min.dnapp.R import com.min.dnapp.domain.model.EmotionType import com.min.dnapp.domain.model.LocalPlace @@ -68,6 +69,7 @@ import com.min.dnapp.util.toLocalDate @OptIn(ExperimentalMaterial3Api::class) @Composable fun RecordWriteScreen( + navController: NavHostController, searchViewModel: SearchViewModel = hiltViewModel() ) { val searchState by searchViewModel.searchState.collectAsStateWithLifecycle() @@ -110,7 +112,7 @@ fun RecordWriteScreen( navigationIcon = { Icon( modifier = Modifier - .clickable { } + .clickable { navController.popBackStack() } .padding(16.dp), imageVector = AppIcons.Back, contentDescription = null @@ -725,6 +727,6 @@ fun FixedSizeThumbBox() { @Composable fun RecordWriteScreenPreview() { DngoTheme { - RecordWriteScreen() +// RecordWriteScreen() } } From 2d29c4c3686da6e904e615e556e39aa16850bb6d Mon Sep 17 00:00:00 2001 From: min486 Date: Mon, 27 Oct 2025 22:56:06 +0900 Subject: [PATCH 45/98] =?UTF-8?q?design:=20BottomBar=20=EC=83=81=EB=8B=A8?= =?UTF-8?q?=EC=97=90=20=EA=B5=AC=EB=B6=84=EC=84=A0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../min/dnapp/presentation/ui/component/MomentoBottomNav.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/component/MomentoBottomNav.kt b/app/src/main/java/com/min/dnapp/presentation/ui/component/MomentoBottomNav.kt index 48c6c81..9b2faf3 100644 --- a/app/src/main/java/com/min/dnapp/presentation/ui/component/MomentoBottomNav.kt +++ b/app/src/main/java/com/min/dnapp/presentation/ui/component/MomentoBottomNav.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -50,6 +51,8 @@ fun MomentoBottomNav( Column( modifier = Modifier.fillMaxWidth() ) { + HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW90) + Row( modifier = Modifier .fillMaxWidth() From 3f57bde7c4ac2846030da6ad9d17e631ffec71be Mon Sep 17 00:00:00 2001 From: min486 Date: Tue, 28 Oct 2025 18:05:35 +0900 Subject: [PATCH 46/98] =?UTF-8?q?refactor:=20RecordWriteViewModel=20-=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20?= =?UTF-8?q?=EB=B0=A9=EC=8B=9D=20=EA=B0=9C=EC=84=A0=20(=EB=8B=A8=EC=9D=BC?= =?UTF-8?q?=20StateFlow=20=ED=86=B5=ED=95=A9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/write/RecordWriteScreen.kt | 83 +++++------ .../presentation/write/RecordWriteUiState.kt | 28 ++++ ...chViewModel.kt => RecordWriteViewModel.kt} | 131 ++++++++---------- .../dnapp/presentation/write/SearchState.kt | 10 -- 4 files changed, 132 insertions(+), 120 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/write/RecordWriteUiState.kt rename app/src/main/java/com/min/dnapp/presentation/write/{SearchViewModel.kt => RecordWriteViewModel.kt} (67%) delete mode 100644 app/src/main/java/com/min/dnapp/presentation/write/SearchState.kt diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index 9e10c18..ebc4698 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -1,6 +1,5 @@ package com.min.dnapp.presentation.write -import android.util.Log import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -70,25 +69,17 @@ import com.min.dnapp.util.toLocalDate @Composable fun RecordWriteScreen( navController: NavHostController, - searchViewModel: SearchViewModel = hiltViewModel() + viewModel: RecordWriteViewModel = hiltViewModel() ) { - val searchState by searchViewModel.searchState.collectAsStateWithLifecycle() - val selectedPlace by searchViewModel.selectedPlace.collectAsStateWithLifecycle() - val overseasPlace by searchViewModel.overseasPlace.collectAsStateWithLifecycle() - val recordTitle by searchViewModel.recordTitle.collectAsStateWithLifecycle() - val recordContent by searchViewModel.recordContent.collectAsStateWithLifecycle() - val selectedEmotion by searchViewModel.selectedEmotion.collectAsStateWithLifecycle() - val selectedWeather by searchViewModel.selectedWeather.collectAsStateWithLifecycle() - val isChecked by searchViewModel.isChecked.collectAsStateWithLifecycle() - - // 캘린더 + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + + // 캘린더 모달 표시상태 var showDatePicker by remember { mutableStateOf(false) } - val dateRangePickerState = rememberDateRangePickerState() var showEmotionBottomSheet by remember { mutableStateOf(false) } var showWeatherBottomSheet by remember { mutableStateOf(false) } - // 여행지 - 위치 추가 + // 여행지 추가 모달 표시상태 var showPlaceBottomSheet by remember { mutableStateOf(false) } val sheetState = rememberModalBottomSheetState( // halfExpanded 상태 건너뛰기 @@ -146,8 +137,8 @@ fun RecordWriteScreen( // 날짜 영역 WriteDateSection( - startMillis = dateRangePickerState.selectedStartDateMillis, - endMillis = dateRangePickerState.selectedEndDateMillis, + startMillis = uiState.selectedStartDateMillis, + endMillis = uiState.selectedEndDateMillis, onClick = { showDatePicker = true } ) @@ -155,8 +146,8 @@ fun RecordWriteScreen( // 감정 & 날씨 영역 EmotionAndWeatherSection( - selectedEmotion = selectedEmotion, - selectedWeather = selectedWeather, + selectedEmotion = uiState.selectedEmotion, + selectedWeather = uiState.selectedWeather, onClickEmotion = { showEmotionBottomSheet = true }, onClickWeather = { showWeatherBottomSheet = true } ) @@ -165,9 +156,9 @@ fun RecordWriteScreen( // 제목 영역 WriteTitleSection( - recordTitle = recordTitle, + recordTitle = uiState.recordTitle, onValueChange = { newValue -> - searchViewModel.updateTitle(newValue) + viewModel.updateTitle(newValue) } ) @@ -175,10 +166,10 @@ fun RecordWriteScreen( // 여행지 영역 WritePlaceSection( - selectedPlace = selectedPlace, - overseasPlace = overseasPlace, + selectedPlace = uiState.selectedPlace, + overseasPlace = uiState.overseasPlace, onValueChange = { newValue -> - searchViewModel.updateOverseas(newValue) + viewModel.updateOverseas(newValue) }, onClick = { showPlaceBottomSheet = true } ) @@ -187,30 +178,45 @@ fun RecordWriteScreen( // 내용 영역 WriteContentSection( - recordContent = recordContent, + recordContent = uiState.recordContent, onValueChange = { newValue -> - searchViewModel.updateContent(newValue) + viewModel.updateContent(newValue) } ) } // 이미지 아이콘 & 공유여부 스위치 영역 ImageAndShareSection( - isChecked = isChecked, + isChecked = uiState.isShareChecked, onCheckedChange = { newChecked -> - searchViewModel.updateShare(newChecked) + viewModel.updateShare(newChecked) } ) } } - // 캘린더(날짜 선택) 모달 + // 캘린더 모달 if (showDatePicker) { + val dateRangePickerState = rememberDateRangePickerState( + initialSelectedStartDateMillis = uiState.selectedStartDateMillis, + initialSelectedEndDateMillis = uiState.selectedEndDateMillis + ) + DatePickerDialog( onDismissRequest = { showDatePicker = false }, confirmButton = { TextButton( - onClick = { showDatePicker = false } + onClick = { + val startMillis = dateRangePickerState.selectedStartDateMillis + val endMillis = dateRangePickerState.selectedEndDateMillis + + viewModel.updateDateRange( + startDateMillis = startMillis, + endDateMillis = endMillis + ) + + showDatePicker = false + } ) { Text( text = "확인", @@ -274,7 +280,7 @@ fun RecordWriteScreen( ) { EmotionBottomSheetContent( onConfirm = { emotionType -> - searchViewModel.selectEmotion(emotionType) + viewModel.updateEmotion(emotionType) showEmotionBottomSheet = false } ) @@ -291,7 +297,7 @@ fun RecordWriteScreen( ) { WeatherBottomSheetContent ( onConfirm = { weatherType -> - searchViewModel.selectWeather(weatherType) + viewModel.updateWeather(weatherType) showWeatherBottomSheet = false } ) @@ -308,18 +314,17 @@ fun RecordWriteScreen( shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) ) { PlaceBottomSheetContent( - value = searchState.query, - places = searchState.places, + value = uiState.searchState.query, + places = uiState.searchState.places, onValueChange = { newValue -> - Log.e("naver", "newValue : $newValue") - searchViewModel.updateQuery(newValue) + viewModel.updateQuery(newValue) }, - onSearch = { searchViewModel.searchPlace() }, - onClear = { searchViewModel.clearSearchResult() }, + onSearch = { viewModel.searchPlace() }, + onClear = { viewModel.clearSearchResult() }, onConfirm = { place -> - searchViewModel.selectPlace(place) + viewModel.updatePlace(place) showPlaceBottomSheet = false - }, + } ) } } diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteUiState.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteUiState.kt new file mode 100644 index 0000000..a73496d --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteUiState.kt @@ -0,0 +1,28 @@ +package com.min.dnapp.presentation.write + +import android.net.Uri +import com.min.dnapp.domain.model.EmotionType +import com.min.dnapp.domain.model.LocalPlace +import com.min.dnapp.domain.model.WeatherType + +data class SearchState( + val isLoading: Boolean = false, + val places: List = emptyList(), + val error: String? = null, + val query: String = "" +) + +data class RecordWriteUiState( + val isSaving: Boolean = false, + val recordTitle: String = "", + val recordContent: String = "", + val selectedStartDateMillis: Long? = null, + val selectedEndDateMillis: Long? = null, + val selectedEmotion: EmotionType? = null, + val selectedWeather : WeatherType? = null, + val searchState: SearchState = SearchState(), + val selectedPlace: LocalPlace? = null, + val overseasPlace: String = "", + val selectedImageUri: Uri? = null, + val isShareChecked: Boolean = false +) diff --git a/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt similarity index 67% rename from app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt rename to app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt index fbbdd48..1394b24 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/SearchViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt @@ -18,33 +18,12 @@ import kotlinx.coroutines.flow.onEach import javax.inject.Inject @HiltViewModel -class SearchViewModel @Inject constructor( +class RecordWriteViewModel @Inject constructor( private val localSearchUseCase: LocalSearchUseCase ) : ViewModel() { - private val _searchState = MutableStateFlow(SearchState()) - val searchState: StateFlow = _searchState.asStateFlow() - - private val _selectedPlace = MutableStateFlow(null) - val selectedPlace: StateFlow = _selectedPlace.asStateFlow() - - private val _overseasPlace = MutableStateFlow("") - val overseasPlace: StateFlow = _overseasPlace.asStateFlow() - - private val _recordTitle = MutableStateFlow("") - val recordTitle: StateFlow = _recordTitle.asStateFlow() - - private val _recordContent = MutableStateFlow("") - val recordContent: StateFlow = _recordContent.asStateFlow() - - private val _selectedEmotion = MutableStateFlow(null) - val selectedEmotion: StateFlow = _selectedEmotion.asStateFlow() - - private val _selectedWeather = MutableStateFlow(null) - val selectedWeather: StateFlow = _selectedWeather.asStateFlow() - - private val _isChecked = MutableStateFlow(true) - val isChecked: StateFlow = _isChecked.asStateFlow() + private val _uiState = MutableStateFlow(RecordWriteUiState()) + val uiState: StateFlow = _uiState.asStateFlow() // 이전 검색 작업을 취소하기 위한 Job private var searchJob: Job? = null @@ -53,11 +32,53 @@ class SearchViewModel @Inject constructor( // searchPlace("광안리해수욕장") // } + /** + * 제목 - textField의 입력 값 업데이트 + */ + fun updateTitle(newText: String) { + _uiState.value = _uiState.value.copy(recordTitle = newText) + Log.d("write", "updateTitle - newText : $newText") + } + + /** + * 내용 - textField의 입력 값 업데이트 + */ + fun updateContent(newText: String) { + _uiState.value = _uiState.value.copy(recordContent = newText) + Log.d("write", "updateContent - newText : $newText") + } + + /** + * 선택된 출발일과 도착일을 동시에 업데이트 + */ + fun updateDateRange(startDateMillis: Long?, endDateMillis: Long?) { + _uiState.value = _uiState.value.copy( + selectedStartDateMillis = startDateMillis, + selectedEndDateMillis = endDateMillis + ) + } + + /** + * 선택된 감정 업데이트 + */ + fun updateEmotion(emotionType: EmotionType) { + _uiState.value = _uiState.value.copy(selectedEmotion = emotionType) + Log.d("write", "selectEmotion - emotionType : $emotionType") + } + + /** + * 선택된 날씨 업데이트 + */ + fun updateWeather(weatherType: WeatherType) { + _uiState.value = _uiState.value.copy(selectedWeather = weatherType) + Log.d("write", "selectWeather - weatherType : $weatherType") + } + /** * textField의 입력 값만 업데이트하고, 검색 API 호출은 생략 */ fun updateQuery(newQuery: String) { - _searchState.value = _searchState.value.copy(query = newQuery) + _uiState.value = _uiState.value.copy(searchState = _uiState.value.searchState.copy(query = newQuery)) // 검색어가 빈 경우 목록 지우기 if (newQuery.isBlank()) { @@ -71,7 +92,7 @@ class SearchViewModel @Inject constructor( * 검색 버튼 클릭 시, 검색 API 호출 */ fun searchPlace() { - val currentQuery = _searchState.value.query + val currentQuery = _uiState.value.searchState.query // 검색어가 빈 경우 if (currentQuery.isBlank()) { @@ -88,29 +109,29 @@ class SearchViewModel @Inject constructor( when (result) { is Resource.Loading -> { // 로딩 시작 - _searchState.value = _searchState.value.copy( + _uiState.value = _uiState.value.copy(searchState = _uiState.value.searchState.copy( isLoading = true, places = result.data ?: emptyList(), error = null - ) + )) Log.d("naver", "search for $currentQuery : Loading...") } is Resource.Success -> { // 성공 - _searchState.value = _searchState.value.copy( + _uiState.value = _uiState.value.copy(searchState = _uiState.value.searchState.copy( isLoading = false, places = result.data ?: emptyList(), error = null - ) + )) Log.d("naver", "search success : ${result.data?.size} 개") } is Resource.Error -> { // 에러 - _searchState.value = _searchState.value.copy( + _uiState.value = _uiState.value.copy(searchState = _uiState.value.searchState.copy( isLoading = false, places = result.data ?: emptyList(), error = result.message ?: "알 수 없는 에러 발생" - ) + )) Log.e("naver", "search error : ${result.message}") } } @@ -127,66 +148,34 @@ class SearchViewModel @Inject constructor( searchJob?.cancel() // query는 그대로 유지, 결과 목록만 초기화 - _searchState.value = _searchState.value.copy( + _uiState.value = _uiState.value.copy(searchState = _uiState.value.searchState.copy( isLoading = false, places = emptyList(), error = null - ) + )) Log.d("naver", "result cleared") } /** - * 국내 - 선택된 장소 저장 + * 국내 - 선택된 장소 업데이트 */ - fun selectPlace(place: LocalPlace) { - _selectedPlace.value = place + fun updatePlace(place: LocalPlace) { + _uiState.value = _uiState.value.copy(selectedPlace = place) } /** * 해외 - textField의 입력 값 업데이트 */ fun updateOverseas(newText: String) { - _overseasPlace.value = newText + _uiState.value = _uiState.value.copy(overseasPlace = newText) Log.d("write", "updateOverseas - newText : $newText") } - /** - * 제목 - textField의 입력 값 업데이트 - */ - fun updateTitle(newText: String) { - _recordTitle.value = newText - Log.d("write", "updateTitle - newText : $newText") - } - - /** - * 내용 - textField의 입력 값 업데이트 - */ - fun updateContent(newText: String) { - _recordContent.value = newText - Log.d("write", "updateContent - newText : $newText") - } - - /** - * 선택된 감정 저장 - */ - fun selectEmotion(emotionType: EmotionType) { - _selectedEmotion.value = emotionType - Log.d("write", "selectEmotion - emotionType : $emotionType") - } - - /** - * 선택된 날씨 저장 - */ - fun selectWeather(weatherType: WeatherType) { - _selectedWeather.value = weatherType - Log.d("write", "selectWeather - weatherType : $weatherType") - } - /** * 공유여부 설정 상태 업데이트 */ fun updateShare(newChecked: Boolean) { - _isChecked.value = newChecked + _uiState.value = _uiState.value.copy(isShareChecked = newChecked) Log.d("write", "updateShare - newChecked : $newChecked") } } diff --git a/app/src/main/java/com/min/dnapp/presentation/write/SearchState.kt b/app/src/main/java/com/min/dnapp/presentation/write/SearchState.kt deleted file mode 100644 index 8951eb0..0000000 --- a/app/src/main/java/com/min/dnapp/presentation/write/SearchState.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.min.dnapp.presentation.write - -import com.min.dnapp.domain.model.LocalPlace - -data class SearchState( - val isLoading: Boolean = false, - val places: List = emptyList(), - val error: String? = null, - val query: String = "" -) From 0d1423ebed68da62b9d9067f0411aa8476ec2ff8 Mon Sep 17 00:00:00 2001 From: min486 Date: Tue, 28 Oct 2025 19:18:48 +0900 Subject: [PATCH 47/98] =?UTF-8?q?feat:=20Single=20Image=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/write/RecordWriteScreen.kt | 47 +++++++++++++++++-- .../write/RecordWriteViewModel.kt | 27 +++++++++++ 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index ebc4698..a1bfb21 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -1,5 +1,9 @@ package com.min.dnapp.presentation.write +import android.content.Intent +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.PickVisualMediaRequest +import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -36,6 +40,7 @@ import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberDateRangePickerState import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -44,6 +49,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -72,6 +78,7 @@ fun RecordWriteScreen( viewModel: RecordWriteViewModel = hiltViewModel() ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val context = LocalContext.current // 캘린더 모달 표시상태 var showDatePicker by remember { mutableStateOf(false) } @@ -86,6 +93,34 @@ fun RecordWriteScreen( skipPartiallyExpanded = true ) + // Photo Picker 런처 등록 + val singlePhotoPickerLauncher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.PickVisualMedia() + ) { uri -> + // URI 결과 전달 + viewModel.onPhotoSelected(uri) + + // URI 접근권한 지속적으로 요청 + if (uri != null) { + val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION + context.contentResolver.takePersistableUriPermission(uri, flags) + } + } + + // Photo Picker 실행 요청 + LaunchedEffect(viewModel.imageEvent) { + viewModel.imageEvent.collect { shouldLaunch -> + if (shouldLaunch) { + // Photo Picker 실행 + singlePhotoPickerLauncher.launch( + input = PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly) + ) + // 이벤트 처리 후 viewModel에 알림 + viewModel.photoPickerEventHandled() + } + } + } + Scaffold( containerColor = MomentoTheme.colors.brownW90, topBar = { @@ -112,7 +147,7 @@ fun RecordWriteScreen( actions = { Text( modifier = Modifier - .clickable { } + .clickable { } .padding(16.dp), text = "완료", style = MomentoTheme.typography.title02, @@ -190,7 +225,8 @@ fun RecordWriteScreen( isChecked = uiState.isShareChecked, onCheckedChange = { newChecked -> viewModel.updateShare(newChecked) - } + }, + onGalleryClick = { viewModel.onGalleryIconClicked() } ) } } @@ -670,7 +706,8 @@ fun WriteContentSection( @Composable fun ImageAndShareSection( isChecked: Boolean, - onCheckedChange: (Boolean) -> Unit + onCheckedChange: (Boolean) -> Unit, + onGalleryClick: () -> Unit ) { Row( modifier = Modifier @@ -681,8 +718,8 @@ fun ImageAndShareSection( ) { Icon( modifier = Modifier - .clickable { } - .padding(20.dp), + .clickable { onGalleryClick() } + .padding(horizontal = 20.dp, vertical = 10.dp), imageVector = AppIcons.Gallery, contentDescription = null, tint = MomentoTheme.colors.grayW60 diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt index 1394b24..c4fb954 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt @@ -1,5 +1,6 @@ package com.min.dnapp.presentation.write +import android.net.Uri import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -25,6 +26,10 @@ class RecordWriteViewModel @Inject constructor( private val _uiState = MutableStateFlow(RecordWriteUiState()) val uiState: StateFlow = _uiState.asStateFlow() + // Photo Picker를 실행하도록 요청하는 이벤트 + private val _imageEvent = MutableStateFlow(false) + val imageEvent: StateFlow = _imageEvent.asStateFlow() + // 이전 검색 작업을 취소하기 위한 Job private var searchJob: Job? = null @@ -178,4 +183,26 @@ class RecordWriteViewModel @Inject constructor( _uiState.value = _uiState.value.copy(isShareChecked = newChecked) Log.d("write", "updateShare - newChecked : $newChecked") } + + /** + * 갤러리 아이콘 클릭 - Photo Picker 실행 요청 + */ + fun onGalleryIconClicked() { + _imageEvent.value = true + } + + /** + * Photo Picker 실행 이벤트가 처리되었음을 알림 + */ + fun photoPickerEventHandled() { + _imageEvent.value = false + } + + /** + * Photo Picker에서 선택된 URI를 받아 상태 업데이트 + */ + fun onPhotoSelected(uri: Uri?) { + _uiState.value = _uiState.value.copy(selectedImageUri = uri) + Log.d("write", "onPhotoSelected - uri : $uri") + } } From 41fbe9bd6bfd20b6d728c95135e163392c86bb44 Mon Sep 17 00:00:00 2001 From: min486 Date: Tue, 28 Oct 2025 20:21:00 +0900 Subject: [PATCH 48/98] =?UTF-8?q?build:=20Coil=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=84=A0=ED=83=9D?= =?UTF-8?q?=EB=90=9C=20Image=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 3 ++ .../main/java/com/min/dnapp/MainActivity.kt | 2 +- .../presentation/write/RecordWriteScreen.kt | 51 ++++++++++++++----- gradle/libs.versions.toml | 3 ++ 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b78655f..358913d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -105,6 +105,9 @@ dependencies { implementation(libs.kotlinx.serialization.json) // okhttp (logging interceptor) implementation(libs.okhttp.logging) + // coil + implementation(libs.coil) + implementation(libs.coil.okhttp) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index 60db65a..7aca415 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -55,7 +55,7 @@ fun MomentoApp( val currentRoute = navBackStackEntry?.destination?.route ?: "home" val showBottomBar = when (currentRoute) { - "login", "bell", "explore_detail" -> false + "login", "bell", "explore_detail", "record_write" -> false else -> true } diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index a1bfb21..90c3434 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -1,6 +1,7 @@ package com.min.dnapp.presentation.write -import android.content.Intent +import android.content.Intent +import android.net.Uri import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.PickVisualMediaRequest import androidx.activity.result.contract.ActivityResultContracts @@ -19,9 +20,11 @@ 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.rememberScrollState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.DatePickerDefaults import androidx.compose.material3.DatePickerDialog @@ -49,6 +52,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview @@ -56,6 +60,7 @@ import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavHostController +import coil3.compose.AsyncImage import com.min.dnapp.R import com.min.dnapp.domain.model.EmotionType import com.min.dnapp.domain.model.LocalPlace @@ -155,12 +160,23 @@ fun RecordWriteScreen( ) } ) + }, + bottomBar = { + // 이미지 아이콘 & 공유여부 스위치 영역 + ImageAndShareSection( + isChecked = uiState.isShareChecked, + onCheckedChange = { newChecked -> + viewModel.updateShare(newChecked) + }, + onGalleryClick = { viewModel.onGalleryIconClicked() } + ) } ) { paddingValues -> Column( modifier = Modifier .padding(paddingValues) - .fillMaxSize(), + .fillMaxSize() + .verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.SpaceBetween ) { Column( @@ -213,21 +229,13 @@ fun RecordWriteScreen( // 내용 영역 WriteContentSection( + selectedImageUri = uiState.selectedImageUri, recordContent = uiState.recordContent, onValueChange = { newValue -> viewModel.updateContent(newValue) } ) } - - // 이미지 아이콘 & 공유여부 스위치 영역 - ImageAndShareSection( - isChecked = uiState.isShareChecked, - onCheckedChange = { newChecked -> - viewModel.updateShare(newChecked) - }, - onGalleryClick = { viewModel.onGalleryIconClicked() } - ) } } @@ -666,6 +674,7 @@ fun WriteTitleSection( @Composable fun WriteContentSection( + selectedImageUri: Uri?, recordContent: String, onValueChange: (String) -> Unit ) { @@ -682,8 +691,8 @@ fun WriteContentSection( modifier = Modifier .fillMaxWidth() .height(310.dp) - .background(color = MomentoTheme.colors.brownBg, shape = RoundedCornerShape(5.dp)) - .padding(12.dp) + .background(color = MomentoTheme.colors.brownBg) + .padding(16.dp) ) { if (recordContent.isEmpty()) { Text( @@ -700,6 +709,22 @@ fun WriteContentSection( singleLine = false ) } + // 선택된 이미지 + selectedImageUri?.let { uri -> + Box( + modifier = Modifier + .fillMaxWidth() + .background(color = MomentoTheme.colors.brownBg) + .padding(start = 16.dp, bottom = 16.dp) + ) { + AsyncImage( + model = uri, + contentDescription = null, + modifier = Modifier.size(72.dp), + contentScale = ContentScale.Crop + ) + } + } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 284b9cb..ee4f951 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -20,6 +20,7 @@ splash = "1.0.1" retrofit = "3.0.0" kotlinSerialization = "1.9.0" okhttp = "5.0.0" +coil = "3.1.0" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -51,6 +52,8 @@ retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit retrofit-converter-kotlinx-serialization = { module = "com.squareup.retrofit2:converter-kotlinx-serialization", version.ref = "retrofit" } kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinSerialization" } okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" } +coil = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" } +coil-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } From 7c648c85f96f68d160b40c474c39533f94c1a88b Mon Sep 17 00:00:00 2001 From: min486 Date: Wed, 29 Oct 2025 23:24:39 +0900 Subject: [PATCH 49/98] =?UTF-8?q?feat:=20Firebase=EC=97=90=20=EC=97=AC?= =?UTF-8?q?=ED=96=89=EA=B8=B0=EB=A1=9D=20=EC=A0=80=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 1 + .../main/java/com/min/dnapp/MainActivity.kt | 4 +- .../com/min/dnapp/data/di/FirebaseModule.kt | 7 +++ .../com/min/dnapp/data/di/RepositoryModule.kt | 8 +++ .../com/min/dnapp/data/mapper/RecordMapper.kt | 37 ++++++++++++ .../min/dnapp/data/remote/dto/RecordEntity.kt | 39 +++++++++++++ .../data/repository/AuthRepositoryImpl.kt | 7 +++ .../data/repository/RecordRepositoryImpl.kt | 58 +++++++++++++++++++ .../dnapp/domain/repository/AuthRepository.kt | 1 + .../domain/repository/RecordRepository.kt | 10 ++++ .../dnapp/domain/usecase/SaveRecordUseCase.kt | 41 +++++++++++++ .../presentation/write/RecordWriteScreen.kt | 4 +- .../write/RecordWriteViewModel.kt | 31 +++++++++- gradle/libs.versions.toml | 1 + 14 files changed, 245 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/data/mapper/RecordMapper.kt create mode 100644 app/src/main/java/com/min/dnapp/data/remote/dto/RecordEntity.kt create mode 100644 app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt create mode 100644 app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt create mode 100644 app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 358913d..47040b4 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -89,6 +89,7 @@ dependencies { implementation(libs.firebase.analytics) implementation(libs.firebase.auth) implementation(libs.firebase.firestore) + implementation(libs.firebase.storage) // kakao implementation(libs.kakao.sdk) // compose navigation diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index 7aca415..5daa91a 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -77,8 +77,8 @@ fun MomentoApp( NavHost( modifier = Modifier.padding(paddingValues), navController = navController, -// startDestination = startDestination - startDestination = "home" + startDestination = startDestination +// startDestination = "home" // startDestination = "login" ) { composable("login") { diff --git a/app/src/main/java/com/min/dnapp/data/di/FirebaseModule.kt b/app/src/main/java/com/min/dnapp/data/di/FirebaseModule.kt index 76c3209..15a303f 100644 --- a/app/src/main/java/com/min/dnapp/data/di/FirebaseModule.kt +++ b/app/src/main/java/com/min/dnapp/data/di/FirebaseModule.kt @@ -2,6 +2,7 @@ package com.min.dnapp.data.di import com.google.firebase.auth.FirebaseAuth import com.google.firebase.firestore.FirebaseFirestore +import com.google.firebase.storage.FirebaseStorage import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -23,4 +24,10 @@ object FirebaseModule { fun provideFirebaseFirestore(): FirebaseFirestore { return FirebaseFirestore.getInstance() } + + @Provides + @Singleton + fun provideFirebaseStorage(): FirebaseStorage { + return FirebaseStorage.getInstance() + } } diff --git a/app/src/main/java/com/min/dnapp/data/di/RepositoryModule.kt b/app/src/main/java/com/min/dnapp/data/di/RepositoryModule.kt index 8cf545f..daa1a1e 100644 --- a/app/src/main/java/com/min/dnapp/data/di/RepositoryModule.kt +++ b/app/src/main/java/com/min/dnapp/data/di/RepositoryModule.kt @@ -2,8 +2,10 @@ package com.min.dnapp.data.di import com.min.dnapp.data.repository.AuthRepositoryImpl import com.min.dnapp.data.repository.LocalSearchRepositoryImpl +import com.min.dnapp.data.repository.RecordRepositoryImpl import com.min.dnapp.domain.repository.AuthRepository import com.min.dnapp.domain.repository.LocalSearchRepository +import com.min.dnapp.domain.repository.RecordRepository import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -25,4 +27,10 @@ abstract class RepositoryModule { abstract fun bindLocalSearchRepository( localSearchRepositoryImpl: LocalSearchRepositoryImpl ): LocalSearchRepository + + @Binds + @Singleton + abstract fun bindRecordRepository( + recordRepositoryImpl: RecordRepositoryImpl + ): RecordRepository } diff --git a/app/src/main/java/com/min/dnapp/data/mapper/RecordMapper.kt b/app/src/main/java/com/min/dnapp/data/mapper/RecordMapper.kt new file mode 100644 index 0000000..d89c01c --- /dev/null +++ b/app/src/main/java/com/min/dnapp/data/mapper/RecordMapper.kt @@ -0,0 +1,37 @@ +package com.min.dnapp.data.mapper + +import com.min.dnapp.data.remote.dto.PlaceEntity +import com.min.dnapp.data.remote.dto.RecordEntity +import com.min.dnapp.domain.model.LocalPlace +import com.min.dnapp.presentation.write.RecordWriteUiState + +/** + * RecordWriteUiState -> RecordEntity 변환 + */ +fun RecordWriteUiState.toEntity(userId: String, imageUrl: String?): RecordEntity { + return RecordEntity( + userId = userId, + title = this.recordTitle, + content = this.recordContent, + startDateMillis = this.selectedStartDateMillis, + endDateMillis = this.selectedEndDateMillis, + emotionKey = this.selectedEmotion?.key, + weatherKey = this.selectedWeather?.key, + selectedPlace = this.selectedPlace?.toEntity(), + overseasPlace = this.overseasPlace, + isShareChecked = this.isShareChecked, + // 업로드 후 받은 URL + imageUrl = imageUrl + ) +} + +/** + * LocalPlace -> PlaceEntity 변환 + */ +fun LocalPlace.toEntity(): PlaceEntity { + return PlaceEntity( + title = this.title, + category = this.category, + roadAddress = this.roadAddress + ) +} diff --git a/app/src/main/java/com/min/dnapp/data/remote/dto/RecordEntity.kt b/app/src/main/java/com/min/dnapp/data/remote/dto/RecordEntity.kt new file mode 100644 index 0000000..2de08b7 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/data/remote/dto/RecordEntity.kt @@ -0,0 +1,39 @@ +package com.min.dnapp.data.remote.dto + +import com.google.firebase.firestore.Exclude +import com.google.firebase.firestore.ServerTimestamp +import java.util.Date + +data class RecordEntity( + // firestore 문서 ID 값 + @get:Exclude + var recordId: String = "", + + val userId: String = "", + + val title: String = "", + val content: String = "", + + val startDateMillis: Long? = null, + val endDateMillis: Long? = null, + + val emotionKey: String? = null, + val weatherKey: String? = null, + + val selectedPlace: PlaceEntity? = null, + val overseasPlace :String? = "", + + val isShareChecked: Boolean = false, + + val imageUrl: String? = null, + + // 서버 타임스탬프 + @ServerTimestamp + val createdAt: Date? = null +) + +data class PlaceEntity( + val title: String, + val category: String, + val roadAddress: String +) diff --git a/app/src/main/java/com/min/dnapp/data/repository/AuthRepositoryImpl.kt b/app/src/main/java/com/min/dnapp/data/repository/AuthRepositoryImpl.kt index 5cc7c00..c6e9820 100644 --- a/app/src/main/java/com/min/dnapp/data/repository/AuthRepositoryImpl.kt +++ b/app/src/main/java/com/min/dnapp/data/repository/AuthRepositoryImpl.kt @@ -238,4 +238,11 @@ class AuthRepositoryImpl @Inject constructor( } } } + + /** + * 현재 로그인된 사용자의 UID를 반환 + */ + override suspend fun getCurrentUserId(): String? { + return firebaseAuth.currentUser?.uid + } } diff --git a/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt b/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt new file mode 100644 index 0000000..4c4ae35 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt @@ -0,0 +1,58 @@ +package com.min.dnapp.data.repository + +import android.net.Uri +import com.google.firebase.firestore.FirebaseFirestore +import com.google.firebase.storage.FirebaseStorage +import com.min.dnapp.data.remote.dto.RecordEntity +import com.min.dnapp.domain.repository.RecordRepository +import kotlinx.coroutines.tasks.await +import javax.inject.Inject + +class RecordRepositoryImpl @Inject constructor( + private val firestore: FirebaseFirestore, + private val storage: FirebaseStorage +) : RecordRepository { + /** + * Storage에 이미지 업로드 및 URL 반환 + */ + override suspend fun uploadImageAndGetUrl(imageUri: Uri, userId: String): String { + // firebase storage 경로는 사용자별로 분리 + val storageRef = storage.reference + .child("images") + .child(userId) + .child("${System.currentTimeMillis()}_${imageUri.lastPathSegment}") + + // 이미지 업로드 및 URL 가져오기 + storageRef.putFile(imageUri).await() + return storageRef.downloadUrl.await().toString() + } + + /** + * 개인 기록 컬렉션에 저장 + */ + override suspend fun savePrivateRecord(record: RecordEntity): RecordEntity { + val recordCollection = firestore.collection("records") + + // firestore에서 새로운 문서 ID 생성 + val newDoc = recordCollection.document() + val recordId = newDoc.id + + // RecordEntity의 recordId 필드 채우기 + val recordWithId = record.copy(recordId = recordId) + + // set()을 사용하여 해당 ID로 저장 + newDoc.set(recordWithId).await() + + return recordWithId + } + + /** + * 전체공유 컬렉션에 저장 + */ + override suspend fun saveSharedRecord(record: RecordEntity) { + val sharedCollection = firestore.collection("shared_records") + + // set()을 사용하여 개인 기록과 동일한 ID로 저장 + sharedCollection.document(record.recordId).set(record).await() + } +} diff --git a/app/src/main/java/com/min/dnapp/domain/repository/AuthRepository.kt b/app/src/main/java/com/min/dnapp/domain/repository/AuthRepository.kt index d0beaa3..d1f05a4 100644 --- a/app/src/main/java/com/min/dnapp/domain/repository/AuthRepository.kt +++ b/app/src/main/java/com/min/dnapp/domain/repository/AuthRepository.kt @@ -7,4 +7,5 @@ interface AuthRepository { suspend fun signInWithKakao(context: Context): Result suspend fun logout(): Result suspend fun unlinkUser(): Result + suspend fun getCurrentUserId(): String? } diff --git a/app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt b/app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt new file mode 100644 index 0000000..2b56fb8 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt @@ -0,0 +1,10 @@ +package com.min.dnapp.domain.repository + +import android.net.Uri +import com.min.dnapp.data.remote.dto.RecordEntity + +interface RecordRepository { + suspend fun uploadImageAndGetUrl(imageUri: Uri, userId: String): String + suspend fun savePrivateRecord(record: RecordEntity): RecordEntity + suspend fun saveSharedRecord(record: RecordEntity) +} diff --git a/app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt b/app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt new file mode 100644 index 0000000..d72484f --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt @@ -0,0 +1,41 @@ +package com.min.dnapp.domain.usecase + +import android.net.Uri +import com.min.dnapp.data.mapper.toEntity +import com.min.dnapp.domain.repository.AuthRepository +import com.min.dnapp.domain.repository.RecordRepository +import com.min.dnapp.presentation.write.RecordWriteUiState +import javax.inject.Inject + +class SaveRecordUseCase @Inject constructor( + private val recordRepository: RecordRepository, + private val authRepository: AuthRepository +) { + suspend operator fun invoke( + uiState: RecordWriteUiState, + imageUri: Uri? + ) { + val userId = authRepository.getCurrentUserId() + ?: throw IllegalStateException("user not login") + + // 이미지 업로드 (URL 획득) + val imageUrl = if (imageUri != null) { + recordRepository.uploadImageAndGetUrl(imageUri, userId) + } else { + null + } + + // uiState를 Entity로 변환 + val recordEntity = uiState.toEntity(userId, imageUrl) + + // 개인 기록 컬렉션에 저장 (필수) + // recordId가 포함된 RecordEntity를 받아 새 변수에 저장 + val savedRecord = recordRepository.savePrivateRecord(recordEntity) + + // 공유 여부에 따라 전체공유 컬렉션에도 저장 (선택) + if (uiState.isShareChecked) { + // ID가 포함된 savedRecord 사용 + recordRepository.saveSharedRecord(savedRecord) + } + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index 90c3434..422cd9e 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -152,7 +152,9 @@ fun RecordWriteScreen( actions = { Text( modifier = Modifier - .clickable { } + .clickable { + viewModel.saveRecord() + } .padding(16.dp), text = "완료", style = MomentoTheme.typography.title02, diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt index c4fb954..49b0bb7 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt @@ -8,19 +8,25 @@ import com.min.dnapp.domain.model.EmotionType import com.min.dnapp.domain.model.LocalPlace import com.min.dnapp.domain.model.WeatherType import com.min.dnapp.domain.usecase.LocalSearchUseCase +import com.min.dnapp.domain.usecase.SaveRecordUseCase import com.min.dnapp.util.Resource import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Job +import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class RecordWriteViewModel @Inject constructor( - private val localSearchUseCase: LocalSearchUseCase + private val localSearchUseCase: LocalSearchUseCase, + private val saveRecordUseCase: SaveRecordUseCase ) : ViewModel() { private val _uiState = MutableStateFlow(RecordWriteUiState()) @@ -205,4 +211,27 @@ class RecordWriteViewModel @Inject constructor( _uiState.value = _uiState.value.copy(selectedImageUri = uri) Log.d("write", "onPhotoSelected - uri : $uri") } + + /** + * Firebase에 기록 저장 + */ + fun saveRecord() { + // 중복 저장 방지 + if (uiState.value.isSaving) return + + val currentUiState = uiState.value + val imageUrl = currentUiState.selectedImageUri + + _uiState.update { it.copy(isSaving = true) } + + viewModelScope.launch { + try { + saveRecordUseCase(currentUiState, imageUrl) + } catch (e: Exception) { + Log.e("write", "saveRecord - exception : $e") + } finally { + _uiState.update { it.copy(isSaving = false) } + } + } + } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ee4f951..742dcbc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -42,6 +42,7 @@ firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "fir firebase-analytics = { module = "com.google.firebase:firebase-analytics" } firebase-auth = { module = "com.google.firebase:firebase-auth" } firebase-firestore = { module = "com.google.firebase:firebase-firestore" } +firebase-storage = { module = "com.google.firebase:firebase-storage" } kakao-sdk = { module = "com.kakao.sdk:v2-user", version.ref = "kakao" } androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "nav" } hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" } From 544fe6d92bfa726bcf0dfdf1323a2505cba26ad2 Mon Sep 17 00:00:00 2001 From: min486 Date: Thu, 30 Oct 2025 01:28:03 +0900 Subject: [PATCH 50/98] =?UTF-8?q?feat:=20=EA=B8=B0=EB=A1=9D=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5=20=EC=99=84=EB=A3=8C=20=ED=9B=84=20=ED=99=94=EB=A9=B4?= =?UTF-8?q?=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 6 ++- .../dnapp/domain/usecase/SaveRecordUseCase.kt | 41 +++++++++++-------- .../presentation/write/RecordWriteScreen.kt | 14 +++++++ .../write/RecordWriteViewModel.kt | 20 ++++++--- .../presentation/write/WriteFinishScreen.kt | 12 ++++-- 5 files changed, 64 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index 5daa91a..103cbaf 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -25,6 +25,7 @@ import com.min.dnapp.presentation.mypage.MypageScreen import com.min.dnapp.presentation.ui.component.MomentoBottomNav import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.write.RecordWriteScreen +import com.min.dnapp.presentation.write.WriteFinishScreen import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -55,7 +56,7 @@ fun MomentoApp( val currentRoute = navBackStackEntry?.destination?.route ?: "home" val showBottomBar = when (currentRoute) { - "login", "bell", "explore_detail", "record_write" -> false + "login", "bell", "explore_detail", "record_write", "write_finish" -> false else -> true } @@ -102,6 +103,9 @@ fun MomentoApp( composable("record_write") { RecordWriteScreen(navController = navController) } + composable("write_finish") { + WriteFinishScreen(navController = navController) + } } } } diff --git a/app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt b/app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt index d72484f..6e1bd7a 100644 --- a/app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt +++ b/app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt @@ -14,28 +14,33 @@ class SaveRecordUseCase @Inject constructor( suspend operator fun invoke( uiState: RecordWriteUiState, imageUri: Uri? - ) { - val userId = authRepository.getCurrentUserId() - ?: throw IllegalStateException("user not login") + ): Result { + return try { + val userId = authRepository.getCurrentUserId() ?: return Result.failure(IllegalStateException("user not login")) - // 이미지 업로드 (URL 획득) - val imageUrl = if (imageUri != null) { - recordRepository.uploadImageAndGetUrl(imageUri, userId) - } else { - null - } + // 이미지 업로드 (URL 획득) + val imageUrl = if (imageUri != null) { + recordRepository.uploadImageAndGetUrl(imageUri, userId) + } else { + null + } + + // uiState를 Entity로 변환 + val recordEntity = uiState.toEntity(userId, imageUrl) - // uiState를 Entity로 변환 - val recordEntity = uiState.toEntity(userId, imageUrl) + // 개인 기록 컬렉션에 저장 (필수) + // recordId가 포함된 RecordEntity를 받아 새 변수에 저장 + val savedRecord = recordRepository.savePrivateRecord(recordEntity) - // 개인 기록 컬렉션에 저장 (필수) - // recordId가 포함된 RecordEntity를 받아 새 변수에 저장 - val savedRecord = recordRepository.savePrivateRecord(recordEntity) + // 공유 여부에 따라 전체공유 컬렉션에도 저장 (선택) + if (uiState.isShareChecked) { + // ID가 포함된 savedRecord 사용 + recordRepository.saveSharedRecord(savedRecord) + } - // 공유 여부에 따라 전체공유 컬렉션에도 저장 (선택) - if (uiState.isShareChecked) { - // ID가 포함된 savedRecord 사용 - recordRepository.saveSharedRecord(savedRecord) + Result.success(Unit) + } catch (e: Exception) { + Result.failure(e) } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index 422cd9e..ff15aa5 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -2,6 +2,7 @@ package com.min.dnapp.presentation.write import android.content.Intent import android.net.Uri +import android.util.Log import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.PickVisualMediaRequest import androidx.activity.result.contract.ActivityResultContracts @@ -126,6 +127,19 @@ fun RecordWriteScreen( } } + // 1회성 이벤트 Flow 수집 및 처리 + LaunchedEffect(Unit) { + // 구독 + viewModel.completeSaveRecordFlow.collect { + // 기록저장 성공 후 화면 이동 + navController.navigate("write_finish") { + popUpTo("record_write") { + inclusive = true + } + } + } + } + Scaffold( containerColor = MomentoTheme.colors.brownW90, topBar = { diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt index 49b0bb7..77aefdf 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt @@ -19,6 +19,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import javax.inject.Inject @@ -36,6 +37,9 @@ class RecordWriteViewModel @Inject constructor( private val _imageEvent = MutableStateFlow(false) val imageEvent: StateFlow = _imageEvent.asStateFlow() + private val _completeSaveRecord = Channel() + val completeSaveRecordFlow = _completeSaveRecord.receiveAsFlow() + // 이전 검색 작업을 취소하기 위한 Job private var searchJob: Job? = null @@ -225,13 +229,17 @@ class RecordWriteViewModel @Inject constructor( _uiState.update { it.copy(isSaving = true) } viewModelScope.launch { - try { - saveRecordUseCase(currentUiState, imageUrl) - } catch (e: Exception) { - Log.e("write", "saveRecord - exception : $e") - } finally { - _uiState.update { it.copy(isSaving = false) } + val result = saveRecordUseCase(currentUiState, imageUrl) + + result.onSuccess { + // 저장 성공 + _completeSaveRecord.send(Unit) + }.onFailure { exception -> + // 저장 실패 + Log.e("write", "saveRecord - exception : $exception") } + + _uiState.update { it.copy(isSaving = false) } } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt index 0403447..9bf368e 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt @@ -24,14 +24,16 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController import com.min.dnapp.R import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.ui.theme.MomentoTheme import com.min.dnapp.presentation.write.component.WriteStampDialog @Composable -fun WriteFinishScreen() { - +fun WriteFinishScreen( + navController: NavHostController +) { var showStampDialog by remember { mutableStateOf(true) } Surface( @@ -67,7 +69,9 @@ fun WriteFinishScreen() { ) { Box( modifier = Modifier - .clickable { } + .clickable { + navController.navigate("home") + } .fillMaxWidth() .background(color = MomentoTheme.colors.brownBase, shape = RoundedCornerShape(10.dp)) .padding(vertical = 16.dp), @@ -97,6 +101,6 @@ fun WriteFinishScreen() { @Composable fun WriteFinishScreenPreview() { DngoTheme { - WriteFinishScreen() +// WriteFinishScreen() } } From ad8af1f30bc97799dea8d75a316d842de62e2ec2 Mon Sep 17 00:00:00 2001 From: min486 Date: Thu, 30 Oct 2025 17:23:20 +0900 Subject: [PATCH 51/98] =?UTF-8?q?feat:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EC=8B=9C=20Firestore=EC=97=90=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EC=A0=95=EB=B3=B4=20=EC=A0=80=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 2 - .../com/min/dnapp/data/mapper/UserMapper.kt | 40 +++ .../min/dnapp/data/remote/dto/UserEntity.kt | 14 + .../dnapp/data/remote/dto/UserEntityExt.kt | 14 + .../data/repository/AuthRepositoryImpl.kt | 256 ++++++++++-------- .../java/com/min/dnapp/domain/model/User.kt | 12 + .../com/min/dnapp/domain/model/UserProfile.kt | 6 - .../dnapp/domain/repository/AuthRepository.kt | 8 +- ...akaoUseCase.kt => AuthWithKakaoUseCase.kt} | 6 +- .../min/dnapp/presentation/home/HomeScreen.kt | 22 +- .../dnapp/presentation/login/LoginScreen.kt | 41 ++- .../dnapp/presentation/login/LoginScreen2.kt | 21 +- .../presentation/login/LoginViewModel.kt | 43 +-- 13 files changed, 302 insertions(+), 183 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/data/mapper/UserMapper.kt create mode 100644 app/src/main/java/com/min/dnapp/data/remote/dto/UserEntity.kt create mode 100644 app/src/main/java/com/min/dnapp/data/remote/dto/UserEntityExt.kt create mode 100644 app/src/main/java/com/min/dnapp/domain/model/User.kt delete mode 100644 app/src/main/java/com/min/dnapp/domain/model/UserProfile.kt rename app/src/main/java/com/min/dnapp/domain/usecase/{SignInWithKakaoUseCase.kt => AuthWithKakaoUseCase.kt} (58%) diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index 103cbaf..f3c917f 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -79,8 +79,6 @@ fun MomentoApp( modifier = Modifier.padding(paddingValues), navController = navController, startDestination = startDestination -// startDestination = "home" -// startDestination = "login" ) { composable("login") { LoginScreen2(navController = navController) diff --git a/app/src/main/java/com/min/dnapp/data/mapper/UserMapper.kt b/app/src/main/java/com/min/dnapp/data/mapper/UserMapper.kt new file mode 100644 index 0000000..4375e9d --- /dev/null +++ b/app/src/main/java/com/min/dnapp/data/mapper/UserMapper.kt @@ -0,0 +1,40 @@ +package com.min.dnapp.data.mapper + +import com.min.dnapp.data.remote.dto.UserEntity +import com.min.dnapp.domain.model.User + +object UserMapper { + /** + * Entity -> Domain 변환 + */ + fun toDomain(entity: UserEntity): User { + return User( + userId = entity.userId ?: "", + nickname = entity.nickname ?: "", + profileImageName = entity.profileImageName ?: "01_boat", + badgeLv = entity.badgeLv ?: 1, + badgeName = entity.badgeName ?: "새내기", + recordCnt = entity.recordCnt ?: 0, + stampCnt = entity.stampCnt ?: 0, + // Timestamp -> Long 변환 + createdAt = entity.createdAt?.toDate()?.time ?: 0L + ) + } + + /** + * Domain -> Entity 변환 + */ + fun toEntity(domain: User): UserEntity { + return UserEntity( + userId = domain.userId, + nickname = domain.nickname, + profileImageName = domain.profileImageName, + badgeLv = domain.badgeLv, + badgeName = domain.badgeName, + recordCnt = domain.recordCnt, + stampCnt = domain.stampCnt, + // firestore 서버에서 시간 기록 + createdAt = null + ) + } +} diff --git a/app/src/main/java/com/min/dnapp/data/remote/dto/UserEntity.kt b/app/src/main/java/com/min/dnapp/data/remote/dto/UserEntity.kt new file mode 100644 index 0000000..55bc463 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/data/remote/dto/UserEntity.kt @@ -0,0 +1,14 @@ +package com.min.dnapp.data.remote.dto + +import com.google.firebase.Timestamp + +data class UserEntity( + val userId: String? = null, + val nickname: String? = null, + val profileImageName: String? = "01_boat", + val badgeLv: Int? = 1, + val badgeName: String? = "새내기", + val recordCnt: Int? = 0, + val stampCnt: Int? = 0, + val createdAt: Timestamp? = null +) diff --git a/app/src/main/java/com/min/dnapp/data/remote/dto/UserEntityExt.kt b/app/src/main/java/com/min/dnapp/data/remote/dto/UserEntityExt.kt new file mode 100644 index 0000000..02a4f76 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/data/remote/dto/UserEntityExt.kt @@ -0,0 +1,14 @@ +package com.min.dnapp.data.remote.dto + +fun UserEntity.toSaveMap(): MutableMap { + return mutableMapOf( + "userId" to this.userId, + "nickname" to this.nickname, + "profileImageName" to this.profileImageName, + "badgeLv" to this.badgeLv, + "badgeName" to this.badgeName, + "recordCnt" to this.recordCnt, + "stampCnt" to this.stampCnt, + "createdAt" to this.createdAt + ) +} diff --git a/app/src/main/java/com/min/dnapp/data/repository/AuthRepositoryImpl.kt b/app/src/main/java/com/min/dnapp/data/repository/AuthRepositoryImpl.kt index c6e9820..c09b2b9 100644 --- a/app/src/main/java/com/min/dnapp/data/repository/AuthRepositoryImpl.kt +++ b/app/src/main/java/com/min/dnapp/data/repository/AuthRepositoryImpl.kt @@ -7,17 +7,23 @@ import com.google.firebase.firestore.FieldValue import com.google.firebase.firestore.FirebaseFirestore import com.kakao.sdk.auth.model.OAuthToken import com.kakao.sdk.user.UserApiClient -import com.min.dnapp.domain.model.UserProfile +import com.min.dnapp.data.mapper.UserMapper +import com.min.dnapp.data.remote.dto.toSaveMap +import com.min.dnapp.domain.model.User import com.min.dnapp.domain.repository.AuthRepository import kotlinx.coroutines.CancellableContinuation +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.coroutines.tasks.await import javax.inject.Inject class AuthRepositoryImpl @Inject constructor( private val firebaseAuth: FirebaseAuth, private val firestore: FirebaseFirestore ) : AuthRepository { - override suspend fun signInWithKakao(context: Context): Result = + override suspend fun signInWithKakao(context: Context): Result = suspendCancellableCoroutine { continuation -> // 카카오톡 앱 설치 여부에 따라 로그인 방식 결정 @@ -38,86 +44,29 @@ class AuthRepositoryImpl @Inject constructor( handleKakaoLoginResult(token, error, continuation) } } - } - /** - * 로그아웃 처리 - * - 카카오 SDK 로그아웃 - * - firebase auth 로그아웃 - */ - override suspend fun logout(): Result = suspendCancellableCoroutine { continuation -> - // 카카오 SDK 로그아웃 - UserApiClient.instance.logout { error -> - if (error != null) { - Log.e("AuthRepository", "카카오 로그아웃 실패", error) - continuation.resumeWith(Result.failure(error)) - return@logout - } - - // firebase auth 로그아웃 - firebaseAuth.signOut() - continuation.resumeWith(Result.success(Result.success(Unit))) - Log.d("AuthRepository", "카카오 & firebase 로그아웃 성공") - } - } - - override suspend fun unlinkUser(): Result = suspendCancellableCoroutine { continuation -> - val firebaseUser = firebaseAuth.currentUser - if (firebaseUser == null) { - continuation.resumeWith(Result.failure(Exception("로그인된 사용자가 없습니다"))) - return@suspendCancellableCoroutine - } - - // firebase auth 사용자 삭제 - firebaseUser.delete() - .addOnCompleteListener { authTask -> - Log.d("AuthRepository", "firebase 계정 삭제 성공") - if (authTask.isSuccessful) { - // firestore 문서 삭제 - firestore.collection("users").document(firebaseUser.uid).delete() - .addOnSuccessListener { - Log.d("AuthRepository", "firestore 문서 삭제 성공") - // 카카오 연결 끊기 - UserApiClient.instance.unlink { unlinkError -> - if (unlinkError != null) { - continuation.resumeWith(Result.failure(unlinkError)) - } else { - continuation.resumeWith(Result.success(Result.success(Unit))) - Log.d("AuthRepository", "카카오 연결 끊기 성공") - } - } - } - .addOnFailureListener { firestoreException -> - continuation.resumeWith(Result.failure(firestoreException)) - } - } else { - continuation.resumeWith(Result.failure(authTask.exception ?: Exception("firebase 계정 삭제 실패"))) - } - } - } - - // 카카오 로그인 결과를 처리 + // 카카오 로그인 콜백 결과 처리 private fun handleKakaoLoginResult( token: OAuthToken?, error: Throwable?, - continuation: CancellableContinuation> + continuation: CancellableContinuation> ) { if (error != null) { // 카카오 로그인 실패 시 continuation.resumeWith(Result.failure(error)) } else if (token != null) { // 카카오 로그인 성공 시, 사용자 정보 조회 - getUserInfoAndSignInToFirebase(continuation) + getUserInfoAndReadyAuth(continuation) } else { // 토큰이 null인 경우 continuation.resumeWith(Result.failure(Exception("카카오 로그인 토큰을 받을 수 없습니다"))) } } - // 카카오 사용자 정보를 가져오고 firebase에 로그인/회원가입 - private fun getUserInfoAndSignInToFirebase( - continuation: CancellableContinuation> + // 카카오 사용자 정보 조회 및 인증 준비 + private fun getUserInfoAndReadyAuth( + continuation: CancellableContinuation> ) { UserApiClient.instance.me { user, error -> // 코루틴이 취소된 경우 처리 중단 @@ -139,22 +88,20 @@ class AuthRepositoryImpl @Inject constructor( val email = "$userId@kakao.com" val password = userId - val userProfile = UserProfile( - nickname = user.kakaoAccount?.profile?.nickname, - profileImageUrl = user.kakaoAccount?.profile?.profileImageUrl - ) + // 카카오 닉네임 + val nickname = user.kakaoAccount?.profile?.nickname - // firebase auth에 로그인 시도 (기존 사용자인 경우) - signInToFirebaseAuth(email, password, userProfile, continuation) + // firebase auth에 로그인/회원가입 + signInToFirebaseAuth(email, password, nickname, continuation) } } - // firebase auth 로그인 처리 + // firebase auth 기존 사용자 로그인 처리 private fun signInToFirebaseAuth( email: String, password: String, - userProfile: UserProfile, - continuation: CancellableContinuation> + nickname: String?, + continuation: CancellableContinuation> ) { firebaseAuth.signInWithEmailAndPassword(email, password) .addOnCompleteListener { task -> @@ -162,35 +109,55 @@ class AuthRepositoryImpl @Inject constructor( if (task.isSuccessful) { // 기존 사용자 로그인 성공 - Log.e("AuthRepository", "kakao : 기존 사용자 로그인 성공") - continuation.resumeWith(Result.success(Result.success(userProfile))) + Log.d("auth", "signInToFirebaseAuth - 기존 사용자 로그인 성공") + continuation.resumeWith(Result.success(Result.success(Unit))) } else { // 기존 사용자가 아닌 경우, 새로 회원가입 진행 - Log.e("AuthRepository", "kakao : 새로운 사용자! 회원가입 진행") - createFirebaseUser(email, password, userProfile, continuation) - } - } - .addOnFailureListener { exception -> - if (!continuation.isCancelled) { - continuation.resumeWith(Result.failure(exception)) + Log.d("auth", "signInToFirebaseAuth - 새로운 사용자! 회원가입 진행") + createFirebaseUser(email, password, nickname, continuation) } } } - // firebase auth 회원가입 및 firestore에 사용자 정보 저장 + // firebase auth 회원가입 및 사용자 정보 저장 private fun createFirebaseUser( email: String, password: String, - userProfile: UserProfile, - continuation: CancellableContinuation> + nickname: String?, + continuation: CancellableContinuation> ) { firebaseAuth.createUserWithEmailAndPassword(email, password) .addOnCompleteListener { createTask -> if (continuation.isCancelled) return@addOnCompleteListener if (createTask.isSuccessful) { - // firebase auth 회원가입 성공, firestore에 사용자 정보 저장 - saveUserToFirestore(userProfile, continuation) + // firebase auth 회원가입 성공 + val firebaseUser = firebaseAuth.currentUser + + if (firebaseUser == null) { + continuation.resumeWith(Result.failure(Exception("firebase 사용자 정보를 찾을 수 없습니다"))) + return@addOnCompleteListener + } + + // 카카오 닉네임 사용하여 User Domain Model 생성 + val newUser = createUserDomainModel(firebaseUser.uid, nickname) + + // 콜백 내에서 suspend 함수를 호출하기 위해 코루틴 스코프 시작 + CoroutineScope(Dispatchers.IO).launch { + val saveResult = runCatching { + // firestore에 저장 + saveNewUser(newUser) + } + + if (saveResult.isSuccess) { + // firestore 저장 성공 + Log.d("auth", "createFirebaseUser - firestore 저장 성공. 닉네임 : $nickname") + continuation.resumeWith(Result.success(Result.success(Unit))) + } else { + // firestore 저장 실패 + continuation.resumeWith(Result.failure(saveResult.exceptionOrNull() ?: Exception("사용자 정보 저장 실패"))) + } + } } else { // 회원가입 실패 val exception = createTask.exception ?: Exception("firebase 회원가입 실패") @@ -198,43 +165,96 @@ class AuthRepositoryImpl @Inject constructor( } } - .addOnFailureListener { exception -> - if (!continuation.isCancelled) { - continuation.resumeWith(Result.failure(exception)) - } - } } - // firestore에 사용자 정보 저장 함수 - private fun saveUserToFirestore( - userProfile: UserProfile, - continuation: CancellableContinuation> - ) { - val firebaseUser = firebaseAuth.currentUser + private fun createUserDomainModel( + firebaseUid: String, + nickname: String? + ): User { + return User( + userId = firebaseUid, + nickname = nickname ?: "카카오 사용자", + profileImageName = "01_boat", + badgeLv = 1, + badgeName = "새내기", + recordCnt = 0, + stampCnt = 0, + createdAt = 0L + ) + } - if (firebaseUser == null) { - continuation.resumeWith(Result.failure(Exception("firebase 사용자 정보를 찾을 수 없습니다"))) - return + /** + * firestore에 사용자 정보 저장 + */ + override suspend fun saveNewUser(user: User) { + val userEntity = UserMapper.toEntity(user) + val userId = userEntity.userId ?: throw IllegalArgumentException("saveNewUser - user ID null") + + // Entity를 Map으로 변환 + val dataMap = userEntity.toSaveMap().apply { + this["createdAt"] = FieldValue.serverTimestamp() } - // firestore에 저장할 사용자 데이터 맵 - val userMap = mapOf( - "nickname" to userProfile.nickname, - "profileImageUrl" to userProfile.profileImageUrl, - "createdAt" to FieldValue.serverTimestamp() - ) + // Map 사용하여 firestore에 저장 + firestore.collection("users").document(userId).set(dataMap).await() + } - // firestore의 users 컬렉션에 사용자 정보 저장 - firestore.collection("users").document(firebaseUser.uid) - .set(userMap) - .addOnSuccessListener { - // firestore 저장 성공 - continuation.resumeWith(Result.success(Result.success(userProfile))) + override suspend fun getUser(): User { + TODO("Not yet implemented") + } + + /** + * 로그아웃 처리 + * - 카카오 SDK 로그아웃 + * - firebase auth 로그아웃 + */ + override suspend fun logout(): Result = suspendCancellableCoroutine { continuation -> + // 카카오 SDK 로그아웃 + UserApiClient.instance.logout { error -> + if (error != null) { + Log.e("auth", "logout - 카카오 로그아웃 실패", error) + continuation.resumeWith(Result.failure(error)) + return@logout } - .addOnFailureListener { exception -> - // firestore 저장 실패 - if (!continuation.isCancelled) { - continuation.resumeWith(Result.failure(exception)) + + // firebase auth 로그아웃 + firebaseAuth.signOut() + continuation.resumeWith(Result.success(Result.success(Unit))) + Log.d("auth", "logout - 카카오 & firebase 로그아웃 성공") + } + } + + override suspend fun unlinkUser(): Result = suspendCancellableCoroutine { continuation -> + val firebaseUser = firebaseAuth.currentUser + if (firebaseUser == null) { + continuation.resumeWith(Result.failure(Exception("로그인된 사용자가 없습니다"))) + return@suspendCancellableCoroutine + } + + // firebase auth 사용자 삭제 + firebaseUser.delete() + .addOnCompleteListener { authTask -> + Log.d("auth", "unlinkUser - firebase 계정 삭제 성공") + if (authTask.isSuccessful) { + // firestore 문서 삭제 + firestore.collection("users").document(firebaseUser.uid).delete() + .addOnSuccessListener { + Log.d("auth", "unlinkUser - firestore 문서 삭제 성공") + // 카카오 연결 끊기 + UserApiClient.instance.unlink { unlinkError -> + if (unlinkError != null) { + continuation.resumeWith(Result.failure(unlinkError)) + } else { + continuation.resumeWith(Result.success(Result.success(Unit))) + Log.d("auth", "unlinkUser - 카카오 연결 끊기 성공") + } + } + } + .addOnFailureListener { firestoreException -> + continuation.resumeWith(Result.failure(firestoreException)) + } + } else { + continuation.resumeWith(Result.failure(authTask.exception ?: Exception("firebase 계정 삭제 실패"))) } } } diff --git a/app/src/main/java/com/min/dnapp/domain/model/User.kt b/app/src/main/java/com/min/dnapp/domain/model/User.kt new file mode 100644 index 0000000..b338020 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/model/User.kt @@ -0,0 +1,12 @@ +package com.min.dnapp.domain.model + +data class User( + val userId: String, + val nickname: String, + val profileImageName: String, + val badgeLv: Int, + val badgeName: String, + val recordCnt: Int, + val stampCnt: Int, + val createdAt: Long +) diff --git a/app/src/main/java/com/min/dnapp/domain/model/UserProfile.kt b/app/src/main/java/com/min/dnapp/domain/model/UserProfile.kt deleted file mode 100644 index 5210695..0000000 --- a/app/src/main/java/com/min/dnapp/domain/model/UserProfile.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.min.dnapp.domain.model - -data class UserProfile( - val nickname: String?, - val profileImageUrl: String? -) diff --git a/app/src/main/java/com/min/dnapp/domain/repository/AuthRepository.kt b/app/src/main/java/com/min/dnapp/domain/repository/AuthRepository.kt index d1f05a4..a19be38 100644 --- a/app/src/main/java/com/min/dnapp/domain/repository/AuthRepository.kt +++ b/app/src/main/java/com/min/dnapp/domain/repository/AuthRepository.kt @@ -1,11 +1,15 @@ package com.min.dnapp.domain.repository import android.content.Context -import com.min.dnapp.domain.model.UserProfile +import com.min.dnapp.domain.model.User interface AuthRepository { - suspend fun signInWithKakao(context: Context): Result +// suspend fun signInWithKakao(context: Context): Result +// suspend fun signInWithKakao(context: Context): Result + suspend fun signInWithKakao(context: Context): Result suspend fun logout(): Result suspend fun unlinkUser(): Result suspend fun getCurrentUserId(): String? + suspend fun saveNewUser(user: User) + suspend fun getUser(): User } diff --git a/app/src/main/java/com/min/dnapp/domain/usecase/SignInWithKakaoUseCase.kt b/app/src/main/java/com/min/dnapp/domain/usecase/AuthWithKakaoUseCase.kt similarity index 58% rename from app/src/main/java/com/min/dnapp/domain/usecase/SignInWithKakaoUseCase.kt rename to app/src/main/java/com/min/dnapp/domain/usecase/AuthWithKakaoUseCase.kt index 402f536..d28d3e4 100644 --- a/app/src/main/java/com/min/dnapp/domain/usecase/SignInWithKakaoUseCase.kt +++ b/app/src/main/java/com/min/dnapp/domain/usecase/AuthWithKakaoUseCase.kt @@ -1,14 +1,14 @@ package com.min.dnapp.domain.usecase import android.content.Context -import com.min.dnapp.domain.model.UserProfile import com.min.dnapp.domain.repository.AuthRepository import javax.inject.Inject -class SignInWithKakaoUseCase @Inject constructor( +class AuthWithKakaoUseCase @Inject constructor( private val authRepository: AuthRepository ) { - suspend operator fun invoke(context: Context): Result { +// suspend operator fun invoke(context: Context): Result { + suspend operator fun invoke(context: Context): Result { return authRepository.signInWithKakao(context) } } diff --git a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen.kt b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen.kt index 0be9a55..4d7282f 100644 --- a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen.kt @@ -65,17 +65,17 @@ fun HomeScreen( Button( onClick = { - loginViewModel.onUnlinkClicked( - onSuccess = { - Toast.makeText(context, "회원탈퇴 성공", Toast.LENGTH_SHORT).show() - navController.navigate("login") { - popUpTo("login") { inclusive = true } - } - }, - onFailure = { - Toast.makeText(context, "회원탈퇴 실패 : ${it.message}", Toast.LENGTH_SHORT).show() - } - ) +// loginViewModel.onUnlinkClicked( +// onSuccess = { +// Toast.makeText(context, "회원탈퇴 성공", Toast.LENGTH_SHORT).show() +// navController.navigate("login") { +// popUpTo("login") { inclusive = true } +// } +// }, +// onFailure = { +// Toast.makeText(context, "회원탈퇴 실패 : ${it.message}", Toast.LENGTH_SHORT).show() +// } +// ) } ) { Text("회원탈퇴") diff --git a/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen.kt b/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen.kt index 195e423..68659c4 100644 --- a/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen.kt @@ -25,7 +25,6 @@ fun LoginScreen( navController: NavController ) { // viewModel의 상태를 구독 - val loginResult by loginViewModel.loginResult.collectAsStateWithLifecycle() val isLoading by loginViewModel.isLoading.collectAsStateWithLifecycle() val context = LocalContext.current @@ -33,25 +32,25 @@ fun LoginScreen( val snackbarHostState = remember { SnackbarHostState() } // 로그인 결과에 따른 처리 - LaunchedEffect(loginResult) { - loginResult?.let { result -> - result.onSuccess { - navController.navigate("home") { - popUpTo("login") { inclusive = true } - } - loginViewModel.clearLoginResult() - }.onFailure { exception -> - val errorMessage = when { - exception.message?.contains("network", ignoreCase = true) == true -> - "네트워크 연결을 확인해주세요" - exception.message?.contains("cancelled", ignoreCase = true ) == true -> - "로그인이 취소되었습니다" - else -> "로그인에 실패했습니다" - } - snackbarHostState.showSnackbar(errorMessage) - } - } - } +// LaunchedEffect(loginResult) { +// loginResult?.let { result -> +// result.onSuccess { +// navController.navigate("home") { +// popUpTo("login") { inclusive = true } +// } +// loginViewModel.clearLoginResult() +// }.onFailure { exception -> +// val errorMessage = when { +// exception.message?.contains("network", ignoreCase = true) == true -> +// "네트워크 연결을 확인해주세요" +// exception.message?.contains("cancelled", ignoreCase = true ) == true -> +// "로그인이 취소되었습니다" +// else -> "로그인에 실패했습니다" +// } +// snackbarHostState.showSnackbar(errorMessage) +// } +// } +// } Scaffold( snackbarHost = { SnackbarHost(snackbarHostState) } @@ -69,7 +68,7 @@ fun LoginScreen( } else { Button( onClick = { - loginViewModel.onKakaoLoginClicked(context) +// loginViewModel.onKakaoLoginClicked(context) } ) { Text("카카오 로그인") diff --git a/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt b/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt index 29943f4..eed0d37 100644 --- a/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt +++ b/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt @@ -21,10 +21,12 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavHostController import com.min.dnapp.R import com.min.dnapp.presentation.ui.icon.AppIcons @@ -34,7 +36,12 @@ import com.min.dnapp.presentation.ui.theme.KakaoYellow import com.min.dnapp.presentation.ui.theme.MomentoTheme @Composable -fun LoginScreen2(navController: NavHostController) { +fun LoginScreen2( + navController: NavHostController, + viewModel: LoginViewModel = hiltViewModel() +) { + val context = LocalContext.current + Surface( modifier = Modifier.fillMaxSize(), color = MomentoTheme.colors.brownW80 @@ -46,7 +53,17 @@ fun LoginScreen2(navController: NavHostController) { LoginHeaderSection() LoginButtonSection( onClick = { - navController.navigate("home") + viewModel.onKakaoLoginClicked( + context = context, + onSuccess = { + navController.navigate("home") { + popUpTo("login") { inclusive = true } + } + }, + onFailure = { + + } + ) } ) } diff --git a/app/src/main/java/com/min/dnapp/presentation/login/LoginViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/login/LoginViewModel.kt index e0be30f..527b0ee 100644 --- a/app/src/main/java/com/min/dnapp/presentation/login/LoginViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/login/LoginViewModel.kt @@ -1,11 +1,11 @@ package com.min.dnapp.presentation.login import android.content.Context +import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.min.dnapp.domain.model.UserProfile import com.min.dnapp.domain.usecase.LogoutUseCase -import com.min.dnapp.domain.usecase.SignInWithKakaoUseCase +import com.min.dnapp.domain.usecase.AuthWithKakaoUseCase import com.min.dnapp.domain.usecase.UnlinkUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow @@ -16,15 +16,11 @@ import javax.inject.Inject @HiltViewModel class LoginViewModel @Inject constructor( - private val signInWithKakaoUseCase: SignInWithKakaoUseCase, + private val authWithKakaoUseCase: AuthWithKakaoUseCase, private val logoutUseCase: LogoutUseCase, private val unlinkUseCase: UnlinkUseCase ) : ViewModel() { - // 로그인 결과 저장 - private val _loginResult = MutableStateFlow?>(null) - val loginResult: StateFlow?> = _loginResult.asStateFlow() - // 로딩 상태 관리 private val _isLoading = MutableStateFlow(false) val isLoading: StateFlow = _isLoading.asStateFlow() @@ -32,16 +28,26 @@ class LoginViewModel @Inject constructor( /** * 카카오 로그인 버튼 클릭 시 호출 */ - fun onKakaoLoginClicked(context: Context) { + fun onKakaoLoginClicked( + context: Context, + onSuccess: () -> Unit, + onFailure: (Throwable) -> Unit + ) { viewModelScope.launch { + _isLoading.value = true + try { - _isLoading.value = true - _loginResult.value = null + val result = authWithKakaoUseCase(context) + Log.d("auth", "onKakaoLoginClicked - result : $result") - val result = signInWithKakaoUseCase(context) - _loginResult.value = result + result.onSuccess { + onSuccess() + }.onFailure { exception -> + onFailure(exception) + } } catch (e: Exception) { - _loginResult.value = Result.failure(e) + Log.e("auth", "onKakaoLoginClicked - unexpected error", e) + onFailure(e) } finally { _isLoading.value = false } @@ -50,7 +56,7 @@ class LoginViewModel @Inject constructor( // 로그인 결과 상태를 초기화 fun clearLoginResult() { - _loginResult.value = null +// _loginResult.value = null } /** @@ -74,17 +80,18 @@ class LoginViewModel @Inject constructor( /** * 회원탈퇴 버튼 클릭 시 호출 */ - fun onUnlinkClicked(onSuccess: () -> Unit, onFailure: (Throwable) -> Unit) { +// fun onUnlinkClicked(onSuccess: () -> Unit, onFailure: (Throwable) -> Unit) { + fun onUnlinkClicked() { viewModelScope.launch { try { val result = unlinkUseCase() result.onSuccess { - onSuccess() +// onSuccess() }.onFailure { exception -> - onFailure(exception) +// onFailure(exception) } } catch (e: Exception) { - onFailure(e) +// onFailure(e) } } } From a56be5051e723b1cea81649ce312357b5299016b Mon Sep 17 00:00:00 2001 From: min486 Date: Thu, 30 Oct 2025 17:55:47 +0900 Subject: [PATCH 52/98] =?UTF-8?q?feat:=20LoginScreen=20-=20=EB=A1=9C?= =?UTF-8?q?=EB=94=A9=20=EC=9D=B8=EB=94=94=EC=BC=80=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 3 ++- .../dnapp/presentation/login/LoginScreen2.kt | 22 ++++++++++++++++++- .../presentation/login/LoginViewModel.kt | 9 ++------ 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index f3c917f..e1b567a 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -78,7 +78,8 @@ fun MomentoApp( NavHost( modifier = Modifier.padding(paddingValues), navController = navController, - startDestination = startDestination +// startDestination = startDestination + startDestination = "login" ) { composable("login") { LoginScreen2(navController = navController) diff --git a/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt b/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt index eed0d37..1596b25 100644 --- a/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt +++ b/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt @@ -13,11 +13,14 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Icon import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale @@ -27,6 +30,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavHostController import com.min.dnapp.R import com.min.dnapp.presentation.ui.icon.AppIcons @@ -41,6 +45,7 @@ fun LoginScreen2( viewModel: LoginViewModel = hiltViewModel() ) { val context = LocalContext.current + val isLoading by viewModel.isLoading.collectAsStateWithLifecycle() Surface( modifier = Modifier.fillMaxSize(), @@ -68,6 +73,21 @@ fun LoginScreen2( ) } } + + if (isLoading) { + Box( + modifier = Modifier + .fillMaxSize() + .background(MomentoTheme.colors.black.copy(alpha = 0.5f)), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator( + modifier = Modifier.size(40.dp), + color = MomentoTheme.colors.white, + strokeWidth = 4.dp + ) + } + } } @Composable @@ -140,7 +160,7 @@ fun LoginButtonSection( contentDescription = null ) Text( - modifier = Modifier.fillMaxWidth( ), + modifier = Modifier.fillMaxWidth(), text = "카카오로 로그인하기", style = MomentoTheme.typography.title02, color = MomentoTheme.colors.grayW20, diff --git a/app/src/main/java/com/min/dnapp/presentation/login/LoginViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/login/LoginViewModel.kt index 527b0ee..b786c9f 100644 --- a/app/src/main/java/com/min/dnapp/presentation/login/LoginViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/login/LoginViewModel.kt @@ -21,12 +21,12 @@ class LoginViewModel @Inject constructor( private val unlinkUseCase: UnlinkUseCase ) : ViewModel() { - // 로딩 상태 관리 + // 로딩 상태 private val _isLoading = MutableStateFlow(false) val isLoading: StateFlow = _isLoading.asStateFlow() /** - * 카카오 로그인 버튼 클릭 시 호출 + * 카카오 로그인 */ fun onKakaoLoginClicked( context: Context, @@ -54,11 +54,6 @@ class LoginViewModel @Inject constructor( } } - // 로그인 결과 상태를 초기화 - fun clearLoginResult() { -// _loginResult.value = null - } - /** * 로그아웃 버튼 클릭 시 호출 */ From e4e5ddda1399d0ddde918492752162a422b582ea Mon Sep 17 00:00:00 2001 From: min486 Date: Thu, 30 Oct 2025 19:30:15 +0900 Subject: [PATCH 53/98] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=95=84?= =?UTF-8?q?=EC=9B=83=20=EB=B0=8F=20=ED=9A=8C=EC=9B=90=ED=83=88=ED=87=B4=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=99=84=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 11 +++-- .../data/repository/AuthRepositoryImpl.kt | 7 +--- .../dnapp/domain/repository/AuthRepository.kt | 3 -- .../domain/usecase/AuthWithKakaoUseCase.kt | 1 - .../presentation/login/LoginViewModel.kt | 32 ++++++++++---- .../dnapp/presentation/mypage/MypageScreen.kt | 20 ++++++--- .../presentation/mypage/SettingScreen.kt | 42 ++++++++++++++++--- 7 files changed, 83 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index e1b567a..390cbfa 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -22,6 +22,7 @@ import com.min.dnapp.presentation.find.FindScreen import com.min.dnapp.presentation.home.HomeScreen2 import com.min.dnapp.presentation.login.LoginScreen2 import com.min.dnapp.presentation.mypage.MypageScreen +import com.min.dnapp.presentation.mypage.SettingScreen import com.min.dnapp.presentation.ui.component.MomentoBottomNav import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.write.RecordWriteScreen @@ -56,7 +57,7 @@ fun MomentoApp( val currentRoute = navBackStackEntry?.destination?.route ?: "home" val showBottomBar = when (currentRoute) { - "login", "bell", "explore_detail", "record_write", "write_finish" -> false + "login", "bell", "explore_detail", "record_write", "write_finish", "setting" -> false else -> true } @@ -78,8 +79,7 @@ fun MomentoApp( NavHost( modifier = Modifier.padding(paddingValues), navController = navController, -// startDestination = startDestination - startDestination = "login" + startDestination = startDestination ) { composable("login") { LoginScreen2(navController = navController) @@ -91,7 +91,7 @@ fun MomentoApp( FindScreen(navController = navController) } composable("my") { - MypageScreen() + MypageScreen(navController = navController) } composable("bell") { BellScreen(navController = navController) @@ -105,6 +105,9 @@ fun MomentoApp( composable("write_finish") { WriteFinishScreen(navController = navController) } + composable("setting") { + SettingScreen(navController = navController) + } } } } diff --git a/app/src/main/java/com/min/dnapp/data/repository/AuthRepositoryImpl.kt b/app/src/main/java/com/min/dnapp/data/repository/AuthRepositoryImpl.kt index c09b2b9..f8dba15 100644 --- a/app/src/main/java/com/min/dnapp/data/repository/AuthRepositoryImpl.kt +++ b/app/src/main/java/com/min/dnapp/data/repository/AuthRepositoryImpl.kt @@ -186,7 +186,7 @@ class AuthRepositoryImpl @Inject constructor( /** * firestore에 사용자 정보 저장 */ - override suspend fun saveNewUser(user: User) { + private suspend fun saveNewUser(user: User) { val userEntity = UserMapper.toEntity(user) val userId = userEntity.userId ?: throw IllegalArgumentException("saveNewUser - user ID null") @@ -203,11 +203,6 @@ class AuthRepositoryImpl @Inject constructor( TODO("Not yet implemented") } - /** - * 로그아웃 처리 - * - 카카오 SDK 로그아웃 - * - firebase auth 로그아웃 - */ override suspend fun logout(): Result = suspendCancellableCoroutine { continuation -> // 카카오 SDK 로그아웃 UserApiClient.instance.logout { error -> diff --git a/app/src/main/java/com/min/dnapp/domain/repository/AuthRepository.kt b/app/src/main/java/com/min/dnapp/domain/repository/AuthRepository.kt index a19be38..99f5855 100644 --- a/app/src/main/java/com/min/dnapp/domain/repository/AuthRepository.kt +++ b/app/src/main/java/com/min/dnapp/domain/repository/AuthRepository.kt @@ -4,12 +4,9 @@ import android.content.Context import com.min.dnapp.domain.model.User interface AuthRepository { -// suspend fun signInWithKakao(context: Context): Result -// suspend fun signInWithKakao(context: Context): Result suspend fun signInWithKakao(context: Context): Result suspend fun logout(): Result suspend fun unlinkUser(): Result suspend fun getCurrentUserId(): String? - suspend fun saveNewUser(user: User) suspend fun getUser(): User } diff --git a/app/src/main/java/com/min/dnapp/domain/usecase/AuthWithKakaoUseCase.kt b/app/src/main/java/com/min/dnapp/domain/usecase/AuthWithKakaoUseCase.kt index d28d3e4..ef5edef 100644 --- a/app/src/main/java/com/min/dnapp/domain/usecase/AuthWithKakaoUseCase.kt +++ b/app/src/main/java/com/min/dnapp/domain/usecase/AuthWithKakaoUseCase.kt @@ -7,7 +7,6 @@ import javax.inject.Inject class AuthWithKakaoUseCase @Inject constructor( private val authRepository: AuthRepository ) { -// suspend operator fun invoke(context: Context): Result { suspend operator fun invoke(context: Context): Result { return authRepository.signInWithKakao(context) } diff --git a/app/src/main/java/com/min/dnapp/presentation/login/LoginViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/login/LoginViewModel.kt index b786c9f..a0853a0 100644 --- a/app/src/main/java/com/min/dnapp/presentation/login/LoginViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/login/LoginViewModel.kt @@ -55,38 +55,54 @@ class LoginViewModel @Inject constructor( } /** - * 로그아웃 버튼 클릭 시 호출 + * 로그아웃 처리 + * - 카카오 SDK 로그아웃 + * - firebase auth 로그아웃 */ - fun onLogoutClicked(onSuccess: () -> Unit, onFailure: (Throwable) -> Unit) { + fun onLogoutClicked( + onSuccess: () -> Unit, + onFailure: (Throwable) -> Unit + ) { viewModelScope.launch { try { val result = logoutUseCase() + Log.d("auth", "onLogoutClicked - result : $result") + result.onSuccess { onSuccess() }.onFailure { exception -> onFailure(exception) } } catch (e: Exception) { + Log.e("auth", "onLogoutClicked - unexpected error", e) onFailure(e) } } } /** - * 회원탈퇴 버튼 클릭 시 호출 + * 회원탈퇴 처리 + * - firebase auth 사용자 삭제 + * - firestore "users" 문서 삭제 + * - 카카오 연결 끊기 */ -// fun onUnlinkClicked(onSuccess: () -> Unit, onFailure: (Throwable) -> Unit) { - fun onUnlinkClicked() { + fun onUnlinkClicked( + onSuccess: () -> Unit, + onFailure: (Throwable) -> Unit + ) { viewModelScope.launch { try { val result = unlinkUseCase() + Log.d("auth", "onUnlinkClicked - result : $result") + result.onSuccess { -// onSuccess() + onSuccess() }.onFailure { exception -> -// onFailure(exception) + onFailure(exception) } } catch (e: Exception) { -// onFailure(e) + Log.e("auth", "onUnlinkClicked - unexpected error", e) + onFailure(e) } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt index b9ecb9c..c2996d8 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt @@ -35,6 +35,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController import com.min.dnapp.R import com.min.dnapp.presentation.mypage.component.ProfileImageDialog import com.min.dnapp.presentation.ui.icon.AppIcons @@ -45,8 +46,9 @@ import com.min.dnapp.presentation.ui.theme.MomentoTheme @OptIn(ExperimentalMaterial3Api::class) @Composable -fun MypageScreen() { - +fun MypageScreen( + navController: NavHostController +) { var showProfileImageDialog by remember { mutableStateOf(false) } Scaffold( @@ -96,7 +98,11 @@ fun MypageScreen() { Spacer(Modifier.height(20.dp)) - MypageMenuSection() + MypageMenuSection( + onSettingClick = { + navController.navigate("setting") + } + ) } } @@ -294,7 +300,9 @@ fun RecordAndStampNum() { } @Composable -fun MypageMenuSection() { +fun MypageMenuSection( + onSettingClick: () -> Unit +) { Column( modifier = Modifier .fillMaxWidth() @@ -312,7 +320,7 @@ fun MypageMenuSection() { Spacer(Modifier.height(28.dp)) MypageMenuItem( text = "설정", - onClick = {} + onClick = { onSettingClick() } ) } } @@ -339,6 +347,6 @@ fun MypageMenuItem( @Composable fun MypageScreenPreview() { DngoTheme { - MypageScreen() +// MypageScreen() } } diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/SettingScreen.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/SettingScreen.kt index 523d38d..bd746c5 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/SettingScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/SettingScreen.kt @@ -18,6 +18,9 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavHostController +import com.min.dnapp.presentation.login.LoginViewModel import com.min.dnapp.presentation.ui.icon.AppIcons import com.min.dnapp.presentation.ui.icon.appicons.Back import com.min.dnapp.presentation.ui.theme.DngoTheme @@ -25,7 +28,10 @@ import com.min.dnapp.presentation.ui.theme.MomentoTheme @OptIn(ExperimentalMaterial3Api::class) @Composable -fun SettingScreen() { +fun SettingScreen( + navController: NavHostController, + viewModel: LoginViewModel = hiltViewModel() +) { Scaffold( containerColor = MomentoTheme.colors.brownBg, topBar = { @@ -43,7 +49,7 @@ fun SettingScreen() { navigationIcon = { Icon( modifier = Modifier - .clickable { } + .clickable { navController.popBackStack() } .padding(16.dp), imageVector = AppIcons.Back, contentDescription = null @@ -63,7 +69,20 @@ fun SettingScreen() { Row( modifier = Modifier .fillMaxWidth() - .clickable { } + .clickable { + viewModel.onLogoutClicked( + onSuccess = { + // 로그아웃 성공 후 이동 + navController.navigate("login") { + // 최상위 그래프의 ID까지 스택 모두 제거 + popUpTo(navController.graph.id) { inclusive = true } + } + }, + onFailure = { + + } + ) + } ) { Text( text = "로그아웃", @@ -77,7 +96,20 @@ fun SettingScreen() { Row( modifier = Modifier .fillMaxWidth() - .clickable { } + .clickable { + viewModel.onUnlinkClicked( + onSuccess = { + // 회원탈퇴 성공 후 이동 + navController.navigate("login") { + // 최상위 그래프의 ID까지 스택 모두 제거 + popUpTo(navController.graph.id) { inclusive = true } + } + }, + onFailure = { + + } + ) + } ) { Text( text = "계정 탈퇴", @@ -93,6 +125,6 @@ fun SettingScreen() { @Composable fun SettingScreenPreview() { DngoTheme { - SettingScreen() +// SettingScreen() } } From 8e7c4c8ceee620214109ddd6a5c2c12d7d161d09 Mon Sep 17 00:00:00 2001 From: min486 Date: Fri, 31 Oct 2025 17:45:05 +0900 Subject: [PATCH 54/98] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20=EB=B0=8F=20=ED=91=9C?= =?UTF-8?q?=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/min/dnapp/data/di/RepositoryModule.kt | 8 + .../data/repository/UserRepositoryImpl.kt | 32 ++++ .../dnapp/domain/repository/UserRepository.kt | 7 + .../domain/usecase/GetCurrentUserIdUseCase.kt | 12 ++ .../domain/usecase/GetUserDataUseCase.kt | 17 +++ .../dnapp/presentation/common/BadgeMapper.kt | 15 ++ .../dnapp/presentation/home/HomeScreen2.kt | 141 ++++++++++++------ .../dnapp/presentation/home/HomeUiState.kt | 14 ++ .../dnapp/presentation/home/HomeViewModel.kt | 75 ++++++++++ .../dnapp/presentation/mypage/MypageScreen.kt | 24 +-- .../presentation/ui/component/UserBadge.kt | 43 ++++++ 11 files changed, 320 insertions(+), 68 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/data/repository/UserRepositoryImpl.kt create mode 100644 app/src/main/java/com/min/dnapp/domain/repository/UserRepository.kt create mode 100644 app/src/main/java/com/min/dnapp/domain/usecase/GetCurrentUserIdUseCase.kt create mode 100644 app/src/main/java/com/min/dnapp/domain/usecase/GetUserDataUseCase.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/common/BadgeMapper.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/home/HomeUiState.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/home/HomeViewModel.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/component/UserBadge.kt diff --git a/app/src/main/java/com/min/dnapp/data/di/RepositoryModule.kt b/app/src/main/java/com/min/dnapp/data/di/RepositoryModule.kt index daa1a1e..8d71d5d 100644 --- a/app/src/main/java/com/min/dnapp/data/di/RepositoryModule.kt +++ b/app/src/main/java/com/min/dnapp/data/di/RepositoryModule.kt @@ -3,9 +3,11 @@ package com.min.dnapp.data.di import com.min.dnapp.data.repository.AuthRepositoryImpl import com.min.dnapp.data.repository.LocalSearchRepositoryImpl import com.min.dnapp.data.repository.RecordRepositoryImpl +import com.min.dnapp.data.repository.UserRepositoryImpl import com.min.dnapp.domain.repository.AuthRepository import com.min.dnapp.domain.repository.LocalSearchRepository import com.min.dnapp.domain.repository.RecordRepository +import com.min.dnapp.domain.repository.UserRepository import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -33,4 +35,10 @@ abstract class RepositoryModule { abstract fun bindRecordRepository( recordRepositoryImpl: RecordRepositoryImpl ): RecordRepository + + @Binds + @Singleton + abstract fun bindUserRepository( + userRepositoryImpl: UserRepositoryImpl + ): UserRepository } diff --git a/app/src/main/java/com/min/dnapp/data/repository/UserRepositoryImpl.kt b/app/src/main/java/com/min/dnapp/data/repository/UserRepositoryImpl.kt new file mode 100644 index 0000000..5f33fe9 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/data/repository/UserRepositoryImpl.kt @@ -0,0 +1,32 @@ +package com.min.dnapp.data.repository + +import com.google.firebase.firestore.FirebaseFirestore +import com.min.dnapp.data.remote.dto.UserEntity +import com.min.dnapp.domain.repository.UserRepository +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.tasks.await +import kotlinx.coroutines.withContext +import javax.inject.Inject + +class UserRepositoryImpl @Inject constructor( + private val firestore: FirebaseFirestore +) : UserRepository { + override suspend fun getUserData(uid: String): UserEntity { + // I/O 작업을 위해 Dispatchers.IO로 스레드 전환 + return withContext(Dispatchers.IO) { + try { + val document = firestore + .collection("users") + .document(uid) + .get() + .await() + + val userEntity = document.toObject(UserEntity::class.java) + + return@withContext userEntity ?: throw Exception("user document problem") + } catch (e: Exception) { + throw Exception("failed getUserData: ${e.message}", e) + } + } + } +} diff --git a/app/src/main/java/com/min/dnapp/domain/repository/UserRepository.kt b/app/src/main/java/com/min/dnapp/domain/repository/UserRepository.kt new file mode 100644 index 0000000..9ab1aba --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/repository/UserRepository.kt @@ -0,0 +1,7 @@ +package com.min.dnapp.domain.repository + +import com.min.dnapp.data.remote.dto.UserEntity + +interface UserRepository { + suspend fun getUserData(uid: String): UserEntity +} diff --git a/app/src/main/java/com/min/dnapp/domain/usecase/GetCurrentUserIdUseCase.kt b/app/src/main/java/com/min/dnapp/domain/usecase/GetCurrentUserIdUseCase.kt new file mode 100644 index 0000000..dc89bad --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/usecase/GetCurrentUserIdUseCase.kt @@ -0,0 +1,12 @@ +package com.min.dnapp.domain.usecase + +import com.min.dnapp.domain.repository.AuthRepository +import javax.inject.Inject + +class GetCurrentUserIdUseCase @Inject constructor( + private val authRepository: AuthRepository +) { + suspend operator fun invoke(): String? { + return authRepository.getCurrentUserId() + } +} diff --git a/app/src/main/java/com/min/dnapp/domain/usecase/GetUserDataUseCase.kt b/app/src/main/java/com/min/dnapp/domain/usecase/GetUserDataUseCase.kt new file mode 100644 index 0000000..c593298 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/usecase/GetUserDataUseCase.kt @@ -0,0 +1,17 @@ +package com.min.dnapp.domain.usecase + +import com.min.dnapp.data.mapper.UserMapper +import com.min.dnapp.domain.model.User +import com.min.dnapp.domain.repository.UserRepository +import javax.inject.Inject + +class GetUserDataUseCase @Inject constructor( + private val userRepository: UserRepository +) { + suspend operator fun invoke(uid: String): User { + val userEntity = userRepository.getUserData(uid) + + // UserEntity -> User 변환 + return UserMapper.toDomain(userEntity) + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/common/BadgeMapper.kt b/app/src/main/java/com/min/dnapp/presentation/common/BadgeMapper.kt new file mode 100644 index 0000000..f8780de --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/common/BadgeMapper.kt @@ -0,0 +1,15 @@ +package com.min.dnapp.presentation.common + +import com.min.dnapp.R + +object BadgeMapper { + fun getBadgeImageResId(badgeLv: Int): Int { + return when (badgeLv) { + 1 -> R.drawable.badge_new + 2 -> R.drawable.badge_bronze + 3 -> R.drawable.badge_silver + 4 -> R.drawable.badge_gold + else -> R.drawable.badge_new + } + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt index 0f8447d..fb00068 100644 --- a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt +++ b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt @@ -1,5 +1,6 @@ package com.min.dnapp.presentation.home +import android.util.Log import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -18,6 +19,7 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.Scaffold @@ -25,6 +27,7 @@ import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.VerticalDivider import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -33,11 +36,13 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController import com.min.dnapp.R -import com.min.dnapp.presentation.mypage.UserBadge import com.min.dnapp.presentation.ui.component.CustomFloatingActionButton +import com.min.dnapp.presentation.ui.component.UserBadge import com.min.dnapp.presentation.ui.icon.AppIcons import com.min.dnapp.presentation.ui.icon.appicons.ArrowRight import com.min.dnapp.presentation.ui.icon.appicons.Bell @@ -47,7 +52,12 @@ import com.min.dnapp.presentation.ui.theme.MomentoTheme @OptIn(ExperimentalMaterial3Api::class) @Composable -fun HomeScreen2(navController: NavHostController) { +fun HomeScreen2( + navController: NavHostController, + homeViewModel: HomeViewModel = hiltViewModel() +) { + val uiState by homeViewModel.uiState.collectAsStateWithLifecycle() + Scaffold( containerColor = MomentoTheme.colors.brownW90, topBar = { @@ -85,77 +95,116 @@ fun HomeScreen2(navController: NavHostController) { ) } ) { paddingValues -> - Column( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - ) { - Spacer(Modifier.height(20.dp)) - HomeHeaderSection() - - Spacer(Modifier.height(20.dp)) - - // 여행 기록 영역 - Column( - modifier = Modifier - .fillMaxWidth() - .background(color = MomentoTheme.colors.brownBg, shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp)) - .padding(horizontal = 20.dp) - ) { - Spacer(Modifier.height(20.dp)) - - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically + when (uiState) { + is HomeUiState.Loading -> { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center ) { - Text( - text = "내 여행 기록", - style = MomentoTheme.typography.title02, - color = MomentoTheme.colors.grayW20 - ) - Icon( - modifier = Modifier.clickable { }, - imageVector = AppIcons.ArrowRight, - contentDescription = null, - tint = MomentoTheme.colors.grayW20 + CircularProgressIndicator( + modifier = Modifier.size(40.dp), + color = MomentoTheme.colors.brownW20, + strokeWidth = 4.dp ) } + } + is HomeUiState.Error -> { + Log.e("home", "home 데이터 로드 실패") + } + is HomeUiState.Success -> { + // Success 데이터 추출 + val data = uiState as HomeUiState.Success + + Column( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize() + ) { + Spacer(Modifier.height(20.dp)) + + HomeHeaderSection( + nickname = data.nickname, + recordCnt = data.recordCnt, + stampCnt = data.stampCnt, + badgeName = data.badgeName, + badgeImageResId = data.badgeImageResId + ) - Spacer(Modifier.height(12.dp)) + Spacer(Modifier.height(20.dp)) - // 카드형 영역 - HomeCardSection() + // 여행 기록 영역 + Column( + modifier = Modifier + .fillMaxWidth() + .background(color = MomentoTheme.colors.brownBg, shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp)) + .padding(horizontal = 20.dp) + ) { + Spacer(Modifier.height(20.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "내 여행 기록", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 + ) + Icon( + modifier = Modifier.clickable { }, + imageVector = AppIcons.ArrowRight, + contentDescription = null, + tint = MomentoTheme.colors.grayW20 + ) + } + + Spacer(Modifier.height(12.dp)) + + // 카드형 영역 + HomeCardSection() - Spacer(Modifier.height(20.dp)) + Spacer(Modifier.height(20.dp)) - // 타임라인형 영역 - TimelineSection() + // 타임라인형 영역 + TimelineSection() + } + } } } } } @Composable -fun HomeHeaderSection() { +fun HomeHeaderSection( + nickname: String, + recordCnt: Int, + stampCnt: Int, + badgeName: String, + badgeImageResId: Int +) { Column( modifier = Modifier .fillMaxWidth() .padding(horizontal = 20.dp) ) { - UserBadge() + UserBadge( + badgeName = badgeName, + badgeImageResId = badgeImageResId + ) Spacer(Modifier.height(12.dp)) Text( - text = "성민 님,", + text = "$nickname 님,", style = MomentoTheme.typography.title02, color = MomentoTheme.colors.grayW20 ) Spacer(Modifier.height(4.dp)) Text( - text = "이번 달엔 총2번 여행을 다녀왔어요!", +// text = "이번 달엔 총0번 여행을 다녀왔어요!", + text = "지금까지 총 ${recordCnt}번 여행을 다녀왔어요!", style = MomentoTheme.typography.body01, color = MomentoTheme.colors.grayW20 ) @@ -172,7 +221,7 @@ fun HomeHeaderSection() { ) Spacer(Modifier.width(4.dp)) Text( - text = "모은 스탬프 12개", + text = "모은 스탬프 ${stampCnt}개", style = MomentoTheme.typography.label, color = MomentoTheme.colors.grayW20 ) diff --git a/app/src/main/java/com/min/dnapp/presentation/home/HomeUiState.kt b/app/src/main/java/com/min/dnapp/presentation/home/HomeUiState.kt new file mode 100644 index 0000000..e1019e4 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/home/HomeUiState.kt @@ -0,0 +1,14 @@ +package com.min.dnapp.presentation.home + +sealed class HomeUiState { + data object Loading : HomeUiState() + data class Success( + val nickname: String, + val badgeName: String, + val recordCnt: Int, + val stampCnt: Int, + // badgeLv을 통해 매핑된 이미지 리소스 ID + val badgeImageResId: Int + ) : HomeUiState() + data class Error(val message: String) : HomeUiState() +} diff --git a/app/src/main/java/com/min/dnapp/presentation/home/HomeViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/home/HomeViewModel.kt new file mode 100644 index 0000000..444a5a0 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/home/HomeViewModel.kt @@ -0,0 +1,75 @@ +package com.min.dnapp.presentation.home + +import android.util.Log +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.min.dnapp.domain.model.User +import com.min.dnapp.domain.usecase.GetCurrentUserIdUseCase +import com.min.dnapp.domain.usecase.GetUserDataUseCase +import com.min.dnapp.presentation.common.BadgeMapper +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class HomeViewModel @Inject constructor( + private val getUserDataUseCase: GetUserDataUseCase, + private val getCurrentUserIdUseCase: GetCurrentUserIdUseCase +) : ViewModel() { + + private val _uiState = MutableStateFlow(HomeUiState.Loading) + val uiState: StateFlow = _uiState.asStateFlow() + + init { + loadHomeData() + } + + private fun loadHomeData() { + viewModelScope.launch { + // 로딩 상태 시작 + _uiState.value = HomeUiState.Loading + + // 인증 정보 요청 + val uid = try { + getCurrentUserIdUseCase() + } catch (e: Exception) { + _uiState.value = HomeUiState.Error("인증 정보 가져오기 실패") + return@launch + } + + // uid 유효성 검사 + if (uid.isNullOrEmpty()) { + _uiState.value = HomeUiState.Error("로그인 필요") + return@launch + } + + // firestore 데이터 요청 및 매핑 + try { + val user = getUserDataUseCase(uid) + Log.d("home", "loadHomeData - user: $user") + + val successState = mapUserToHomeUiState(user) + Log.d("home", "loadHomeData - successState: $successState") + + _uiState.value = successState + } catch (e: Exception) { + _uiState.value = HomeUiState.Error("사용자 정보 가져오기 실패: ${e.message}") + } + } + } + + private fun mapUserToHomeUiState(user: User): HomeUiState.Success { + val imageResId = BadgeMapper.getBadgeImageResId(user.badgeLv) + + return HomeUiState.Success( + nickname = user.nickname, + recordCnt = user.recordCnt, + stampCnt = user.stampCnt, + badgeName = user.badgeName, + badgeImageResId = imageResId + ) + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt index c2996d8..c295861 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt @@ -38,6 +38,7 @@ import androidx.compose.ui.unit.dp import androidx.navigation.NavHostController import com.min.dnapp.R import com.min.dnapp.presentation.mypage.component.ProfileImageDialog +import com.min.dnapp.presentation.ui.component.UserBadge import com.min.dnapp.presentation.ui.icon.AppIcons import com.min.dnapp.presentation.ui.icon.appicons.Bell import com.min.dnapp.presentation.ui.icon.appicons.PenSmall @@ -130,7 +131,7 @@ fun MypageProfileSection(onClick: () -> Unit) { Spacer(Modifier.height(12.dp)) // 뱃지 - UserBadge() +// UserBadge() Spacer(Modifier.height(16.dp)) @@ -183,27 +184,6 @@ fun UserProfileImage(onClick: () -> Unit) { } } -@Composable -fun UserBadge() { - Row( - modifier = Modifier - .background(color = MomentoTheme.colors.white, shape = RoundedCornerShape(20.dp)) - .padding(horizontal = 12.dp, vertical = 6.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Image( - painter = painterResource(R.drawable.badge_new), - contentDescription = null - ) - Spacer(Modifier.width(4.dp)) - Text( - text = "새내기", - style = MomentoTheme.typography.caption, - color = MomentoTheme.colors.grayW20 - ) - } -} - @Composable fun RecordAndStampNum() { Row( diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/component/UserBadge.kt b/app/src/main/java/com/min/dnapp/presentation/ui/component/UserBadge.kt new file mode 100644 index 0000000..ffb46e6 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/component/UserBadge.kt @@ -0,0 +1,43 @@ +package com.min.dnapp.presentation.ui.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +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.painterResource +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun UserBadge( + badgeName: String, + badgeImageResId: Int +) { + Row( + modifier = Modifier + .background(color = MomentoTheme.colors.white, shape = RoundedCornerShape(20.dp)) + .padding(horizontal = 12.dp, vertical = 6.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Image( + modifier = Modifier.size(24.dp), + painter = painterResource(badgeImageResId), + contentDescription = null, + ) + Spacer(Modifier.width(4.dp)) + Text( + text = badgeName, +// style = MomentoTheme.typography.caption, + style = MomentoTheme.typography.body03, + color = MomentoTheme.colors.grayW20 + ) + } +} From 04f997c42506e0df29d9cc381e69cf3960ad76af Mon Sep 17 00:00:00 2001 From: min486 Date: Sat, 1 Nov 2025 19:25:06 +0900 Subject: [PATCH 55/98] =?UTF-8?q?feat:=20=EC=97=AC=ED=96=89=EA=B8=B0?= =?UTF-8?q?=EB=A1=9D=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EB=B0=8F=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/min/dnapp/data/mapper/PlaceMapper.kt | 26 ++ .../com/min/dnapp/data/mapper/RecordMapper.kt | 70 +++-- .../min/dnapp/data/remote/dto/RecordEntity.kt | 22 +- .../data/repository/RecordRepositoryImpl.kt | 52 ++- .../com/min/dnapp/domain/model/TripRecord.kt | 18 ++ .../domain/repository/RecordRepository.kt | 2 + .../domain/usecase/GetUserRecordUseCase.kt | 13 + .../dnapp/domain/usecase/SaveRecordUseCase.kt | 4 +- .../dnapp/presentation/home/HomeScreen2.kt | 297 ++++++++++-------- .../dnapp/presentation/home/HomeUiState.kt | 6 +- .../dnapp/presentation/home/HomeViewModel.kt | 40 ++- .../java/com/min/dnapp/util/DateTimeExt.kt | 17 + app/src/main/res/drawable/record_empty.xml | 18 ++ 13 files changed, 397 insertions(+), 188 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/data/mapper/PlaceMapper.kt create mode 100644 app/src/main/java/com/min/dnapp/domain/model/TripRecord.kt create mode 100644 app/src/main/java/com/min/dnapp/domain/usecase/GetUserRecordUseCase.kt create mode 100644 app/src/main/res/drawable/record_empty.xml diff --git a/app/src/main/java/com/min/dnapp/data/mapper/PlaceMapper.kt b/app/src/main/java/com/min/dnapp/data/mapper/PlaceMapper.kt new file mode 100644 index 0000000..69d7209 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/data/mapper/PlaceMapper.kt @@ -0,0 +1,26 @@ +package com.min.dnapp.data.mapper + +import com.min.dnapp.data.remote.dto.PlaceEntity +import com.min.dnapp.domain.model.LocalPlace + +/** + * LocalPlace -> PlaceEntity 변환 + */ +fun LocalPlace.toEntity(): PlaceEntity { + return PlaceEntity( + title = this.title, + category = this.category, + roadAddress = this.roadAddress + ) +} + +/** + * PlaceEntity -> LocalPlace 변환 + */ +fun PlaceEntity.toDomain(): LocalPlace { + return LocalPlace( + title = this.title ?: "", + category = this.category ?: "", + roadAddress = this.roadAddress ?: "" + ) +} diff --git a/app/src/main/java/com/min/dnapp/data/mapper/RecordMapper.kt b/app/src/main/java/com/min/dnapp/data/mapper/RecordMapper.kt index d89c01c..4c355b3 100644 --- a/app/src/main/java/com/min/dnapp/data/mapper/RecordMapper.kt +++ b/app/src/main/java/com/min/dnapp/data/mapper/RecordMapper.kt @@ -1,37 +1,47 @@ package com.min.dnapp.data.mapper -import com.min.dnapp.data.remote.dto.PlaceEntity import com.min.dnapp.data.remote.dto.RecordEntity -import com.min.dnapp.domain.model.LocalPlace +import com.min.dnapp.domain.model.TripRecord import com.min.dnapp.presentation.write.RecordWriteUiState -/** - * RecordWriteUiState -> RecordEntity 변환 - */ -fun RecordWriteUiState.toEntity(userId: String, imageUrl: String?): RecordEntity { - return RecordEntity( - userId = userId, - title = this.recordTitle, - content = this.recordContent, - startDateMillis = this.selectedStartDateMillis, - endDateMillis = this.selectedEndDateMillis, - emotionKey = this.selectedEmotion?.key, - weatherKey = this.selectedWeather?.key, - selectedPlace = this.selectedPlace?.toEntity(), - overseasPlace = this.overseasPlace, - isShareChecked = this.isShareChecked, - // 업로드 후 받은 URL - imageUrl = imageUrl - ) -} +object RecordMapper { + /** + * RecordWriteUiState -> RecordEntity 변환 + */ + fun toEntity(uiState: RecordWriteUiState, imageUrl: String?): RecordEntity { + return RecordEntity( + title = uiState.recordTitle, + content = uiState.recordContent, + startDateMillis = uiState.selectedStartDateMillis, + endDateMillis = uiState.selectedEndDateMillis, + emotionKey = uiState.selectedEmotion?.key, + weatherKey = uiState.selectedWeather?.key, + selectedPlace = uiState.selectedPlace?.toEntity(), + overseasPlace = uiState.overseasPlace, + isShareChecked = uiState.isShareChecked, + // 업로드 후 받은 URL + imageUrl = imageUrl + ) + } -/** - * LocalPlace -> PlaceEntity 변환 - */ -fun LocalPlace.toEntity(): PlaceEntity { - return PlaceEntity( - title = this.title, - category = this.category, - roadAddress = this.roadAddress - ) + /** + * Entity -> Domain 변환 + */ + fun toDomain(entity: RecordEntity): TripRecord { + return TripRecord( + recordId = entity.recordId ?: "", + userId = entity.userId ?: "", + title = entity.title ?: "", + content = entity.content ?: "", + startDateMillis = entity.startDateMillis ?: 0L, + endDateMillis = entity.endDateMillis ?: 0L, + emotionKey = entity.emotionKey ?: "", + weatherKey = entity.weatherKey ?: "", + selectedPlace = entity.selectedPlace?.toDomain(), + overseasPlace = entity.overseasPlace ?: "", + isShareChecked = entity.isShareChecked ?: false, + imageUrl = entity.imageUrl ?: "", + createdAt = entity.createdAt?.toDate()?.time ?: 0L + ) + } } diff --git a/app/src/main/java/com/min/dnapp/data/remote/dto/RecordEntity.kt b/app/src/main/java/com/min/dnapp/data/remote/dto/RecordEntity.kt index 2de08b7..d49af2a 100644 --- a/app/src/main/java/com/min/dnapp/data/remote/dto/RecordEntity.kt +++ b/app/src/main/java/com/min/dnapp/data/remote/dto/RecordEntity.kt @@ -1,18 +1,18 @@ package com.min.dnapp.data.remote.dto +import com.google.firebase.Timestamp import com.google.firebase.firestore.Exclude import com.google.firebase.firestore.ServerTimestamp -import java.util.Date data class RecordEntity( // firestore 문서 ID 값 @get:Exclude - var recordId: String = "", + var recordId: String? = null, - val userId: String = "", + val userId: String? = null, - val title: String = "", - val content: String = "", + val title: String? = null, + val content: String? = null, val startDateMillis: Long? = null, val endDateMillis: Long? = null, @@ -21,19 +21,19 @@ data class RecordEntity( val weatherKey: String? = null, val selectedPlace: PlaceEntity? = null, - val overseasPlace :String? = "", + val overseasPlace: String? = null, - val isShareChecked: Boolean = false, + val isShareChecked: Boolean? = null, val imageUrl: String? = null, // 서버 타임스탬프 @ServerTimestamp - val createdAt: Date? = null + val createdAt: Timestamp? = null ) data class PlaceEntity( - val title: String, - val category: String, - val roadAddress: String + val title: String? = null, + val category: String? = null, + val roadAddress: String? = null ) diff --git a/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt b/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt index 4c4ae35..e109c56 100644 --- a/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt +++ b/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt @@ -1,17 +1,30 @@ package com.min.dnapp.data.repository import android.net.Uri +import android.util.Log +import com.google.firebase.auth.FirebaseAuth import com.google.firebase.firestore.FirebaseFirestore +import com.google.firebase.firestore.toObjects import com.google.firebase.storage.FirebaseStorage +import com.min.dnapp.data.mapper.RecordMapper import com.min.dnapp.data.remote.dto.RecordEntity +import com.min.dnapp.domain.model.TripRecord import com.min.dnapp.domain.repository.RecordRepository +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.tasks.await +import kotlinx.coroutines.withContext import javax.inject.Inject class RecordRepositoryImpl @Inject constructor( private val firestore: FirebaseFirestore, - private val storage: FirebaseStorage + private val storage: FirebaseStorage, + private val firebaseAuth: FirebaseAuth ) : RecordRepository { + + // 현재 로그인된 사용자 ID 가져오기 + private val currentUserId: String + get() = firebaseAuth.currentUser?.uid ?: throw IllegalStateException("user not authenticated") + /** * Storage에 이미지 업로드 및 URL 반환 */ @@ -31,7 +44,13 @@ class RecordRepositoryImpl @Inject constructor( * 개인 기록 컬렉션에 저장 */ override suspend fun savePrivateRecord(record: RecordEntity): RecordEntity { - val recordCollection = firestore.collection("records") + // 사용자 ID 가져오기 + val userId = currentUserId + + val recordCollection = firestore + .collection("records") + .document(userId) + .collection("private_records") // firestore에서 새로운 문서 ID 생성 val newDoc = recordCollection.document() @@ -53,6 +72,33 @@ class RecordRepositoryImpl @Inject constructor( val sharedCollection = firestore.collection("shared_records") // set()을 사용하여 개인 기록과 동일한 ID로 저장 - sharedCollection.document(record.recordId).set(record).await() + record.recordId?.let { recordId -> + sharedCollection.document(recordId).set(record).await() + } + } + + override suspend fun getUserRecord(): List { + // 사용자 ID 가져오기 + val userId = currentUserId + + return withContext(Dispatchers.IO) { + try { + // querySnapshot 객체 가져오기 (사용자의 전체 문서) + val querySnapshot = firestore + .collection("records") + .document(userId) + .collection("private_records") + .get() + .await() + + val entityList = querySnapshot.toObjects() + val domainList = entityList.map { RecordMapper.toDomain(it) } + + return@withContext domainList + } catch (e: Exception) { + Log.e("record", "getUserRecord error", e) + return@withContext emptyList() + } + } } } diff --git a/app/src/main/java/com/min/dnapp/domain/model/TripRecord.kt b/app/src/main/java/com/min/dnapp/domain/model/TripRecord.kt new file mode 100644 index 0000000..2029204 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/model/TripRecord.kt @@ -0,0 +1,18 @@ +package com.min.dnapp.domain.model + +data class TripRecord( + var recordId: String, + val userId: String, + val title: String, + val content: String, + val startDateMillis: Long, + val endDateMillis: Long, + val emotionKey: String, + val weatherKey: String, + // 복합 객체여서 nullable일 수 있음 + val selectedPlace: LocalPlace?, + val overseasPlace: String, + val isShareChecked: Boolean, + val imageUrl: String, + val createdAt: Long +) diff --git a/app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt b/app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt index 2b56fb8..c5fe365 100644 --- a/app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt +++ b/app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt @@ -2,9 +2,11 @@ package com.min.dnapp.domain.repository import android.net.Uri import com.min.dnapp.data.remote.dto.RecordEntity +import com.min.dnapp.domain.model.TripRecord interface RecordRepository { suspend fun uploadImageAndGetUrl(imageUri: Uri, userId: String): String suspend fun savePrivateRecord(record: RecordEntity): RecordEntity suspend fun saveSharedRecord(record: RecordEntity) + suspend fun getUserRecord(): List } diff --git a/app/src/main/java/com/min/dnapp/domain/usecase/GetUserRecordUseCase.kt b/app/src/main/java/com/min/dnapp/domain/usecase/GetUserRecordUseCase.kt new file mode 100644 index 0000000..2d98262 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/usecase/GetUserRecordUseCase.kt @@ -0,0 +1,13 @@ +package com.min.dnapp.domain.usecase + +import com.min.dnapp.domain.model.TripRecord +import com.min.dnapp.domain.repository.RecordRepository +import javax.inject.Inject + +class GetUserRecordUseCase @Inject constructor( + private val recordRepository: RecordRepository +) { + suspend operator fun invoke(): List { + return recordRepository.getUserRecord() + } +} diff --git a/app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt b/app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt index 6e1bd7a..9008b2f 100644 --- a/app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt +++ b/app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt @@ -1,7 +1,7 @@ package com.min.dnapp.domain.usecase import android.net.Uri -import com.min.dnapp.data.mapper.toEntity +import com.min.dnapp.data.mapper.RecordMapper import com.min.dnapp.domain.repository.AuthRepository import com.min.dnapp.domain.repository.RecordRepository import com.min.dnapp.presentation.write.RecordWriteUiState @@ -26,7 +26,7 @@ class SaveRecordUseCase @Inject constructor( } // uiState를 Entity로 변환 - val recordEntity = uiState.toEntity(userId, imageUrl) + val recordEntity = RecordMapper.toEntity(uiState, imageUrl) // 개인 기록 컬렉션에 저장 (필수) // recordId가 포함된 RecordEntity를 받아 새 변수에 저장 diff --git a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt index fb00068..90a88c0 100644 --- a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt +++ b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt @@ -16,6 +16,9 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.CenterAlignedTopAppBar @@ -31,8 +34,9 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -40,7 +44,9 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController +import coil3.compose.AsyncImage import com.min.dnapp.R +import com.min.dnapp.domain.model.TripRecord import com.min.dnapp.presentation.ui.component.CustomFloatingActionButton import com.min.dnapp.presentation.ui.component.UserBadge import com.min.dnapp.presentation.ui.icon.AppIcons @@ -49,6 +55,7 @@ import com.min.dnapp.presentation.ui.icon.appicons.Bell import com.min.dnapp.presentation.ui.icon.appicons.Year import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.ui.theme.MomentoTheme +import com.min.dnapp.util.toDateString @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -133,10 +140,11 @@ fun HomeScreen2( Spacer(Modifier.height(20.dp)) - // 여행 기록 영역 + // 여행 기록 영역 (카드형 + 타임라인형) Column( modifier = Modifier .fillMaxWidth() + .weight(1f) .background(color = MomentoTheme.colors.brownBg, shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp)) .padding(horizontal = 20.dp) ) { @@ -162,13 +170,36 @@ fun HomeScreen2( Spacer(Modifier.height(12.dp)) - // 카드형 영역 - HomeCardSection() + if (data.records.isEmpty()) { + // 기록 없는 경우 + Column( + modifier = Modifier + .fillMaxWidth() + .weight(1f), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(Modifier.height(20.dp)) + Image( + painter = painterResource(R.drawable.record_empty), + contentDescription = null + ) + Spacer(Modifier.height(12.dp)) + Text( + text = "아직 기록이 없네요. \n첫 여행을 기록해보세요!", + style = MomentoTheme.typography.title01, + color = MomentoTheme.colors.grayW20, + textAlign = TextAlign.Center + ) + } + } else { + // 카드형 영역 + HomeCardSection(records = data.records) - Spacer(Modifier.height(20.dp)) + Spacer(Modifier.height(20.dp)) - // 타임라인형 영역 - TimelineSection() + // 타임라인형 영역 + TimelineSection(records = data.records) + } } } } @@ -230,163 +261,168 @@ fun HomeHeaderSection( } @Composable -fun HomeCardSection() { - Row( - modifier = Modifier.fillMaxWidth(), +fun HomeCardSection( + records: List +) { + LazyRow( horizontalArrangement = Arrangement.spacedBy(8.dp) ) { - HomeCardImage( - image = painterResource(R.drawable.trip), - text = "제주특별자치도" - ) - HomeCardNoImage() - HomeCardImage( - image = painterResource(R.drawable.trip2), - text = "일본 도쿄" + items(records) { record -> + if (record.imageUrl.isEmpty()) { + HomeCardNoImage(record = record) + } else { + HomeCardImage(record = record) + } + } + } +} + +@Composable +fun HomeCardNoImage( + record: TripRecord +) { + Box( + modifier = Modifier + .size(100.dp) + .background(color = MomentoTheme.colors.greenW80) + .padding(horizontal = 12.dp), + contentAlignment = Alignment.Center + ) { + Image( + painter = painterResource(R.drawable.image_basic), + contentDescription = null ) + record.selectedPlace?.let { selectedPlace -> + Text( + text = selectedPlace.title, + style = MomentoTheme.typography.label, + color = MomentoTheme.colors.grayW20, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } } } @Composable fun HomeCardImage( - image: Painter, - text: String + record: TripRecord ) { Box( modifier = Modifier, contentAlignment = Alignment.CenterStart ) { - Image( + AsyncImage( modifier = Modifier.size(100.dp), - painter = image, - contentDescription = null + model = record.imageUrl, + contentDescription = null, + contentScale = ContentScale.Crop ) + // 이미지 어둡게 처리 Box( modifier = Modifier .matchParentSize() .background(color = Color.Black.copy(alpha = 0.3f)) ) - Text( - modifier = Modifier - .width(88.dp) - .padding(start = 12.dp), - text = text, - style = MomentoTheme.typography.label, - color = MomentoTheme.colors.white, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } -} -@Composable -fun HomeCardNoImage() { - Box( - modifier = Modifier - .size(100.dp) - .background(color = MomentoTheme.colors.greenW80) - .padding(horizontal = 12.dp), - contentAlignment = Alignment.Center - ) { - Image( - painter = painterResource(R.drawable.image_basic), - contentDescription = null - ) - Text( - text = "제주특별자치도", - style = MomentoTheme.typography.label, - color = MomentoTheme.colors.grayW20, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) + record.selectedPlace?.let { selectedPlace -> + Text( + modifier = Modifier + .width(88.dp) + .padding(start = 12.dp), + text = selectedPlace.title, + style = MomentoTheme.typography.label, + color = MomentoTheme.colors.white, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } } } @Composable -fun TimelineSection() { +fun TimelineSection( + records: List +) { LazyColumn( modifier = Modifier .fillMaxWidth() .padding(top = 20.dp), - verticalArrangement = Arrangement.spacedBy(20.dp) ) { - item { - TimelineYear(year = 2024) + itemsIndexed(records) { idx, record -> + // 현재 항목의 년도 + val currentYear = record.startDateMillis.toDateString("yyyy") + Log.d("home", "toDateString - currentYear: $currentYear") + + // 직전 항목의 년도와 비교 + val previousYear = if (idx > 0) { + records[idx-1].startDateMillis.toDateString("yyyy") + } else { + null + } + + // 년도별 첫번째 항목 여부 + val isYearStart = (idx == 0) || (currentYear != previousYear) + + // 1번째 항목인 경우 or 년도가 바뀌는 시점에 년도 표시 + if (idx == 0 || currentYear != previousYear) { + if (idx != 0) { + Spacer(Modifier.height(20.dp)) + } + YearHeader(year = currentYear) + Spacer(Modifier.height(12.dp)) + } + + TimelineItem( + record = record, + isYearStart = isYearStart + ) } + item { - TimelineYear(year = 2023) + Spacer(Modifier.height(20.dp)) } } } @Composable -fun TimelineYear( - year: Int +fun YearHeader( + year: String ) { - Column( - modifier = Modifier.fillMaxWidth() - ) { - Row { - Icon( - imageVector = AppIcons.Year, - contentDescription = null, - tint = MomentoTheme.colors.brownBase - ) - Spacer(Modifier.width(6.dp)) - Text( - text = "${year}년", - style = MomentoTheme.typography.title02, - color = MomentoTheme.colors.grayW20 - ) - } - - Spacer(Modifier.height(12.dp)) - - // 타임라인형 아이템 - TimelineItem( - idx = 0, - image = painterResource(R.drawable.trip), - startDate = "07.25", - endDate = "07.28", - title = "제주도 동쪽 투어!", - place = "제주특별자치도" - ) - TimelineItem( - idx = 1, - image = painterResource(R.drawable.trip3), - startDate = "03.05", - endDate = "03.08", - title = "너와 함께 한 시간 속", - place = "부산광역시 수영구" + Row { + Icon( + imageVector = AppIcons.Year, + contentDescription = null, + tint = MomentoTheme.colors.brownBase ) - TimelineItem( - idx = 2, - image = painterResource(R.drawable.trip3), - startDate = "01.05", - endDate = "01.07", - title = "신년맞이", - place = "부산광역시 수영구" + Spacer(Modifier.width(6.dp)) + Text( + text = "${year}년", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 ) } } @Composable fun TimelineItem( - idx: Int, - image: Painter, - startDate: String, - endDate: String, - title: String, - place: String + record: TripRecord, + isYearStart: Boolean ) { + // 월.일 추출 (예: 07.25) + val startDate = record.startDateMillis.toDateString("MM.dd") + val endDate = record.endDateMillis.toDateString("MM.dd") + Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { - Row { - HomeGrayLine(idx = idx) + Row( + modifier = Modifier.weight(1f) + ) { + HomeGrayLine(isYearStart = isYearStart) Spacer(Modifier.width(12.dp)) @@ -395,14 +431,16 @@ fun TimelineItem( ) { Spacer(Modifier.height(4.dp)) Text( - text = "${startDate} ~ ${endDate}", + text = "$startDate ~ $endDate", style = MomentoTheme.typography.body03, color = MomentoTheme.colors.grayW20 ) Text( - text = title, + text = record.title, style = MomentoTheme.typography.body02, - color = MomentoTheme.colors.grayW20 + color = MomentoTheme.colors.grayW20, + maxLines = 1, + overflow = TextOverflow.Ellipsis ) Row( verticalAlignment = Alignment.CenterVertically @@ -412,31 +450,36 @@ fun TimelineItem( contentDescription = null ) Spacer(Modifier.width(6.dp)) - Text( - text = place, - style = MomentoTheme.typography.body03, - color = MomentoTheme.colors.grayW20 - ) + record.selectedPlace?.let { selectedPlace -> + Text( + text = selectedPlace.title, + style = MomentoTheme.typography.body03, + color = MomentoTheme.colors.grayW20 + ) + } } } } - Image( - modifier = Modifier.size(90.dp), - painter = image, - contentDescription = null - ) + if (record.imageUrl.isNotEmpty()) { + AsyncImage( + modifier = Modifier.size(90.dp), + model = record.imageUrl, + contentDescription = null, + contentScale = ContentScale.Crop + ) + } } } @Composable fun HomeGrayLine( - idx: Int + isYearStart: Boolean ) { Column( horizontalAlignment = Alignment.CenterHorizontally ) { - if (idx == 0) { + if (isYearStart) { Box( modifier = Modifier .size(8.dp) diff --git a/app/src/main/java/com/min/dnapp/presentation/home/HomeUiState.kt b/app/src/main/java/com/min/dnapp/presentation/home/HomeUiState.kt index e1019e4..5a983cc 100644 --- a/app/src/main/java/com/min/dnapp/presentation/home/HomeUiState.kt +++ b/app/src/main/java/com/min/dnapp/presentation/home/HomeUiState.kt @@ -1,5 +1,7 @@ package com.min.dnapp.presentation.home +import com.min.dnapp.domain.model.TripRecord + sealed class HomeUiState { data object Loading : HomeUiState() data class Success( @@ -8,7 +10,9 @@ sealed class HomeUiState { val recordCnt: Int, val stampCnt: Int, // badgeLv을 통해 매핑된 이미지 리소스 ID - val badgeImageResId: Int + val badgeImageResId: Int, + // 기록 목록 + val records: List = emptyList() ) : HomeUiState() data class Error(val message: String) : HomeUiState() } diff --git a/app/src/main/java/com/min/dnapp/presentation/home/HomeViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/home/HomeViewModel.kt index 444a5a0..9317cbc 100644 --- a/app/src/main/java/com/min/dnapp/presentation/home/HomeViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/home/HomeViewModel.kt @@ -6,6 +6,7 @@ import androidx.lifecycle.viewModelScope import com.min.dnapp.domain.model.User import com.min.dnapp.domain.usecase.GetCurrentUserIdUseCase import com.min.dnapp.domain.usecase.GetUserDataUseCase +import com.min.dnapp.domain.usecase.GetUserRecordUseCase import com.min.dnapp.presentation.common.BadgeMapper import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow @@ -17,7 +18,8 @@ import javax.inject.Inject @HiltViewModel class HomeViewModel @Inject constructor( private val getUserDataUseCase: GetUserDataUseCase, - private val getCurrentUserIdUseCase: GetCurrentUserIdUseCase + private val getCurrentUserIdUseCase: GetCurrentUserIdUseCase, + private val getUserRecordUseCase: GetUserRecordUseCase ) : ViewModel() { private val _uiState = MutableStateFlow(HomeUiState.Loading) @@ -29,34 +31,44 @@ class HomeViewModel @Inject constructor( private fun loadHomeData() { viewModelScope.launch { - // 로딩 상태 시작 + // 로딩 시작 _uiState.value = HomeUiState.Loading // 인증 정보 요청 val uid = try { - getCurrentUserIdUseCase() + getCurrentUserIdUseCase() ?: throw Exception("사용자 인증 정보 없음") } catch (e: Exception) { - _uiState.value = HomeUiState.Error("인증 정보 가져오기 실패") + _uiState.value = HomeUiState.Error("인증 정보 로드 실패: ${e.message}") return@launch } - // uid 유효성 검사 - if (uid.isNullOrEmpty()) { - _uiState.value = HomeUiState.Error("로그인 필요") - return@launch - } - - // firestore 데이터 요청 및 매핑 + // 사용자 정보 로드 및 Success 상태 초기화 + val successState: HomeUiState.Success try { val user = getUserDataUseCase(uid) Log.d("home", "loadHomeData - user: $user") - val successState = mapUserToHomeUiState(user) - Log.d("home", "loadHomeData - successState: $successState") + successState = mapUserToHomeUiState(user) _uiState.value = successState } catch (e: Exception) { - _uiState.value = HomeUiState.Error("사용자 정보 가져오기 실패: ${e.message}") + _uiState.value = HomeUiState.Error("사용자 정보 로드 실패: ${e.message}") + return@launch + } + + // 여행기록 정보 로드 및 상태 업데이트 + try { + val userRecords = getUserRecordUseCase() + Log.d("home", "loadHomeData - userRecords: $userRecords") + val finalSuccessState = successState.copy( + records = userRecords + ) + _uiState.value = finalSuccessState + } catch (e: Exception) { + _uiState.value = successState.copy( + records = emptyList() + ) + Log.e("home", "기록 정보 로드 실패", e) } } } diff --git a/app/src/main/java/com/min/dnapp/util/DateTimeExt.kt b/app/src/main/java/com/min/dnapp/util/DateTimeExt.kt index 37e3a79..837ae03 100644 --- a/app/src/main/java/com/min/dnapp/util/DateTimeExt.kt +++ b/app/src/main/java/com/min/dnapp/util/DateTimeExt.kt @@ -1,8 +1,12 @@ package com.min.dnapp.util +import android.util.Log +import java.text.SimpleDateFormat import java.time.Instant import java.time.LocalDate import java.time.ZoneId +import java.util.Date +import java.util.Locale /** * Long(밀리초) 값을 시스템 기본 시간대를 기준으로 LocalDate로 변환 @@ -16,3 +20,16 @@ fun Long?.toLocalDate(): LocalDate? { .atZone(ZoneId.systemDefault()) .toLocalDate() } + +/** + * 원하는 날짜 포맷으로 변환 + */ +fun Long.toDateString(format: String): String { + val date = Date(this) + Log.d("home", "toDateString - date: $date") + + val formatter = SimpleDateFormat(format, Locale.getDefault()) + Log.d("home", "toDateString - formatter: $formatter") + + return formatter.format(date) +} diff --git a/app/src/main/res/drawable/record_empty.xml b/app/src/main/res/drawable/record_empty.xml new file mode 100644 index 0000000..8f693ed --- /dev/null +++ b/app/src/main/res/drawable/record_empty.xml @@ -0,0 +1,18 @@ + + + + + + From 92f988490259cb54e38c4ec3d54267a762b86160 Mon Sep 17 00:00:00 2001 From: min486 Date: Sat, 1 Nov 2025 19:39:18 +0900 Subject: [PATCH 56/98] =?UTF-8?q?feat:=20=EC=97=AC=ED=96=89=EA=B8=B0?= =?UTF-8?q?=EB=A1=9D=20=EC=B5=9C=EC=8B=A0=EC=88=9C=20=EC=A0=95=EB=A0=AC=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt b/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt index e109c56..479d3af 100644 --- a/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt +++ b/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt @@ -4,6 +4,7 @@ import android.net.Uri import android.util.Log import com.google.firebase.auth.FirebaseAuth import com.google.firebase.firestore.FirebaseFirestore +import com.google.firebase.firestore.Query import com.google.firebase.firestore.toObjects import com.google.firebase.storage.FirebaseStorage import com.min.dnapp.data.mapper.RecordMapper @@ -88,6 +89,7 @@ class RecordRepositoryImpl @Inject constructor( .collection("records") .document(userId) .collection("private_records") + .orderBy("startDateMillis", Query.Direction.DESCENDING) .get() .await() From 579bc2d230ec62db660a695d2525197d4d737909 Mon Sep 17 00:00:00 2001 From: min486 Date: Sat, 1 Nov 2025 23:43:26 +0900 Subject: [PATCH 57/98] =?UTF-8?q?feat:=20=ED=95=84=EC=88=98=20=ED=95=AD?= =?UTF-8?q?=EB=AA=A9=20=EB=AF=B8=EC=9E=85=EB=A0=A5=20=EC=8B=9C=20snackbar?= =?UTF-8?q?=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/common/SnackbarMessage.kt | 5 ++ .../ui/component/CustomSnackbar.kt | 54 +++++++++++++++++++ .../presentation/write/RecordWriteScreen.kt | 26 ++++++++- .../write/RecordWriteViewModel.kt | 49 +++++++++++++++++ .../dnapp/presentation/write/WriteMessage.kt | 10 ++++ app/src/main/res/drawable/logo_snackbar.xml | 29 ++++++++++ 6 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/common/SnackbarMessage.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/component/CustomSnackbar.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/write/WriteMessage.kt create mode 100644 app/src/main/res/drawable/logo_snackbar.xml diff --git a/app/src/main/java/com/min/dnapp/presentation/common/SnackbarMessage.kt b/app/src/main/java/com/min/dnapp/presentation/common/SnackbarMessage.kt new file mode 100644 index 0000000..0640995 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/common/SnackbarMessage.kt @@ -0,0 +1,5 @@ +package com.min.dnapp.presentation.common + +data class SnackbarMessage( + val message: String +) diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/component/CustomSnackbar.kt b/app/src/main/java/com/min/dnapp/presentation/ui/component/CustomSnackbar.kt new file mode 100644 index 0000000..323ed7c --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/component/CustomSnackbar.kt @@ -0,0 +1,54 @@ +package com.min.dnapp.presentation.ui.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.SnackbarData +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.R +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun CustomSnackbar( + snackbarData: SnackbarData +) { + Row( + modifier = Modifier + .clip(RoundedCornerShape(100.dp)) + .background(color = MomentoTheme.colors.grayW20) + .padding(horizontal = 12.dp, vertical = 8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(R.drawable.logo_snackbar), + contentDescription = null + ) + Spacer(Modifier.width(10.dp)) + Text( + text = snackbarData.visuals.message, +// style = MomentoTheme.typography.label, + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.white + ) + } +} + +@Preview +@Composable +fun CustomSnackbarPreview() { + DngoTheme { +// CustomSnackbar() + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index ff15aa5..7c742d2 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -1,8 +1,7 @@ package com.min.dnapp.presentation.write -import android.content.Intent +import android.content.Intent import android.net.Uri -import android.util.Log import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.PickVisualMediaRequest import androidx.activity.result.contract.ActivityResultContracts @@ -36,6 +35,9 @@ import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.RadioButton import androidx.compose.material3.RadioButtonDefaults import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarDuration +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Switch import androidx.compose.material3.SwitchDefaults import androidx.compose.material3.Text @@ -66,6 +68,7 @@ import com.min.dnapp.R import com.min.dnapp.domain.model.EmotionType import com.min.dnapp.domain.model.LocalPlace import com.min.dnapp.domain.model.WeatherType +import com.min.dnapp.presentation.ui.component.CustomSnackbar import com.min.dnapp.presentation.ui.icon.AppIcons import com.min.dnapp.presentation.ui.icon.appicons.Back import com.min.dnapp.presentation.ui.icon.appicons.Calendar @@ -86,6 +89,8 @@ fun RecordWriteScreen( val uiState by viewModel.uiState.collectAsStateWithLifecycle() val context = LocalContext.current + val snackbarHostState = remember { SnackbarHostState() } + // 캘린더 모달 표시상태 var showDatePicker by remember { mutableStateOf(false) } @@ -140,6 +145,16 @@ fun RecordWriteScreen( } } + // 메시지 발행을 수집하여 스낵바 표시 + LaunchedEffect(Unit) { + viewModel.snackbarMessage.collect { message -> + snackbarHostState.showSnackbar( + message = message.message, + duration = SnackbarDuration.Short + ) + } + } + Scaffold( containerColor = MomentoTheme.colors.brownW90, topBar = { @@ -186,6 +201,13 @@ fun RecordWriteScreen( }, onGalleryClick = { viewModel.onGalleryIconClicked() } ) + }, + snackbarHost = { + SnackbarHost(hostState = snackbarHostState) { data -> + CustomSnackbar( + snackbarData = data + ) + } } ) { paddingValues -> Column( diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt index 77aefdf..666f9c5 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt @@ -9,13 +9,16 @@ import com.min.dnapp.domain.model.LocalPlace import com.min.dnapp.domain.model.WeatherType import com.min.dnapp.domain.usecase.LocalSearchUseCase import com.min.dnapp.domain.usecase.SaveRecordUseCase +import com.min.dnapp.presentation.common.SnackbarMessage import com.min.dnapp.util.Resource import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Job import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -40,6 +43,9 @@ class RecordWriteViewModel @Inject constructor( private val _completeSaveRecord = Channel() val completeSaveRecordFlow = _completeSaveRecord.receiveAsFlow() + private val _snackbarMessage = MutableSharedFlow() + val snackbarMessage = _snackbarMessage.asSharedFlow() + // 이전 검색 작업을 취소하기 위한 Job private var searchJob: Job? = null @@ -220,6 +226,14 @@ class RecordWriteViewModel @Inject constructor( * Firebase에 기록 저장 */ fun saveRecord() { + // 필수 항목 미입력 시, 메시지 발행 후 종료 + getSnackbarMessage(uiState.value)?.let { message -> + viewModelScope.launch { + _snackbarMessage.emit(message) + } + return + } + // 중복 저장 방지 if (uiState.value.isSaving) return @@ -242,4 +256,39 @@ class RecordWriteViewModel @Inject constructor( _uiState.update { it.copy(isSaving = false) } } } + + private fun getSnackbarMessage(uiState: RecordWriteUiState): SnackbarMessage? { + if (uiState.recordTitle.isBlank()) { + return SnackbarMessage( + message = WriteMessage.TITLE_EMPTY + ) + } + if (uiState.recordContent.isBlank()) { + return SnackbarMessage( + message = WriteMessage.CONTENT_EMPTY + ) + } + if (uiState.selectedStartDateMillis == null) { + return SnackbarMessage( + message = WriteMessage.DATE_EMPTY + ) + } + if (uiState.selectedEmotion == null) { + return SnackbarMessage( + message = WriteMessage.EMOTION_EMPTY + ) + } + if (uiState.selectedWeather == null) { + return SnackbarMessage( + message = WriteMessage.WEATHER_EMPTY + ) + } + if (uiState.selectedPlace == null && uiState.overseasPlace.isBlank()) { + return SnackbarMessage( + message = WriteMessage.PLACE_EMPTY + ) + } + + return null + } } diff --git a/app/src/main/java/com/min/dnapp/presentation/write/WriteMessage.kt b/app/src/main/java/com/min/dnapp/presentation/write/WriteMessage.kt new file mode 100644 index 0000000..8cec782 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/write/WriteMessage.kt @@ -0,0 +1,10 @@ +package com.min.dnapp.presentation.write + +object WriteMessage { + const val TITLE_EMPTY = "제목을 입력해주세요" + const val CONTENT_EMPTY = "내용을 입력해주세요" + const val DATE_EMPTY = "날짜를 선택해주세요" + const val EMOTION_EMPTY = "감정 태그를 선택해주세요" + const val WEATHER_EMPTY = "날씨를 선택해주세요" + const val PLACE_EMPTY = "여행지를 입력해주세요" +} diff --git a/app/src/main/res/drawable/logo_snackbar.xml b/app/src/main/res/drawable/logo_snackbar.xml new file mode 100644 index 0000000..0846c94 --- /dev/null +++ b/app/src/main/res/drawable/logo_snackbar.xml @@ -0,0 +1,29 @@ + + + + + + + + From 6a8abf49b108fff1fa55a71f1da1494c095babf1 Mon Sep 17 00:00:00 2001 From: min486 Date: Sun, 2 Nov 2025 00:21:10 +0900 Subject: [PATCH 58/98] =?UTF-8?q?feat:=20=EA=B8=B0=EB=A1=9D=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=20=EC=99=84=EB=A3=8C=20=EC=8B=9C=20=EA=B8=B0=EB=A1=9D?= =?UTF-8?q?/=EC=8A=A4=ED=83=AC=ED=94=84=20=EC=88=98=20=EC=A6=9D=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/RecordRepositoryImpl.kt | 17 +++++++++++++++++ .../dnapp/domain/repository/RecordRepository.kt | 1 + .../dnapp/domain/usecase/SaveRecordUseCase.kt | 3 +++ 3 files changed, 21 insertions(+) diff --git a/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt b/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt index 479d3af..99d2fa3 100644 --- a/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt +++ b/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt @@ -3,6 +3,7 @@ package com.min.dnapp.data.repository import android.net.Uri import android.util.Log import com.google.firebase.auth.FirebaseAuth +import com.google.firebase.firestore.FieldValue import com.google.firebase.firestore.FirebaseFirestore import com.google.firebase.firestore.Query import com.google.firebase.firestore.toObjects @@ -103,4 +104,20 @@ class RecordRepositoryImpl @Inject constructor( } } } + + /** + * 기록/스탬프 수 1씩 증가 + */ + override suspend fun increaseRecordAndStamp() { + val userId = currentUserId + val userDoc = firestore.collection("users").document(userId) + + // Map으로 업데이트할 필드와 값을 지정 + val updateCnt = mapOf( + "recordCnt" to FieldValue.increment(1), + "stampCnt" to FieldValue.increment(1) + ) + + userDoc.update(updateCnt).await() + } } diff --git a/app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt b/app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt index c5fe365..35b717a 100644 --- a/app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt +++ b/app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt @@ -9,4 +9,5 @@ interface RecordRepository { suspend fun savePrivateRecord(record: RecordEntity): RecordEntity suspend fun saveSharedRecord(record: RecordEntity) suspend fun getUserRecord(): List + suspend fun increaseRecordAndStamp() } diff --git a/app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt b/app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt index 9008b2f..9f9f591 100644 --- a/app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt +++ b/app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt @@ -38,6 +38,9 @@ class SaveRecordUseCase @Inject constructor( recordRepository.saveSharedRecord(savedRecord) } + // 기록/스탬프 수 1씩 증가 + recordRepository.increaseRecordAndStamp() + Result.success(Unit) } catch (e: Exception) { Result.failure(e) From 8e2fdbb7dfa124f5a3aeabf20ae584a95ffe8e86 Mon Sep 17 00:00:00 2001 From: min486 Date: Sun, 2 Nov 2025 01:11:49 +0900 Subject: [PATCH 59/98] =?UTF-8?q?feat:=20=EA=B3=B5=EC=9C=A0=20=EC=95=88?= =?UTF-8?q?=EB=82=B4=20=EB=A7=90=ED=92=8D=EC=84=A0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dnapp/presentation/ui/icon/__AppIcons.kt | 8 +- .../ui/icon/appicons/DeleteLine.kt | 88 +++++++++++++++++++ .../ui/icon/appicons/ShareTriangle.kt | 62 +++++++++++++ .../presentation/write/RecordWriteScreen.kt | 32 +++++-- .../presentation/write/RecordWriteUiState.kt | 2 +- .../write/component/ShareGuide.kt | 64 ++++++++++++++ 6 files changed, 244 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/DeleteLine.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/ShareTriangle.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/write/component/ShareGuide.kt diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt index 034c738..5767381 100644 --- a/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/__AppIcons.kt @@ -6,6 +6,7 @@ import com.min.dnapp.presentation.ui.icon.appicons.Back import com.min.dnapp.presentation.ui.icon.appicons.Bell import com.min.dnapp.presentation.ui.icon.appicons.Calendar import com.min.dnapp.presentation.ui.icon.appicons.Delete +import com.min.dnapp.presentation.ui.icon.appicons.DeleteLine import com.min.dnapp.presentation.ui.icon.appicons.Explore import com.min.dnapp.presentation.ui.icon.appicons.Gallery import com.min.dnapp.presentation.ui.icon.appicons.Home @@ -19,6 +20,7 @@ import com.min.dnapp.presentation.ui.icon.appicons.RecordBookmark import com.min.dnapp.presentation.ui.icon.appicons.RecordComment import com.min.dnapp.presentation.ui.icon.appicons.RecordLike import com.min.dnapp.presentation.ui.icon.appicons.RecordSurprise +import com.min.dnapp.presentation.ui.icon.appicons.ShareTriangle import com.min.dnapp.presentation.ui.icon.appicons.Year import kotlin.collections.List as ____KtList @@ -31,8 +33,8 @@ public val AppIcons.AllIcons: ____KtList if (__AllIcons != null) { return __AllIcons!! } - __AllIcons= listOf(ArrowRight, Back, Bell, Calendar, Delete, Explore, Gallery, Home, Kakao, - More, My, Pen, PenSmall, RecordBest, RecordBookmark, RecordComment, RecordLike, - RecordSurprise, Year) + __AllIcons= listOf(ArrowRight, Back, Bell, Calendar, Delete, DeleteLine, Explore, Gallery, Home, + Kakao, More, My, Pen, PenSmall, RecordBest, RecordBookmark, RecordComment, RecordLike, + RecordSurprise, ShareTriangle, Year) return __AllIcons!! } diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/DeleteLine.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/DeleteLine.kt new file mode 100644 index 0000000..5a27d43 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/DeleteLine.kt @@ -0,0 +1,88 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.DeleteLine: ImageVector + get() { + if (_deleteLine != null) { + return _deleteLine!! + } + _deleteLine = Builder(name = "DeleteLine", defaultWidth = 16.0.dp, defaultHeight = 16.0.dp, + viewportWidth = 16.0f, viewportHeight = 16.0f).apply { + path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(11.764f, 3.764f) + curveTo(11.895f, 3.634f, 12.106f, 3.634f, 12.236f, 3.764f) + curveTo(12.366f, 3.894f, 12.366f, 4.105f, 12.236f, 4.235f) + lineTo(8.471f, 8.0f) + lineTo(12.236f, 11.764f) + curveTo(12.366f, 11.894f, 12.366f, 12.105f, 12.236f, 12.236f) + curveTo(12.106f, 12.366f, 11.895f, 12.366f, 11.764f, 12.236f) + lineTo(8.0f, 8.471f) + lineTo(4.236f, 12.236f) + curveTo(4.106f, 12.366f, 3.895f, 12.366f, 3.764f, 12.236f) + curveTo(3.634f, 12.105f, 3.634f, 11.894f, 3.764f, 11.764f) + lineTo(7.529f, 8.0f) + lineTo(3.764f, 4.235f) + curveTo(3.634f, 4.105f, 3.634f, 3.894f, 3.764f, 3.764f) + curveTo(3.895f, 3.634f, 4.106f, 3.634f, 4.236f, 3.764f) + lineTo(8.0f, 7.528f) + lineTo(11.764f, 3.764f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.2f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(11.764f, 3.764f) + curveTo(11.895f, 3.634f, 12.106f, 3.634f, 12.236f, 3.764f) + curveTo(12.366f, 3.894f, 12.366f, 4.105f, 12.236f, 4.235f) + lineTo(8.471f, 8.0f) + lineTo(12.236f, 11.764f) + curveTo(12.366f, 11.894f, 12.366f, 12.105f, 12.236f, 12.236f) + curveTo(12.106f, 12.366f, 11.895f, 12.366f, 11.764f, 12.236f) + lineTo(8.0f, 8.471f) + lineTo(4.236f, 12.236f) + curveTo(4.106f, 12.366f, 3.895f, 12.366f, 3.764f, 12.236f) + curveTo(3.634f, 12.105f, 3.634f, 11.894f, 3.764f, 11.764f) + lineTo(7.529f, 8.0f) + lineTo(3.764f, 4.235f) + curveTo(3.634f, 4.105f, 3.634f, 3.894f, 3.764f, 3.764f) + curveTo(3.895f, 3.634f, 4.106f, 3.634f, 4.236f, 3.764f) + lineTo(8.0f, 7.528f) + lineTo(11.764f, 3.764f) + close() + } + } + .build() + return _deleteLine!! + } + +private var _deleteLine: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.DeleteLine, contentDescription = "") + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/ShareTriangle.kt b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/ShareTriangle.kt new file mode 100644 index 0000000..caf6778 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/ui/icon/appicons/ShareTriangle.kt @@ -0,0 +1,62 @@ +package com.min.dnapp.presentation.ui.icon.appicons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.PathFillType +import androidx.compose.ui.graphics.PathFillType.Companion.NonZero +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeCap.Companion.Butt +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.ImageVector.Builder +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import kotlin.Unit + +public val AppIcons.ShareTriangle: ImageVector + get() { + if (_shareTriangle != null) { + return _shareTriangle!! + } + _shareTriangle = Builder(name = "ShareTriangle", defaultWidth = 12.0.dp, defaultHeight = + 8.0.dp, viewportWidth = 12.0f, viewportHeight = 8.0f).apply { + path(fill = SolidColor(Color(0xFF6E8B74)), stroke = null, strokeLineWidth = 0.0f, + strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f, + pathFillType = NonZero) { + moveTo(6.0f, 8.0f) + lineTo(12.0f, 0.0f) + horizontalLineTo(0.0f) + lineTo(6.0f, 8.0f) + close() + } + path(fill = SolidColor(Color(0xFFffffff)), stroke = null, fillAlpha = 0.6f, + strokeLineWidth = 0.0f, strokeLineCap = Butt, strokeLineJoin = Miter, + strokeLineMiter = 4.0f, pathFillType = NonZero) { + moveTo(6.0f, 8.0f) + lineTo(12.0f, 0.0f) + horizontalLineTo(0.0f) + lineTo(6.0f, 8.0f) + close() + } + } + .build() + return _shareTriangle!! + } + +private var _shareTriangle: ImageVector? = null + +@Preview +@Composable +private fun Preview(): Unit { + Box(modifier = Modifier.padding(12.dp)) { + Image(imageVector = AppIcons.ShareTriangle, contentDescription = "") + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index 7c742d2..7ed5348 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -77,6 +77,7 @@ import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.ui.theme.MomentoTheme import com.min.dnapp.presentation.write.component.EmotionBottomSheetContent import com.min.dnapp.presentation.write.component.PlaceBottomSheetContent +import com.min.dnapp.presentation.write.component.ShareGuide import com.min.dnapp.presentation.write.component.WeatherBottomSheetContent import com.min.dnapp.util.toLocalDate @@ -91,6 +92,9 @@ fun RecordWriteScreen( val snackbarHostState = remember { SnackbarHostState() } + // 공유 안내 말풍선 표시상태 + var isShareGuideVisible by remember { mutableStateOf(true) } + // 캘린더 모달 표시상태 var showDatePicker by remember { mutableStateOf(false) } @@ -193,14 +197,26 @@ fun RecordWriteScreen( ) }, bottomBar = { - // 이미지 아이콘 & 공유여부 스위치 영역 - ImageAndShareSection( - isChecked = uiState.isShareChecked, - onCheckedChange = { newChecked -> - viewModel.updateShare(newChecked) - }, - onGalleryClick = { viewModel.onGalleryIconClicked() } - ) + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.End + ) { + // 공유 안내 말풍선 + if (isShareGuideVisible) { + ShareGuide( + onClick = { isShareGuideVisible = false } + ) + } + + // 이미지 아이콘 & 공유여부 스위치 영역 + ImageAndShareSection( + isChecked = uiState.isShareChecked, + onCheckedChange = { newChecked -> + viewModel.updateShare(newChecked) + }, + onGalleryClick = { viewModel.onGalleryIconClicked() } + ) + } }, snackbarHost = { SnackbarHost(hostState = snackbarHostState) { data -> diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteUiState.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteUiState.kt index a73496d..e08d4a9 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteUiState.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteUiState.kt @@ -24,5 +24,5 @@ data class RecordWriteUiState( val selectedPlace: LocalPlace? = null, val overseasPlace: String = "", val selectedImageUri: Uri? = null, - val isShareChecked: Boolean = false + val isShareChecked: Boolean = true ) diff --git a/app/src/main/java/com/min/dnapp/presentation/write/component/ShareGuide.kt b/app/src/main/java/com/min/dnapp/presentation/write/component/ShareGuide.kt new file mode 100644 index 0000000..bb5bc8c --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/write/component/ShareGuide.kt @@ -0,0 +1,64 @@ +package com.min.dnapp.presentation.write.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +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.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.icon.AppIcons +import com.min.dnapp.presentation.ui.icon.appicons.DeleteLine +import com.min.dnapp.presentation.ui.icon.appicons.ShareTriangle +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun ShareGuide( + onClick: () -> Unit +) { + Box( + modifier = Modifier.padding(end = 20.dp) + ) { + Column( + horizontalAlignment = Alignment.End + ) { + Row( + modifier = Modifier + .background(color = MomentoTheme.colors.greenW60, shape = RoundedCornerShape(5.dp)) + .padding(start = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "발견 탭에 나의 여행 기록을 공유합니다", + style = MomentoTheme.typography.label, + color = MomentoTheme.colors.grayW20 + ) + Icon( + modifier = Modifier + .clickable { onClick() } + .padding(12.dp), + imageVector = AppIcons.DeleteLine, + contentDescription = null, + tint = MomentoTheme.colors.grayW20 + ) + } + + Row { + Icon( + imageVector = AppIcons.ShareTriangle, + contentDescription = null, + tint = MomentoTheme.colors.greenW60 + ) + Spacer(Modifier.width(16.dp)) + } + } + } +} From e0f892d91c48e91f9ea344ec120539f3ded60624 Mon Sep 17 00:00:00 2001 From: min486 Date: Sun, 2 Nov 2025 01:33:05 +0900 Subject: [PATCH 60/98] =?UTF-8?q?feat:=20=EA=B8=B0=EB=A1=9D=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=20=EC=A7=84=ED=96=89=20=EC=8B=9C=20=EB=A1=9C=EB=94=A9?= =?UTF-8?q?=20=EC=9D=B8=EB=94=94=EC=BC=80=EC=9D=B4=ED=84=B0=20=ED=91=9C?= =?UTF-8?q?=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/write/RecordWriteScreen.kt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index 7ed5348..62f015f 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -26,6 +26,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.verticalScroll import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.DatePickerDefaults import androidx.compose.material3.DatePickerDialog import androidx.compose.material3.DateRangePicker @@ -293,6 +294,22 @@ fun RecordWriteScreen( } } + // 기록 등록 진행 시 로딩 인디케이터 표시 + if (uiState.isSaving) { + Box( + modifier = Modifier + .fillMaxSize() + .background(MomentoTheme.colors.black.copy(alpha = 0.5f)), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator( + modifier = Modifier.size(40.dp), + color = MomentoTheme.colors.white, + strokeWidth = 4.dp + ) + } + } + // 캘린더 모달 if (showDatePicker) { val dateRangePickerState = rememberDateRangePickerState( From 12bee4d53e6f3490dcccb28d610bce7082c7ec73 Mon Sep 17 00:00:00 2001 From: min486 Date: Sun, 2 Nov 2025 02:00:00 +0900 Subject: [PATCH 61/98] =?UTF-8?q?feat:=20WriteFinishScreen=20-=20=EC=8A=A4?= =?UTF-8?q?=ED=83=AC=ED=94=84=20=EC=A7=80=EA=B8=89=20Dialog=EB=A5=BC=20del?= =?UTF-8?q?ay=20=ED=9B=84=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dnapp/presentation/write/RecordWriteScreen.kt | 2 +- .../dnapp/presentation/write/WriteFinishScreen.kt | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index 62f015f..25cde5f 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -761,7 +761,7 @@ fun WriteContentSection( Box( modifier = Modifier .fillMaxWidth() - .height(310.dp) + .height(300.dp) .background(color = MomentoTheme.colors.brownBg) .padding(16.dp) ) { diff --git a/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt index 9bf368e..544f687 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt @@ -15,6 +15,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -29,12 +30,18 @@ import com.min.dnapp.R import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.ui.theme.MomentoTheme import com.min.dnapp.presentation.write.component.WriteStampDialog +import kotlinx.coroutines.delay @Composable fun WriteFinishScreen( navController: NavHostController ) { - var showStampDialog by remember { mutableStateOf(true) } + var showStampDialog by remember { mutableStateOf(false) } + + LaunchedEffect(Unit) { + delay(1000) + showStampDialog = true + } Surface( modifier = Modifier.fillMaxSize(), @@ -70,7 +77,10 @@ fun WriteFinishScreen( Box( modifier = Modifier .clickable { - navController.navigate("home") + navController.navigate("home") { + // 스택 모두 제거 + popUpTo(navController.graph.id) { inclusive = true } + } } .fillMaxWidth() .background(color = MomentoTheme.colors.brownBase, shape = RoundedCornerShape(10.dp)) From bcbd766da691f739ccfc5f2d9ef6f709aa70b619 Mon Sep 17 00:00:00 2001 From: min486 Date: Mon, 3 Nov 2025 01:30:29 +0900 Subject: [PATCH 62/98] =?UTF-8?q?feat:=20=EC=97=AC=ED=96=89=EA=B8=B0?= =?UTF-8?q?=EB=A1=9D=20=EC=A0=80=EC=9E=A5=20=EC=8B=9C=20UserData=20?= =?UTF-8?q?=EA=B2=B0=ED=95=A9=20(TripRecord=20+=20UserData)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/min/dnapp/data/mapper/RecordMapper.kt | 51 ++++++++++++++----- .../min/dnapp/data/mapper/UserDataMapper.kt | 40 +++++++++++++++ .../min/dnapp/data/remote/dto/RecordEntity.kt | 7 +++ .../data/repository/RecordRepositoryImpl.kt | 23 ++++++--- .../com/min/dnapp/domain/model/TripRecord.kt | 9 +++- .../domain/repository/RecordRepository.kt | 2 +- .../dnapp/domain/usecase/SaveRecordUseCase.kt | 29 ++++++++--- 7 files changed, 132 insertions(+), 29 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/data/mapper/UserDataMapper.kt diff --git a/app/src/main/java/com/min/dnapp/data/mapper/RecordMapper.kt b/app/src/main/java/com/min/dnapp/data/mapper/RecordMapper.kt index 4c355b3..647a960 100644 --- a/app/src/main/java/com/min/dnapp/data/mapper/RecordMapper.kt +++ b/app/src/main/java/com/min/dnapp/data/mapper/RecordMapper.kt @@ -2,34 +2,58 @@ package com.min.dnapp.data.mapper import com.min.dnapp.data.remote.dto.RecordEntity import com.min.dnapp.domain.model.TripRecord +import com.min.dnapp.domain.model.UserData import com.min.dnapp.presentation.write.RecordWriteUiState object RecordMapper { /** - * RecordWriteUiState -> RecordEntity 변환 + * RecordWriteUiState -> TripRecord (Domain) 변환 */ - fun toEntity(uiState: RecordWriteUiState, imageUrl: String?): RecordEntity { - return RecordEntity( + fun fromUiState(uiState: RecordWriteUiState, imageUrl: String?): TripRecord { + return TripRecord( title = uiState.recordTitle, content = uiState.recordContent, - startDateMillis = uiState.selectedStartDateMillis, - endDateMillis = uiState.selectedEndDateMillis, - emotionKey = uiState.selectedEmotion?.key, - weatherKey = uiState.selectedWeather?.key, - selectedPlace = uiState.selectedPlace?.toEntity(), + startDateMillis = uiState.selectedStartDateMillis ?: 0L, + endDateMillis = uiState.selectedEndDateMillis ?: 0L, + emotionKey = uiState.selectedEmotion?.key ?: "", + weatherKey = uiState.selectedWeather?.key ?: "", + selectedPlace = uiState.selectedPlace, overseasPlace = uiState.overseasPlace, isShareChecked = uiState.isShareChecked, // 업로드 후 받은 URL - imageUrl = imageUrl + imageUrl = imageUrl ?: "", + createdAt = 0L, + userId = "", + userData = null, + ) + } + + /** + * TripRecord (Domain) -> RecordEntity 변환 + */ + fun fromDomain(tripRecord: TripRecord, userData: UserData): RecordEntity { + return RecordEntity( + title = tripRecord.title, + content = tripRecord.content, + startDateMillis = tripRecord.startDateMillis, + endDateMillis = tripRecord.endDateMillis, + emotionKey = tripRecord.emotionKey, + weatherKey = tripRecord.weatherKey, + selectedPlace = tripRecord.selectedPlace?.toEntity(), + overseasPlace = tripRecord.overseasPlace, + isShareChecked = tripRecord.isShareChecked, + // 업로드 후 받은 URL + imageUrl = tripRecord.imageUrl, + userData = UserDataMapper.fromUserData(userData) ) } /** - * Entity -> Domain 변환 + * RecordEntity -> TripRecord (Domain) 변환 */ - fun toDomain(entity: RecordEntity): TripRecord { + fun fromEntity(entity: RecordEntity): TripRecord { return TripRecord( - recordId = entity.recordId ?: "", +// recordId = entity.recordId ?: "", userId = entity.userId ?: "", title = entity.title ?: "", content = entity.content ?: "", @@ -41,7 +65,8 @@ object RecordMapper { overseasPlace = entity.overseasPlace ?: "", isShareChecked = entity.isShareChecked ?: false, imageUrl = entity.imageUrl ?: "", - createdAt = entity.createdAt?.toDate()?.time ?: 0L + createdAt = entity.createdAt?.toDate()?.time ?: 0L, + userData = entity.userData?.let { UserDataMapper.fromUserDataEntity(it) } ) } } diff --git a/app/src/main/java/com/min/dnapp/data/mapper/UserDataMapper.kt b/app/src/main/java/com/min/dnapp/data/mapper/UserDataMapper.kt new file mode 100644 index 0000000..87334c3 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/data/mapper/UserDataMapper.kt @@ -0,0 +1,40 @@ +package com.min.dnapp.data.mapper + +import com.min.dnapp.data.remote.dto.UserDataEntity +import com.min.dnapp.domain.model.User +import com.min.dnapp.domain.model.UserData + +object UserDataMapper { + /** + * User -> UserData 변환 + */ + fun fromUser(user: User): UserData { + return UserData( + badgeLv = user.badgeLv, + nickname = user.badgeName, + profileImageName = user.profileImageName + ) + } + + /** + * UserData -> UserDataEntity 변환 + */ + fun fromUserData(userData: UserData): UserDataEntity { + return UserDataEntity( + badgeLv = userData.badgeLv, + nickname = userData.nickname, + profileImageName = userData.profileImageName + ) + } + + /** + * UserDataEntity -> UserData 변환 + */ + fun fromUserDataEntity(userDataEntity: UserDataEntity): UserData { + return UserData( + badgeLv = userDataEntity.badgeLv ?: 1, + nickname = userDataEntity.nickname ?: "", + profileImageName = userDataEntity.profileImageName ?: "01_boat" + ) + } +} diff --git a/app/src/main/java/com/min/dnapp/data/remote/dto/RecordEntity.kt b/app/src/main/java/com/min/dnapp/data/remote/dto/RecordEntity.kt index d49af2a..65c3a6b 100644 --- a/app/src/main/java/com/min/dnapp/data/remote/dto/RecordEntity.kt +++ b/app/src/main/java/com/min/dnapp/data/remote/dto/RecordEntity.kt @@ -10,6 +10,7 @@ data class RecordEntity( var recordId: String? = null, val userId: String? = null, + val userData: UserDataEntity? = null, val title: String? = null, val content: String? = null, @@ -37,3 +38,9 @@ data class PlaceEntity( val category: String? = null, val roadAddress: String? = null ) + +data class UserDataEntity( + val badgeLv: Int? = 1, + val nickname: String? = null, + val profileImageName: String? = "01_boat", +) diff --git a/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt b/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt index 99d2fa3..0799c01 100644 --- a/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt +++ b/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt @@ -30,7 +30,10 @@ class RecordRepositoryImpl @Inject constructor( /** * Storage에 이미지 업로드 및 URL 반환 */ - override suspend fun uploadImageAndGetUrl(imageUri: Uri, userId: String): String { + override suspend fun uploadImageAndGetUrl(imageUri: Uri): String { + // 사용자 ID 가져오기 + val userId = currentUserId + // firebase storage 경로는 사용자별로 분리 val storageRef = storage.reference .child("images") @@ -58,8 +61,11 @@ class RecordRepositoryImpl @Inject constructor( val newDoc = recordCollection.document() val recordId = newDoc.id - // RecordEntity의 recordId 필드 채우기 - val recordWithId = record.copy(recordId = recordId) + // RecordEntity의 ID 관련 필드 채우기 + val recordWithId = record.copy( + recordId = recordId, + userId = userId + ) // set()을 사용하여 해당 ID로 저장 newDoc.set(recordWithId).await() @@ -71,11 +77,16 @@ class RecordRepositoryImpl @Inject constructor( * 전체공유 컬렉션에 저장 */ override suspend fun saveSharedRecord(record: RecordEntity) { + // 사용자 ID 가져오기 + val userId = currentUserId + val sharedCollection = firestore.collection("shared_records") + val recordWithId = record.copy(userId = userId) + // set()을 사용하여 개인 기록과 동일한 ID로 저장 - record.recordId?.let { recordId -> - sharedCollection.document(recordId).set(record).await() + recordWithId.recordId?.let { recordId -> + sharedCollection.document(recordId).set(recordWithId).await() } } @@ -95,7 +106,7 @@ class RecordRepositoryImpl @Inject constructor( .await() val entityList = querySnapshot.toObjects() - val domainList = entityList.map { RecordMapper.toDomain(it) } + val domainList = entityList.map { RecordMapper.fromEntity(it) } return@withContext domainList } catch (e: Exception) { diff --git a/app/src/main/java/com/min/dnapp/domain/model/TripRecord.kt b/app/src/main/java/com/min/dnapp/domain/model/TripRecord.kt index 2029204..92a713d 100644 --- a/app/src/main/java/com/min/dnapp/domain/model/TripRecord.kt +++ b/app/src/main/java/com/min/dnapp/domain/model/TripRecord.kt @@ -1,8 +1,9 @@ package com.min.dnapp.domain.model data class TripRecord( - var recordId: String, +// var recordId: String, val userId: String, + val userData: UserData?, val title: String, val content: String, val startDateMillis: Long, @@ -16,3 +17,9 @@ data class TripRecord( val imageUrl: String, val createdAt: Long ) + +data class UserData( + val badgeLv: Int, + val nickname: String, + val profileImageName: String, +) diff --git a/app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt b/app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt index 35b717a..d4594fc 100644 --- a/app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt +++ b/app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt @@ -5,7 +5,7 @@ import com.min.dnapp.data.remote.dto.RecordEntity import com.min.dnapp.domain.model.TripRecord interface RecordRepository { - suspend fun uploadImageAndGetUrl(imageUri: Uri, userId: String): String + suspend fun uploadImageAndGetUrl(imageUri: Uri): String suspend fun savePrivateRecord(record: RecordEntity): RecordEntity suspend fun saveSharedRecord(record: RecordEntity) suspend fun getUserRecord(): List diff --git a/app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt b/app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt index 9f9f591..c1d5951 100644 --- a/app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt +++ b/app/src/main/java/com/min/dnapp/domain/usecase/SaveRecordUseCase.kt @@ -1,32 +1,45 @@ package com.min.dnapp.domain.usecase import android.net.Uri +import com.google.firebase.auth.FirebaseAuth import com.min.dnapp.data.mapper.RecordMapper -import com.min.dnapp.domain.repository.AuthRepository +import com.min.dnapp.data.mapper.UserDataMapper import com.min.dnapp.domain.repository.RecordRepository import com.min.dnapp.presentation.write.RecordWriteUiState import javax.inject.Inject class SaveRecordUseCase @Inject constructor( private val recordRepository: RecordRepository, - private val authRepository: AuthRepository + private val getUserDataUseCase: GetUserDataUseCase, + private val firebaseAuth: FirebaseAuth ) { suspend operator fun invoke( uiState: RecordWriteUiState, imageUri: Uri? ): Result { return try { - val userId = authRepository.getCurrentUserId() ?: return Result.failure(IllegalStateException("user not login")) - // 이미지 업로드 (URL 획득) val imageUrl = if (imageUri != null) { - recordRepository.uploadImageAndGetUrl(imageUri, userId) + recordRepository.uploadImageAndGetUrl(imageUri) } else { null } - // uiState를 Entity로 변환 - val recordEntity = RecordMapper.toEntity(uiState, imageUrl) + // domain 모델 생성 (UiState -> TripRecord) + val tripRecord = RecordMapper.fromUiState(uiState, imageUrl) + + // 현재 사용자 ID + val userId = firebaseAuth.currentUser?.uid ?: return Result.failure(IllegalStateException("user not login")) + + // 사용자 데이터 가져오기 + val user = getUserDataUseCase(userId) + + // User -> UserData 변환 + val userData = UserDataMapper.fromUser(user) + + // TripRecord + UserData -> RecordEntity + val recordEntity = RecordMapper.fromDomain(tripRecord, userData) + .copy(userId = userId) // 개인 기록 컬렉션에 저장 (필수) // recordId가 포함된 RecordEntity를 받아 새 변수에 저장 @@ -34,7 +47,7 @@ class SaveRecordUseCase @Inject constructor( // 공유 여부에 따라 전체공유 컬렉션에도 저장 (선택) if (uiState.isShareChecked) { - // ID가 포함된 savedRecord 사용 + // 동일한 recordId 포함된 savedRecord 사용 recordRepository.saveSharedRecord(savedRecord) } From d44bc866dfdfffbd4f1caeabb96709f2f513db05 Mon Sep 17 00:00:00 2001 From: min486 Date: Mon, 3 Nov 2025 15:40:59 +0900 Subject: [PATCH 63/98] =?UTF-8?q?feat:=20=EA=B3=B5=EC=9C=A0=EA=B8=B0?= =?UTF-8?q?=EB=A1=9D=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EB=B0=8F=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../min/dnapp/data/mapper/UserDataMapper.kt | 2 +- .../data/repository/RecordRepositoryImpl.kt | 19 +++++ .../domain/repository/RecordRepository.kt | 1 + .../domain/usecase/GetSharedRecordUseCase.kt | 13 ++++ .../presentation/common/ProfileMapper.kt | 19 +++++ .../presentation/find/FindDetailScreen.kt | 8 +- .../min/dnapp/presentation/find/FindScreen.kt | 70 +++++++++++++----- .../dnapp/presentation/find/FindUiState.kt | 11 +++ .../dnapp/presentation/find/FindViewModel.kt | 47 ++++++++++++ .../component/SharedRecordContentSection.kt | 73 +++++++++++++------ .../find/component/SharedRecordItem.kt | 45 ++++++++---- .../find/component/SharedRecordTimeSection.kt | 13 +++- .../ui/profile/ProfileImageCircle.kt | 25 ++++--- .../java/com/min/dnapp/util/DateTimeExt.kt | 4 +- 14 files changed, 273 insertions(+), 77 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/domain/usecase/GetSharedRecordUseCase.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/common/ProfileMapper.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/find/FindUiState.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/find/FindViewModel.kt diff --git a/app/src/main/java/com/min/dnapp/data/mapper/UserDataMapper.kt b/app/src/main/java/com/min/dnapp/data/mapper/UserDataMapper.kt index 87334c3..536a1bd 100644 --- a/app/src/main/java/com/min/dnapp/data/mapper/UserDataMapper.kt +++ b/app/src/main/java/com/min/dnapp/data/mapper/UserDataMapper.kt @@ -11,7 +11,7 @@ object UserDataMapper { fun fromUser(user: User): UserData { return UserData( badgeLv = user.badgeLv, - nickname = user.badgeName, + nickname = user.nickname, profileImageName = user.profileImageName ) } diff --git a/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt b/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt index 0799c01..65750e3 100644 --- a/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt +++ b/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt @@ -131,4 +131,23 @@ class RecordRepositoryImpl @Inject constructor( userDoc.update(updateCnt).await() } + + override suspend fun getSharedRecord(): List { + return withContext(Dispatchers.IO) { + try { + val querySnapshot = firestore + .collection("shared_records") + .get() + .await() + + val entityList = querySnapshot.toObjects() + val domainList = entityList.map { RecordMapper.fromEntity(it) } + + return@withContext domainList + } catch (e: Exception) { + Log.e("record", "getSharedRecord error", e) + return@withContext emptyList() + } + } + } } diff --git a/app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt b/app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt index d4594fc..4ac3ca5 100644 --- a/app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt +++ b/app/src/main/java/com/min/dnapp/domain/repository/RecordRepository.kt @@ -10,4 +10,5 @@ interface RecordRepository { suspend fun saveSharedRecord(record: RecordEntity) suspend fun getUserRecord(): List suspend fun increaseRecordAndStamp() + suspend fun getSharedRecord(): List } diff --git a/app/src/main/java/com/min/dnapp/domain/usecase/GetSharedRecordUseCase.kt b/app/src/main/java/com/min/dnapp/domain/usecase/GetSharedRecordUseCase.kt new file mode 100644 index 0000000..b901321 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/usecase/GetSharedRecordUseCase.kt @@ -0,0 +1,13 @@ +package com.min.dnapp.domain.usecase + +import com.min.dnapp.domain.model.TripRecord +import com.min.dnapp.domain.repository.RecordRepository +import javax.inject.Inject + +class GetSharedRecordUseCase @Inject constructor( + private val recordRepository: RecordRepository +) { + suspend operator fun invoke(): List { + return recordRepository.getSharedRecord() + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/common/ProfileMapper.kt b/app/src/main/java/com/min/dnapp/presentation/common/ProfileMapper.kt new file mode 100644 index 0000000..ee925c4 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/common/ProfileMapper.kt @@ -0,0 +1,19 @@ +package com.min.dnapp.presentation.common + +import com.min.dnapp.R + +object ProfileMapper { + fun getProfileImageResId(profileName: String): Int { + return when (profileName) { + "01_boat" -> R.drawable.logo_profile + "02_tent" -> R.drawable.logo_profile2 + "03_sea" -> R.drawable.logo_profile3 + "04_bag" -> R.drawable.logo_profile4 + "05_plane" -> R.drawable.logo_profile5 + "06_telescope" -> R.drawable.logo_profile6 + "07_map" -> R.drawable.logo_profile7 + "08_mount" -> R.drawable.logo_profile8 + else -> R.drawable.logo_profile + } + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/find/FindDetailScreen.kt b/app/src/main/java/com/min/dnapp/presentation/find/FindDetailScreen.kt index 017c8a0..c27d226 100644 --- a/app/src/main/java/com/min/dnapp/presentation/find/FindDetailScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/find/FindDetailScreen.kt @@ -85,7 +85,7 @@ fun FindDetailScreen(navController: NavHostController) { .padding(20.dp) ) { // 프로필 이미지 - ProfileImageCircle(modifier = Modifier.size(36.dp)) +// ProfileImageCircle(modifier = Modifier.size(36.dp)) Spacer(Modifier.width(8.dp)) @@ -106,7 +106,7 @@ fun FindDetailScreen(navController: NavHostController) { Spacer(Modifier.height(8.dp)) // 기록 내용 - SharedRecordContentSection() +// SharedRecordContentSection() } } } @@ -138,7 +138,7 @@ fun SharedRecordMoreSection() { horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { - SharedRecordTimeSection() +// SharedRecordTimeSection() Icon( modifier = Modifier @@ -259,7 +259,7 @@ fun CommentItem() { .padding(horizontal = 20.dp, vertical = 12.dp) ) { // 프로필 이미지 - ProfileImageCircle(modifier = Modifier.size(24.dp)) +// ProfileImageCircle(modifier = Modifier.size(24.dp)) Spacer(Modifier.width(8.dp)) diff --git a/app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt b/app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt index 1692a9f..576a4da 100644 --- a/app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt @@ -5,8 +5,11 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon @@ -14,10 +17,14 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavHostController import com.min.dnapp.R import com.min.dnapp.presentation.find.component.SharedRecordItem @@ -28,7 +35,12 @@ import com.min.dnapp.presentation.ui.theme.MomentoTheme @OptIn(ExperimentalMaterial3Api::class) @Composable -fun FindScreen(navController: NavHostController) { +fun FindScreen( + navController: NavHostController, + findViewModel: FindViewModel = hiltViewModel() +) { + val uiState by findViewModel.uiState.collectAsStateWithLifecycle() + Scaffold( containerColor = MomentoTheme.colors.brownBg, topBar = { @@ -59,29 +71,51 @@ fun FindScreen(navController: NavHostController) { ) } ) { paddingValues -> - LazyColumn( - modifier = Modifier - .fillMaxSize() - .padding(paddingValues) - ) { - item { - HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW80) - } - val itemCnt = 5 - - items(count = itemCnt) { idx -> + when (uiState) { + is FindUiState.Loading -> { Box( - modifier = Modifier.padding(20.dp) + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center ) { - // 발견 탭에 공유된 여행기록 아이템 - SharedRecordItem( - onClick = { navController.navigate("explore_detail") } + CircularProgressIndicator( + modifier = Modifier.size(40.dp), + color = MomentoTheme.colors.brownW20, + strokeWidth = 4.dp ) } + } + is FindUiState.Error -> {} + is FindUiState.Success -> { + // Success 데이터 추출 + val data = uiState as FindUiState.Success + + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + ) { + item { + HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW80) + } + + itemsIndexed(data.records) { idx, record -> + Box( + modifier = Modifier.padding(20.dp) + ) { + // 발견 탭에 공유된 여행기록 아이템 + SharedRecordItem( + record = record, + onClick = { +// navController.navigate("explore_detail") + } + ) + } - if (idx < itemCnt - 1) { - HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW80) + if (idx < data.records.size - 1) { + HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW80) + } + } } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/find/FindUiState.kt b/app/src/main/java/com/min/dnapp/presentation/find/FindUiState.kt new file mode 100644 index 0000000..adc5987 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/find/FindUiState.kt @@ -0,0 +1,11 @@ +package com.min.dnapp.presentation.find + +import com.min.dnapp.domain.model.TripRecord + +sealed class FindUiState { + data object Loading: FindUiState() + data class Success( + val records: List = emptyList() + ) : FindUiState() + data class Error(val message: String): FindUiState() +} diff --git a/app/src/main/java/com/min/dnapp/presentation/find/FindViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/find/FindViewModel.kt new file mode 100644 index 0000000..1ff7b39 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/find/FindViewModel.kt @@ -0,0 +1,47 @@ +package com.min.dnapp.presentation.find + +import android.util.Log +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.min.dnapp.domain.usecase.GetSharedRecordUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class FindViewModel @Inject constructor( + private val getSharedRecordUseCase: GetSharedRecordUseCase +) : ViewModel() { + + private val _uiState = MutableStateFlow(FindUiState.Loading) + val uiState: StateFlow = _uiState.asStateFlow() + + init { + loaFindData() + } + + private fun loaFindData() { + viewModelScope.launch { + // 로딩 시작 + _uiState.value = FindUiState.Loading + + // 공유된 기록 목록 가져오기 + try { + val sharedRecords = getSharedRecordUseCase() + Log.d("record", "loaFindData - sharedRecords: $sharedRecords") + val successState = FindUiState.Success( + records = sharedRecords + ) + _uiState.value = successState + } catch (e: Exception) { + _uiState.value = FindUiState.Success( + records = emptyList() + ) + Log.e("record", "기록 목록 조회 실패", e) + } + } + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt index 00fd194..175b0f8 100644 --- a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt +++ b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt @@ -19,11 +19,26 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp +import coil3.compose.AsyncImage import com.min.dnapp.R import com.min.dnapp.presentation.ui.theme.MomentoTheme +import com.min.dnapp.util.toDateString @Composable -fun SharedRecordContentSection() { +fun SharedRecordContentSection( + title: String, + content: String, + startDateMillis: Long, + endDateMillis: Long?, + placeName: String?, + imageUrl: String? +) { + val startDate = startDateMillis.toDateString("yy.MM.dd") + val endDate = endDateMillis?.toDateString("yy.MM.dd") + + // 여행 날짜 텍스트 계산 + val dateText = endDate?.let { "$startDate ~ $it" } ?: startDate + Column( modifier = Modifier .fillMaxWidth() @@ -32,8 +47,9 @@ fun SharedRecordContentSection() { ) { Spacer(Modifier.height(16.dp)) + // 여행 제목 Text( - text = "제주도 동쪽 투어!", + text = title, style = MomentoTheme.typography.label, color = MomentoTheme.colors.grayW20 ) @@ -49,12 +65,14 @@ fun SharedRecordContentSection() { horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { + // 여행 날짜 Text( - text = "25.08.20 ~ 25.08.22", + text = dateText, style = MomentoTheme.typography.body03, color = MomentoTheme.colors.grayW20 ) + // 날씨 & 감정 Row( verticalAlignment = Alignment.CenterVertically ) { @@ -74,37 +92,44 @@ fun SharedRecordContentSection() { Spacer(Modifier.height(4.dp)) - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Image( - painter = painterResource(R.drawable.write_place), - contentDescription = null - ) - Spacer(Modifier.width(6.dp)) - Text( - text = "제주특별자치도", - style = MomentoTheme.typography.body03 , - color = MomentoTheme.colors.grayW20 - ) + // 여행 장소 + placeName?.let { place -> + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(R.drawable.write_place), + contentDescription = null + ) + Spacer(Modifier.width(6.dp)) + Text( + text = place, + style = MomentoTheme.typography.body03 , + color = MomentoTheme.colors.grayW20 + ) + } } Spacer(Modifier.height(6.dp)) + // 여행 내용 Text( - text = "비 오는 날 이호해수욕장... 너무 좋았어요", - style = MomentoTheme.typography.body02 , + text = content, + style = MomentoTheme.typography.body02, color = MomentoTheme.colors.grayW20 ) Spacer(Modifier.height(6.dp)) - Image( - modifier = Modifier.fillMaxWidth(), - painter = painterResource(R.drawable.beach ), - contentDescription = null, - contentScale = ContentScale.Crop - ) + // 여행 이미지 + imageUrl?.let { image -> + AsyncImage( + modifier = Modifier.fillMaxWidth(), + model = image, + contentDescription = null, + contentScale = ContentScale.Crop + ) + } Spacer(Modifier.height(12.dp)) } diff --git a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt index 38865d2..d1657cc 100644 --- a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt +++ b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt @@ -13,21 +13,26 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.min.dnapp.domain.model.TripRecord import com.min.dnapp.presentation.ui.profile.ProfileImageCircle import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.ui.theme.MomentoTheme @Composable fun SharedRecordItem( + record: TripRecord, onClick: () -> Unit ) { Row( modifier = Modifier - .clickable { onClick() } +// .clickable { onClick() } .fillMaxWidth() ) { // 프로필 이미지 - ProfileImageCircle(modifier = Modifier.size(36.dp)) + ProfileImageCircle( + profileImageName = record.userData?.profileImageName, + modifier = Modifier.size(36.dp) + ) Spacer(Modifier.width(8.dp)) @@ -35,30 +40,40 @@ fun SharedRecordItem( modifier = Modifier.weight(1f) ) { // 공유 경과시간 영역 - SharedRecordTimeSection() + SharedRecordTimeSection( + nickname = record.userData?.nickname ?: "", + badgeLv = record.userData?.badgeLv ?: 1 + ) Spacer(Modifier.height(8.dp)) Text( - text = "시골청년님이 여행 기록을 공유했어요.", + text = "${record.userData?.nickname}님이 여행 기록을 공유했어요.", style = MomentoTheme.typography.body01, color = MomentoTheme.colors.grayW20 ) Spacer(Modifier.height(8.dp)) - // 기록 내용 - SharedRecordContentSection() - - Spacer(Modifier.height(12.dp)) - - // 반응 이모지 영역 - FindReactionIconSection( - bestNum = 1, - likeNum = 2, - surpriseNum = 12, - commentNum = 2 + // 기록 전체내용 + SharedRecordContentSection( + title = record.title, + content = record.content, + startDateMillis = record.startDateMillis, + endDateMillis = if (record.endDateMillis == 0L) null else record.endDateMillis, + placeName = record.selectedPlace?.title, + imageUrl = if (record.imageUrl.isEmpty()) null else record.imageUrl ) + +// Spacer(Modifier.height(12.dp)) +// +// // 반응 이모지 영역 +// FindReactionIconSection( +// bestNum = 1, +// likeNum = 2, +// surpriseNum = 12, +// commentNum = 2 +// ) } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordTimeSection.kt b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordTimeSection.kt index dfab459..9ed040f 100644 --- a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordTimeSection.kt +++ b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordTimeSection.kt @@ -12,21 +12,28 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import com.min.dnapp.R +import com.min.dnapp.presentation.common.BadgeMapper import com.min.dnapp.presentation.ui.theme.MomentoTheme @Composable -fun SharedRecordTimeSection() { +fun SharedRecordTimeSection( + nickname: String, + badgeLv: Int +) { + val imageResId = BadgeMapper.getBadgeImageResId(badgeLv) + Row( verticalAlignment = Alignment.CenterVertically ) { Text( - text = "시골청년", + text = nickname, style = MomentoTheme.typography.body01, color = MomentoTheme.colors.grayW20 ) Image( modifier = Modifier.size(20.dp), - painter = painterResource(R.drawable.badge_bronze), +// painter = painterResource(R.drawable.badge_bronze), + painter = painterResource(imageResId), contentDescription = null ) Spacer(Modifier.width(4.dp)) diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/profile/ProfileImageCircle.kt b/app/src/main/java/com/min/dnapp/presentation/ui/profile/ProfileImageCircle.kt index df00263..de0c349 100644 --- a/app/src/main/java/com/min/dnapp/presentation/ui/profile/ProfileImageCircle.kt +++ b/app/src/main/java/com/min/dnapp/presentation/ui/profile/ProfileImageCircle.kt @@ -9,21 +9,26 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import com.min.dnapp.R +import com.min.dnapp.presentation.common.ProfileMapper import com.min.dnapp.presentation.ui.theme.MomentoTheme @Composable fun ProfileImageCircle( + profileImageName: String?, modifier: Modifier = Modifier ) { - Box( - modifier = modifier - .clip(CircleShape) - .border(width = 2.dp, color = MomentoTheme.colors.grayW90, shape = CircleShape) - ) { - Image( - painter = painterResource(R.drawable.logo_profile), - contentDescription = null - ) + profileImageName?.let { name -> + val imageResId = ProfileMapper.getProfileImageResId(name) + + Box( + modifier = modifier + .clip(CircleShape) + .border(width = 2.dp, color = MomentoTheme.colors.grayW90, shape = CircleShape) + ) { + Image( + painter = painterResource(imageResId), + contentDescription = null + ) + } } } diff --git a/app/src/main/java/com/min/dnapp/util/DateTimeExt.kt b/app/src/main/java/com/min/dnapp/util/DateTimeExt.kt index 837ae03..6b02cce 100644 --- a/app/src/main/java/com/min/dnapp/util/DateTimeExt.kt +++ b/app/src/main/java/com/min/dnapp/util/DateTimeExt.kt @@ -26,10 +26,10 @@ fun Long?.toLocalDate(): LocalDate? { */ fun Long.toDateString(format: String): String { val date = Date(this) - Log.d("home", "toDateString - date: $date") + Log.d("record", "toDateString - date: $date") val formatter = SimpleDateFormat(format, Locale.getDefault()) - Log.d("home", "toDateString - formatter: $formatter") + Log.d("record", "toDateString - formatter: $formatter") return formatter.format(date) } From 1a63665421d11b0926df2684a029a926ef3f727f Mon Sep 17 00:00:00 2001 From: min486 Date: Mon, 3 Nov 2025 16:58:15 +0900 Subject: [PATCH 64/98] =?UTF-8?q?feat:=20=EB=82=A0=EC=94=A8/=EA=B0=90?= =?UTF-8?q?=EC=A0=95=20=ED=85=8D=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=EB=A6=AC=EC=86=8C=EC=8A=A4=EB=A1=9C=20?= =?UTF-8?q?=EB=A7=A4=ED=95=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dnapp/presentation/common/EmotionMapper.kt | 18 ++++++++++++++++++ .../dnapp/presentation/common/WeatherMapper.kt | 18 ++++++++++++++++++ .../component/SharedRecordContentSection.kt | 12 ++++++++++-- .../find/component/SharedRecordItem.kt | 2 ++ 4 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/common/EmotionMapper.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/common/WeatherMapper.kt diff --git a/app/src/main/java/com/min/dnapp/presentation/common/EmotionMapper.kt b/app/src/main/java/com/min/dnapp/presentation/common/EmotionMapper.kt new file mode 100644 index 0000000..06693fd --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/common/EmotionMapper.kt @@ -0,0 +1,18 @@ +package com.min.dnapp.presentation.common + +import com.min.dnapp.R + +object EmotionMapper { + fun getEmotionImageResId(emotionName: String): Int { + return when (emotionName) { + "happy" -> R.drawable.emotion_happy + "love" -> R.drawable.emotion_love + "surprise" -> R.drawable.emotion_surprise + "angry" -> R.drawable.emotion_angry + "feel" -> R.drawable.emotion_feel + "sad" -> R.drawable.emotion_sad + "shine" -> R.drawable.emotion_shine + else -> R.drawable.emotion_happy + } + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/common/WeatherMapper.kt b/app/src/main/java/com/min/dnapp/presentation/common/WeatherMapper.kt new file mode 100644 index 0000000..81c397c --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/common/WeatherMapper.kt @@ -0,0 +1,18 @@ +package com.min.dnapp.presentation.common + +import com.min.dnapp.R + +object WeatherMapper { + fun getWeatherImageResId(weatherName: String): Int { + return when (weatherName) { + "sun" -> R.drawable.weather_sun + "wind" -> R.drawable.weather_wind + "moon" -> R.drawable.weather_moon + "thunder" -> R.drawable.weather_thunder + "rain" -> R.drawable.weather_rain + "cloud" -> R.drawable.weather_cloud + "snow" -> R.drawable.weather_snow + else -> R.drawable.weather_sun + } + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt index 175b0f8..2108606 100644 --- a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt +++ b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt @@ -21,6 +21,8 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage import com.min.dnapp.R +import com.min.dnapp.presentation.common.EmotionMapper +import com.min.dnapp.presentation.common.WeatherMapper import com.min.dnapp.presentation.ui.theme.MomentoTheme import com.min.dnapp.util.toDateString @@ -30,6 +32,8 @@ fun SharedRecordContentSection( content: String, startDateMillis: Long, endDateMillis: Long?, + weatherName: String, + emotionName: String, placeName: String?, imageUrl: String? ) { @@ -39,6 +43,10 @@ fun SharedRecordContentSection( // 여행 날짜 텍스트 계산 val dateText = endDate?.let { "$startDate ~ $it" } ?: startDate + // 날씨 & 감정 이미지 리소스로 변환 + val weatherImageResId = WeatherMapper.getWeatherImageResId(weatherName) + val emotionImageResId = EmotionMapper.getEmotionImageResId(emotionName) + Column( modifier = Modifier .fillMaxWidth() @@ -78,13 +86,13 @@ fun SharedRecordContentSection( ) { Image( modifier = Modifier.size(28.dp), - painter = painterResource(R.drawable.weather_sun), + painter = painterResource(weatherImageResId), contentDescription = null ) Spacer(Modifier.width(4.dp)) Image( modifier = Modifier.size(28.dp), - painter = painterResource(R.drawable.emotion_feel), + painter = painterResource(emotionImageResId), contentDescription = null ) } diff --git a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt index d1657cc..d399921 100644 --- a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt +++ b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt @@ -61,6 +61,8 @@ fun SharedRecordItem( content = record.content, startDateMillis = record.startDateMillis, endDateMillis = if (record.endDateMillis == 0L) null else record.endDateMillis, + weatherName = record.weatherKey, + emotionName = record.emotionKey, placeName = record.selectedPlace?.title, imageUrl = if (record.imageUrl.isEmpty()) null else record.imageUrl ) From c982ada86f34434a4cdae814fefe45f4dfdd539a Mon Sep 17 00:00:00 2001 From: min486 Date: Mon, 3 Nov 2025 18:03:56 +0900 Subject: [PATCH 65/98] =?UTF-8?q?feat:=20=EA=B3=B5=EC=9C=A0=EA=B8=B0?= =?UTF-8?q?=EB=A1=9D=20=EA=B2=BD=EA=B3=BC=20=EC=8B=9C=EA=B0=84=20=EA=B3=84?= =?UTF-8?q?=EC=82=B0=20=EB=B0=8F=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/RecordRepositoryImpl.kt | 1 + .../component/SharedRecordContentSection.kt | 6 ++- .../find/component/SharedRecordItem.kt | 3 +- .../find/component/SharedRecordTimeSection.kt | 9 +++- .../java/com/min/dnapp/util/DateTimeExt.kt | 43 +++++++++++++++++++ 5 files changed, 58 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt b/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt index 65750e3..525e717 100644 --- a/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt +++ b/app/src/main/java/com/min/dnapp/data/repository/RecordRepositoryImpl.kt @@ -137,6 +137,7 @@ class RecordRepositoryImpl @Inject constructor( try { val querySnapshot = firestore .collection("shared_records") + .orderBy("createdAt", Query.Direction.DESCENDING) .get() .await() diff --git a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt index 2108606..554fc34 100644 --- a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt +++ b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -132,7 +133,10 @@ fun SharedRecordContentSection( // 여행 이미지 imageUrl?.let { image -> AsyncImage( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .fillMaxWidth() + // 가로:세로 비율 1:1 + .aspectRatio(1f), model = image, contentDescription = null, contentScale = ContentScale.Crop diff --git a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt index d399921..8d213b1 100644 --- a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt +++ b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordItem.kt @@ -42,7 +42,8 @@ fun SharedRecordItem( // 공유 경과시간 영역 SharedRecordTimeSection( nickname = record.userData?.nickname ?: "", - badgeLv = record.userData?.badgeLv ?: 1 + badgeLv = record.userData?.badgeLv ?: 1, + createdAtMillis = record.createdAt ) Spacer(Modifier.height(8.dp)) diff --git a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordTimeSection.kt b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordTimeSection.kt index 9ed040f..101d777 100644 --- a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordTimeSection.kt +++ b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordTimeSection.kt @@ -14,14 +14,19 @@ import androidx.compose.ui.unit.dp import com.min.dnapp.R import com.min.dnapp.presentation.common.BadgeMapper import com.min.dnapp.presentation.ui.theme.MomentoTheme +import com.min.dnapp.util.toTimeAgoString @Composable fun SharedRecordTimeSection( nickname: String, - badgeLv: Int + badgeLv: Int, + createdAtMillis: Long ) { val imageResId = BadgeMapper.getBadgeImageResId(badgeLv) + // 경과 시간 텍스트 (현재 시간 기준으로 공유된 시간 계산) + val timeAgoText = createdAtMillis.toTimeAgoString() + Row( verticalAlignment = Alignment.CenterVertically ) { @@ -38,7 +43,7 @@ fun SharedRecordTimeSection( ) Spacer(Modifier.width(4.dp)) Text( - text = "2분 전", + text = timeAgoText, style = MomentoTheme.typography.body02, color = MomentoTheme.colors.grayW20 ) diff --git a/app/src/main/java/com/min/dnapp/util/DateTimeExt.kt b/app/src/main/java/com/min/dnapp/util/DateTimeExt.kt index 6b02cce..09493bc 100644 --- a/app/src/main/java/com/min/dnapp/util/DateTimeExt.kt +++ b/app/src/main/java/com/min/dnapp/util/DateTimeExt.kt @@ -7,6 +7,7 @@ import java.time.LocalDate import java.time.ZoneId import java.util.Date import java.util.Locale +import java.util.concurrent.TimeUnit /** * Long(밀리초) 값을 시스템 기본 시간대를 기준으로 LocalDate로 변환 @@ -33,3 +34,45 @@ fun Long.toDateString(format: String): String { return formatter.format(date) } + +/** + * 현재 시간 기준, 경과 시간으로 변환 + * + * @return (예: "5분 전, "2시간 전") + */ +fun Long?.toTimeAgoString(): String { + if (this == null || this == 0L) { + return "날짜 없음" + } + + // 현재 시간 + val nowMillis = System.currentTimeMillis() + // 입력된 시간 + val inputMillis = this + + // 시간 차이 + val diffMillis = Math.abs(nowMillis - inputMillis) + + // 시간 차이를 단위별로 변환 + val seconds = TimeUnit.MILLISECONDS.toSeconds(diffMillis) + val minutes = TimeUnit.MILLISECONDS.toMinutes(diffMillis) + val hours = TimeUnit.MILLISECONDS.toHours(diffMillis) + val days = TimeUnit.MILLISECONDS.toDays(diffMillis) + + return when { + // 1분 미만 + seconds < 60 -> "방금 전" + // 1시간 미만 + minutes < 60 -> "${minutes}분 전" + // 24시간 미만 + hours < 24 -> "${hours}시간 전" + // 7일 미만 + days < 7 -> "${days}일 전" + // 30일 미만 + days < 30 -> "${days / 7}주 전" + // 1년 미만 + days < 365 -> "${days / 30}달 전" + // 1년 이상 + else -> "${days / 365}년 전" + } +} From 3e9c939b67017b7feacdbb0b513639e0c1ec5454 Mon Sep 17 00:00:00 2001 From: min486 Date: Mon, 3 Nov 2025 19:35:33 +0900 Subject: [PATCH 66/98] =?UTF-8?q?feat:=20MypageScreen=20-=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EC=9E=90=20=EC=A0=95=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EB=B0=8F=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dnapp/presentation/home/HomeScreen2.kt | 12 +- .../dnapp/presentation/home/HomeUiState.kt | 3 +- .../dnapp/presentation/home/HomeViewModel.kt | 9 +- .../dnapp/presentation/mypage/MypageScreen.kt | 109 +++++++++++++----- .../presentation/mypage/MypageUiState.kt | 11 ++ .../presentation/mypage/MypageViewModel.kt | 54 +++++++++ .../presentation/ui/component/UserBadge.kt | 10 +- 7 files changed, 166 insertions(+), 42 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/mypage/MypageUiState.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/mypage/MypageViewModel.kt diff --git a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt index 90a88c0..9a0ade8 100644 --- a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt +++ b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt @@ -132,10 +132,10 @@ fun HomeScreen2( HomeHeaderSection( nickname = data.nickname, - recordCnt = data.recordCnt, - stampCnt = data.stampCnt, + badgeLv = data.badgeLv, badgeName = data.badgeName, - badgeImageResId = data.badgeImageResId + recordCnt = data.recordCnt, + stampCnt = data.stampCnt ) Spacer(Modifier.height(20.dp)) @@ -212,8 +212,9 @@ fun HomeHeaderSection( nickname: String, recordCnt: Int, stampCnt: Int, + badgeLv: Int, badgeName: String, - badgeImageResId: Int +// badgeImageResId: Int ) { Column( modifier = Modifier @@ -221,8 +222,9 @@ fun HomeHeaderSection( .padding(horizontal = 20.dp) ) { UserBadge( + badgeLv = badgeLv, badgeName = badgeName, - badgeImageResId = badgeImageResId +// badgeImageResId = badgeImageResId ) Spacer(Modifier.height(12.dp)) diff --git a/app/src/main/java/com/min/dnapp/presentation/home/HomeUiState.kt b/app/src/main/java/com/min/dnapp/presentation/home/HomeUiState.kt index 5a983cc..e49a643 100644 --- a/app/src/main/java/com/min/dnapp/presentation/home/HomeUiState.kt +++ b/app/src/main/java/com/min/dnapp/presentation/home/HomeUiState.kt @@ -6,11 +6,10 @@ sealed class HomeUiState { data object Loading : HomeUiState() data class Success( val nickname: String, + val badgeLv: Int, val badgeName: String, val recordCnt: Int, val stampCnt: Int, - // badgeLv을 통해 매핑된 이미지 리소스 ID - val badgeImageResId: Int, // 기록 목록 val records: List = emptyList() ) : HomeUiState() diff --git a/app/src/main/java/com/min/dnapp/presentation/home/HomeViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/home/HomeViewModel.kt index 9317cbc..20c6597 100644 --- a/app/src/main/java/com/min/dnapp/presentation/home/HomeViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/home/HomeViewModel.kt @@ -7,7 +7,6 @@ import com.min.dnapp.domain.model.User import com.min.dnapp.domain.usecase.GetCurrentUserIdUseCase import com.min.dnapp.domain.usecase.GetUserDataUseCase import com.min.dnapp.domain.usecase.GetUserRecordUseCase -import com.min.dnapp.presentation.common.BadgeMapper import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -74,14 +73,12 @@ class HomeViewModel @Inject constructor( } private fun mapUserToHomeUiState(user: User): HomeUiState.Success { - val imageResId = BadgeMapper.getBadgeImageResId(user.badgeLv) - return HomeUiState.Success( nickname = user.nickname, - recordCnt = user.recordCnt, - stampCnt = user.stampCnt, + badgeLv = user.badgeLv, badgeName = user.badgeName, - badgeImageResId = imageResId + recordCnt = user.recordCnt, + stampCnt = user.stampCnt ) } } diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt index c295861..1c6943a 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt @@ -18,6 +18,7 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon @@ -35,8 +36,11 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavHostController import com.min.dnapp.R +import com.min.dnapp.presentation.common.ProfileMapper import com.min.dnapp.presentation.mypage.component.ProfileImageDialog import com.min.dnapp.presentation.ui.component.UserBadge import com.min.dnapp.presentation.ui.icon.AppIcons @@ -48,8 +52,11 @@ import com.min.dnapp.presentation.ui.theme.MomentoTheme @OptIn(ExperimentalMaterial3Api::class) @Composable fun MypageScreen( - navController: NavHostController + navController: NavHostController, + mypageViewModel: MypageViewModel = hiltViewModel() ) { + val uiState by mypageViewModel.uiState.collectAsStateWithLifecycle() + var showProfileImageDialog by remember { mutableStateOf(false) } Scaffold( @@ -82,28 +89,55 @@ fun MypageScreen( ) } ) { paddingValues -> - Column( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - ) { - Spacer(Modifier.height(20.dp)) - MypageProfileSection( - onClick = { showProfileImageDialog = true } - ) + when (uiState) { + is MypageUiState.Loading -> { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator( + modifier = Modifier.size(40.dp), + color = MomentoTheme.colors.brownW20, + strokeWidth = 4.dp + ) + } + } + is MypageUiState.Error -> {} + is MypageUiState.Success -> { + // Success 데이터 추출 + val data = uiState as MypageUiState.Success + + Column( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize() + ) { + Spacer(Modifier.height(20.dp)) + + MypageProfileSection( + profileImageName = data.user.profileImageName, + badgeLv = data.user.badgeLv, + badgeName = data.user.badgeName, + nickname = data.user.nickname, + recordCnt = data.user.recordCnt, + stampCnt = data.user.stampCnt, + onClick = { showProfileImageDialog = true } + ) - Spacer(Modifier.height(20.dp)) + Spacer(Modifier.height(20.dp)) - HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.brownW60) + HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.brownW60) - Spacer(Modifier.height(20.dp)) + Spacer(Modifier.height(20.dp)) - MypageMenuSection( - onSettingClick = { - navController.navigate("setting") + MypageMenuSection( + onSettingClick = { + navController.navigate("setting") + } + ) } - ) + } } } @@ -118,26 +152,38 @@ fun MypageScreen( } @Composable -fun MypageProfileSection(onClick: () -> Unit) { +fun MypageProfileSection( + profileImageName: String, + badgeLv: Int, + badgeName: String, + nickname: String, + recordCnt: Int, + stampCnt: Int, + onClick: () -> Unit +) { Column( modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally ) { // 프로필 이미지 (수정 가능) UserProfileImage( + profileImageName = profileImageName, onClick = { onClick() } ) Spacer(Modifier.height(12.dp)) // 뱃지 -// UserBadge() + UserBadge( + badgeLv = badgeLv, + badgeName = badgeName + ) Spacer(Modifier.height(16.dp)) // 닉네임 Text( - text = "성민", + text = nickname, style = MomentoTheme.typography.title01, color = MomentoTheme.colors.grayW20 ) @@ -145,12 +191,20 @@ fun MypageProfileSection(onClick: () -> Unit) { Spacer(Modifier.height(28.dp)) // 기록/스탬프 개수 - RecordAndStampNum() + RecordAndStampNum( + recordCnt = recordCnt, + stampCnt = stampCnt + ) } } @Composable -fun UserProfileImage(onClick: () -> Unit) { +fun UserProfileImage( + profileImageName: String, + onClick: () -> Unit +) { + val profileImageResId = ProfileMapper.getProfileImageResId(profileImageName) + Box( modifier = Modifier .clickable { onClick() } @@ -162,7 +216,7 @@ fun UserProfileImage(onClick: () -> Unit) { .border(width = 2.dp, color = MomentoTheme.colors.grayW80, shape = RoundedCornerShape(10.dp)) ) { Image( - painter = painterResource(R.drawable.logo_profile), + painter = painterResource(profileImageResId), contentDescription = null ) } @@ -185,7 +239,10 @@ fun UserProfileImage(onClick: () -> Unit) { } @Composable -fun RecordAndStampNum() { +fun RecordAndStampNum( + recordCnt: Int, + stampCnt: Int +) { Row( modifier = Modifier .padding(horizontal = 20.dp) @@ -223,7 +280,7 @@ fun RecordAndStampNum() { Text( modifier = Modifier.fillMaxWidth(), - text = "10개", + text = "${recordCnt}개", style = MomentoTheme.typography.label, color = MomentoTheme.colors.grayW20, textAlign = TextAlign.End @@ -267,7 +324,7 @@ fun RecordAndStampNum() { Text( modifier = Modifier.fillMaxWidth(), - text = "0개", + text = "${stampCnt}개", style = MomentoTheme.typography.label, color = MomentoTheme.colors.grayW20, textAlign = TextAlign.End diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageUiState.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageUiState.kt new file mode 100644 index 0000000..c7740a2 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageUiState.kt @@ -0,0 +1,11 @@ +package com.min.dnapp.presentation.mypage + +import com.min.dnapp.domain.model.User + +sealed class MypageUiState { + data object Loading : MypageUiState() + data class Success( + val user: User + ) : MypageUiState() + data class Error(val message: String) : MypageUiState() +} diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageViewModel.kt new file mode 100644 index 0000000..31e30cc --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageViewModel.kt @@ -0,0 +1,54 @@ +package com.min.dnapp.presentation.mypage + +import android.util.Log +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.min.dnapp.domain.usecase.GetCurrentUserIdUseCase +import com.min.dnapp.domain.usecase.GetUserDataUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class MypageViewModel @Inject constructor( + private val getCurrentUserIdUseCase: GetCurrentUserIdUseCase, + private val getUserDataUseCase: GetUserDataUseCase +) : ViewModel() { + + private val _uiState = MutableStateFlow(MypageUiState.Loading) + val uiState: StateFlow = _uiState.asStateFlow() + + init { + loadMyData() + } + + private fun loadMyData() { + viewModelScope.launch { + // 로딩 시작 + _uiState.value = MypageUiState.Loading + + // 사용자 ID 가져오기 + val uid = try { + getCurrentUserIdUseCase() ?: throw Exception("사용자 인증 정보 없음") + } catch (e: Exception) { + _uiState.value = MypageUiState.Error("인증 정보 조회 실패: ${e.message}") + return@launch + } + + // 사용자 정보 가져오기 + try { + val user = getUserDataUseCase(uid) + Log.d("my", "loadMyData - user: $user") + val successState = MypageUiState.Success( + user = user + ) + _uiState.value = successState + } catch (e: Exception) { + Log.e("my", "사용자 정보 조회 실패", e) + } + } + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/component/UserBadge.kt b/app/src/main/java/com/min/dnapp/presentation/ui/component/UserBadge.kt index ffb46e6..d6d5d7a 100644 --- a/app/src/main/java/com/min/dnapp/presentation/ui/component/UserBadge.kt +++ b/app/src/main/java/com/min/dnapp/presentation/ui/component/UserBadge.kt @@ -14,13 +14,17 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.common.BadgeMapper import com.min.dnapp.presentation.ui.theme.MomentoTheme @Composable fun UserBadge( - badgeName: String, - badgeImageResId: Int + badgeLv: Int, + badgeName: String ) { + // badgeLv을 통해 매핑된 이미지 리소스 ID + val badgeImageResId = BadgeMapper.getBadgeImageResId(badgeLv) + Row( modifier = Modifier .background(color = MomentoTheme.colors.white, shape = RoundedCornerShape(20.dp)) @@ -30,7 +34,7 @@ fun UserBadge( Image( modifier = Modifier.size(24.dp), painter = painterResource(badgeImageResId), - contentDescription = null, + contentDescription = null ) Spacer(Modifier.width(4.dp)) Text( From ca3d4de68dca1d8cb13671b369f4abdfceca60ab Mon Sep 17 00:00:00 2001 From: min486 Date: Mon, 3 Nov 2025 22:28:23 +0900 Subject: [PATCH 67/98] =?UTF-8?q?feat:=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=84=A0=ED=83=9D=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dnapp/presentation/mypage/MypageScreen.kt | 6 +- .../presentation/mypage/MypageViewModel.kt | 10 ++ .../presentation/mypage/ProfileImageType.kt | 18 +++ .../mypage/component/ProfileImageDialog.kt | 152 ++++++------------ 4 files changed, 84 insertions(+), 102 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/mypage/ProfileImageType.kt diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt index 1c6943a..a0f7d28 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt @@ -56,6 +56,7 @@ fun MypageScreen( mypageViewModel: MypageViewModel = hiltViewModel() ) { val uiState by mypageViewModel.uiState.collectAsStateWithLifecycle() + val selectedImage by mypageViewModel.selectedImage.collectAsStateWithLifecycle() var showProfileImageDialog by remember { mutableStateOf(false) } @@ -144,8 +145,11 @@ fun MypageScreen( // 프로필이미지 수정 모달창 if (showProfileImageDialog) { ProfileImageDialog( + selectedImage = selectedImage, + onImageClick = { profileImageType -> + mypageViewModel.selectImage(profileImageType) + }, onDismiss = { showProfileImageDialog = false }, - onCancel = { showProfileImageDialog = false }, onConfirm = {} ) } diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageViewModel.kt index 31e30cc..3aef604 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageViewModel.kt @@ -21,6 +21,10 @@ class MypageViewModel @Inject constructor( private val _uiState = MutableStateFlow(MypageUiState.Loading) val uiState: StateFlow = _uiState.asStateFlow() + // 현재 선택된 프로필 이미지 + private val _selectedImage = MutableStateFlow(null) + val selectedImage: StateFlow = _selectedImage.asStateFlow() + init { loadMyData() } @@ -51,4 +55,10 @@ class MypageViewModel @Inject constructor( } } } + + // 프로필 이미지 선택 + fun selectImage(image: ProfileImageType) { + // 선택된 이미지 다시 선택하면 해제 + _selectedImage.value = if (_selectedImage.value == image) null else image + } } diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/ProfileImageType.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/ProfileImageType.kt new file mode 100644 index 0000000..c705b35 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/ProfileImageType.kt @@ -0,0 +1,18 @@ +package com.min.dnapp.presentation.mypage + +import androidx.annotation.DrawableRes +import com.min.dnapp.R + +enum class ProfileImageType( + val key: String, + @DrawableRes val resId: Int +) { + BOAT("boat", R.drawable.logo_profile), + TENT("tent", R.drawable.logo_profile2), + SEA("sea", R.drawable.logo_profile3), + BAG("bag", R.drawable.logo_profile4), + PLANE("plane", R.drawable.logo_profile5), + TELESCOPE("telescope", R.drawable.logo_profile6), + MAP("map", R.drawable.logo_profile7), + MOUNT("mount", R.drawable.logo_profile8) +} diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/component/ProfileImageDialog.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/component/ProfileImageDialog.kt index 1e5fe36..47a9b24 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/component/ProfileImageDialog.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/component/ProfileImageDialog.kt @@ -1,7 +1,6 @@ package com.min.dnapp.presentation.mypage.component import androidx.compose.foundation.Image -import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -12,25 +11,30 @@ import androidx.compose.foundation.layout.Spacer 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.shape.RoundedCornerShape import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog -import com.min.dnapp.R +import com.min.dnapp.presentation.mypage.ProfileImageType +import com.min.dnapp.presentation.ui.component.SelectButton import com.min.dnapp.presentation.ui.theme.MomentoTheme @Composable fun ProfileImageDialog( + selectedImage: ProfileImageType?, + onImageClick: (ProfileImageType) -> Unit, onDismiss: () -> Unit, - onCancel: () -> Unit, onConfirm: () -> Unit ) { + // 프로필 이미지 목록 (8개) + val allImages = ProfileImageType.entries.toList() + Dialog( onDismissRequest = onDismiss ) { @@ -53,111 +57,57 @@ fun ProfileImageDialog( Spacer(Modifier.height(20.dp)) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.Center - ) { - Image( - painter = painterResource(R.drawable.logo_profile), - contentDescription = null - ) - Spacer(Modifier.width(20.dp)) - Image( - painter = painterResource(R.drawable.logo_profile2), - contentDescription = null - ) - } - Spacer(Modifier.height(16.dp)) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.Center - ) { - Image( - painter = painterResource(R.drawable.logo_profile3), - contentDescription = null - ) - Spacer(Modifier.width(20.dp)) - Image( - painter = painterResource(R.drawable.logo_profile4), - contentDescription = null - ) - } - Spacer(Modifier.height(16.dp)) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.Center - ) { - Image( - painter = painterResource(R.drawable.logo_profile5), - contentDescription = null - ) - Spacer(Modifier.width(20.dp)) - Box( - modifier = Modifier - .border(width = 3.dp, color = MomentoTheme.colors.pinkBase, shape = RoundedCornerShape(10.dp)) - ) { - Image( - painter = painterResource(R.drawable.logo_profile6), - contentDescription = null - ) - } + for (idx in 0 until allImages.size step 2) { - } - Spacer(Modifier.height(16.dp)) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.Center - ) { - Image( - painter = painterResource(R.drawable.logo_profile7), - contentDescription = null - ) - Spacer(Modifier.width(20.dp)) - Image( - painter = painterResource(R.drawable.logo_profile8), - contentDescription = null - ) - } - - Spacer(Modifier.height(24.dp)) - - // 취소/확인 버튼 영역 - Row( - modifier = Modifier.fillMaxWidth() - ) { - Box( - modifier = Modifier - .clickable { onCancel() } - .weight(1f) - .background(color = MomentoTheme.colors.grayW80, shape = RoundedCornerShape(10.dp)) - .padding(16.dp), - contentAlignment = Alignment.Center - ) { - Text( - text = "취소", - style = MomentoTheme.typography.body01, - color = MomentoTheme.colors.white - ) + // 처음 Row가 아니면, Row 위에 간격 추가 + if (idx > 0) { + Spacer(Modifier.height(16.dp)) } - Spacer(Modifier.width(8.dp)) - - Box( - modifier = Modifier - .clickable { onConfirm() } - .weight(1f) - .background(color = MomentoTheme.colors.brownBase, shape = RoundedCornerShape(10.dp)) - .padding(16.dp), - contentAlignment = Alignment.Center + Row( + horizontalArrangement = Arrangement.spacedBy(20.dp) ) { - Text( - text = "확인", - style = MomentoTheme.typography.body01, - color = MomentoTheme.colors.white + ProfileImageItem( + profileImageType = allImages[idx], + isSelected = selectedImage == allImages[idx], + onClick = onImageClick + ) + ProfileImageItem( + profileImageType = allImages[idx+1], + isSelected = selectedImage == allImages[idx+1], + onClick = onImageClick ) } } + + Spacer(Modifier.height(24.dp)) + + // 확인 버튼 + SelectButton( + enabled = selectedImage != null, + onConfirm = onConfirm + ) } } } } + +@Composable +fun ProfileImageItem( + profileImageType: ProfileImageType, + isSelected: Boolean, + onClick: (ProfileImageType) -> Unit +) { + val borderColor = if (isSelected) MomentoTheme.colors.pinkBase else Color.Transparent + + Box( + modifier = Modifier + .clickable { onClick(profileImageType) } + .border(width = 3.dp, color = borderColor, shape = RoundedCornerShape(10.dp)) + ) { + Image( + painter = painterResource(profileImageType.resId), + contentDescription = null + ) + } +} From 22d9a59d9c2983172b5b204adc1e184d05078dd8 Mon Sep 17 00:00:00 2001 From: min486 Date: Mon, 3 Nov 2025 23:49:18 +0900 Subject: [PATCH 68/98] =?UTF-8?q?feat:=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EB=B3=80=EA=B2=BD=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/UserRepositoryImpl.kt | 30 ++++++++++++- .../dnapp/domain/repository/UserRepository.kt | 1 + .../usecase/UpdateProfileImageUseCase.kt | 12 +++++ .../dnapp/presentation/mypage/MypageScreen.kt | 16 +++---- .../presentation/mypage/MypageViewModel.kt | 45 ++++++++++++++++++- .../presentation/mypage/ProfileImageType.kt | 16 +++---- 6 files changed, 99 insertions(+), 21 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/domain/usecase/UpdateProfileImageUseCase.kt diff --git a/app/src/main/java/com/min/dnapp/data/repository/UserRepositoryImpl.kt b/app/src/main/java/com/min/dnapp/data/repository/UserRepositoryImpl.kt index 5f33fe9..48a2dd4 100644 --- a/app/src/main/java/com/min/dnapp/data/repository/UserRepositoryImpl.kt +++ b/app/src/main/java/com/min/dnapp/data/repository/UserRepositoryImpl.kt @@ -1,5 +1,7 @@ package com.min.dnapp.data.repository +import android.util.Log +import com.google.firebase.auth.FirebaseAuth import com.google.firebase.firestore.FirebaseFirestore import com.min.dnapp.data.remote.dto.UserEntity import com.min.dnapp.domain.repository.UserRepository @@ -9,8 +11,14 @@ import kotlinx.coroutines.withContext import javax.inject.Inject class UserRepositoryImpl @Inject constructor( - private val firestore: FirebaseFirestore + private val firestore: FirebaseFirestore, + private val firebaseAuth: FirebaseAuth ) : UserRepository { + + // 사용자 ID 가져오기 + private val currentUserId: String + get() = firebaseAuth.currentUser?.uid ?: throw IllegalStateException("user not authenticated") + override suspend fun getUserData(uid: String): UserEntity { // I/O 작업을 위해 Dispatchers.IO로 스레드 전환 return withContext(Dispatchers.IO) { @@ -29,4 +37,24 @@ class UserRepositoryImpl @Inject constructor( } } } + + override suspend fun updateProfileImage(profileImageName: String): Result { + val userID = currentUserId + val userDoc = firestore.collection("users").document(userID) + + val updateImage = mapOf( + "profileImageName" to profileImageName + ) + + return withContext(Dispatchers.IO) { + try { + userDoc.update(updateImage).await() + Result.success(Unit) + } catch (e: Exception) { + Log.e("record", "updateProfileImage error", e) + // 실패 정보 상위 레이어로 전달 + Result.failure(e) + } + } + } } diff --git a/app/src/main/java/com/min/dnapp/domain/repository/UserRepository.kt b/app/src/main/java/com/min/dnapp/domain/repository/UserRepository.kt index 9ab1aba..8d388a3 100644 --- a/app/src/main/java/com/min/dnapp/domain/repository/UserRepository.kt +++ b/app/src/main/java/com/min/dnapp/domain/repository/UserRepository.kt @@ -4,4 +4,5 @@ import com.min.dnapp.data.remote.dto.UserEntity interface UserRepository { suspend fun getUserData(uid: String): UserEntity + suspend fun updateProfileImage(profileImageName: String): Result } diff --git a/app/src/main/java/com/min/dnapp/domain/usecase/UpdateProfileImageUseCase.kt b/app/src/main/java/com/min/dnapp/domain/usecase/UpdateProfileImageUseCase.kt new file mode 100644 index 0000000..87b8b72 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/usecase/UpdateProfileImageUseCase.kt @@ -0,0 +1,12 @@ +package com.min.dnapp.domain.usecase + +import com.min.dnapp.domain.repository.UserRepository +import javax.inject.Inject + +class UpdateProfileImageUseCase @Inject constructor( + private val userRepository: UserRepository +) { + suspend operator fun invoke(profileImageName: String): Result { + return userRepository.updateProfileImage(profileImageName) + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt index a0f7d28..d417a69 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt @@ -27,9 +27,6 @@ import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults 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.painterResource @@ -56,10 +53,9 @@ fun MypageScreen( mypageViewModel: MypageViewModel = hiltViewModel() ) { val uiState by mypageViewModel.uiState.collectAsStateWithLifecycle() + val showImageUpdateDialog by mypageViewModel.showImageUpdateDialog.collectAsStateWithLifecycle() val selectedImage by mypageViewModel.selectedImage.collectAsStateWithLifecycle() - var showProfileImageDialog by remember { mutableStateOf(false) } - Scaffold( containerColor = MomentoTheme.colors.brownW90, topBar = { @@ -123,7 +119,7 @@ fun MypageScreen( nickname = data.user.nickname, recordCnt = data.user.recordCnt, stampCnt = data.user.stampCnt, - onClick = { showProfileImageDialog = true } + onClick = { mypageViewModel.openDialog() } ) Spacer(Modifier.height(20.dp)) @@ -142,15 +138,15 @@ fun MypageScreen( } } - // 프로필이미지 수정 모달창 - if (showProfileImageDialog) { + // 프로필 이미지 변경 모달창 + if (showImageUpdateDialog) { ProfileImageDialog( selectedImage = selectedImage, onImageClick = { profileImageType -> mypageViewModel.selectImage(profileImageType) }, - onDismiss = { showProfileImageDialog = false }, - onConfirm = {} + onDismiss = { mypageViewModel.closeDialog() }, + onConfirm = { mypageViewModel.updateProfileImage() } ) } } diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageViewModel.kt index 3aef604..259c1a6 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.min.dnapp.domain.usecase.GetCurrentUserIdUseCase import com.min.dnapp.domain.usecase.GetUserDataUseCase +import com.min.dnapp.domain.usecase.UpdateProfileImageUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -15,12 +16,17 @@ import javax.inject.Inject @HiltViewModel class MypageViewModel @Inject constructor( private val getCurrentUserIdUseCase: GetCurrentUserIdUseCase, - private val getUserDataUseCase: GetUserDataUseCase + private val getUserDataUseCase: GetUserDataUseCase, + private val updateProfileImageUseCase: UpdateProfileImageUseCase ) : ViewModel() { private val _uiState = MutableStateFlow(MypageUiState.Loading) val uiState: StateFlow = _uiState.asStateFlow() + // 프로필 이미지 변경 모달창 상태 + private val _showImageUpdateDialog = MutableStateFlow(false) + val showImageUpdateDialog: StateFlow = _showImageUpdateDialog.asStateFlow() + // 현재 선택된 프로필 이미지 private val _selectedImage = MutableStateFlow(null) val selectedImage: StateFlow = _selectedImage.asStateFlow() @@ -56,9 +62,44 @@ class MypageViewModel @Inject constructor( } } - // 프로필 이미지 선택 + /** + * 프로필 이미지 선택 + */ fun selectImage(image: ProfileImageType) { // 선택된 이미지 다시 선택하면 해제 _selectedImage.value = if (_selectedImage.value == image) null else image } + + /** + * 프로필 이미지 변경 모달창 열기 + */ + fun openDialog() { + _showImageUpdateDialog.value = true + } + + /** + * 프로필 이미지 변경 모달창 닫기 + */ + fun closeDialog() { + _showImageUpdateDialog.value = false + } + + /** + * 프로필 이미지 변경 + */ + fun updateProfileImage() { + viewModelScope.launch { + selectedImage.value?.let { image -> + val result = updateProfileImageUseCase(image.key) + + result.onSuccess { + closeDialog() + loadMyData() + Log.d("my", "updateProfileImage 성공") + }.onFailure { exception -> + Log.e("my", "updateProfileImage 실패", exception) + } + } + } + } } diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/ProfileImageType.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/ProfileImageType.kt index c705b35..239cef3 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/ProfileImageType.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/ProfileImageType.kt @@ -7,12 +7,12 @@ enum class ProfileImageType( val key: String, @DrawableRes val resId: Int ) { - BOAT("boat", R.drawable.logo_profile), - TENT("tent", R.drawable.logo_profile2), - SEA("sea", R.drawable.logo_profile3), - BAG("bag", R.drawable.logo_profile4), - PLANE("plane", R.drawable.logo_profile5), - TELESCOPE("telescope", R.drawable.logo_profile6), - MAP("map", R.drawable.logo_profile7), - MOUNT("mount", R.drawable.logo_profile8) + BOAT("01_boat", R.drawable.logo_profile), + TENT("02_tent", R.drawable.logo_profile2), + SEA("03_sea", R.drawable.logo_profile3), + BAG("04_bag", R.drawable.logo_profile4), + PLANE("05_plane", R.drawable.logo_profile5), + TELESCOPE("06_telescope", R.drawable.logo_profile6), + MAP("07_map", R.drawable.logo_profile7), + MOUNT("08_mount", R.drawable.logo_profile8) } From a207d25755755a2b67d07d6692c946a0fbaea63d Mon Sep 17 00:00:00 2001 From: min486 Date: Tue, 4 Nov 2025 01:28:31 +0900 Subject: [PATCH 69/98] =?UTF-8?q?feat:=20=EB=82=B4=20=EA=B8=B0=EB=A1=9D=20?= =?UTF-8?q?=EB=AA=A8=EC=95=84=EB=B3=B4=EA=B8=B0=20=EA=B5=AC=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 6 +- .../presentation/mypage/MyRecordScreen.kt | 108 ++++++++++++++++++ .../presentation/mypage/MyRecordUiState.kt | 11 ++ .../presentation/mypage/MyRecordViewModel.kt | 47 ++++++++ .../dnapp/presentation/mypage/MypageScreen.kt | 6 +- .../mypage/component/MyRecordItem.kt | 40 +++++++ 6 files changed, 216 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/mypage/MyRecordScreen.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/mypage/MyRecordUiState.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/mypage/MyRecordViewModel.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/mypage/component/MyRecordItem.kt diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index 390cbfa..bffb4fe 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -21,6 +21,7 @@ import com.min.dnapp.presentation.find.FindDetailScreen import com.min.dnapp.presentation.find.FindScreen import com.min.dnapp.presentation.home.HomeScreen2 import com.min.dnapp.presentation.login.LoginScreen2 +import com.min.dnapp.presentation.mypage.MyRecordScreen import com.min.dnapp.presentation.mypage.MypageScreen import com.min.dnapp.presentation.mypage.SettingScreen import com.min.dnapp.presentation.ui.component.MomentoBottomNav @@ -57,7 +58,7 @@ fun MomentoApp( val currentRoute = navBackStackEntry?.destination?.route ?: "home" val showBottomBar = when (currentRoute) { - "login", "bell", "explore_detail", "record_write", "write_finish", "setting" -> false + "login", "bell", "explore_detail", "record_write", "write_finish", "my_record", "setting" -> false else -> true } @@ -105,6 +106,9 @@ fun MomentoApp( composable("write_finish") { WriteFinishScreen(navController = navController) } + composable("my_record") { + MyRecordScreen(navController = navController) + } composable("setting") { SettingScreen(navController = navController) } diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MyRecordScreen.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MyRecordScreen.kt new file mode 100644 index 0000000..2221318 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MyRecordScreen.kt @@ -0,0 +1,108 @@ +package com.min.dnapp.presentation.mypage + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.NavHostController +import com.min.dnapp.presentation.mypage.component.MyRecordItem +import com.min.dnapp.presentation.ui.icon.AppIcons +import com.min.dnapp.presentation.ui.icon.appicons.Back +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun MyRecordScreen( + navController: NavHostController, + myRecordViewModel: MyRecordViewModel = hiltViewModel() +) { + val uiState by myRecordViewModel.uiState.collectAsStateWithLifecycle() + + Scaffold( + containerColor = MomentoTheme.colors.brownBg, + topBar = { + CenterAlignedTopAppBar( + title = { + Text( + text = "내 기록 모아보기", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 + ) + }, + colors = TopAppBarDefaults.centerAlignedTopAppBarColors( + MomentoTheme.colors.brownBg + ), + navigationIcon = { + Icon( + modifier = Modifier + .clickable { navController.popBackStack() } + .padding(16.dp), + imageVector = AppIcons.Back, + contentDescription = null + ) + } + ) + } + ) { paddingValues -> + + when (uiState) { + is MyRecordUiState.Loading -> { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator( + modifier = Modifier.size(40.dp), + color = MomentoTheme.colors.brownW20, + strokeWidth = 4.dp + ) + } + } + is MyRecordUiState.Error -> {} + is MyRecordUiState.Success -> { + // Success 데이터 추출 + val data = uiState as MyRecordUiState.Success + + LazyColumn( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize() + ) { + itemsIndexed(data.records) { idx, record -> + Box( + modifier = Modifier.padding(20.dp) + ) { + // 내 여행기록 아이템 + MyRecordItem( + record = record, + onClick = {} + ) + } + + if (idx < data.records.size - 1) { + HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW80) + } + } + } + } + } + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MyRecordUiState.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MyRecordUiState.kt new file mode 100644 index 0000000..4be113b --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MyRecordUiState.kt @@ -0,0 +1,11 @@ +package com.min.dnapp.presentation.mypage + +import com.min.dnapp.domain.model.TripRecord + +sealed class MyRecordUiState { + data object Loading: MyRecordUiState() + data class Success( + val records: List = emptyList() + ) : MyRecordUiState() + data class Error(val message: String): MyRecordUiState() +} \ No newline at end of file diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MyRecordViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MyRecordViewModel.kt new file mode 100644 index 0000000..a95a207 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MyRecordViewModel.kt @@ -0,0 +1,47 @@ +package com.min.dnapp.presentation.mypage + +import android.util.Log +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.min.dnapp.domain.usecase.GetUserRecordUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class MyRecordViewModel @Inject constructor( + private val getUserRecordUseCase: GetUserRecordUseCase +) : ViewModel() { + + private val _uiState = MutableStateFlow(MyRecordUiState.Loading) + val uiState: StateFlow = _uiState.asStateFlow() + + init { + loadMyRecordData() + } + + private fun loadMyRecordData() { + viewModelScope.launch { + // 로딩 시작 + _uiState.value = MyRecordUiState.Loading + + // 내 여행기록 목록 가져오기 + try { + val myRecords = getUserRecordUseCase() + Log.d("my", "loadMyRecordData - myRecords: $myRecords") + val successState = MyRecordUiState.Success( + records = myRecords + ) + _uiState.value = successState + } catch (e: Exception) { + _uiState.value = MyRecordUiState.Success( + records = emptyList() + ) + Log.e("my", "내 여행기록 조회 실패", e) + } + } + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt index d417a69..68b6fc7 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt @@ -129,6 +129,9 @@ fun MypageScreen( Spacer(Modifier.height(20.dp)) MypageMenuSection( + onRecordClick = { + navController.navigate("my_record") + }, onSettingClick = { navController.navigate("setting") } @@ -338,6 +341,7 @@ fun RecordAndStampNum( @Composable fun MypageMenuSection( + onRecordClick: () -> Unit, onSettingClick: () -> Unit ) { Column( @@ -347,7 +351,7 @@ fun MypageMenuSection( ) { MypageMenuItem( text = "내 기록 모아보기", - onClick = {} + onClick = { onRecordClick() } ) Spacer(Modifier.height(28.dp)) MypageMenuItem( diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/component/MyRecordItem.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/component/MyRecordItem.kt new file mode 100644 index 0000000..c4369ad --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/component/MyRecordItem.kt @@ -0,0 +1,40 @@ +package com.min.dnapp.presentation.mypage.component + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.min.dnapp.domain.model.TripRecord +import com.min.dnapp.presentation.find.component.SharedRecordContentSection +import com.min.dnapp.presentation.ui.theme.DngoTheme + +@Composable +fun MyRecordItem( + record: TripRecord, + onClick: () -> Unit +) { + Column( + modifier = Modifier.fillMaxWidth() + ) { + // 기록 전체내용 + SharedRecordContentSection( + title = record.title, + content = record.content, + startDateMillis = record.startDateMillis, + endDateMillis = if (record.endDateMillis == 0L) null else record.endDateMillis, + weatherName = record.weatherKey, + emotionName = record.emotionKey, + placeName = record.selectedPlace?.title, + imageUrl = if (record.imageUrl.isEmpty()) null else record.imageUrl + ) + } +} + +@Preview +@Composable +fun MyRecordItemPreview() { + DngoTheme { +// MyRecordItem() + } +} From e6b187a1367dc013eb37b7f14eb836c61e46455a Mon Sep 17 00:00:00 2001 From: min486 Date: Tue, 4 Nov 2025 02:38:43 +0900 Subject: [PATCH 70/98] =?UTF-8?q?feat:=20=ED=83=88=ED=87=B4=20=ED=99=95?= =?UTF-8?q?=EC=9D=B8,=20=ED=83=88=ED=87=B4=20=EC=99=84=EB=A3=8C=20Dialog?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/login/LoginViewModel.kt | 23 +++- .../presentation/mypage/SettingScreen.kt | 64 ++++++---- .../mypage/component/UserRemoveDialog.kt | 112 ++++++++++++++++++ .../component/UserRemoveSuccessDialog.kt | 85 +++++++++++++ 4 files changed, 259 insertions(+), 25 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/mypage/component/UserRemoveDialog.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/mypage/component/UserRemoveSuccessDialog.kt diff --git a/app/src/main/java/com/min/dnapp/presentation/login/LoginViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/login/LoginViewModel.kt index a0853a0..904e2ed 100644 --- a/app/src/main/java/com/min/dnapp/presentation/login/LoginViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/login/LoginViewModel.kt @@ -25,6 +25,10 @@ class LoginViewModel @Inject constructor( private val _isLoading = MutableStateFlow(false) val isLoading: StateFlow = _isLoading.asStateFlow() + // 회원탈퇴 완료 모달창 상태 + private val _showUserRemoveSuccessDialog = MutableStateFlow(false) + val showUserRemoveSuccessDialog: StateFlow = _showUserRemoveSuccessDialog.asStateFlow() + /** * 카카오 로그인 */ @@ -80,6 +84,13 @@ class LoginViewModel @Inject constructor( } } + /** + * 회원탈퇴 완료 모달창 열기 + */ + fun openDialog() { + _showUserRemoveSuccessDialog.value = true + } + /** * 회원탈퇴 처리 * - firebase auth 사용자 삭제 @@ -87,8 +98,8 @@ class LoginViewModel @Inject constructor( * - 카카오 연결 끊기 */ fun onUnlinkClicked( - onSuccess: () -> Unit, - onFailure: (Throwable) -> Unit +// onSuccess: () -> Unit, +// onFailure: (Throwable) -> Unit ) { viewModelScope.launch { try { @@ -96,13 +107,15 @@ class LoginViewModel @Inject constructor( Log.d("auth", "onUnlinkClicked - result : $result") result.onSuccess { - onSuccess() +// onSuccess() + openDialog() }.onFailure { exception -> - onFailure(exception) +// onFailure(exception) + Log.e("auth", "회원탈퇴 처리 실패", exception) } } catch (e: Exception) { Log.e("auth", "onUnlinkClicked - unexpected error", e) - onFailure(e) +// onFailure(e) } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/SettingScreen.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/SettingScreen.kt index bd746c5..1046a53 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/SettingScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/SettingScreen.kt @@ -15,12 +15,19 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults 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.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavHostController import com.min.dnapp.presentation.login.LoginViewModel +import com.min.dnapp.presentation.mypage.component.UserRemoveDialog +import com.min.dnapp.presentation.mypage.component.UserRemoveSuccessDialog import com.min.dnapp.presentation.ui.icon.AppIcons import com.min.dnapp.presentation.ui.icon.appicons.Back import com.min.dnapp.presentation.ui.theme.DngoTheme @@ -30,8 +37,12 @@ import com.min.dnapp.presentation.ui.theme.MomentoTheme @Composable fun SettingScreen( navController: NavHostController, - viewModel: LoginViewModel = hiltViewModel() + loginViewModel: LoginViewModel = hiltViewModel() ) { + val showUserRemoveSuccessDialog by loginViewModel.showUserRemoveSuccessDialog.collectAsStateWithLifecycle() + + var showUserRemoveDialog by remember { mutableStateOf(false) } + Scaffold( containerColor = MomentoTheme.colors.brownBg, topBar = { @@ -70,7 +81,7 @@ fun SettingScreen( modifier = Modifier .fillMaxWidth() .clickable { - viewModel.onLogoutClicked( + loginViewModel.onLogoutClicked( onSuccess = { // 로그아웃 성공 후 이동 navController.navigate("login") { @@ -78,9 +89,7 @@ fun SettingScreen( popUpTo(navController.graph.id) { inclusive = true } } }, - onFailure = { - - } + onFailure = {} ) } ) { @@ -96,29 +105,44 @@ fun SettingScreen( Row( modifier = Modifier .fillMaxWidth() - .clickable { - viewModel.onUnlinkClicked( - onSuccess = { - // 회원탈퇴 성공 후 이동 - navController.navigate("login") { - // 최상위 그래프의 ID까지 스택 모두 제거 - popUpTo(navController.graph.id) { inclusive = true } - } - }, - onFailure = { - - } - ) - } + .clickable { showUserRemoveDialog = true } ) { Text( - text = "계정 탈퇴", + text = "탈퇴하기", style = MomentoTheme.typography.body01, color = MomentoTheme.colors.grayW20 ) } } } + + // 회원탈퇴 확인 모달창 + if (showUserRemoveDialog) { + UserRemoveDialog( + onDismiss = { showUserRemoveDialog = false }, + onCancel = { showUserRemoveDialog = false }, + onConfirm = { + showUserRemoveDialog = false + loginViewModel.onUnlinkClicked() + } + ) + } + + // 회원탈퇴 완료 모달창 + if (showUserRemoveSuccessDialog) { + UserRemoveSuccessDialog( + onDismiss = { + navController.navigate("login") { + popUpTo(navController.graph.id) { inclusive = true } + } + }, + onConfirm = { + navController.navigate("login") { + popUpTo(navController.graph.id) { inclusive = true } + } + } + ) + } } @Preview diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/component/UserRemoveDialog.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/component/UserRemoveDialog.kt new file mode 100644 index 0000000..f6f24b7 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/component/UserRemoveDialog.kt @@ -0,0 +1,112 @@ +package com.min.dnapp.presentation.mypage.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +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.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun UserRemoveDialog( + onDismiss: () -> Unit, + onCancel: () -> Unit, + onConfirm: () -> Unit +) { + Dialog( + onDismissRequest = onDismiss + ) { + Surface( + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(16.dp), + color = MomentoTheme.colors.brownBg + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(20.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "정말 탈퇴하시겠어요?", + style = MomentoTheme.typography.title01, + color = MomentoTheme.colors.grayW20 + ) + + Spacer(Modifier.height(8.dp)) + + Text( + text = "회원탈퇴 후 계정 복구가 불가능합니다. \n탈퇴하시겠습니까?", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW20, + textAlign = TextAlign.Center, + ) + + Spacer(Modifier.height(20.dp)) + + // 버튼 영역 + Row( + modifier = Modifier.fillMaxWidth() + ) { + Box( + modifier = Modifier + .clickable { onCancel() } + .weight(1f) + .background(color = MomentoTheme.colors.white) + .border(width = 1.dp, color = MomentoTheme.colors.grayW60, shape = RoundedCornerShape(5.dp)) + .padding(vertical = 16.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "취소", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + } + + Spacer(Modifier.width(12.dp)) + + Box( + modifier = Modifier + .clickable { onConfirm() } + .weight(1f) + .background(color = MomentoTheme.colors.brownBase, shape = RoundedCornerShape(5.dp)) + .padding(vertical = 16.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "탈퇴", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.white + ) + } + } + } + } + } +} + +@Preview +@Composable +fun UserRemoveDialogPreview() { + DngoTheme { +// UserRemoveDialog() + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/component/UserRemoveSuccessDialog.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/component/UserRemoveSuccessDialog.kt new file mode 100644 index 0000000..3e35271 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/component/UserRemoveSuccessDialog.kt @@ -0,0 +1,85 @@ +package com.min.dnapp.presentation.mypage.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun UserRemoveSuccessDialog( + onDismiss: () -> Unit, + onConfirm: () -> Unit +) { + Dialog( + onDismissRequest = onDismiss + ) { + Surface( + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(16.dp), + color = MomentoTheme.colors.brownBg + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(20.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "탈퇴가 완료되었습니다.", + style = MomentoTheme.typography.title01, + color = MomentoTheme.colors.grayW20 + ) + + Spacer(Modifier.height(8.dp)) + + Text( + text = "그동안 모멘토를 이용해주셔서 감사합니다.", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW20, + textAlign = TextAlign.Center, + ) + + Spacer(Modifier.height(20.dp)) + + Box( + modifier = Modifier + .clickable { onConfirm() } + .fillMaxWidth() + .background(color = MomentoTheme.colors.brownBase, shape = RoundedCornerShape(5.dp)) + .padding(vertical = 16.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "확인", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.white + ) + } + } + } + } +} + +@Preview +@Composable +fun UserRemoveSuccessDialogPreview() { + DngoTheme { +// UserRemoveSuccessDialog() + } +} From 6681c9f95102fee6b38d3db8b1a6fd4dccfde92c Mon Sep 17 00:00:00 2001 From: min486 Date: Tue, 4 Nov 2025 14:11:36 +0900 Subject: [PATCH 71/98] =?UTF-8?q?chore:=20BottomBar=20=EB=B0=9C=EA=B2=AC?= =?UTF-8?q?=20=ED=83=AD=20=ED=85=8D=EC=8A=A4=ED=8A=B8=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/min/dnapp/MainActivity.kt | 6 +++--- .../min/dnapp/presentation/ui/component/MomentoBottomNav.kt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index bffb4fe..ae3b275 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -58,7 +58,7 @@ fun MomentoApp( val currentRoute = navBackStackEntry?.destination?.route ?: "home" val showBottomBar = when (currentRoute) { - "login", "bell", "explore_detail", "record_write", "write_finish", "my_record", "setting" -> false + "login", "bell", "find_detail", "record_write", "write_finish", "my_record", "setting" -> false else -> true } @@ -88,7 +88,7 @@ fun MomentoApp( composable("home") { HomeScreen2(navController = navController) } - composable("explore") { + composable("find") { FindScreen(navController = navController) } composable("my") { @@ -97,7 +97,7 @@ fun MomentoApp( composable("bell") { BellScreen(navController = navController) } - composable("explore_detail") { + composable("find_detail") { FindDetailScreen(navController = navController) } composable("record_write") { diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/component/MomentoBottomNav.kt b/app/src/main/java/com/min/dnapp/presentation/ui/component/MomentoBottomNav.kt index 9b2faf3..cde822d 100644 --- a/app/src/main/java/com/min/dnapp/presentation/ui/component/MomentoBottomNav.kt +++ b/app/src/main/java/com/min/dnapp/presentation/ui/component/MomentoBottomNav.kt @@ -44,7 +44,7 @@ fun MomentoBottomNav( ) { val items = listOf( BottonNavItem(AppIcons.Home, R.drawable.ic_home, "Home", "home"), - BottonNavItem(AppIcons.Explore, R.drawable.ic_explore, "Explore", "explore"), + BottonNavItem(AppIcons.Explore, R.drawable.ic_explore, "Discover", "find"), BottonNavItem(AppIcons.My, R.drawable.ic_my, "My", "my") ) From 9d1e9eca73c11d7784b6acc199621c6c7323a0ec Mon Sep 17 00:00:00 2001 From: min486 Date: Tue, 4 Nov 2025 14:34:18 +0900 Subject: [PATCH 72/98] =?UTF-8?q?feat:=20Navigation=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../min/dnapp/presentation/bell/BellScreen.kt | 22 +++++++++---------- .../min/dnapp/presentation/find/FindScreen.kt | 7 +++--- .../component/SharedRecordContentSection.kt | 3 ++- .../dnapp/presentation/home/HomeScreen2.kt | 9 +++++--- .../dnapp/presentation/mypage/MypageScreen.kt | 7 +++--- 5 files changed, 27 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/com/min/dnapp/presentation/bell/BellScreen.kt b/app/src/main/java/com/min/dnapp/presentation/bell/BellScreen.kt index bef42fc..4f0a48a 100644 --- a/app/src/main/java/com/min/dnapp/presentation/bell/BellScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/bell/BellScreen.kt @@ -67,17 +67,17 @@ fun BellScreen(navController: NavHostController) { ) { HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW80) - BellCommentItem( - image = painterResource(R.drawable.trip), - nickname = "안녕하세요안녕하세요" - ) - - for (i in 0 until 3) { - BellCommentItem( - image = painterResource(R.drawable.trip3), - nickname = "박사과" - ) - } +// BellCommentItem( +// image = painterResource(R.drawable.trip), +// nickname = "안녕하세요안녕하세요" +// ) +// +// for (i in 0 until 3) { +// BellCommentItem( +// image = painterResource(R.drawable.trip3), +// nickname = "박사과" +// ) +// } } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt b/app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt index 576a4da..136f97e 100644 --- a/app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt @@ -52,8 +52,9 @@ fun FindScreen( navigationIcon = { Image( modifier = Modifier - .clickable { } - .padding(16.dp), +// .clickable { } +// .padding(16.dp), + .padding(start = 16.dp), painter = painterResource(R.drawable.logo_momento), contentDescription = null ) @@ -61,7 +62,7 @@ fun FindScreen( actions = { Icon( modifier = Modifier - .clickable { } + .clickable { navController.navigate("bell") } .padding(16.dp), imageVector = AppIcons.Bell, contentDescription = null, diff --git a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt index 554fc34..d16671b 100644 --- a/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt +++ b/app/src/main/java/com/min/dnapp/presentation/find/component/SharedRecordContentSection.kt @@ -59,7 +59,8 @@ fun SharedRecordContentSection( // 여행 제목 Text( text = title, - style = MomentoTheme.typography.label, +// style = MomentoTheme.typography.label, + style = MomentoTheme.typography.body02, color = MomentoTheme.colors.grayW20 ) diff --git a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt index 9a0ade8..e0e675f 100644 --- a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt +++ b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt @@ -76,8 +76,9 @@ fun HomeScreen2( navigationIcon = { Image( modifier = Modifier - .clickable { } - .padding(16.dp), +// .clickable { } +// .padding(16.dp), + .padding(start = 16.dp), painter = painterResource(R.drawable.logo_momento), contentDescription = null ) @@ -161,7 +162,9 @@ fun HomeScreen2( color = MomentoTheme.colors.grayW20 ) Icon( - modifier = Modifier.clickable { }, + modifier = Modifier.clickable { + navController.navigate("my_record") + }, imageVector = AppIcons.ArrowRight, contentDescription = null, tint = MomentoTheme.colors.grayW20 diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt index 68b6fc7..5148b00 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt @@ -67,8 +67,9 @@ fun MypageScreen( navigationIcon = { Image( modifier = Modifier - .clickable { } - .padding(16.dp), +// .clickable { } +// .padding(16.dp), + .padding(start = 16.dp), painter = painterResource(R.drawable.logo_momento), contentDescription = null ) @@ -76,7 +77,7 @@ fun MypageScreen( actions = { Icon( modifier = Modifier - .clickable { } + .clickable { navController.navigate("bell") } .padding(16.dp), imageVector = AppIcons.Bell, contentDescription = null, From 039806b90af4ada79ecef3231f3ad975da1951ab Mon Sep 17 00:00:00 2001 From: min486 Date: Tue, 4 Nov 2025 19:18:30 +0900 Subject: [PATCH 73/98] =?UTF-8?q?fix:=20EdgeToEdge=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20API=2035=20=EC=9D=B4=EC=83=81=20=EC=8B=9C=EC=8A=A4?= =?UTF-8?q?=ED=85=9C=EB=B0=94=20=EB=8C=80=EC=9D=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/min/dnapp/MainActivity.kt | 16 ++++++++++++++-- .../min/dnapp/presentation/find/FindScreen.kt | 2 ++ .../min/dnapp/presentation/home/HomeScreen2.kt | 2 ++ .../min/dnapp/presentation/login/LoginScreen2.kt | 6 +++++- .../ui/component/MomentoBottomNav.kt | 6 +++++- .../presentation/write/RecordWriteScreen.kt | 5 ++++- .../presentation/write/WriteFinishScreen.kt | 5 ++++- 7 files changed, 36 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index ae3b275..e73c8ed 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -3,12 +3,18 @@ package com.min.dnapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBars import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen +import androidx.core.view.WindowCompat import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.compose.NavHost @@ -37,7 +43,10 @@ class MainActivity : ComponentActivity() { val splashScreen = installSplashScreen() super.onCreate(savedInstanceState) -// enableEdgeToEdge() + + // 콘텐츠를 화면 끝까지 확장 (Insets 처리는 Composable에게 맡기기) + enableEdgeToEdge() + setContent { DngoTheme { MomentoApp() @@ -63,6 +72,8 @@ fun MomentoApp( } Scaffold( + // Padding 중복을 막기 위해 모든 Insets 차단 + contentWindowInsets = WindowInsets(0, 0, 0, 0), bottomBar = { if (showBottomBar) { MomentoBottomNav( @@ -80,7 +91,8 @@ fun MomentoApp( NavHost( modifier = Modifier.padding(paddingValues), navController = navController, - startDestination = startDestination +// startDestination = startDestination + startDestination = "home" ) { composable("login") { LoginScreen2(navController = navController) diff --git a/app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt b/app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt index 136f97e..f47f9dc 100644 --- a/app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/find/FindScreen.kt @@ -3,6 +3,7 @@ package com.min.dnapp.presentation.find import androidx.compose.foundation.Image import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -42,6 +43,7 @@ fun FindScreen( val uiState by findViewModel.uiState.collectAsStateWithLifecycle() Scaffold( + contentWindowInsets = WindowInsets(0, 0, 0, 0), containerColor = MomentoTheme.colors.brownBg, topBar = { CenterAlignedTopAppBar( diff --git a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt index e0e675f..33e40f1 100644 --- a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt +++ b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt @@ -9,6 +9,7 @@ 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.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -66,6 +67,7 @@ fun HomeScreen2( val uiState by homeViewModel.uiState.collectAsStateWithLifecycle() Scaffold( + contentWindowInsets = WindowInsets(0, 0, 0, 0), containerColor = MomentoTheme.colors.brownW90, topBar = { CenterAlignedTopAppBar( diff --git a/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt b/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt index 1596b25..37ee538 100644 --- a/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt +++ b/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Icon @@ -48,7 +49,10 @@ fun LoginScreen2( val isLoading by viewModel.isLoading.collectAsStateWithLifecycle() Surface( - modifier = Modifier.fillMaxSize(), + modifier = Modifier + // 시스템바 영역 피하기 (status bar, navigation bar 모두 적용) + .systemBarsPadding() + .fillMaxSize(), color = MomentoTheme.colors.brownW80 ) { Column( diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/component/MomentoBottomNav.kt b/app/src/main/java/com/min/dnapp/presentation/ui/component/MomentoBottomNav.kt index cde822d..57e75e5 100644 --- a/app/src/main/java/com/min/dnapp/presentation/ui/component/MomentoBottomNav.kt +++ b/app/src/main/java/com/min/dnapp/presentation/ui/component/MomentoBottomNav.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.Text @@ -49,7 +50,10 @@ fun MomentoBottomNav( ) Column( - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() + // bottomNav가 navigationBar 위에 올라가도록 padding 처리 + .navigationBarsPadding() ) { HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW90) diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index 25cde5f..087fadd 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -17,6 +17,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width @@ -199,7 +200,9 @@ fun RecordWriteScreen( }, bottomBar = { Column( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .fillMaxWidth() + .navigationBarsPadding(), horizontalAlignment = Alignment.End ) { // 공유 안내 말풍선 diff --git a/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt index 544f687..2dcc4b4 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt @@ -11,6 +11,7 @@ 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.systemBarsPadding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -44,7 +45,9 @@ fun WriteFinishScreen( } Surface( - modifier = Modifier.fillMaxSize(), + modifier = Modifier + .systemBarsPadding() + .fillMaxSize(), color = MomentoTheme.colors.white ) { Column( From c29876ea8c27a6ac27d28ac191a6bb1b1804c608 Mon Sep 17 00:00:00 2001 From: min486 Date: Tue, 4 Nov 2025 19:46:46 +0900 Subject: [PATCH 74/98] =?UTF-8?q?chore:=20=EB=B2=84=EC=A0=84=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=201.6=20(6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 4 ++-- app/src/main/java/com/min/dnapp/MainActivity.kt | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 47040b4..218dc95 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -29,8 +29,8 @@ android { applicationId = "com.min.dnapp" minSdk = 30 targetSdk = 36 - versionCode = 1 - versionName = "1.0" + versionCode = 6 + versionName = "1.6" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index e73c8ed..af1431f 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -91,8 +91,7 @@ fun MomentoApp( NavHost( modifier = Modifier.padding(paddingValues), navController = navController, -// startDestination = startDestination - startDestination = "home" + startDestination = startDestination ) { composable("login") { LoginScreen2(navController = navController) From 336482964b5191b0c8dfdd08a494bedde7f75c75 Mon Sep 17 00:00:00 2001 From: min486 Date: Wed, 5 Nov 2025 01:04:25 +0900 Subject: [PATCH 75/98] README --- README.assets/image.png | Bin 0 -> 56274 bytes README.assets/image2.png | Bin 0 -> 155826 bytes README.assets/image3.png | Bin 0 -> 112047 bytes README.assets/image4.png | Bin 0 -> 173699 bytes README.assets/image5.png | Bin 0 -> 90379 bytes README.md | 10 ++++++++++ 6 files changed, 10 insertions(+) create mode 100644 README.assets/image.png create mode 100644 README.assets/image2.png create mode 100644 README.assets/image3.png create mode 100644 README.assets/image4.png create mode 100644 README.assets/image5.png diff --git a/README.assets/image.png b/README.assets/image.png new file mode 100644 index 0000000000000000000000000000000000000000..e1bee008d71c663bc9ed91674b6ccae3422bcd80 GIT binary patch literal 56274 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
eN8&2U0mIS?Z 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 KMNUMnLSTZhhiE+j literal 0 HcmV?d00001 diff --git a/README.assets/image2.png b/README.assets/image2.png new file mode 100644 index 0000000000000000000000000000000000000000..d0c8a7b8f33edd6f0416b04fab70c80bd66d95e6 GIT binary patch literal 155826 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�w~Av4AB+o{pU(Hi=);W&dg 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 pV8!Cnwl`x6OVq2>f@5A1qmi`W=t@ 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 literal 0 HcmV?d00001 diff --git a/README.assets/image3.png b/README.assets/image3.png new file mode 100644 index 0000000000000000000000000000000000000000..32632e8049d6ee6446cb647f0092898f901cb58c GIT binary patch literal 112047 zcmeEtWm8;Tur=;(32wnHKyVG3;4VRfyG?Kl?hu^8-5Gpf2u{$!A-KCc44#+g{(|@W zy;F6n>zt~oeRiL48j z<%>Q54i1y>zY88NGyDD9LwJCOyc8U0oZ|592Fd!f@@F`>`UK49@5pfQ%`#tQK5Kcw zpX8vLQuO~FT+eM|fOtA=t9TYIBcX-bY5c_dg1|^ki_Q?HLMBFAkSv8BG>MM)jRx;y z!TY+y{vRuF%NxcFi#oqw_Quvu#>U5u6PwzSU;YKLuR3Nq^8WKaA0sdGK4ndR8ygPJ z?8DpGZ$ECt9{4x&b0KKszgx)@NtgdDjR%e3e-=*!?`>*uaFLW~IRDu{I7q1fSu@mN z#Q$vl|NZ^{T=%~XHku0geHkKw;;T;^eXsl6MRHTz@>D9WJm!1sKA)eN?{ay7clZ*N zW813AWi3`+$AP&%lR=+sp9PN`j*gEHGmo8bB$Gq#Slw1oy`CeOLR&(6 z;h%eg`P29Blc1oK)b_2%s@hTJ&})B_QIujf%oOmfYTM+VudRqDh+IX8{zcp+Bw*`u zFf1?3V^-NOwq*^-fy@{a@r^bBrF0~@X8U?h+|K&^}LXWyWdhIz<9|Ps*F81S$~Dr5($CO74^}y zosk1(y)VXYi`tvkN|9axPF#fNM|$6ToiR(5e65MOMu3r&lGWu-Uvry8L=Btc)ARuwxzu4p(c zAgQfVISlOp550?VU>A)`Z7nfnM17Hb^YD`S+u&g}O?VWLH@9pZ(8muw7P=*zg#meA zCJ2{p26m$7<}$K+l;ts-*XF38X`ySp->Z}gK%}s{Rs=iTHfY7zZaD}CNp%kM*eGZ2 zBLG>SevW%s0IspIJf<#bq4k{hchxke+gWCC2>H6^xS)uJ!+{}NHBmBSEFsK^#@%v3 zp{&n+&v`<~pwnE~A*Wrnv8n#4gv05}q>!Xb@dn(0gQ1)E#piLIAXj83l*vneil7Mz zMniqhf*&Olsd5HBY>a~xu3jps!~zQH#2)p%2+Fv6+s6jw7!lhNf_fmaAE6t9r?bhs z3Bly{FG3c)b*GRmIc0(QJkPVm#E$;Yh)*rYi%nwxy2rOw#VHRWvB(6~zVY0zxv1tL zTJJ}$V|DfUQ9A|~jn|!$V7NA5waK8nP6yhFWzg?+-+w}yi+ZJ@I1;{GPT z;@@Kx=z?6B%3~Pe>Ec}Vnp`R%;o7}m=}!ZOisd{q7qw`97hZIcG;Ai;Uo9xtF-~*a zTH1LQG9GKU05K%&cU!$0t!I3|!14Hdk`of6dXCqfnk4b|%H65ui`SyAOZBsfE)0%^ za;gWo{9SsE*gD9@mPAahNcJAcJaLR_L19c(fz|8RRxt*kISMC-XiJMZe_XLykniZ{ zIEV+_`%ci~lN0&$aNOBcZ}cMm9Cvs`tqEXtoenYo;hx>CaD~6!NFGHMV9ic=OUf=l z8MO!@NA&bulXThXKIi<+W3f8apY8BC!h74`kcu1=XYdD>lW5&5NBh#ve&uCTcJ$q~ zc7()&nY`#Xpw`CG%F-ybNq2OY%)U-2(eYCd#+MyAW=-i-uIJeHi)r?Mx%GARx7{KH z;^}Q3k#l}6yDNmk>Oo*b>O=R)>LMIbn!5PIt>#3<_Q-enJ{U$!XOA|4N z6%j2i@_&>+D%gL;xyergrQLy~jaCnX)wM7L@s-i+UXMBd;nz+J0x1?0z22Vr_j^lk;iSQ`!FJk)psz<{ULN0|hK3}^^ zosp@lAG|sSEC#SW?>=wkaT*I#8go(ie2;ILNbwO!PM98Lm?ohXfxX|`)1w{BSqDeQ zaQA1QZ8rnWyT0D&tPtW1NRhV_)a}*A7 zzHM(Bap##8%Cz6c>0(JWYTwBI_SJ!--ob@UpWsIhmeD_BpBBGmOS;%F6LPTWXW?G8 z116G2eiv=9ds{V7YJWdI^m?!~pXwq0d4}qY37jU+dcfp?{M3uROrSGRI0X0h{$x7@ zpDmMULAPYlF&a^a>wXfqpQh_vmd>X1Hs!nwpD3)Ah`L0wAp+@M zc%VT&ioXLy6b=~n0V;T(GT##MzJ`$sDd%GMXE1?XAr7iRzKc+o7 zl|k$+zyEz>jlQegn8-)EoNj;HHLNENiRq%^YgF7_-Rv~stH#r~73G$(v91d7Sg*b_ z+Nibgyi&{a3CGk~;;Hcgwn2(yGj`6WWbfUi-6?(zCF=T~x}ix95(>nAtGlrh*CF>I zYlCsmI@dtRwq;w1QcH0AKDW2o1LXVE=3n1C6&g(J&Mw!siG{ZBZH4@(o<_7kH)x{$ zGDuZA-M5--DND19lm;uWlme+}B(e%aqK?1UVgj8-bX-nm;18?E{NNX_;1+na8Y*;d zeb%#Ij0bj4OFCS+4GS74gsIPbH#TGGNtBMYi1q*@J&--#9>Asr=2@d<*(eiG*GHmf z;H)8r6Du_$58MBhFrf4yK(2!q+8?!6ATo zwwv5HmkY%o*`%CPHJOAt*@Z{69SNabUf-IEV&^ zOIIhrG;Ls(d~1O8?sRp1P7uM_BLtwv`p?4ryrXo8T2@>~(?C+fD%$C-^xNsUx4S{j z+P^;s>wQ}2s*s3PkE5;SJ!M)`o2QN*iDx@d8j5^E#7)7rG$drGaJ!5#$|K`QvR!y* zl6TiCB5ZeWQ#w4SMA(i~CVl6#WE@r^e-DkVGV`Wzsv5%%@D#;A<(u^D;8jK#pvRv5 zHRvZ_v9r~AndT_o=}v`Sz_jgqowGQHqzx7ocdQ3pc0jJ3=V#VsnfAkgToKh(&$%vT z5h1+W(dl(Pi&`SAE%KmCD|UVd_?IEhrMC)J!!Y0y`E`9So6(Vhl^aW<&hz;+yq(I> z*z>5nPG2w6vUyYg6d%5ygl67&v>nM;b#11${h?*e#+Bg=f@Jjsg_xa2cLu7k^WART zG@6wL!UzPAk*QJLj_B0Bt&U^g?G)y6Smw-_Gb!B*S0?Hl^6UsG$WDyqhpR82C6J~k z*TN0+jk)^{Gjxau#J0T;FngT&G1`KQiyZH%HO&=XJAc?4JS>shJOTJSB+8T~Ja%H^ ze*2KOQ+M38CYhj$+jeoEbD&f;zK4bsf$Sgp#dlKvXNC;liCr<)(=W(ii&myW$mhVd z7>On7-g)Aes8dqTOlSvWuZ=vIa1))40JV^{N8P$ubxj^4zGPr1KjwJo_UCr@%<>^NrOnCklkycy=cL;fZXB338Cd8s6PsZ%uH^gv#m=vcGj7B@7bvxQ| zSVZ%Nkc|(%Y6p;7DutujirWV7U<$e&!hto`}Td#r4x|cKGDOzGVTVPa(j$kK5H6h=)e4uZt~-ES=%pu zT^d0*(>xYUx6J2ZilcPg!Izz#>||4*3-XTTmWYt4y0^iN)Xg*Mont!52TD)IYhOmU z!-`lwrN2J;r-x;^GJ`LI3s0JNi5(WyR#a?#h zt=N3o9bzu8$o~J@yDCuKK^qssL`-38ng)H;^0Dxqb_ExGxgK{ zwo=&)?oIpOEzJbhi`cmp2x{bd7EdgO`f3?kb%NOWZ}JU08CTF)XLxic+Z3aHp_S_9 zRcL--ND;fUYvGwZe~%q>YARJ-T1|*%9&5+KOP>?|;Gx$HN`f@%N@lJBakJCxi`MQI zVw#zO9zX~t(p>EwiO(IzqK_B1+#*)zE)6F*DAD5SHp28jC-!#smM6Z;4Gc(e5QGr$ zjD;mgJTytP(Y@0K{ZVqX>-~`Gpm=+dx^ZaNnD5s2C$(_w-GmMeU-md7^Swx?#~Y0C zcBMchbiB&${<#q5hTAzyR-2gA>Tx&2#vU+asgTS)ccQQe5z+hRZy&7KoP(zyRPKdO zQo}yGe-9yT7cvw)?=3*3Y+Afk&~`xYiZM=DSIix(CveTFUF06(hw8EK@)BX7fBx9l%L??!{FAMH_iUfIhQ)G$&mLkLdN+uX`xE=cs$6jmLkUD z0G=l8SXboq3GgCPgg8V8ylvI^(N!A1Ievb~y?O%;xy>pFT350strk@$j5tH->J!h& zLlVHGBEnBoE;6l=S(UXMu5W!|9gudWj86CAHX8TMbCT3&gDw+1>A62Crp#JhlmrxX z(G_IIG2x;UHn5tAgp}K{c@3&^rk~ABP6Da9mq3z zG&H+#I@IK|*#EBCKJ+Wa1z;)Hx_NHu2sTo{naeZ8wT z+CLit0I2Utf!y7Q*!A$R)*k+=1+X~W0TeDu@VH&()MdTd{XFE)SJ@s%UybI@7uMb< zN@2vC0rA1_Yh+Hji}sViWPf7P+X8e<=XRCoLkc&n0Vn10gbAlL$sK|mXz}AH!9`z8 z*O{OCojbQV?TLIC@ph2lA`!u$HP;#J>5(3QWOIp=lp&Iuq>J80{XFGm@D3ZC*2nk1 zH3k1RDX=+o?u?|6TK{N6$Mv7t{=Bp-axk=63Mr0s;>ywt2DN_FG;B#11VMyQ)xe$+ zt2vamVr)AAEzOxb&y025*Wog!E%X`TBR`Q!6`k2XTGn%=au0`jpUM9BvbJ^ofb|gE zsm*nfc;gJAm?dfXQzr6xW6u!L@oaC*ayFL{Qfugy$De@vvW|8>U;foMLZ`{%kmo_) zNcEN!4iC2kshgzxKOXKgBI;!E<+e2R=!o2AxWRJE(|^O)DPzrNf3^Ba{BfwS0$j@I zCb3xl?$`wI5~n|(^~Tv1K5v(UdPG$GrJV*h0fEmIW&L-kL;gRI7Rg?($AuJ)ovnr& zN*daQA95R)ROP#2H+v#y#c$jdl&A98*6fLsFa!k)&3|xkSbpeWAG3Q81qpS5u65^% ztz@C~_2^Q_xrnUP!G*pjxTvO1&HFfK@pa#43a-Is(|=A&_i6o{*OI3h+37-0)Ll-R z-}BW^|1LB0DE7GDecX90Ae|F(f^p14@}51^EvR;JbA4ih_4;Df^N~(*Js}`hz5F^I zh8B$IQ2Ivc%83s0Ys7q{Q$wyw3W@!KH_a67_G?z;#tuK-bj|Z|fOMT1{j=g@w~|eJ7};GAcJE1z!GNa6Vr%YwDo0Qhqcp}B0~oE-qYSW?7gT%RYmx} zRQ5{XtGe<Ex&F%cE-<|VRrW$Gt(#1PH6P3->gjkx=g zC`SH+qj^hAO&jI;P)_6EGep+yiS|dcxX6^E<4Ac;(z^7SU4W?A?`@0{$i2diWYvSW z_m9ReJjp__d3pVfc_bSG-!ChJC{0Jy@L5)p{ zn`B5gB0lUK+FSb0`|?J2u&-jaC%n;bz%&1g@0ArGTix^Z(0&vHuKUNg7&V*-!dwk2 zr03w1vTga@(n>lEIJwEbRJ)cqWQ z$8R(B1tY*ZA}*%-^{*zmx=5kD$iC|()b!L^k@RE^t~X31S?&WmpOY|`{QNr-g=P@f z>vv_}ecR6s3?edt#NS2Hy@LW@Md9m85PIPGeT_5t6!~o&ruPTfN6geTHIHF3sfW4b zGENz-pLgLTJ&Z2aSH8Fv4aMpCMr3AU!@T!>q!mw*JC|)~k3s7c4uYcCrOZ7Wk zxU3SEDJR4K!aBbm?=s?wC~`9&B?;l~P3qm1*c)02Logu(%ZOgiYBsd{Idc8JFKqu4 zBWz8~{9r&E(CX(G&yEEU+h>j!zlxj`s&AbHehLU~pYRiB6))qc+r>&lhiiBfxA^U~ zf|*D#SKc@Nmg+~#sJoSVhij*WA;5UTss@cu^cJX;HTO=ZHlL)L;`UraSPwSiUtt$s z=-Aqw8uG)!`LXl8Vr8MhSL!r^+*3T84ZJSU2W2xQdX9B!@=F6M(B^D`%k+V=QD(+RJP$}itRQhz9;o`CVBja$9X1R!SZ zoW-*9OR@h?dc}Rd!^CtfkeB7%Jur9!E{pBI#TdFxJ1+E(?m@tSGsSd65PlbDn53^8 zI_u`71qs^CZ3%`gst0&?xbB+Q69;W8?-hr~_zaRWn^P?KxEiBcVmV^6|G1am9Un^7 z%|##3I@ll8$zaOe*_eVo1NIg$JVGwK8yR*p=(|z@N)fqYT2?=aNwC0jvBPFjL+K?I z_{@l?H!Ykkkn@z?(KKePpJSwGICYCX+*qvph)@4+!{dAtR({o2g|WSgyn6W0z0@m) zlk0G49ugBV`5-XcrUE~TtHm?PNcW$`f(Q8j1i977^qhq%eI2|}=VU*y7`aRl2@UIe zi%+{9TLVBu6Zffi$R_l!+=mCWJ%s&`b?+H$DVHB-2k+q8=>GFZ2)QJGmulw6abdeR zX4z@dt0Nxkj+ZxiFXjxP?X{Avy2HdNWkT$qR3Imwm`ag2-G#b;?VeA4&s^5h5!fh3 zDQfUNr#)kj>zI4sb;PV(oZIF?%65Ps&x=a*A9Ch4_Lmn?n#bGir_nj=&U3pD8bqQG z#+~~5LIN?ttFmZx$TV1QF@hcPyoJfbnYZ+n6P*O#4x!ay(6HeLvg z-k1=0-oc1kjbqm|+<_~WEj-|L>a|@V2KZIJ5b3*nu@Z53K#z0&sfYWv8?l6V$1~l8 zp_)Phz2El2yDGNg2@R^fQny?x1`%3_ZkR|BTPDs^N5n*5z5BJmWD;^vTNwJ9OVFM@O^WY`z=$hu;2ROI`8`I7I#CXY*?%w|| zF+V5iI?($p4CyBd?r!$ocCzK%*IbN_$)~sScCgu(THSJ+J$z=kL1-9#2_$<%Rx=G1aHt+F|^_^VS!S6fV1^`*Of> z-Q8Jri#ECJ`cLz2mlF$Ense7O&Slx&V1bYt25ljUEUr;M zh!NoW!hO$vg;euz)xP`mJ^E~!Czlm}Uu!ziY*nRICTS7>`|(zX=9c1MGx(J;Ft8R&BX zU+{AH6xYV+CrUzTg@di44YIP^MG58&k{jzL(*{GX_lAK6w~NN^M;eFi$8;kDaUAI( zjd54aEjcEo0BA({%P5|u+Pom)?bhSPgG(hWKKnD@4BrTUR8ABp$tciF|JO%e!qu|3AE zW45{vXf?aLpPiRjvL%*DpXspmm|CnV^LFcZ}F`_ z6i`vqBd8qtF4u(Kq_tNR*1o}><2RnoBa%)kqbjuR(50?UeD#)<>`V~$rZP^2`N6@|$Qkw4g8orSS^-T_YgTUZO^B-jpKeZ-vefL#ovHb;aP86cA8I zQ@jx(Zf$yv5NwVaVWGY_EF^={G?rpuvJNKYvn=^QR`^Xwe=+ryf|M(A z26o!*U_^kT!Mn~xq$ z^^*NaT6u?wmy3}zEc@f)!L`pUm-=7b`;lEAO2D5@okXS@sja15yE$0sM0@q|F7Gj` zfE531VO~ax zjCrUrMS1Etwtmi)pFjg~I<2et~Cr`end_(S|j> zZap?XE{z}0AX=+uxgd|50E)ApLoaH}Ggshp@ap3P^t7H_}fR z-m-bB-4B&IdJ_SEi7gshd5ekh5we^ghoxIRU^kwnsdwB8RSfX!>f-9w8G@l)ZQXCu zAI$3>RyG{I7g1P0rd7d4$Y(awyun>C6`$kc^0+?04yfYf;oBT@ofHE?#z|@jOHXu z7rlUAWV*eEERFgZzC$a0<0a~e*n#u;zZKTqwNC-()1*ZGF}+MZyH7=lYG+(MzH>=^7zrBp;62};2~VbJAk zp~LxPXqI9%a-M(*b*IOJF$@qoEcR~csBymko4AW~w*5&YDaAu?wLWbXe2nS@ox9=C zAon|K3CAyqBaya^nj}{xVWK&Bx#IBZ($Vl`4TtF5K zfw|gyI1(FxaJ&XTDs`ui;j$|%)}v{K8M2fT>C?n??Ct@vIye(DjOp(rx*)9|V2k$A zM3*ZMt#9=c-7$Q?MCudaTpR}`T095dU;CYbYBh>e$;4HTvZ9N^rI!N(dt?-CKf@KY8Pe^bnqugwKpd&S;bJN$LkIxXC?$`h#;gZWUg z56)|xFTL3?NAiPSq}QK1-0TCAO9JY)-^%3@!y*18CN`nHYPB;C#`*BC0#8}x_$#)|JyE7h53zHItLdCu|D z4Jlce zqI|?(GT27k%o-W%Rr7|^WVL}+kcRp5lo za)G>pc?Glzd|ZgQDkS5Dx2DKI;{Np*n=J# zx7mx{na6rb?a6+hc{KNNEk2JB@M$Dg3u|c2+v;BX9OHNJ&3@*Dv=u0IPCGJ=1OIJ) zXlJLD3z&QkapZ-z5<>d%E&FT!;Ba{k>neEI&w*kxO5H|5|zgZh1{zJEt zk*5t&LNIG0rgKI2rOHpEsl?B8n8=7+B{_c`InbKHG!LmqpX=yen!h zKMna?HTJKq>gTPj{qhW@= z@s1@$TT)sso8H!WmXz8BqX+F&unq4oj;9AFX;l75QU*2?53b(cPw^S<>9PqJ%%h=1 ziQ9wL?wBr%ZeJzxuu0EdRGrYf^q7yX&kpXBVVBG?O7K~Txa`qhNH}R}71v?RyW_~X z>ef((zBGDq>dtd^LH%Egxt}{dAmfQeguA&Gn6&>E)cQ{Ux-Rp&QXUBZ2dSNH)NxcC z5R~EPWb7@ohZa4(IVU?rRxrTqtR4C0?!>d$;130@M)k=|k6CTem8(~8@%{6QCa!4y zDkxrXYNif4W&Y0Oz+i2`Y`CvxG4-hAk3`ho^A6ENN9_9W$7DD0x(&N3`}m4Osapga zYCMX3qn%7!p85P9v(LymZc@A|-G5S#y0vykT@hHvWw7zrH1cik}U9Cc@-! z&fCR&&$Bo_0SSKeBgYs6a;Z2m2an66HWzw-e6t%T_ZY4~$6oAOq$!?xQ%&zt8v z&i-NwHP)OnT{CRlF&P)I+AkU#UP0!^>q3X8yRe-{%d3Q{RH%fUjI14~Ed482#8QN@ z(}RG1yfl$uY1WUIV^fawdS`#2H>H#%{kGTMI{uUP?&Vhv3u$w)v{Nt8t}jN~s!xZ} z(+iepa+*D!U|LD`)mgdkPIw-2qag?a7;HE%cU*OWjNKv**5%MA-g@&*e0`GSpE~%E z?E)F~3}tRr?Vxb<{|EokC37CsOV|+Bof@<)STIqUH2H6w7?7oucfHufY7KfCZ|ZOq zYc$-eFPt0mSn(Uu;=K0kTz1!jP+U?ANIn9JKGx>F=0K>I_sh+}mIlo$9!6S_S;zu- zLhIGA*0ytA{D?w&9bkX9^UrVOS|JL>-SNgg)luS92vwFYG2eoR)Ms#3DCmC*fl!aA zXf0XF<^)M(d7?$rOz2qGZG%-Mk>g<9DVu@!nEzgzGUHU5?P@uX6`?%%YRAnOynQ@4 z1`Z^L@F%VH&NgmaIqlqDSrC4+Girp7`NmZ_x)(6&Z|NgmG*VTY2fa=^rR14lnE~Lt z=M|0EpY`e7mGfBo1m2t{IVBOO&>deV)ts1K!v~x54$MtHK{c#24J^%^@|J$4ENT^I zyMEoyuQ<1q?gND&m5en$uFG^n_?xIBq)L}2F9|BTZr!60Iv5RhNdLgiV2qcn{p{NVi|EN=#cK*P@1}K5h8>(mf3g z`VtL2vm;zz$t?3X>JjG$iTL*XU7NQLVC$ms>TBKH$!T4V%L`{fAO6^vFi?ayW!yxN z+?pr}>2ay}J?MAn9ecU^m^JHBPSfhdtoVyNb8AiDbL9BX2A)eF;GgtIatHCZeV0+@ zR)uKKx-ocf!r`@v4?~?KT1|E6W7qO%?<@CkmDdkm&pG34u#;)mA#P%aa)(2k{ye+% z!2(hBhg%-+Ob*2fb!Rxr5kIQ5t7GV`vW*QdfB+NTcHQ?6r(q~8y38o@SJ ztAsE9j#_>N#yMH9#{rDQC|5o|A#YQ@G;vMKV3Q`HW4prtFB%5j6<1MYpj z&Ti1ni1Mx77*)xl^r#O1;FW-EB>VEC9DN3QR%;4zTXMgn8CvfokAUF-GhzEbkwX;n zn^3~FE{O9ouj!|ZE1&Wwi)!cQP8*$|ShE#80{8+O<0n6;vNt=guJ)E`aAM_hnw=3wRj!%%>6zw9+pTREysAt&A0;mEQYEp-FgqFYw4eVj#4E~5UVycazuR_059>^^91|3XC z&;N333n2{d9w!o1fZZLQFeo%dz+E*SxMSwl^he$rFp;B7l)LYQtSXZ}gbkfG%VBF` z%@Ry6Io~8^gbvTUjKONarhRC;bsHLA9)~tbK$`S?^hxhen0gX(VxR#u&82#IX`FW% z5&}X;l7GiAvf`w3vd0fTpLOnND7+IT22-^)5DBJqlsVq*K|<1$wDrCgP4lx+pDw@` zSU%2EKDj>UHtIr4Yr`1llwk7R*-D=YJE~7KNzx_hze6}*Sq|dj$PKO1*1K?`E+FA# zs!$KRb=s`-4}#X!xt z+n3zHIwQ0u$4c?(yF}3M>5dB|fuUDOF>J#Q6;1abyi*;!IMA_`@}~1k(wc!PgT^j@ZHzJ4bagZIEar6e ztAqji$nML$!h2zAmd<8h%jmFB;c!mB8v>EBR;^d;!K@l8X3OjUL;#l(P4{;a_G%8Im>>(U!trDI(W;0R5^7$!Epu0QcxWHam@WKR!S-I)xGY| zJ}@{AHfkLtu2(%-;rl^Ivbb3D1+ z*TRSEi{n$+hJi2s8}_AtWL*rN#JJPTY71JZoBt{8TS=sko(D?Kl0SWosmOQRo~Tr^ z@^*NNZLsN{p5pttae#otCWN8SHr@7V~N{UwCNr>3!vm| zBxF{-Flz4l2hS#B2eYLu0K-BfIE7+zSwwu&84C&CdSxi3u#;Vgn$4CD2$4O`<#SFA?#73;4 z-q6|0(7x|1Cjkf?nX4%~o(t|B5H)hwM==XriT2Iw{}W$sHGXQwSPS$gZ=@~k z-oJoYvIRPA#~0->G+vHr)yNvvZn#}%+zn*W)%rdzmDIXEKF~IpJSj~$a85`wx|)h( zZo0qFTlzaYo_8@_rSLJ@RDAI=>%*&UdkT9e{OCF0eB1Ik1+_iHC1S#(kd61Tec6$B zTB0lXt$l+bn{cdlUMT*Fn}a`COy4N9JXdk4jkb%SK~GqzP&V2wmZHcH7^=+A6BC^; zIW&i7$(YA;MErX(q$w))WbhMt{ek-flh`bOd!PY>V^tGx4PkTF%J>A4j_~0V>EB<= z;{pr6O7a@>1&fEwW${VuOEX518KQZq*=G1~)@BT01tzG4 z)%|+Yg4!J3%Yqv=6Qx?_S*u{;Rv!^9_!#bg+CF7#9o(zJjkymviHz7kXfss*i8MTm z!kY;*Ym6=K4_}NdkJf~;)o8b?lVJNxM4Os#TC9lMQG?~ib*5y{>0i9Sj=Yq~Q%t1| zsjD88g{<`n! zn`6Gi)A+uRm2kRY0ubu{cYdb!YpFGlrqC%#QvRfxd#JJKi(c;UKisc()dmXX2bMZ> z@ywVJteUgeX~(z7Ir1z)g?&Vb;PDirk80g+n_uIKZL&3_J^*igL)O~9E_yXLG1}f9 z{cW;Z6=ucH6X4^Y4v!<>Z5taK+j&g;^#j?QWc2Ilry6a z4C%yRVS(fE>KHHG6?7wio7UIB#o88`b<=ELb+a1!r#yj`v8jroZzqhT%6O7n_R4eq_{7kFE_iAZ-6T_d*7c38;&$aPS^R6n zaV-T)`N~FP!T5x`27U7E?Ny$)Ip9S!Zh!9CSR`hnQ8AOqrJ1(3EsT-xneB!1V4{WG ztJD(ma!mB{3boEUcl{dm%)-V|l9@^7ZNkPnVk_AdFk4ee-V6qpg7O-|7Z~Xj&W&(j z%6~OqVHHA|Zp7exub*K>3m4>yfAvb(gtPdh{#7p_le~XUD(zCm#97m?D8~}d2Z<=j~qG87Wv{0PIPDPY^6B{}uX!cIA;x(L!JG+U2 z4RveFS4^Fm^RAHo{K~4p>dDQMNK9*q94!cN`cwAvVCwkwCcbIRaQohtwn%3l+;lRb zleQ7ih%JwmM$_jbr(ZN7E%LSp*KlK>F+9G=TOjW%N$uCEC|f7Tf`L*-I~$vP_v5+g@Nn$e55l}+vSPe;f6yvxK$jy7 z{VsHtx04)H=v~(ZsL4kY*;LgSnDUp1J?a)2P6)R=$lE-@Qo(^th=p{wMm(o-n-j;! zM>dz!3^)DLmY?iq(a1QBADy(d8|Hf?lndQ{EjKYD4x-<1J`ao>Gc@0p;J|R=&WsGA z>;wx(4;~-%M)s_htW9AmKK{#YBb|;!I=t?vgjnvGhg?C+Z37^vjgbJT= zb_2v#lq|>GUI6Zz7C)NR>KynBcJ?kQ?w>vhqo|}D(#>>=9QmU$ulemjI`uDJV6RG; zJlZBh>m>|VTdAq3P#i1+@zz}ZPCubBe9GLk0YXyWT-UIYBl1=M!WbMQ zi;Uw#Nf)9wPEa=77BV@tjXZsZFaPaRl9QU@L9m6L;_EFGs7t1^5IU zlRB`QRbR)rc>blh_#dc(i9i&oEFwDwr7KY-JT46jbSoQ|h&f~Y7&Kj;mSTkvOy7hh zz2d-Q6Z;NBr*7xmZEipNRzlZ*(?xFV-x$4&_X1b~d%kCC@|@2!w~_lvcO}=IFp-y@|&irT~*zW z`-w(99mYSh-rmG~=$@y&6B1>XifI}q>P(Je7HHZj>Aq>&%936Pe+VgXN0oQj`^G)#UWibYU2#?d2Ai&2W-slgFuWy-G)u$Cp5RI{fmVx1D7#J+@Hj*o+wy z-QAvs*192SD?qk(i;`)k9G+<(Bs9q8uu>O9ChJ_2!UV$jWas0Y&TGtY+iMdj99}*- zV#lr^;Pc!<_^AcTztT)azig>MW;SYbjyTWh74LKd%9&K5OH)s4AlvG5buW2um^RC< z-DV%&PsBj)dE8p^XpB(BpgC9ts!6LyFR-S+(yy;6*Y7nfsusfc?^qr6l%^;STax=R z*o!T?{lN(0$7xw2rKP2%=BUhZOFo$pj!h}m7vZeD8YaSU2yXEECBgo&HD15nhL$5k zB%Lunk7nifs(;U>J|6-6v0QIGRvg2;=ZhfzoPwIye@A@82(qU*$b8@`2;P6C7wu(Gz8mn#E=soJJ5u8xBuoax)*xs*Q z9`FTQA6Tx~v3oXe*(;RagX6m!l;XaZ<4=%AEHRR32Gg76#b?zy6vd})3b`o;`%aTp zlBApClUcG$DFUi!wRjBvZqZ!hi@Z`g9E+IHAxY}%lWIpkmbR59q2N$R(#v6$U2YG~ z%vMCGpXd6AmNcuMm3(WLSQ+*{EJ?S?nliV!=ne`njBuLzQoJQ*0m;7c-$FmV(IbqE z-$Dv58k*eZdB3_#+ogERpBz4^7TD-(*;g9(>9|?IX1e%t+P~MVNSobUaWKodL%C(m zhixoR!X#cszr(J%$;*qLkDxP8TOU{Iyi$?WM^DDF>O6KW(6lV9oSmmttqJoN)mM5S z-L1Amz|Z1N90yYEbI3p#CJL_{CeEN4>0#s@BSm4NZP_V4g=6;^(aC{@OYMcX1p!6r zKZzFs0Urt^77--$zSIq?M&%!Fw?`INVa={;X2$33BmPo{z@!)JKX2QM-O=BwGQ5M; zgGp)JlA?rH9PER6-8Ee>mA017w5F<5%{D!8PJRP6CYE-K}Po_HS5PKMVpyVGWI_&_$A|F4J>Ida6N zBf3Ae<1G3aBXM@p|0C(DXB`wk*A<{MJPH6-rr8`GVkPr}%mhP7B5&O^z z(%s!LYK+`|^ZWaM+w;2jxjXlqcbwDxCi;8S_ZOz$-2DQUEAS7)F_o4DbCXGHWIA*; z+twaFF-ZAP2$*KS;MN=yoqX^fJwCmUAjzSsF*WH*YIlA0GKGin>HemmdutyX@KZ60 z!Ml!}uB3#u*UCtvwj1#rc4#ig9Dcr`N!$ks030>4OJ@Jx(E0G?y*D`n%D2-)`Nom( zD@;D}k&Q+C7Mhku3AEf(&#b#*IhrhDcUfvu>CV=YykJ>MA5iKs2GKq4Xaa~8O@95dd>sQ{W@OQs^M3khn{^sre15ltabullz z{-M+0{1dR}C2zt9XoN-K?u)g?CLujQf%5l=TKi!)Uq3mP#i%-Q+**i*Fw1U5syDZ+!B$E3-q zOaBT1AAv5Ib>gYZGbcQAI^yxT>c%YTs2Qs^lnsaDl-8i| zjZV@zt)NC#-6w8N)<++Wi2PyKL}uL6>>0b#1D(4UGtHBMK-D_o zX2Fs5>gqprrdmPi>O!yYVJSoGm)s#@y%ohQ?#{b@>_Znyw6||72(jLX9ElO8t*Wrr zsHF~wb|;b7RF$phrjHSyaVormm#)#D3LJ~Mb=G>5$Ub{?lFRK-085iqz&=_B&J)l_ zDFo{-`?4Wp`1A^vA}r>4;#_lKe#_W z%wY^JbC4OB|Dsgv9*~t~y2H^HdH;N=Ez!EqhoA3WIYH!_-1im;FDn7ykX6efeOm3P>9jp0yq^4 z5IC)0X3#S=i%Ta(n_zNZZSs8*2O6{mm^9dM)|V-?=GT}s$K(c_i5(ey zP=H82yqUbKAokG{i=zdEO6N+X4?^3D_!RZS_&F^%36_*-p!E%`uRO2a|#Y~Zlg z0rn6*_i;z&5e@J*QR%?xAtV*-U_fX)s{O23zDCGj5BdFNeDCxe2Y?vk*}GP|UUgHu zul00CUcqu0LM?(iNW@clNxSjSkMv*|W9wv?7L~GB>F43=6_VA!nW_3A208c&kcuAJ zWz8gvhL$s!ABu6`@FnuRpU#VsW(7=*NGa6=@9ZE*rc*)JY+@?f z-6?A4?jR4g*%HOVHUTMp?%5fG=|AjGKSMx01A@*~mY8U05uc)5TFaIZA@5EfX1i44 z!#p}gQ|HoHco0^&t06-F6@Z~f0dEltd14>RwS?!`>~`Y-K^&GXkqw_i3m`1eK% z*l#@_KY=$qp%H4v68-bX$McgvdQ1bn3ciga11?oez<;xTj?$j}EWV7_9c(9Q{~;Q#Ed`@p{bGDE=_3gd1%v~u(0q{`DWj4crsU3 z!u~$YtpP!s1MLjsl=R^1Nu}$( zEH@o5eC%j8-R-C7mUYWFPe&(SHjb8POEJK+-XaRL-;8G*X0Ry0Fq&`1z&xz9W*>LW z-2Xy>dc7xYxw;?dbUcSG{s~BF_u(7I-&eZYM*ONJ$~c&U_5Ud!^-ZYP7YwekI%N32 z9dd3Y5GwU_?R*?|Y6=?QQe_|UtZ1nGt|_^RwC}Im#C+dh*CNJl9idjrL3Mgp%Q5 zPn2X%k;_czPqEWu^;Bk7VQ*glXuhX;ve@&FyA9YJvp{Ph%1g!|FZy-c3_-;cV_>5iJrN! zVppKSWZfq7A!F;h3ib(7|9747q}eW(6ZL;i)aY`AKd*h+>sthzuNX{wnA4%3=a#Gx;s!M!M6pFlp@o35LT+ zH&{(e*cR$6F@n3@>;H-`&8)~v1;UCo;^I7mvyNFZRJrU1{SJ<8#`^KLo;S-r`y&{{ zO)Tm7=JUvNZiLVAyiT+~wXys8NK4RwstGR;&9zDd^z2VIZAsG*ZwD#b-G6-~wViuf zvi2*AjKP9Rk}AD|IUGevo);eyf5`mK#!bo=aMTdLz8I3V(Iy+E>YB31_8|;@{4<0z zwfuMUVZ?PMN&X=#aX1DqQ_w@wBZt+iF6RDwnd2=gYx}V177g~REt#z{#17lbQ1;kV zB+9{xcotUlBaAhh9Z9b8}PWiA5;A z|K{gQgU#0gH|?JfV+YhkN9a=7h9g?aOVd0z)oKqkYnW+h91D`BinBS>zor0kI=(no zaog_>>tA;O%y}^{faqpanyKBstKyu}80!*iED3(ANIr4c-^PRNt8sW~lv~;PPeG4; z?^m9x?m>6E>05qP>Le4@rb0r3&aYOds>aiDmbAIc$dn~MfsNnqe|;H`o~#nuv4r`; z(qn7XR99c0wK2XSqDWKk9MSJwfvl{mswg!Tal}9JU+Lo@lUlZ^3br#i+Z2qojn=yX z1WUg_tgvvs$<2zWDq;cBD2zujg4F$10~uYGwE5H*MjMjc!-e_|=f1X3mO_1w4JIr3 zq?yY~5=l!|Xn9D^I#es&?29Qz476L%q--LWl^C9g=;2S$UfZ=lb+e%Z=tRl;@U)@f z)|Nf-ss?PxLtaSt50t@B9DHE7uRG2l^#siW?ok7`t6O*F6B$P{v9z9I9w|l{!DrPg3mt34)}68r4#rtPhM?~q z3PgL|*o-M5(|8VCiw!Jm(>;)T84h@gPSEUE%DQ`GHrbY)@m~g zB~aTD*ZoFOLh(zn$772!GEv*N@=BAhp$`BkbBMnvQpQPF@3MqvYHF_Wvlb1%eO>lX zCsr+=+;ZYL*+&2F;crTo>=p8^hDoY`r#yCq+WJr6w-v&Ed`PU*TuqUoIVdOhC!&cM z({1wp9#}~%>(NpF?_YRRfB|1lXrYn(+0fkjF+Hf;|LxP`Nu$Fwn_g;Kwd8Xt#@6K4;Snw{qF$xbh>VVbWcMPeGx zBag(G-_JDpe;LE(O+~kozU@h$!NrV=ykHC9=DZLrYGM%-8a5Aw#3kp>a9FH8oXdgt z5f6vMY9K8n_)62H!JB#&Inn1y&6r;FJ4c>V>iht5ID*O+5E8Cs9j@IOcA#@AZx0qt)A|joFMvYxDPW^;LPJrHN{*)sU2Tkf>(bh91(@N6=4B89G6x? zHMd~*Mj5lGtdUQAJjN~RZHzSbuuLJrt69Utq!GTdzV0jf`v;fS==k?dRcbMD5h!Ow zeV*Ss2tfCkRT(=Y$%Z$(aOGU@!YYN|sOoqSy=LPW6R0{W{EMw-X5`m!;hz3m40%{a zo6P3FYuqlWwh0}c7PwwAKWoPI2x)NV$SV_52r#9Eqp}dWBE`5um%;BP49!B2|$|Pp%#oKDqHMT9`3%jF!v^o2Te$fLJF{KR&8EY5NQe_)KwGSMr=}OBDx(Cex zLm^r4!!mEu*f=8TgU9&LBFE?K#6^kmW@^ULO&Vba7FxySyLMLm{qE!pZF(`7!NPss z;I*b(<=FUZH`hnCaIq{Mx!&v_3PmnwvBSf7i*mZQTx6w-u)^N0a2v9rgtD`fX$p{= zgx&X#NYFSyi!t~z`W#xDd`8vsMbLRgS!i~4?Jhd+=*U&TM~|B?I6Q+m3gHq`vd z{w`*qp_h+mQ(_@WHGk$cupzGSQcL$kgUYu=%EL?RDAj~BsfY~@GCN;ByHC5rsr;5h zI2Oy3%t{juWx2ATw#&-z^BME2P6<*6Uuw^2N!dDA!^WkHlC>mq_WowEo8@Ems64gh zmh`Ex%A|~IzY=<1*FAGQ8csQF2{zss<9S0&ht;oc&G3Cwxt2)#4$HbWf3HsMRVLA z?2;;1&#gvkmF2j!@RKst*$3mIH|{6_bdJGEUVDFK@vHDF^w_oIMBNaV${}y93uDCp zDIyl~!yrjaAWF5Mzkt~%GF@y2SI?BogKDVULp|!i0qaPOVrVmUwGmH(Q09b^+P#9D z*mS4Kbyb@$BQG~S%&TI@`+M;+8}rZvlj&r0`con$F6fNAwp0B9`k+rU0kPl@%u8lS zyV1WNWC0X%MeT7z&B}aGA#bXLy z=%%(>GQWdF$yRQQw%W0xqqE6=+!x})!hV&h9|ah{N#+Qi+V|Q6wKs=|EH?8Hw?o%g z$y%3Kkg#)-u*#Tzpr-OcHDe|U~>@w%D2bdJwG_4Tk*?Ihyiggabb zmccYl=Hwww0-Dk|4IbsWo4%v0KTvh4Sx$)?X3wY{B%{D}!@#pT(8tb~PHCJtN_ zb=DC=*MElcNY}+%^%vJZlHRX1oHD+PtMs|3-~dL1QZ{Cq6M8R5VAXv?@)u16c39E- zg|M8k1s=x3S5yA_;*2c~g-I>Tc5i~A5=wvSACGQVob)OFOIh_RnPZFR-a zpT8~(zB$vPrKPc7T>?&eX=>+5ckMhCv2!W5<{>G{&+23i#22A}=Q zNZ*$)U|*H+V@1LxoUtY;f)j6Ig;PJ0`Je=B>(YFv)4}lVvEwO1J z+wnUJ>0}4!bl1&Khk)J~7)qJ_^x3N~GHxphNy^(CbLJ^OycB77(bx-4s2o-m-@M(n zp;WzoBf&^XzfMl6xSYEG7vi@P$Ty1v-_I@V`w?BOK(B3Xz6avv=1%u`r4|u5TD( zg@6#3y*rq4xAzTb%=q&JCqP2Oh<9%9Y2~8v-r90Bli!u@EcjV8_%gfx>Ld^OrtD$( zYA3}ZbnT6FP5TLvUTZh6_Z!NLlO(5kDZ@p@#u_`!#p5kmf@!(#yh2pI_vPnnIoua+ zOm`!HUj*EBPMGiM=-t2ayS<|kvck-PAA22csUek}=4(cbz0ZpRdWlL=ost=`>UE0G zyMB>x<@20N(J#~j2#x@+JOfN8duJQ+Kfa%=rweTs;uhEv!^2lZg+dCmoIfDPZVnkL z^&7?aXS7ht-((^};LX~3bB%4^6()W`3CCatERVI?@q%QKx78-8QmCekvF&J{@0rlh z(@#$HFjz6qe}Y`=BnKZqZE_ILU2Fr19UKP@g+{E;BQ9F=zYpc>l}hO$@(Jo}T}}=r zb-f>$$#MPF}XMvk!bE8%S>IW4zA zP4S>coWR^y3@mH{I*u|z?EJ1BJqzkNJSn26WL53{50W-`G^2L)7#FDE`TqL$`$V5x z0M*iU*hUUIJ*KJPbHbOeKqwfZlwaqyEFONwv&B)-55oP5mhWFEg=(kao8@3f{t@3y z@69F^rxM!SYhyq|BPVq$2b~>fWyn3^=DbX(YUb5zz5b8 z9j%4J_Gf7M3+Dn!`}v}}89)1AmRt}W$24O%zng5@I(PEtsBaZOaBh^3&Yc_VB%?CB zrL$)~0tla>y}#H7Q?r|YP;+61qr)mDd+=tnc=vQUQH?{f6sgFMS^;8NVk;xsM2qXx z*nE^|`Nu!xf=k8+Y>4W{vu9uWSp7@uh!=HFBL_>u`y-QQfjxmEbU+FT<|8EmM5u3|hT^4$3g05@U2x3$B8JhRA&an??$3V!}XYe)bQ>|~` z3sK^(FF%J(qlqZ;EHlyGVf_F~Gz6vgf8;{@vNbf)M>0mY6B&t+c!uu|lxlVnw->A= z{Qr`8At?4<&AJeuochJ^GI;HKU3?JdfPv=0>R&!md^9vX8Gd=WIonH-5`i!e$xK!W zBm3XnVsnyoiS$Af4k*r+>8Ru_u8AlIJJYjtJhXi7R}YE-bB17jqhJF{!s*w}jgeo* zP)PWD`I2QJrRsx`J~0W7cZ9aexTw(uW<*sA3j$l?*~O#6G{oM#DEjk@M(Dd1=r6t) zXq_O09o1<-AY4KxBO=rV2t;V^GESAnf6*^GM?DwkT}k_ywO)~)^BkeqNq}&{nFb-Y z5D^+jNUxW2MjkyRMDJi)`e!eC+V`#hZI1N7m-BB%B77yhYt8cAhYx6I`DmhIGy0D8 z(y9a5Y7v`1&48=LRqZxS7l#g6%qdc+ttcpCpa1nzehG&>&`Q4DC%kl` z`gcD6zn{fK3x?Iup zu+j1lJf6T@rvjFt^{!9ip2<8-1qGpVu@KJG1+|2A4o=RCR;JkbMQ_M|Q#vpIMJXLF z2_D`z!&3Zv*~JQ9Qz4HI4lwkR@7e#gV_Kp9Vg>cH`ksTwX_Ss60CTf_TiV$V=~3ct z@xkQz5G^B7yyvJR{!Mq@PM6OtuB_Fgxb4TgQLy8jku`%tIh-e+fL3H`%624Z$p?1MV&x-ejxJ9+=I?AaB_8qj_Zc1vQZ!oNDvoGC8610;^OFv zXJ#$To}QXIY3c@%Gc>j+Iy*9{kqp!=)P6$e+>f`6IZ-ro$hREktV*D`whq0`o)(o#EdWYYTdd3DsJ zTL?_ekzyXA(&oC3JZFx%9A)e8fULGGYbz*VHAkr%tj}14xOcW|{1;OYol@Q=+VENgvw(X$QtZ7LqX2z1}8-jbF@;gac^WVeT|ijx3@6M(sd~r;FjL z2*!@F2iX-j*9G{pALIR4YeLFgILyaq3i#hYV2ufzQI>#KIQ&Kk)Dr~USx?aIs^j_@ zwmp#X?l9HRq9~45WRl7vLrksSdN!6jDPX{;2r{nyxwj9g^A=QFR`XW$tVkCHRb z2MTNpB;+FqW05Nvcp?cf_~Ropj&4x{iJV90I964v?X~zRGG9IF@1Sy>Wq|zRwkVRO-X_ZH0|E0}J6T z7IMCiXd1#06wcee(TcfM)Im(VF1CfURQJbA%b7H;SEF@B6$T@4V9b8bhlGC6QY8zR zGU~RJ`|2;8GF^IQB$AANcpJ_jxF`a`Mf+&++cnK(F0yrT$E# z64Bj@^Q+&zkt0)Yfc!*f$pZ?Nzhy$3wO21fieSv0$3#veY&wXXXRrLxe` zNZ7qNeM;>T$b~9S60cn+EX!N}M#pnaX=$(%$MZa$15`J^Y69KCYGsK7qz3 zcBK4>s@Kc3`0kH|3{By%sS&8jsT@I`vhI!?Dh=AF0r#&@3MQ@)GFHg9gPKV%AqNS=bPSOk_aYyLjK zPwAIxe*MZG9=Jjs8A%5P|G*pP`}-NW{(D?bQB^gy!?g#-{Qb|J%IQdi6%GHVFYY~W zO4_~laYe=)50@4ltEvyUli|d@Hc~tvo0QM|uD>OEU&YN&mJTYKH2K$i!|IO1L2Ylw zyUuk7ubv*S6fPIn9nU}YTF?0|zZzDC{M` zFN2|9iHh$6PY!f$dstRw0ai$}+D>A%A#P1`;ULYu6W7rLKrmSy!GV+j{P z00$uCbgbh*LWzMly|t-jLZ|oAedF1~$lCrt9YY!>^#!{(tQl13 zH705X?qu*kuw1g8VxeLFSPGmKw7SKi;mL)ZH4Bl`I$p<6LJHV1uMFNc2ujpgh*WCQ z$SZEjoLao{zQ{Mc8J2WWG=A5E95w^S1wC|wVZWf-e^vXP{e;I*JW>Hr^2P!0UP>}yZmCWtOPzHL z6|=#ZkLGLLl%4CczS90Yjqty1KR*Us{cZFJ&u?ZM%SP zYUd}HgpLm+EqAv*$;A`h_E8v4H~=0v<46qn6lAYc7(=cB*Y~t;lg);YiO=!Xu(B@P z9v?=Vu6QLzd_;}zD-OrM*#T{Ux9mP8ow7 zSkbih5ndOOY2~Nwu~FOqh5hcw-9DV(&t=Xn;1UCV%S-PnJyF4?KW{#NIBu9N&KAcT z5qC%zXYS^T$+pnZ^?4zv_Yfg@k9S}r3fwFUrvuk_CI*8To$ zQfYE}T#}upIq#cdKFEMcM_*r|Ua8J??_6r{%P4nEx8nWQ_`~emf`anD9nj$Stt-A+ z2ZxDymk6)TC3^=~lCGt);J_;g@=7!q`LpO>VRR3#E$l?aprQj>i#%1S4nL~2IA;5Y z)0Xr(oHP3Qxfx}q|N2}X;83lO(*}I{pp8&L&;B_*T?17r6ao~?@r#Qtz1|nbMZ*I8 zJv%$wU<%g$miBMNj_6RJ;vh$|1!QJ(Mc<_|R>*!76G1aVvz)G8>8GLSAcdmL}sm|1!hBrPLnm<53 z`V}>K3%NR`JZvS(25E`7F3Ep>d@S=`D2Qr;yxWX4W2m$)**~0EWfjmC++n+D099Nr z%swUMMmqn^g&G@lt!nx3-|(dZ;)oQc8UuAE5OZbbYeOe7@>2 z6k-uCyqU;#ND^&jcA-8N0u4UoTGVV4LXC}Se<~}>mapa+6*LvJ8pnAC-e?@RPqt41 zwycjafN#=3n-LO7FsgxSXA#`SH#%9&RR-g6hdM6nL{lwgdh&r7P z$xcW#w%8=PD)Di~L7LspZCC0TAtf1Q>{tm6ur<+AnVR@(d z>M|<3ZkCTM(}$HKd_@JO1f>;G4DyV@*Cb{^hm1Bw0}@gwE(*u+JG-d2d8Sw_FXV{k zXtgYXxQWU}(&7j6R(B)L2_%Tx?0$&*0CUpeXWceo$ZGGO1ySCzbULon;p5T1>Q-8b z%(b8^4K8jTGEf2uyha|6gh8e0>n+NLHTh>`S@lfrb~+i%ITGPXQaNT)>Rd$3@{eBo zvJkE)&cOV%NY1c^pFG^UZzPcD*pVtmV0A+5xpS)m5KlY_ZmSo^^@9h^400U4|1cS5yoj9j%u+j%i(+MDDd(j4>Is=~c%X12O)JsVW;%Wwg2Q0__#@bHnk&!@k&n<+}G!=+P8 zRsM$vF)Ic8k$pyr*?6<;y?siZ+CZ~XUuiP-Z)k?RT)TwuZubn1zlD)2w#{RnV^-$H#}hyNiZ+qo)y0r38kHH8fT_ zbpDMPq@avkYr5*k4JEa=@s5m70?(m#N3yuAmUbhQ*nD+jVTdh4ZF@o&myI2mPXG#OiyM9EDW zPKO2pdTYH~{%V=5_pKmnNlDW`7KPn#L40oVHX&x%QQ2}{`M==T)vwlo_xA7qr|*3M zpf);cbO8fhZ21n;fs3-xl<9yN407@iyTQ{oX0zZsMvPven8_l=2}a&-jxrw~(fL7r zP^VzC*?qvyklV@6$tll*%OL*tv%L8XK}*Tg*O*GY%jcJ7e!0pW_#-Oa`)HCqf8?^? z3H3#Q3pIb!7ow}`GZ0EieG!ZG71vUFZArzF?~Y2rNbL3|)kBnmjf}+Cn7jU4Hk@*- ze4fSr_@+ESxuI4~tkx;XL8A7Bi&Nz#C&+XT+cHM2l$xGpNSSeC-bd3UoY=Vf<(^-i zCpor#97?UjHRDHU%W%1iZDiYHiroc3dr$RBNh5zARB(-+Nr6dD^$&$*qttUx?q1Qm zI6PfhS<@KZ$3>x5>YBN4t-m?_ZXjV2-tgs?M14?J1XeNLQ&4*YyFN|LNPN8Bt3eI| zwdAji;t$`45XL?VXGAUsSBb zv{1C2%inOjdKv!s675S(sEA5dwd;)aV#@66k0P03F^>=-KOa#_LT@(I8ecnZF~LkN zoJ}Oq*N?47N1sR>JWv><_M?ru?*WTVPMM*D4kdnL_Y6ED-ssk5;#9 z)#%9~W5xXQJ&Ct43YC-R_sR`!XV8mDe~wninplJJZag7L-9$I{gLe}DztLzY{_x%t zwtS;|;8lsKI01GnRY1~;na?qOBSm{Z-&@r%CF2+`?5!~86D>b6YW3e+I>)T?6m%3W z^AFTbQua?@7mm)#VtPGuLuwqlfQIHR6x5T5kR?hQ-y?O<;+OtLh5DQo{(;~sr_R=E zskc_DO~lWu(a?kekKplli>2La!L}LJTwLu`sC@q4uD7JWmQu;GeJ$JvKd5|Rp}Bzq zGZ)l79)pItA~kB2iacLtG!BRL{@d=tuylbg;`?9q70p60D5gS`i2fTC;FbO#70F?3 zv2y;#XQ@wmRP;UIY24tbFO&cB+)t<;=k!^Q38bt)s8Glt?mRN;7d?lWH!AwWaMwP~ zaxnY@iFvMa4if~~ebr(KD8hLBFh4M%eR`)@wZ4*1(ck1QZ_NKnG6n;+E)v^zZ9Wa% zM+2FXO_h}?P+Pnm(-cmxOA%@@$e9H%_S9s#?u?4&|9!V4@`OLy>&p*sp(ekeR7K!Ki1HWec$cOqd$pT*9l9d{W2 zhqB8XM4UcnuB(=_V48Y{W=azePsjx^zv7?+l@QlC{||h%zGs|$=>_fbkd-Mpgng%{ z*ismtQhU#bjy7Q~tDi-i!#@cNTUU;=K}`&!)>cNXNnSJ~J?heU7#`Wn*4IRxh_Xhm z{HT4m)=O4xc1g{1cOLf}t-3T0c7131t{?gw9qmg?;k=t>FYZj>cd=bLE=H?z*El)? z9B~5FnSX0vjZ9H zfLn`AN{W8?oJ(37L3*Z$kak0R25Cvwc+uQ&s69EI!VD#y(z^813zpU5P6%$s_w|sNLLj#eTS*c^iSxrwYoy=k{gg$o^3~wJy?5e`H%>(fnOHXwRa_ z?jp$Xm#GrZXx2dq=rK1t>D+o|X-3|bBJ~=P44-<;(3<*jk?b&YhOO&htFJkfw4ZWL zqagB!zBd;`1Y&KADNr){$Uq?tpf}O0%36?4k*A-Hy}VPj$SCqcgZrava+&ph#@fSpH)!v z?oUEF*tGRqa8yEuGi)qzdJA-axZmV_=XqqHufnYOoqS)HdxZZp0v)`c2cN_Rh{m@t zh^L6h$VdBC-vt?eTN-hOFnG2bm7b{_0BuDr%xh7yD^8BvkJArVA$+$%OsfI&fWx2A zpsW_^cbU#MKm&4AP5!nEdBLuSQk7vmzb?xeN+=4&cs?b5!SHxjJ3lRrN_QWFSg+|y zYl-qqdx62X)F$0ltikt-pLOY6x?ub?lJ5DEtp@dHsq=^o-<1%F`+Lg|)$_iMulY^0 zUgvlSaxn-JOJ?HmIl1kldA~qK=l2WO`?wLsr8}?y{jj&R6{wrt?4!4yjgr8kDkI8(F zEa2JKw0w?Q;=mm`40KNd>XRNim zodH+&_g?SHn^??nFW}fG5I`KA^!HrgJ?Q#(QNpA}O?Q%`qvK9YE|jLlolV>|AJ(>lb>`u9?XnFO1td zLt$tk7ex=mdD>{R{wHTYK%vKFdD;H5_Uk-6)z=H#36sOKRp{&R)8&MC$;YgjH#Ms+ zerp;Dj}JOWtYhi4zY$OOlWt>DrXQo2tU6||SH4qw@3eNy%sdPGIu7b7%bP;M6iQX| zH6?3Zz{$`Ds1kFe+bLk)Y3^6S;kcw4zVyS#n6_Xz0?!4qDjec|T{-J?kg=beKEfTL zylUNQW)C;>OI&UcI;7AEkuiK2r56_jg&&(L$1yO8xk{+hv)$i z!pEhMxy!3S*nO7UBsXff0*U}G{9ieU%_uJgygnaK$cs8g-1sedwVG9ckRgI{C(yM( zXptIUxAM0m&&-Rh*vlY#cDjw<>-9fxq1VXCbhR{XQ~_&`(h`=|TMypKZCHft>Vt3i z<^y_FjRa^E#6qq?fc&pS;@aKIjpiW{T*KTg8|LlDZ}<7)vZw)-3IO7Cz6EdcM$q$J_#7LWBMf-5<%({|Q|%))Y2XJn_tO>! zpu$iZR^St@JQM~%24t^2ZD5FB?E_K^w>Lom#d+i@TV+LcN#>F3^(`5)q;)MMYU}~V zSD}s*_D^8?1RI3t@J-&rj+diyv!!!#L7NKqeXLZ` z$>izhmbZ@u9=hNMh3iNeqYe}M+d0!|ufn$>TYt(98c@i|vg^AvgK85ENY??W$EkGU zNII{nVnXzT&qV;Fz|3zkV-A-D&dt=lhdVNYLZ{@^(s_%Jk{6;m95gG|@%JsANMt9} zLbvJX{=+FVAr<n@<93Tgx$L)Rl*Kyk7{2oWXo%=sWSf&q2%DQ!&PY3WoChlX$x~T4h-@hY0K~LeRAG1+17Pm|9UwERFRpFw#F5RIN(49H7r?>@z0IEaXu9j z?*%KNnb_R}UJA3_2c$QhN&&e|z|v(Q9@D0(m-}@~=W+l(<;2xH^L#lXv7ee$=wJDI z-S|4?V*k7}$s$ETu31QbH+mt6~=opM&w^+ght zuoiAQxjGcYhZ8;ACQnxsbceb^cG(u~A;`@r@B2jvdEr6G{gcA}q+EiuDipWgf6xI? z#0BbhU_(~&%AG_%do~;o7#Wj6e-0QkMMQL$MhwHPu%s{8XAp2d`C?(InU;E zJD{pmu@3`qD1*)!WW}9%lyt7XHrU4^pp%gSpivWeZ@iD!ll5ar^5`40{Z^YtlL-!l z!z4WRj8XP6_+o%c_vDQ2moOt<>t9ycd@0mjA?VSI$=NnnW6Ed7<{WM1yJ$-V+$e~0 zNUeKWzp>EZF3Y^G_ZXARRLc44wQd@lRA^y0&-&-@x}5(`POsi7P*Kvn|I~O!Es>J5 z0xWz81f+Nt+(KC(o%B^(4+#wHzsRw7n+XhG@vVC(+`!s4DM~Lba=g;qlfNf+1;rD* zl(c`EI=?aWni3|ig@A{)O?1$VRN+@@wPBaLJnCSyA@$SRN`P#?cM%F^)oyj2ykG^P+?I>{my5qlEtIU4qPCyi zGI;ih+Kx-v|2XfdG9nR9Zmi0ezYY(`VULLJuCLbthoaDN4>h{CJ? zphzFXu`g1}Ao~FAXeFop*p0dX@keAMn(T#ygr>2#GGUbH$FxxlTqCWgzROcAo900M zw(kqOf+~VwNXL1Q!|BFV4F$Yf32w3(Ql36ODn9vgUPN%>zh_T}D4OPY;Es@1JUkMo z=TH&T0K`HATgT%jGZi&4NlKKBE>4v^0Npjnb_jR=2Jt?(Q6~ zyu#Ee5rt6Jk3-hZMedKfALPw*XPxGi)#eN%h}Sf6VnhalHwLfZvO(Up)rl7`gCDLF z_pegg;9s8;ky6GBfFE)L?P)J0326nwTUaD@ew=@-i9hc6y8H0M`vZxS*oI=l`S!yv z(-@h3bd=v$KHi}I*Zxymd&M;&L7T9w`Y<5!^pMD*bhbBC8&P23pVlQq@F$ z&dZaL_=Xo4UVgqFbj)LH=`I;2{)C#6G&1;g^x}l)XXlVB!lS)D0Of%TKQ75+(^``g zCij8)G|UIppFh=-oRPUcvTMH7f{4NCsP{Krj&&RD`P-vLc@x}lLa(abf@AMvA`uNE zd~ggw4M!)(o$)X&K(ayHzj+YBIgi_n!?#3dZ@m&)>nn8VS~Cz2JIN@HKgXVE6H#so zi8oOg7!DhzVdbpZjG^EzuG+6>&&>}+!oIj?%;+%c>@nuJqtko;hbSzdQG?v=ig}L* z6HTPfKN<_WM}e-61-g5x?B6B$Zs28DQ>!ZU8FH=QtZ*nAFaD%&Ssp`XVQpd%NwHLm zW8=LYn8TB%qLh0hYm(VTqRHICpg9gehP`lHb-K(g?1A-T#5Sf|1gEZ1)Ree|1Xng` zR#Prt)h{Mp)?Sza8)_j$fV3qoZo+!pilyGmlQOVEpkBLHT z#Bp2#HTc6;W;ID#jZm*Zui@DXOL}8)P=-5+OL4umB7XY3ac|cUyigAeaqZgX1#7nH z+|tC6SUv18=5SQ|Jw6ti3F5|s8#-|Gce*aBXA575qdND#ekDou&-$1@7(j$RyNbaU(;GeF_)eWho9P>eMm`58D5A_)6+6=8IOC&LjdVV z{SR61N5wvm=uoeS)*WVA0}yUYf`_f3M~K!WPwP6VP!q!%w^UjZ#hiZ0P)3X>v~%KYdShrN)e)UPzxf+1yVbO=-nAd-$6MA$$4W;9j3;T%M(QN zYSlB;F~TEk3q;xQb~SyUJI7o=62a^L089OeQrY)Zc@|mg@(5(A2C7(&xqll$5zC83vVE(6lSY=Kn(4ZgtHho|Xxuv7xHCLy4I@1-i+KoZkWl+pl`W>O(M!vM8 zWls6InCK54{FKV?!ZDFi))J^(7VCc3`15cg_8W#_d1lYa07&A{`PQ?K_dOo#=^l)X zpv(Fb%ggd4bE&}L=kz2@4@S*io{$cNvOt8vlHLqeIq>boxYyqb_g)^~`$)zDlc&$Ul<4IK;Qe zV}c_grIPHderblIJfb(%7bY|x30Q9AzI`3T|DMv^chl&0386btIsah3Kg- z!%!BD{sP00vyS}-<5>>6zf}7Zbf=!KChjQ#GaI}(Hp6BW_AkcX@7qXZKNWY4i@UGfMP`Zxeugx8MK*+|cOdD*oG zotXW42{E-uUho5l?H7$ZfV`Oo9%dqaWm3-)6A}XVdfG!>BC1)+^4Wa~m%O@TUyqBN zitP=|i@Z%7$-4J8yr@Pjp zS%%c%8d+-QPKc&Lx+v$j?!4WnRox`+@^A>5) z$kv=^m1kW$B^2E1-O2p0)8atxA`vY~bf{PLk2Mu&xDQ4YpX#6>${Abr|F1jA$-(B~ zDLB?wpW~+X2VwO^`95+t{^`f9PS#bszD2U{GC5;JU_{Q-$CFQ6Y`>IMzJa*I_sKu2btipw9(H4>UOSTlJ4448k^#vMsz1$DACokUbXBoy0qEqEXoNVv@E4 z<2_!~rdD~#RFg$NRO-c+Yieb#Vf=V5E++wqIOaweQJ#UR(1Q zrNEQDi|MlgRR+Y(OlFhHdN7r+lSJv3#QpJfxh@nE4?rjgqtW;`;;W4R7lhmlPaz$A zil%{Q=!9gq#==?;vyo)f(nW|#gPP7($t=SG$kTqEcdF%I9iQXVd&q9(@dA4 zrYVnN^l1Eel*8|@b+Rvkx4-!*a7dgz;0YU9-%g7tJn}RGY*QHA_f|J6P*jn|mvR!L|~p`WjJtQP^B-Tk?k;@rvS<2XvAS_qFH1T?VZ-Egs9TDt<@LmU_BLmRFX!xrHDFqkTVgDwc5YO?|b;nP|<1 z5AS76`xa2-7dVXb=p^a%B#~jl;7O01vk!_JxxGGgQ9#;I=45i5H+Ax<@ELx%AL_fC z&C}}Rp9t`C-~HmcPT#m3_!6H$Iu^&o7EDKK?2=p9Dtc}bK6qu$+j&OK9!fFvZU>q;>O`@s}Z)73Jqkj;VKAHsN7Z z4nmP+ucJW6MSpk1AEWEFrNLQV&3l%PqN9e%om~9q}Q{rqFrb`qPk}r50o@@bwbmD0s`LaU?hHv z0M`8T^B1lIwXWEnYzZmjS>4>N=G|Pl-59wQPTPSYA@wDap4@IrT6Ofyx3Z1GbCYIb z{T%!EDsPE+a+!L~ri7D_;2G7+_sH3^(|y;|t`C{WLPr0%&`!R&5%cABPYAN@#i%iM z`ummX+1=#e;4e4G>(q9<&8O5LalyP|V|9H;S1M1lPf5wi5;PHRyqu=DvRl-OU#a|! zh|{Q7Z3ev`uwNR`2RDecwO0>s>bf6<^r9WAfL}0iVLirR+E{DVE*O9JQg;Q9b#=2L z0 z^zPhuH!GywM9^z+TUm{K*4!tnXj!|tX)&^(J&#+mVgG1h4o$mb>Qjb?hm0EtiWvoF zc*8z?5obnhfGBmV%}|+Tn};@>`saB4&2;a8aOPD*E<}`MAp;T7O1)zij^uPIxVC`x z;7&6Ddgu!~$7;+9&dt2CP_mUrWxXV)ZjXV;Ho?7KWebzNN9Q#eN@5qRtr8}J)`a7U ze&1nImyTTQ3)VwQ@UMLM2ISchTA{h$glZ`;bB4EP%u)JinK;-2DwGv$-y@1)u6B3r zgqc7%OW{umTF)-n713XLEXNH<)n@0I!9|@OlAo=@;E=w;e&?Yvb7# z46UIH43Pf7-=KuRl$t{)qzwW1sG>w_r<`n$gHqK8&-9`k|pabobi-`@4BgB?_W8If--^>_tOu+289Vy`m^J+a9 zo@V~yBLfJo#2k|BCGOmj{hDKgajPttMCT9;M55m|=ylbP;>|+eK$1*t((0_vPAmR( z%%q>30JONBZ(>E>Wv&d?FP%b}99vcquWKEp2%3omkm+o7JXAZnN6->M#H5}RXZ4Ed zla0TE>Jb<54sm2LA6;I|bX{LF?w2pR?j^se1(24tC=9i5EDl)bV?Go|EsUm^(WwoE(G5=B_>w}U)!2R`*1)rITxxg|0#VO}`K zl127WjvYT7K>+H2^FWRXRs{g9Rh@P;F-i`kgi|*}YD5cqej0>@N{f^tC=C zf4|n_QD*^gV*KSx)$vJg*UL?1!K(U1AwsaSXq73*;B-fDx5ys{0EV8Q(x>fDs!@-T zI1C7V79&s+wWXwJDzs~~rM!!y6{mD2(H~{QPz5M!n%eW}ptq5n+6+!*=U(mQ$!dYh^Jj_f*?rlcYM|Prmjt}^ zpNAo`6w(DZ7Fgh88bC)bG(x^W0r^=cDCc_UUI)n?`p1a$gnpD$Q(g%Z0=Tr;=)E2m z&>-R9S11N#ke@f-tmfv5Y;A|6wX&$N`Hz_ofxtLe@xm4bJfZFtZE9~*<@|YHXh5Nb zQrq8AmTHK}Y=SjxA5{Kd6=*1AnG-p6tG#C~(C<>USpcooh0 zj~{_T{rdu6ax6l8J~RxEf;AfU!`!JOdBh&xRhemWS#oxD2&;8xd46`1j~b;)RfE$> zB5u2tg|!qXgA3xwQ_gjvpdNl3JRrtNTbS@4>tJ{5`cA)tZc+loiRhl&Rc&PHTp+R? zDlr!8f6E=+N0VeE90eIwgOwnjJ&8NRI=29N=(f= z1WbU@9uX7OX)zxDansK3IdxCC(eE~qvGn44HGati=XQ)TewP zgAwST*b58PL4Pu$j;9W5B5HRdaCE5Df^A50jRJbR;fOv%H1jSarHio_?P{M451X_ zaV1?;yi9^yUB3eEN%bDxS)t*E!Xky!v9q^oMZ%T6Xa`cFcdI!NkO;*@b27N zNee_Xi>bdShO@A4i_GPa$-?~Z1y7a){fEbbgAR~Em`PUV44P!7seHMAr$p}zRLLK= z_Cs8F$dHm@&Y@XZMzTG5OqmL%)XQ(*aM`P8SoS>L@qnBW9dj}`aVBDSF6jJa|l?7!YBF|8j`YFE@D3}HJin211?3d zt#9WZ0doa&dR;2&KLzEm)YTVK_syana<`<@V2f~l0D6*g< ziY9L3v2fFPuVRW^?NzO>X$ct9%#y3LB@l4?dV?me@}l{3e0XoalSxW7TyXL+zqwNc ztjJ*4jIX-gZuWg(X0O~o-|T5nS+9wu<30b(dqnBtN8`uc!h|{-Nb)BQ&UvGL_=1Lq zS*A@35eBm87mi#-k&TM4*;l$s341i?$XnONUlQBW4vy2KI2E(zaPf9Kf9evbH@mV? zSSY&eoo;nVLGd1=TA?d517M+@KBF$bP_qv7Tw@8mUSX(F5Om|1KMESZ*4)iIZo}~Z zAsb1WQJVP>+u%K3`Mq=b z?;^Ve*>v3y&}p>JYUbGf?UC3SR07Q1YLSpI2a~K5R2fogjOMtgk2FqX{H9j4?(-*;)%KfC?9!&wpg(%3;El5r&{%P6 zZfW`laOVkh#Hjihy<4e*mmKkK2o5O{;{n)*A%ltnnhdy2-TS3^JFIhyJ-NqzL@!8 z2SBdpGEzyj1<86Ik@p)mdc+(!NB@rGW@i17;{5t@8Yd{OMCybrw9sbjls%sN2|ed! z1iww782magPo8h&P|mb1L1j~pp`qR*cC?Q-OkPW1z1y)pZmc>-1mY9TSyUElPGw0x$^5v*^L z>JV#1^pFP25hijKMaL?WEuV`leNIrW$096BdW9-nUtP~a_yF)0o+r?!zf9_6B?5Szm>~Yf5l!SsDmb*V@N@$C&r-X{H z`s7M1#eJ@ryS0e!HTWDs8t8RI{yj$~6rYhph&|jIS?9!TmE`^0VzGHQnWY^M-7y28 zSh0}+TSE&}!UQ_;1#KtJ1~%4E19BrzX=am~Z&iNQn1Yoe;WhtY> zic$KE+5uJS2k#3l@9SZn<2uj>GmK_Pd@?DXr(izBJYd3wjf^mOA66aacWhS&PnYV< zj*_K*3AL;NaA&as=`X0azvK86f1)5Z;NmB{9u5dz!zRj1{gEwai{$u%3snU39MOvOsAbJM zs&$pW-P)s6Xw+nwd)yZ)5|hMN&?!@wYs{%6+P5UI9}4@W$e*KWtp*WP zF9Q6PMnw8J-~Lh5C8c^i;tIF4EzBy)CO}va7S#s~2WbQ#L?2zuWR^OwMP;Ow`X6VlSslLK&#+&sjOLS(%4;%rpn=XI1^tEX!tdkBSC)Aoc+XRysyuqZMPsR# zR{u#IyMppd6b5n+1xDE=3a3e|$3-@LLzQL)Oh|`SRFxm|(DAdOvL36};J(dgm9}j` zB|Dm!Ul4oZTPfi(w3n1BxEVj~wvVbwsXaLNCYomy^U`985rZRE z6txfm|5x~7zGc5;IKeA|^rp1zeu(^h*K!aN#Qger)$sF%9}a0GR zr<9}#JJfwDeS^sTe$C^4=;&2Pf54WdW|DUNXkZ~LuOc|&kAjd`JRt+AHyev}E;TWm zV4`Y79`hq!md8D(`-4A{;DdWfwe9WsT=@NxiJpDjnBY%O>1?m}mIxcS=az$`h6UZC zcyC9NG1o0fuE*}GJ=zeQ_^f2gnPc-qtCs54gk-fZ5CFBP6(;8~usR|kBr~$y_Yfpi z!JYIH$oWd&L`y)#xl3|O6;;A1_=Ym70}(IU0~AwWmZ_ozL@sOaCk5W&*}uvT(%JQ9 zqx=jd09N1O9Q%5{%Z67nz}aK81z}s50Dz3Ir~h*EwAiZ{_j8hw_^xftz8)>*wbgUc zVnyzx0d%;R4Q^3rL}ta+oaJTBPZa;C=A8Aq`4sVS>jU40PK^tP7d|}m!t({%Zk52B zfs)h+hJi-LyrVVp&T$4`?H?1N^P~cc=OLxOfcUhZ$W7qgrV-bfSXZHfRy4wCFC9(j zSjWJE`SGlf>GdyCK~=o-0)XboebGU|KMz+nu4mmG+v%{2QvU{6AhmSyMvF$`35XHc zaeTV?0u@^H3Ho~G@J^EzlrhnMc$e^EN@D|r8zj|FqdsAu?Q zR-6%7k8*@uZ;25UiG*V+p|?kKI_$%;_d-Aa)ekmqbW~1=(b5nd7qyX1TOPJ{9Bq1! zwr;(_X}x*J6?u}{ZLpGQoc09_s^Lm(TnQWYK&Pf-t1*s(y4JqYv1=jV{Gzo0C^Tf-f-cMkmmFP#L8?`~2a?7f&B{M;r_4o|Far1l2S&uxD!C;-GM9Of zQ{-f6&*hK-ZDVY#a}LB@GaqZm2^1^`Ku&OK*Vk=??Z_*0BY2YEm_&ZG-uWx@tFe~$ zd#j35o}92hzx5!#Q3liuQRAEIIK?#N&v0}Tix8M>+-U2m=x#TDK){@bj<$5DtChai z-{V(YM7cw5!}Y|pb^f#ux{*YmD3;xtz5a4&MNLCflM^$l~*m0lx*3}wa-*|XgH$}24r-*Ld7WwfORicjVZQQ!xOfheLvF9qz_H0QJ zAlM;~g{!IYi(`5qH>d^nB>~>cOq%P~td3Ny+BUG3n04EvsPvl(fIj{H_B#xJ*Z1sB zBATa0!*d1+Q;ni^PH8?T)Db?|z63(F)>jsgE&|TZfzRbHgdG7t(t%U0R(t;<>`_wCAigl7UkIqc$>5wFA;4(} zlmZ{t(VX2KYL4#dbz&-pZ{R%S0h>qg39)>(VWnl0uM&iC;Q~g9yp3kUha;BOfui$fVWHB6Z0c}70P@Ntp1t29Yss`%30IJy8Q#U zRTq9FLF!uR6nVf;$@`K&{iuf9Z1iOn?UhZDD_x2y3d06-9+n8tOaCa0(9K%DKwWg6 z(A%3jFfG}kX(omnM3(vvfnBjm6U0LtcwDSF0#r^#2|Q9LKtazXTbFY(cZ2 z>tefHlG*!Jjzs0s<>{!a+ggfV=<EG4bDb=x zVgwvWm!MlGtS9cy_tUUBE^}{(=szUc+ks9ReJ^kJ-fX{52OpEFe~K6#ZGV2izoP&B z3b5`;rspFskt=U`Xe70ZbE>J(aw39lDZK}WjS<5e)-iT#2MmFoc7UQml;?*40OF3ZM>>ZB;?J$a`fM;gr`aX=^;Ev(R`l6E7_J-xH_-%yZ9T3F=bSP#TY-}*;`+$G5+J1(Cp!HNp81phd#QQOnB{j=C{ zoGnlD)Cm~65mrwvcKaSk3%&jPkpicTf8eFO{X2LoxQtf~F^_^jW)`||0nLXDPdPRd z9zv{UJIKM|G5i+mJ4RdVJ9{&S4@3d0kpMPwrUyYEgax^-&$hPNrg+>+j zaoeqcg<&WF?Eifqj|vnIHWgF`G;VWG0zw27gw0TKDZwgF=9LG(GKswVq~^(jqTeUw zIOh`R2eH?(O~+FWTGetrqg?@^p%z4C92zD~m7Y^+3W8*j$V2D+e4tbTGO#PM>>);K z!rvM=CZK2s~Q6Ku9{(*gxS>znG4q(V|s%EBUFsj!8j4EEOQco*@zj zTb5;Mm6KE`YTtmUOo6{lSVB@NUeT8%3x)|_t+vuLtw6b{NJX>{P8cy4B5QFTj_#!u zmK+yGO-)zj3y2Z(QJfTV>m!D#+d^A&Zqm`J5M^W*MMZ}}yz;{ogaj@B6EUK|f*|A{ z+^v2qA6BVEe52@ypG69EaB%#los$p(+|=qG1Ap#s_?>!+Gb6!4d5?r0Uk&d-6c?oJk_6@l%I#_9j)kraIlA{An380K6z1%P6_g8fw&Z=8Wi^6nV-+wcSDZbi`|W77i&uSVZ7|#+`fh`A=erJC;~4G519U)OAKdA zO^+`0GaR5^f*C|lh*Q+ojFrSSA)y*0f^-`PeTB~!NBHL?==Uwf2>n0lU#7yN zmZF4>Fm+p`N{`SCI7lmMi@I5&*1$)`afsV|)NQp|hvaM%OaT^1=6?WJ5e>zOuyvuv z_g_z!3(WTgm|&lxYQ-KQa*@SQu;sq0!c_H>8DFPz?Vd1 zPJ-`k6n;`k0+MI5>(yp`@Wg}!#b|=Hy%vB(4ND`}97aV&m2++X4F~*3@Wz{}J_a3~ zgwc!4m{tD%S4J}{nPC?Rr-zPesgc(AT1V$`z~b#`9MiDxw9rqi<(!gABHtVL2+|WP z-0*Bw#Od)zJMiqINUASt)3qiFjg`f%$AtOq?;C5j*cT9X4;!7&SETX1ohp@9R$_wX zNhEL+LkuD+Z^(;H@V(#xk%TnzuRvIj#=+<86b2;5c&*im#is`>jYA)dOjxMx*FQzg zX4_cggFP1WUFc)_fOb^)ySuwvz?6FmFi|2u2?uftBmu=!!TDO-%;i>Jv6c#Z3jzB) z9A75G`ijbIn~Mz&5TZtn_VRK)LRMd5hZgyjH!UoxT9>KXrEj)fd7TYFO<)@8{cI)Rx`jB6eNG^!DxK7MX=iiEz&p?9m1yb33G0CR@|b$Zi1JAE;J0_ zmi}}9jk~D9&?T+sc?Efg;%D$_40cnXVc;Y2B-?raY*GKSr)aiGj__Hr{O0+@M!pRB zZ51Vj-G;zwwK&4V)t_gdh^EnX)Ci03+6Mlt8TTrKZZNT5i6$w>yZO-M*Vawl#HDr?Q2}3+9zr2L} zS#ZHYrY%>SLqF|dR;=18Jk|JKFNKzkPt|dlgXoZ>>P+Vse6~hde>oS*elk+JX_&kGF^TUZcxR0hYI;k5DgGaVhAo ziEvChK=d^zFQA~hp3kUXkR8jpMFDbiELQm#H+{QhVq?rM-D~!tjPysRyI0}c;gVW1>sUyVk(MYmV>SJ4LYx*H}d16RW(q zbbZ8E*K5-KD?qi?y-_nDsGy*`HNYS0?if0+&5Xa-eaQ zkrGQ4p5QEJ(=}#)pZv+?Vfnn5_gQ2MoOX#!>YHI7Wn$r~Or#)8WucL!bANBXI&*9( z^MDV`Z513MU>~AD(o4_O?n|G(c&Y3)T$Ic6z0xApCy)y(SS+7q(tau&hhHDe3*hqs zeQ05bWbLdo>rtZ8a@zTvG{6;+HilGptxB|46gvJE+yGvu+-2#f;j_ ztqxplf=+MY{wY8Q4TO;R(p?0dh#qWS`h8zZuwg!`kP8f^!(!-UQF`=jik%OgPg2!r zN$o9aD}HSx=wzK+m{Z8y3zl=j-C_@N0tbmk)eqdwfX|1j*1x1yeQ+(bWXTb685vdt{Mtm%4~`%8Kq$*B5iP+Ooo)=W$RA{dj0R$RE8Io)xw>)py^igh5@H z8kd}L-GRp|uF3|d*P2|a4KmMIj>l$ZHXSqWy9(BTx8h)2K=3r zpg*W?|7FM(*VIUK>cx}G-h#^(Nw3H2`s~PPwwuP{mDIK^B5BDr`vHDDfumyzwidn> z-VT0xkZ5GBCBJLL?^P^6u?+9a#L!vk`+}++q!Xr~zvS^p3P(pAhz=gqu*AK6$BPW3 zQx}yy6NgN8(H4{4zl*U!CW|pi{2_Y)3sBSDkXWWpKanrt$e38KeKvE$i8MgM1LbZo z5c4S1ghQ)MLD$=$hzX6lw^fz#t4f5P=5C|y(^;>}8~?2O%~{!1yMSCVTRYKQ2o8NO zgVYQTstP#`j3j3dM%)UC>(eO$B?Fu&W9Tog08#9wh9k-hpWB?wS<2@^UQ;Np~tX{W0qmTZD^OPOrOzx>%I z#XaX1wwY8Xk;h;*K|Ju>IK7s7o zR8?BYFer|^A(fJf&Ud>_^u|7?PvV8NXmPKMacnN``^*9gO7PyJY#t?cS9TKlu<4meZ>G`2#`smknd~eGa7}{ zH55Z|*n1aontUW)V?W;{Fv}P}X(6xy*JQ_-@D2tf4jS^V&6)wq98OisP`Y%V?i>F$ z%~iXMlJ@fTpXQu%3|QLD8Q<_B{V%4_Xg+0r!h|>$VbR5*pcjfi2v>B?p-dl~Qpj&fgdbS7qV{ws*4nr|M{YC)erkS)Htsl2oRCHXFMQ)(W zFS-&^QWi9TcLg~|iQcMCytT@jDUew_&jQwZC)8xRNbVp+So;057fbZ_XA}v155x7S`FD|hf zgIQBH5Se`XJkm^LZfBhrVr5z9%$;yVoDN>o-pA4lEQmyu`&*TVv5~6H1YL4na~q8U z7)$^NOcGJg-WJ4T9umQI3{=mWAd$GZU`Sh=PF#3KTjh!LLzlOT&YH>`Ynz8l+e)3w z-P+i=v`d4m+ML>kTxk=oK#h1GHV3fT+R`Kc{8I%bP!ggbmar*r!+r;vMmxB{<2CHg zA7yHXDu!tr+Qk%#YAKUB(j;} zRIjCIzCbDy#kvY7Y!8lJ1<+~_)xH!4BK+k&^;UoXK6=OjJsG*LF{8#uB@Qxyw%_vn zHlfA-Vn?_oOEqKI^mP@-qi}+4Z*ErK2t3;i?GFDVq7#4V5K!Zn9`s~aA3=<={RQ0s zRy+dT2y2)m&}^uG@p*%G5ZtL9z7}j3yl(YFd9CD-g5Zmy0lPxn<*;kGV9UiD=v`2U z1OLAgmbIYe7>I@wLpQSY=W1EiKiz^B3+$HuWys_Z|Hn4u2zd{4dH=s-V(u+}C!=%Y zBq3fF<85VFS`GYb3_pm~vC=BE~;Mcab#U_+@3&Qe( z2@yt~xI9IxO7&;lkV;pdtwme{Zd=4puJ1>dy!ZtMcL%nKgFQX^SV3mim|w;3R&mWa z@7nqn`+$3^|7?_h8e=;y^LZLv&F@;OJu%@{oKf4n&CaZ79KErO!!q;6a2wM*<0wna zdDYcSsJZ^Y#We?!9F{TJL|(3CWb>EdGeL)s|E`O@npNY< z@zxIaD;>M^H@oyB5(R3^C|hNaVHNnqfRugocO3^Bna3bBBz!zPXH3`Owls)88A!qK z;jE<3c%c6XKKC81Z)3WZ8ihgD96nxgv!@oJeB%6Xanj^|SHDVa@Gl^;-wsg)ql&L@ zY*F*(a%c7%&_4xM2&6zfq)@*@Nj|>R)+VqzPI4@Ng%v&8y7~wGE1kP~I77oqplROQWzd&Cq^(bl<#*2Ru1SRjqF%R_EcRW|Pg*{(h3?ELH> zd8IKlHWi#=*}L2OnwvAB8s+T+^^x(!an6bHHGRiT4W`gx7dpv_+I1zxY$aT3)Zc+6 z2P42g@20~0+IL$Y1tXpkCHplZ(d6Ia5ni^ZF^aBkt)=?jLWN#5;D+s>Jkg>~yFK1^ zAz-1kQjL=gTJU=Bhd8q|7x@0}ZRMus!v3k~g9o;jw_z0v+Y2wG-i?1;_2*dxSaI2N!Yiu2-6Gu@p8cgeJUkL|(gEk+X#Hz^o7kP)f7Y9V^#Mr*uyg_&cEnwt|&jAML<@kF%ZQul$=Y5x;XC(0K2>YP%!j>UP8gVVSVP zlk>GG!xij)%_MuaIF#*a{X-{;S=SCWitAWBLEVjn??fZ``DEh_bP(SG{`z!rg0~C1 z&SXMR$uQ3jlK>N7H&7T-WOjK_8iZ3B2Jg0o{j62fSa-{Q(te zsMG13dWSQe_w$IJ;rn^p4)}$KoV^z^d9|$bS%+80>x(}Uzn|XgK6?a5K)FAD$i>Va z|I^p?tNU;}4(O zm@%2fdN;WDjpVLgEsQs1mqR{L`ez)3BA+PA|Jz&9O5Z8vWJvj6G# zZd%XMWnp8xbn-e)(R;qA+UmIQAnd&9+UQ~Ldf%Y@p397f9!^$n_z*i@R9Q*ikd?(u z^1Y3DTl!$7XSPgKss#uP+W9R;&~q}uPdJiH*9Y(*qyC{$=?bb;(!?6<-6;KFiw`fQwX#zkRTt$ zeQzpl2=UelMbJMZUGv)Qu@UKU-i8F=rrUd=v{~KI);eC`?=L=`Q4hM$vX)j>B02Km zZl^e++bA?`;qo={@Jxfsr!26Ujv&sc+us{)14v1Sg7xB{Sp^3y)#qGb7-XMWl?Rrt z!V*W+b|!o}V2d(rN$9;-(w}O&e4gYkFFsa%!#A$UPf*g+aISKYynR_~>8|VFxypaGEt_0)T&Bu-fw={iPx79f%SzpPk1yb4n51gjuHAiX zZG=Z4mus}q)2~e6+-ARSCpTX@RrQ5Z5D;#B03ImNKy*D9-^0_#pfusb&a9GbRMXNh zmmg~cbo=AAVut6m1jqehp6zX{*w4M=hR0nKda24`cIM&)sMu<~_k9;>RyRlrsRHr4 zMTh7>j-!0EtFDbVJ|#ZuK3oP4!iUul5Zu_h@y!uEVf+)k_xp)5J3uSDl@LN3$$FS% zWp>sb@s(NLAamo+Wy2TaMD5B$Zb5{4&@eo^Kd2)8a#?9&Ac0D0s?mwroI-AzD*&^Q zB*WvpMHBxsZ`AwYg@3abj=tN0q0_f)@#ZO!!JD{JY$S<+0`sfWk3MjGdnqk$a;C%) zQ8wktC%J4sa0|66L7^OaZ|AlYiL)SF8{@7gb6S02|DlQ7l9}oxUM*p;qoyJ&pR1FN zKVfg=FQ*Oc?|tHbZ^E&dr@cZ{{<)=6`8BQEQAF{-yGk1e{3)y?NY;BNZGVdkpBfDz z*QrvL(If|EhP{E!58gTU9e%N~s7g`G+-)3ROa z0nyyO3!z^|_tp;b6ViIZvhQwpbCh4moaroTJojKb30vj5UUsrC2PS-ypW4bR?kf`UtN9dHTll z@_N&Jh+q>T(FYSj^m^RXwUcLJek$DsX)U9_prAMkcFiR%-}jgk?F~OuC?gjeRe4Tt z%|}_bQ7uYOiJ=i}{NVP-Au(TeC91auH&HUCe0_cW_Y>R!ZWkKv z5#!7RV1gB`Vln@B{LgIvS|4->HZh-X-8c_E?$Xe!-hy^GU!%p?%;I8rlCF*qz=v^F6veKKFM zFt2p*?VKD934eG-vD^#IdD=v_zgs5xJsKY3jBUB`Knc?-e68m|0iuPvI7NK!=ZQTGgsuT*^dDS15+Sc~DQLyffuaUn8NO5liG zKl!~0ITk0RsV6{R&LdB%y0Y{p{M>FXCwyMxX%ZsCV4}}o;>e_G4s<>Aw_e>Ay_%L> zAGd;Q%w~-Dyc2BMNnbK`GTXt6TI;b$#e?zep>^HOU>KN#trl7vFv9gbVLWObaII{O z62#!iAOv;grW-?kr<7Q8OvmzmR=|6nY`v4#x{Py3{KpC6Sp}le6O5Z;R~~6veNifv z1oKDn0aE*DZm;C?)g7Za1bw%%^v@=czDpe>g6;&u%*hq!7ILisU&Un1L<6%9Ty>sg>q9vi9 zGJNeKvRtYCt+MU1=b?WMcD1@0BS&f5X42{fXqf@9OR2 zrKfs4)w@(gdd_W-n_&QEkTAGO*O54ig(`+-o}zoeeV@)}vh_pV_nGXon01m&u9p`mh$Y1ggCp*xP%A_m|KB+GE*)>E zr~k(58XHBmD5R;wuW;w7W`^j#mAL8{DCUSh@?LmCbq?mAm|%l)1UQ-R+P3~qY{_)G z2Fe;(_NqzmN|V9@ew`;Q&+RV0QL%8iMVbkmgD$-{2JQQQa}AwV{AC=q%+p<94$m6+c$rqa zbe>me-=C`*53sy+h-Gk=6{dy~`cs~4B2~m|HvO&rVeJBy8e?Tbt@EB$+xFd}W~1}v z+6ygJ`yZFo5BxoMQ~kpBh0c9#?YAl){pJwiXRA_XV-Bv&10f{d-Z!e^%GV7fpNPhJ z)va{J^q3d4H-Xg}GnT$svSXmQXn*bDhc z$?OqF!ftX;+kWMA;1F!fG;>*d$~Vi5aS+D;5lF+)(ecKy9nyDo73~9`-Ery=gT?1_ zey+Vm6mL|*!4=?7Q+Ca%`o+LL^Bcw$6SRrC*mr8U&nd*5kC0#-a-Dy5s_vr+w1Hw+ z`>@+!Xe^XdipNC@1;I~*Bgm@Ef#fx(g|$VK><&XM_DDsU;;ah@a~>&$!JJ%by+E&} zPE&L_(p8ZOzCoN0<57b~pJl163JR!(q#=PhXQDd}biX69#`T~ecj=VLQL7_}CD3b> z_1{pNZ5ywIo%KaUxY=*L$@O06e|HW3kEOE?h~oXaxQfytCEWtj-6h>1je>Mamo%t! zOE-u#C`)%pFS&F#3roY&z3=e-z5Kl}!|XFN&pqdJ&rN8{_1^v{dJU#iIc&rs>bPLL z7S=Me8cll>SF0wpE8}QJJJ~s?Q{JdPC^XC-Fhf$D-_nvPzutN^;b~jI*d&lwS>@?| z;u#>J591AqF^n1)!XFpDi=I4L+JL3s2fU8kOBfg4% z*>`{;_}k{Ubb70L5!QL6I#S~_ zbrG~uFhP$!f*JT~H$g{}p-_1_2v!7o00uoX@sKr^GUY;C+}@@S#ftAKR6svWB@3BQ zGwL4YcMj@>O?x4H*?W2Z1T2kC;WGOSYsjxf^i#n!)MZ@NEy{?Q%p`7iA@I_;fR~`R zVW#!Dh03XL$%qK?`siVvekxx~2@coO!-Injj%F&Vo3*|Ntp&z;bPl)hjD$UBPZ#4OH{UL({wsu-9y0^_$s2i zbloVDLN;EplZdOPtD*f)%zmZyqgR8(m8hP;AHr1sVOZ&E@A1`QkM zdaXYapAlNf<*8-;G^ZFSmbmjK_dM5Vovi=d^0Iev>VAh2b^bPBrco;xbN*Zc zK8{li3d+730s154%sGC88gQ1|#Fii%zXe*K^AxGqQ3eUO0;3s-r|YJ@j&5M^NG-Ju zah5%GnQZ*yUvt|Mhzlo|(+I|sv5$KM$Bp}xOG9!$S8rwnIRBBlk+`^T>FBKklU>$@ zgqvHMz3032VeAGu-xXPXkRKaRNLIZqHb#U?<7`1gZx5q;uwt15a+R{E z51Z~Ny-s_JtLpM~j9=9g5f=`u4ebx+Io&AgD+%# zTlbQ!yRCycqZO{TGC@89k}CxvIz0C1809og?61cr8P#!G8dyfd){zKqKjh z2%iHIWT>q!7g{(eUU{bJ^=cyxhGs%OZ>NdOd#fK1zthdet4EY;@OC*!NS&8EWl;P( zpS|(zJuEn*^TP<~lF!U*egXBh^-LUzQyaq+a=8I6?Jnyt$np5-9Lr#^Dr;_aV1YJR zEhX0X-*c1`Tw=lj`Hw6EwiWRd9YspVoC>c5(_{~fV+??_obdxi04v9&jDvO!XtC`%r1Y` zv=6!~coCjB_Mya@VwpQ9teclib8e^A+pW&uX{GvAoaikvLItue!qFt-*f~|UqR+PQ zW~}PdoKvmU@~1~~tnDF5%URIsx4!0uBq#JzHzMu{NeE8-hHP{R!-X)k>C4JveZ%Qs zdenX8j%+(AH0$q=6!mQGS5d}3Xkk1xl>QPK>3mbnsi2D97=hK_4)R|XSs=ohEd0T} z9Ie5!Q8`tHD4ap1mc==K)i!o>)nUMc1Rz2pK#5XaI?(x=%Qa~ncnJaNPHU?>8W3`M zK7O?tzAhW!I4;ngX9P&0x>9CZKPmbEiCp{H1T%^;DxbST`k zM>phksa2f+<7gS!QQBQ((v$=Tfk!y$f0one-EVQUj^|1Qii-!%7r*AN22wR2q8O1xZozasRP)n37m-tGTSKWl z^MU;AqGvDueCi+-dl;Vj7ruW`T62AqsAZm$&3r>KXYyzSt@*`ZtTmgsaE=ha`l#lJ zGZ)z5(2T+t{Zh^5k2S0%I(=%}##{GoiFg8&#kW!~ts*tKrnBVylV#6EERfK#q5IdL zNaZ^(RTHt2=>j82CPPRxu!+IE*TB=SFWYlvB-bMylYQ!5PH7n0grbFCzOi5Ib2?l8 zm~ucx1IaTt8!UKJ6v?|57kFEvo1zk&;GB7tGipj{hw_fLIKMm*_FiZY+$~?Ui^~tW zZk#~$pOw|w?rpkZ=~&+do4mdlU<#nv6K)#*&#dUH^jP8s%c!Y4@zkOAD@_}-ktfnP ze30X(5BW~c7KUVsQ6$e{!M{D}0*nR5v=b>k#U!$ryo?F8tUPqnu#z3TJJ}ox3}642 zrHUl?BJd(})pX%}*K1$a3A$dl+Hv0>O$~*w<;@g{@pU&O{`u zOUZIOdrZ0f{0PO!ZNWSVbulKnVZuTUTjZ!7txq7|F5)7zHMe8op=aI7N7%AyZJr#D zWH$UtE+u?rRh_|IWjPl~9{(3{dlIG(6Zq+KV7q#ETqCeL>&xDj6sC%E)s*K-aJcE= z4iEmUdf=z{ebDXf19(K-Vg+2~4@u*;)xSy$f7y2ZZfRA1h`Rj8?@vaak9OB*1i3iA z+3xo)UIFkZQHOwR`tKwUM^4_8vg01;U5^8Ch*XV8(eX*sJ)R=f-hL9?8BycXWtzYY zZjbEPs|ruUF3=_=zlk91PtC?155tEftRH1xoy{a~gp)SDkbQwHu5;?1Ab%1N@n=Gs zQ+Zb{O*oosdM;%97Ha)TEdj2{k3KXF{g~gDoJr%@w5fK#juW^M@EkQHu|KJF627+F zz?FHR9sQdn% zKfSf;J;@lY-tfCO^8D4`wFJ3;utDUi)reSzFBDswh;UT?Y$tJ*X}QlWTR|ou4zGW5 zAh*f6$;iZJ-vQkOm5>NI8-iudrBmh-(HLeOJf=j}(xzvjv}7+`$qQyjW%yCgOA?US z+cth$<8+TUX1r3!%K#5^FSVj|oBIBN&>N?#dR(AdS0=aHDq2JuvZqG8C7Y0;omEVh z4rU5-A%Ssz`sf^-|H34+ZE)`Klp^;7$Kdg6^H_)7f_^2RWy+18e9Y_Qa%4Fsq?;&4 z^pn4{iE>hF-6rH!YvXvYxf8va-o6S~E#3a7=I=@D+qk>S6PiK9F=0vC(y?f5IMqvX!vb)bTahb9ID+5i*#`n0*erWe{k;`99tn1&z3j=OyG+KSV zuah_bH6EdK1AeAA+MrNYWLGI&C-7ss^e-A1 z-lW?@o5E%s8b;;+k~^d=t%pt9PxLh~GBcx|i7eLrKl4{gs3t-toOj$g;TPZpjz(9r z8OppS-P?0ng7*)Ea3;o}#pYQUT>d;=cLqP1s4p{PG(yoM33sbIzZPJB)fom3X8l|P zEyI^dQJk0!C&o`MWs62iUYtAh>GW7OWj~Kv{C1=>fgU>-;iI60!K1lV)2srprE2Tz z&Bm5xtZXA1moX3S+=&4*E}lk3w*n7`?D_1_;1bz?{^8YYbeT{73a8i+^Hogq`U}S+ z_MB`*Um$>~iUsUwe*8^HJM&9Rmd-8!yEQ!rOu?^wNhAg7>!2d(wo*!w|2f=30+F{B zWklVc#Hw;Hp4?Fpx}Nj%FYUAiUB;G4kq(rEAN&6IkmS^fu_?_E$~duX?#!u0XU5&6YX$b~-@{^HV*f;6;qf+Efn@JT_h z@BgKcYZQnkC4OcY%0IQ5knU9Go$mhMK|VM{ec9j`=$jtQTcmCn9|nBuwaS`*_<_NL zrk~UC!iR3W1fwaIpbjM6Z*D)a6FNz8(l*CJv0SSg6o90nJx_wyNs&7X&GA&AdT+e4 zvi`5lj=-hO#>#_JGP2Jqc`G2>wjUQ><`r=#*!f?^Nqw1CApCE^5WZZFNNSUcQ}1ML z`;*vXy!igDT(fJHo8iL&o&Ll5!^xS>iJP}>ymDIAm1$bl@p_Q%_R$fguDF=0uev&p z1VqZ=uPgEVueY>IPlkz5jkWpqFv-19k`lcte_>xgWXlE6pN(J=*dxN10zISd0FYMgRIYi zZf-o{kMTHw0pi$O3KEokja`qhtGE+5YP>UAc}C$k_S|cv2_#2I_X?O^-2K^eHE1(V zh{4ehFwb0;I}kxpE6$Rw_5%rp*AP{K&4NU=_obNYI~>T@>>{~Q^Lz(&{ZfZl@2c;B zXtf7iNXN;GFU0dc7c7vz?ggzagw8!ZOqMa!P5Q*c^6Z9??LXeoN_0fj5SiVsgqcnA;GoiKYS~E;ex>kS{wgx_ zN1w!6uJAC|YmbTCABwv`pQMDO-|X%^$T71?M~(yJqID5Tcz$eEMbT1kf6@RE?y6p=*xTk8bPD(?~=4r?3zatG&eYIFc2j0G_V>+)2*C5S0kr<9Ez*F zE7%3=O#d>U{8Bso$z=7p$Q97_j%1zVZRHw3ov7p)ssG2Yj&xtZ{=J<63j>cU4IHYa zp8w(9+KDvwIzyVsQ7c&sWSIgB>w@^*o2DP{XZ?mo1bDUzsUWOAZ>+OiNEy_#6d1qh zae3r{0-qrsra3kT7<2wj&l+V4k34QX6L6SQp<@R3NbdClbL>K%HuBdy^5Wr{PR*|n zt+&R4HwB5DRfVsR9v-}aK3jMl$PX7kBXf*9kEEa6<)sz(#TFK*byDC)gND6j9Y03%v;`noxp{1 z51sX&SFzSyQR^EL`)mKl*^6=l`fA`3JN+NJo5G7y<~xi2Bi~j!?(@1_H?f2 zIRZu=cvrmPizh>?_t;OG9(*7!AT3pFx6#~XB7$+P&%m*BqnE?=mHEg*UE_KvSy~s@ zHxIknnmhfj18`HVr5T1UH~uK2xEqNc+BPIN4ivC{2Ie7LZ|aSLk9Fhp!z4TUDLhv~ z#NM#}17d1}l?ih3$iiQ@Atsc$0187cz%PIUFvO!9jPG@8>l&V>=<>1i2C3}Eqaw?r6>2jy zRB>ABLh0qC$AOSSFIw*Wk~ybifBk+DisCFk+Oo6-%@OU`W+}FejEqL6q7=6LJ1JbQ zW1oI{!>V8Ay7I9Vw62zvaX;g)E=Y>>|9omA%|#p(!|R;<$mDq@QR30bY+5?*52|!qa!P4p+U+nBQT#{ih=gahBx3Dn|zoW^Wy*(*k1C+?&b7{TRsj2Y%IAJ{e^z@L? zUetts6;NoNl-7ty`)@k-j6^6!QG!UxmCB?>mGdwy4P@vt0(y+5}HW zwl=`Xz%vVTvNl052Axsa?bZhk!UOH+Dib-26USFKzA~V+oDelXxol_)5z(Y{9sAyj zdSeZx!w3KQ$iroO`u6^TN{=UT_|uV-q|2o{*_+|qupk^kYH?jMIx;<@3xNvf66#mK z3oTzD{8o{0Hm(AjUmUlbe@^2wM_w6G7=!>arQzvJgZ{BJA002q!a^#v3cJ!j5P>4m zBkSacWL4vqND{%oDVepBG!s{`Vm9XtTImZbb2ZvsP$17jJ`a;%vhrPK4mIxl^A)SjQ61yUQ z92q9A?T{ zgDe$mZ}H-3`^~hg(L0tP&ZL(ArHeEkHM$;yQOHRA|UbMjKBo6xHCdLbpaPdzZuM#%|PjCoFmymutS=9_A*mK}+n;ZlKp5 zeN-Q#f45}5vv0HY(&An9_{2oCiAl4^XF@I2SfRalOFnlLr5?bptM}gf?7B@jJY7|M zcq%6FvoD*la7!ckdxmIrzw?etU`SN)=|^I{-l+s+Ic=-{S^c90rumuHWf-Q9s(UIE z#upFOI*$j#`iEliM~(aa=D^M7eW$hl;*!KTf2j0<;gu2-3HNM0O#G?=xtPs$F@W^4IXW#IZRN znb6hw`35i(xsNdLmZ!Pdm-<1ZNF_TK<+vGZvRJh@_S@yma(#$3$#Sh97jm_PSM{4e zI=VG3D36<-SG0R&zAhAp<>p&fvzJcN3r4eL0d?a+&A+`5v-Fm&T*u)%;E?SIedmLZ zX@TdvS@x(vlwVj+f?F}syt4d@LNgcrEkU%!QOqoEJR3n`wWjqXk|Pf+&p>SKmN&ua zZ=)G(l^GRyRag{M#$D6tPM`Q&OjC@om=Wf9r20>icqx?0I+uJ_gyFduWL%Z;uUxm8 z8B>5uA1xjnn8}$3#>{t_;CRQ7WFuDETi}y6dV_6_QOstE%2#8vw~jMe3i%s;_VM3S zm0m29u-LaU_R8<*ZK1m%Yx;{W8UTKdr_tV$3W!^u?>6<=FdY>KibDWgm5iPBlSl~N zwBr6kmw%97{nukpjvv6B%+ri!yN2;bnAfn5%Jbw38}~MWkF(Iwqlb;15)Fhbjc2J- zu@Qx^o6*xfE%LGShDzx&A(}y495%jYNs*n*;~p8HcyxJ@xuqX`k6-Y6-`4W)BQYgy zzb3~hZ&|WOj2Xkzapq`sEV@Y1JYG}uSTmyK8Hlqb3^cQXW;-EQz(*k^TK? zqkLPOyyWX8uM6%434HTG!I=!l-HT4#!v9tCFjNNy+|TfE3R$t8tt5-~*x>&P^iZKx zCA@UAT&ED~?ti?i?_?rCns=T|HUA;OI~LLqc62(e8q?UztVx@h{{)&cGR-%<-KIKH zw6B?&0^<|JdK^FZx&oEAJm=*7K3Z7qTcd9oe?Q8VD%jGg$X*Ls(is3(7FWB-0rb*V zM>+tQ`9zoWFadlEd72vHui}qbm8b@mRk3STV1VWWp^>(r=mXGWityrNqWw6{ zxCxTO>1Ce)_h`KnuUX0NkG-u-8n*OWHRm@UQj@cHCQPTE-VdCLa!Lc=a%`tEVzfs} z1W?PJb%ua1+mD*uU6q`gte8h#WpKf3*geHFzasJ*uvd}FRt_;yQ_ls4dNW31s?ukT z0Ow`eYNBBDi}{U`Z8|5{N|e$U5Or#x%ZApV11Zxr{e>x}f93hOa!q)LB=k!IzIEiR0wI4oir$P5hy=06!dQ8GFt*|G+T<*iihIGp$4xYi{ zi3|+6-zo3W)wtb(b$I;RmBZ-_8Tl5zlOK25yFwiiuKg+qXKBq=1CaZkHut}*NG_uP zc->P}GCXKDgk4g^nmny7--3)P8)sPuBV%JKUC^h(x?IsD-E`!xrKsJvd&9%?GysNf zGMaBD91@C7rViT*Z_Oj`1a7Xm0bI?Tyq&WjH)mDH?RR7hgdWX49@6#0scu?TKukpd z*~jiDh}_*r2~|N@QdLTvRZi(?31q+CTl-U5g_g*uragnjEf#F6>2hef4czn6Y1sMj z9x1sQQM7WTT~4bg58yb&pbv}vhT=qFy?tjz`VCcgeL`+ZPr#*g!C`C=1&G6|vkM0yw3r!xx2d^&Z4JPZ79M-b#f z)##znCEKZVU7(Q^@UiSMvrG(%^awt|Iw3c^-nu3UfcA(Ih90^BP5)t;ZgXrw#IV@% zjU$!8S}3ZX&*gV_T6ajV)k_2YKbSEwlb2n}Is|-|fc-6#Usjee+i%F8%W&^JUh}l% zsNe-D3!0^_*Kmt8GhtsGwVo1D!4TkL$w<*tZgI!#6%kgk=MGiriN^}XHAEnuo*3Hv z1vN0|!TFROeB1r_K(*x(%%{iE@D2eatB0+&n1^Vn{(G}X$}w=?;CDtJDKof4;eG2& zX#vZYX}@@C$EYX44AYY1D-MsN6|uD$5G93Od;t@Yehg92{no>%Fwp&@3Iog^) zVd#{E8;b7FCxKJvAQU_r(G9G9QEGBZlArCAKD08H;)Dh%Zry%|3i3~{9l9jnwZuUa z)1yJy+v6BorlKzy<@!%o2jg;hD10?poBZq6tnyvY{N*m^<$s^oVj4yzn3hx;sUUh8 z@i385PM1K|-xU-TJG(Oe{U|4Ar{!~Ud=xS=a;5jsj6=nBZQM*f|M}IG-4Kcr{rUMt z?`qV6NFZU<+`>X6H74@1lY|JBl%A*Om(?K2(Ie&AD$9M{08v6(b9>h#)AN=2`3TCd zpisOr`zsfP%AlmVI{fCF3rw3keAC&}``>of$ItJiW^uOs!hEno@U~=3=paUyi?vm& zY!50XnU}E2M7l5a7Gg|VFZt2B-%=LUl+ckR10Fi_%P)mvP|1Q378mK5s#hLMcC(=V zge?|9+n)|Ewq7*dGfH%~T}k}w@N{=y2XxEmhJ3d`=y<<=7z66SZ!Y&ZV`fLY+?#TCq<}n*D2WZh=pILP5_H0KWLFcR`a{GabI@}J_ zLb=@5cD*;-5dpYkJ$E+dJvPgsSXJCmnCtZs;^8%5{B}+Qq-Te*+vkHrN~%=v`0 z>>pTM0U-F;tTm(LdDcmR(|FXV8(Ry%F#CgU;KQAS%g|v1BLuf4Q19XF3#-rN zybTUb0HRo8GlX8b(&vKt{tDrjm`KQs7_Nb=*NYrQ8hb8z2sq~Joj(BMI#qC4X|r5O z9sr{46yyc(O?3ujur-u}n_sJPVpnzh0&CyHDEok+up#}qe(0G=cd#{+puKL%4`_1L zoG$NmBIJD}u+6bjugj%=4F-4`sI+ux+R z;Ve?m1;B|NFKSX%kYN)#!V>_$hjJg^sr8%zlp~77{ZWI4-aC_T9!dZQS{b9=?9&XV zn-ThJSeJnxhjh7$bKDGdD5_l0)qRe4E{5aEeS^02T74IeZ%k#JU zDwWp`%@W|G!>jv3ky{aBsb+-x1#W-xi&OpvmA-M$E;z5{s;+X`WLO#wAIl4)92_l7 zw-)ugO}7^E-Z8x@)6=jR{4Q+K9EZ4z0Re3mpA2UEQCFXs#@w3s;lKo0RIOt5el2y0 zkvRFQ$XMxF^{WVl0qHo=K~SKS8xQ(HgMPc8&?g+>*VAnH*G(wnZjIiP4DGQW(3K7v zI!GBQJy`+Lt1}hI(Xho5!i}Lq9KgIr%8g^h-mtGh_7Vz*Dq&qAhL*b#UkK&z7?H(T&l z^sy(=Q1RDj91CH!={q;fFRUf_BV0i1n(+fS<8$M?T&Hz;iMv+}DmL46*FY>XnmoA= zsuusL*Yv#g@0M~h7X5x%hNAfzt6%l?DNN)7@XeQh@{{~&(}^B$8v@r<0e#_e-q*%?8iQx1RP*iFe)+HAk0m4o>Y_J1(mw^4X+;IP9tC&_pcHw z=5sKT2a*eLU=p2^;VbHoBoS%KGt}4G?C)NqP*h5EfV3}XM2>p2Ago=xJk~|A(iT6p zacHq?mnQ*YvIfG@7jPgxm&EN;zvHJa_~;d2M`VOhG4aKTKmR9CIm?NM1v=OGz%Z7& z*afEer7@Kppv01r?g0dtdgtonje6@|mYbmW@8~kTg4+9|I6Y^H;DrU!Ki1nhaRJxT zhFgvBZG(^f&F>O+#VQ2dxm{fa=~zOfC`N@hF)L=Wq=L&x@_mN>r?q=Qzw zP1yH}_==GCGKXKSj?#GS-dx6pZ$+GByg_jmZ#|nKmNa!4dGtEiT1yu?`Gj z?0W_BWh<(w=IweM($Oodr^&_GgHCB2AI$Tl`>lp!q;um|szv*~xE@CPBkgxS-mhU$ z(n%!lNuo#b*hLU6a@?L714SZ-2tS^swIT?utY|)1#}#Xgw^!#$@4wcKvQ zU%zLAyW=E6FGsPDGCPk6?;IX4;{s3BJUSjOyCpzP$bdY~CwNdPeY1mTA~IS77HyVL z=`z}C{A-Sm)|aa-_pVPk54-oG0el)1h_rfpbOn!%TJ1XOx95_qJpJa*MSC$d30aE) zb$s)@J{A%ud1Pai(X0=ffe#k1c-k?5o(_nzaOi{;2s%oZMy3RB#K5f8+L^y7=?LaUYuj ze2q@eMaKrdL3C24m-F{CU3%pccQ?&VtJSXl$SITH=g2@SRohRAvA)JhT(FmyfLSFv zIB^gHH`I3hxve1g->#iBqrjE4C9GSu;?X6g?o!iAFAHNJ7o~hCjZWnl^3u_jP`9 za%d{ELJ%)BydU7mejNLq1#$wgb(Zr|)%AK@K-cL0`y+K10G%_LE}IsF{tD7;F{rjc z)3SdI1_r&ZCtK&lo{fs6st;ckBCdq)FUmSLhm7x#FPGeC*xR6Zj%FLh|0?!)g%OumMoLeT%D?{6|PrGY-xcq5ZkX*&f-O#=1NTs4qw1uX zB;%etiEC5w*G6?#e6eORd8Az}Z^@pN;rGK{v_D$n4}`^Q>{b)h;4w{F5t%^-)eLa# ze9-fm?}=Tf?ViSwxsMxqGybaS+$7eOqhE8|uFMt%%txBB8czp1*2GfV@tr!Le+Bo4 zd9KC&I=#M%&p~sQX}ew6KbZ!)xEzxrb_`Eb1WbQ{j0?V7y{%~bOMyW&43qhGFIZG< zt^refdE@~Sq0(ZgUjzO#n$<_3)p%Vk%i*ts%KRrZpGMbc%#_9^23Kq|#Bn>!C@Wy0 z)Nk1s@rcuUG2+z4*09nioeDb^M-h(~+iWVZwtQ^$ZVdhmxe9a^l1LT*>O@LP+E}wc z+kPs0B(v8=>?sMZoSRaol4}ysp1}Q!mPlgeAw`p;#diux*R1{zfO$h!L0^_bq6n*>R1X}KZ+svRSDR7x!5t0(F|^W${xSsEFFb6Vns>0Sf!%d~_osoP zK)At5w5wa!SjmNF#~p=HXA(9o%akj`b%k4x` z{=GmRoT$Rr>f9bbC4$Zk-k}H|H`&*!F%L;Rdh>nJm;Y#@H2nPTFwPY%T)a&q|-*YIgy z;~&~FnnjUo1BxB5{fIAmV=H)182A=4waMx_UK)v?N9%=0~ z6XFe7L0a@M(QOtragu%te_lQ25+q{X-a7KYt9c%-uyiSVVBJTp-ZHd4{+K;gz&xcO zIS`~I^EY;Tz!E&1N_62$JfDue5|m?p*GU{#U|Kc=pd@jizzbzj<8ag(3ScnE6t4Ul zxEqJ4e>3y?{-LQCVlae1aC2`hJ|Y5P{`xrOT{h5f|I1eiSHPk^VTWo*-q#nU{h|#q zDeT1U^!awwa}6WaKO^ip4vKcH0`g%Zt$zs*&I?~;-LobY?b7#*|J>QnzV-v{G9(ZX zEj$!s6b6MO7txmP936IFbs&(A3>QYVX>UJ^d(Q)$dN+7FgU=40jktSG=fQVC3WL91 zQa8N(*!p-syTKRjl_FvsmW?J2+1Zm+54Xusma@InYJi_xnEpQu7n~j_ZSY3uQ--(T zROKA&hl-#m3cW=7CC@b{Jp=}h=)FRjXuA5!!)SvYE)(+<_ONK|7i6?Kn`=LYEyMv) z$A(p$cMD`oErCqHVLP4+C^3iy+!UN8@J5o~LL*wiIGvapDeo93-+aM{evQ^YK#j?} zkLj_~^p1|{J85rdpHG1Liy@bigAk`i6aCU@Ch|GDn&7R5U;8C-Q_lj#zN=}M^5{wC zRn$o)Au}hs3J-Z_1)Kvw3*8%zp{m%OgogH4 znKl+qLJ-k?V%0P7Pm^rnbR4UZjC5ABe(|H7d@t19pg7SVK$;(1&3B{cP3t~|lXX#? zKgz`zV<9x)aHFAB@gRta1eWE&pOJQMjLpV|f0FHVkF#S%?mrc; zLCf)AB15njW-I(|_BkYzhs+o;n0oEzcJdwNcYFK&V+qaUFr)ZrAZ5nlwsw)pP5oQN z1Ip~XGQHD--`%e$5Q$U|s1lGDbaEDsG{yw9o;JjnjwgG1IiFKdg%8RUGUa&B&@Av| z)T5By!IV#4m|h~!kA9edR2y7iZ9tv|Qpe2$ z6}(;^6Kn^ebXXy=a55#d~-2w z6DA7zpc>s>lgwtd=+KcRPg>Xo3mxVoUZ_B;9WbUDMf2Q;$5v4#L&`6Nu5dm1O<+ zCosYdTb%)|6Q~Uj()s<%@k{+?9p=p?%>O(Ik=vY7hFXJiB-QKp-~M|wOD5k!Jq;Md zYOCUZt%|#xxFVljfFb;u|$K}DpT>pZt#~1 zwYx5%X!<9ab&G*A;dt+h)}aEYd!dWU3UIo9|Big~Xrm)-Z*Yd*z1h9Qn@K|Y&y--s zRIC^ME}7m)w+kqrEw3BfS+ci=>SFRJ`S(8vIR~3({Ua@W@pJ`0V_o)yGY_H>Z~cBG z??YyvwCVehol!gd6FsWITQ|yqpk88urm`Xc@TW0D$E!6<9DdacPFY3Aq@Fct_jnrg zY5afU5MV9^D+*sj9VF9Sy{dHxgjx=4TwdftwAOk!f#aO6ncj$EOwFXLDg+i~ z_B5>KmIDhdwpWJBt_?K`>&i>bX=E-ZAn@An< z1gY>w5?Pb0f-o*#5l@d1J{=Y}%wyC}%%SPH=D72h@6QqIrlc1@Ru$G$gEsfqCH{y- z6KwtZK{G9Jnc6@9ldPY|R~uMSGV$G=nlOhnAdOyQ=VJh+K`@W{jpjg5|?om!FzuJlTR$fY8sG!>RACXhAnq{BR~+y}9u!)-$SXtTxQtNubbWKXnGbtlvrM+05{VOIhi{KNf2# zCC^gtf3$gvwaJif&$0q=q9@1uk1-fP1y*KPc2jLu70d!^#dGrNCj0PNr#H3jd}HV- z<04k%NdNKSb{{0KrA24-u%~y{w;4iY)T1h}LU7nE&9OhGF7m*8&~hy9l7zin?6E&n z^FRde9^&Y4S-DV~nw`#XZ^xE+n1?ve1F0~E?ES~b8vrJEzd_`@(gfPRI*1iHhF-BT+N4WZr{%w(u*E&$LkEenpF5sn3wX>W}GYfE}$$DE?BUoGxt1ygiy71<+=& z>#1V#5MYNPdb_hZ=d|jtVPJp+_-BN!T}ly+V#*_%oY!gHaW%9)rKoQ_R!4id|C2A~ ztOG9^^Gnivg#J30^jI|RQ5UL1%06M8Uu>@U9$QkJGC+Ux9=ZFgi#_nNH?I9?T&mt0 zI=MfKB3T#2p85c|H~li@<>h3lh!a=8H6$t^c4Tti|AYj0E;{%A-1-_6=SMtQ{A6O< zuzotnsx^w3-(g&p^x1Y~-_R*&aI;+fV6_dF%%h(Reo{N5@5l zbl~M4^IVJ5vFYYbEl;oc6KrIdk(qIQENj{LH{;>%$g?Br`2M(I)6T8XM$ok1$qhE!`gp!M*6@QB0Q!)2mC@rgN= zRgEFezN(3JzsTTIeE!v2IhD0{qEK0%aS8|RI&AhAO83`~=fx7HzXG2rr(A9v)IhqDO0}ANP8R`86_)ME&Y+etOb{dwWR)n* zj5p+0RmD3Y0PX8rfZR{^<{ha=e;|`7`mMJhEExoa!m1$w*ai*uTm7(znYpS6up#i- zN^Wa6LK&dmy(3oA2-f({#@PG2qJlbrE>6J&TVU0dr>wkO2o9)r-Oj_~^1X{^J8yMs zd+?jRU4nLjH>i}uYJza?Pn5(DsP!Ak%c;^|p9;V4L_#8*yGkW|bQ4XixEro82p!OBBq@x< z4IYRVtgEj(H8*~M1iEU0=dH6N+U6dOeY_R@{P8fZmV(lw%bJ|PssgJ$mMgKbY89HV zU4%E!c}`{;+ORsVZy!dGlU?oLoE1NoRVj z*zenRrK2!Rq(7y`^*JjLy= zwVk}aWst*TZ{4BwgVIs0YtUk0VKqV%qMEdJj{_0D0UY4cb3k3}XP%MN3UdI`Q)Y;*#lMGsQVxcr0l*g^{I%lSOLgFr6+(H)0o)e&O|C{Hh=E44Nw15HI1Gt`LlI zATq9{rWzPqCm?>7KJ>ee=4$_!4UtfaZ+xj}Q&t?MT-OZ9I8GWzBuNB3n!%TtX=Vk< z8S#G)G%LB!of3GzvDT1hXGQ|vu$X)fO`(;3AKQg{Dk(F=F!mj( z^RqbJ)9YYP_ltN~taL#NK!i!Gu^8WQ>*0mJCl9=bN27+LzTpn@yIWlC!U4>am3cc( zP%Z^5lBMFkyfq_`vPB%wk>h_U^v9q9+d9Vu*(n?l&m(iWc>3s7ywiET@$|SJ{d#k~ z!vYsszO~t1I>qx#Kk?5zL74bGy+T~?r^g-m$Q3YnByl4ZeU_T3;Ix_^i z>o-=yrY>Akl?dT2AlvK+Txvv>t`7CoR8%M(ljmAvmcpk)W)_}r#}-_BHk>9DmAZR) zxH--;g^|A_dq1AFKWU!Z;Ref^$t;b ztv%mjc$wBYObfCqqVkqFYJ=rm3y45}2DzZ}KuS=R(5h&=P8-S}2Ne`B1h|9*4-OPs zdF)xF_m%1%cx#ju`!&O!_Cv3zv)7c}<-YeWCB!O`P#MjhZI8gPD;X3z1^2*oO=l&M z16oBUx&D`?J=Ae-qe6^z;<=!%qZY`tXP;xQ!OE$XD9}^Y7*~qiyYYE-R4lrskrwF16UZ&;G@9Xb-?+|FK3qaaJP7rC8=U{1Z z4_%4XSO0#%$u;sab!kmiOk~(Jsn6w1w+8aM9F)ar-DCKMp=WjfN77Y?HTkwtm2O5z z=SCyl-QA2(It3gZ(%mp%bT=a<1*N4M0cjAVTe?xd@%#SY^k0U{ZK?=T`;$Gr(&!qEjVJmH_H4BRDrCdzYR-L5Vo0&9LcK4Lhg7BeNjs zr4#0vEyNRWBC%o_i?-iw8Y)2}hdpF0Dz3==nQdOO1y&@eVz!4)K~3`WjZOurDIZ!|xV=7XjPhU@Rpb3Ax~r;_|XtE<3Y>}?-SBjkLB>>P(Gm1C0D#J9{6Y;1BN zd=-Kgs`@s6ySP!)>=gZ3l(rTfuaCkd%O`>Izj~LBDyx|3Cb_XNs~qU+J#)Lqnu_?5 z28O06F|WX;Ny<#A3M4U!z8M+khG3+cZzqLijCB`>K;K!_INAQ)RI=E%~^#zqs-n;xq&*X*>ONl@UAd?#Tn|%Dt zGDF*ll4lSva>aP0NB`odYG;l{$;D3?^cfj9$i)`wDB?@(kUHvOi|-l!j3@FB{v2bT zY2%2|TTHY^&2XzyP3|E4U;VE@8f#OHy(WP6LXQ~%ltuT0YiH+<>v2BcRxll!w&me& zqsA?AHb}?%gO`Is*|R9F76%=aFJpLQ35+5KmrR_)w~>S`=|qwILnzg{RQRWkRMRni zPUW>5&vV$)p(o zZ;Fc9x5iojW8oAkRA!EC#cq@>#C&Y^6}l)Xq4@8lWY2={ zgSHIH^3{gJks>(|)^4028nO2L=k~}>uPurGii8Oc#~!{z&WAEefGa5il8R6|X1v2h zd%t5Lv~B($D0okntT8DGT^y;&zRm0ZoZBB`%lV6JZ-@_xhxF*5OEa_?SFpM-GYor~ zfWIFA9SsFi62IU*PUDQ5&k|62JdQ^EKU`66zRh26S7g_32i(4b%+fHQE73F|=CxV4 z@W4A)>wR|hyVpX?&rnTwdUPvtzyxVd4R3i&(&Sai;g_Pe9MZkUpN~r@&)pejlCs`Q zNAvn)Z?7Sp|2i5kiGFixa}W$reqGYVhoI4u0J3P1N5`96+*xklmJ*R|xL3O%2+(Xq zxs_3-Pf}H*QMwq<^|4-bf+-UffpSzGCk4Al%dsmcL@PSPjex!k%p$HNribXC$0vE7ps6UXOppgbfe>X}!NNDuOEX zd{Tsn&$~beBb9mCZMz?Yx9h83S)Zx0=~l%`IQ0)iB@^p`%_Cht&lDZH^-2SA$16G( zqspNPs?Tmh<=3AYSg}}|5I1ICvonnY97Egftf%0~DX;|w@XM@iG|TqT?Ml)YyAz1y zJv0x~;4YuP(-waQtwU}^=QM%fe1mHCatH~%+Cszmr>`bkaD{(EH4i$D*a()zIm)n#Na_1$!iQaUX{c&Dv0ARt(9#=)&l%-Y{z) zp)Q$Vs*MV+Ok%0DrE>t` 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

*^ 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 literal 0 HcmV?d00001 diff --git a/README.assets/image5.png b/README.assets/image5.png new file mode 100644 index 0000000000000000000000000000000000000000..181d26c210ceefd84e54f5011cd02f049772a398 GIT binary patch literal 90379 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

ck%FX%Lp)sX0yK?du-v&nXGs?Z5EOt3?j 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%0A#M59_67?jz0|2>&;00Br44Rc(_ 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 +

+ image + image2 + image3 + image4 + image5 +

+ +
+ ## Android 앱 아키텍처 (MVVM + Clean Architecture) play \ No newline at end of file From a7586f2b0bd3a978c3a4cb58331b0429b83a92f1 Mon Sep 17 00:00:00 2001 From: min486 Date: Wed, 5 Nov 2025 01:09:56 +0900 Subject: [PATCH 76/98] README --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 31c33c8..a8f64e4 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,12 @@
-

- image - image2 - image3 - image4 - image5 +

+ image + image2 + image3 + image4 + image5


From c5c62f288b778617d5beaf797aa9e2c76284541b Mon Sep 17 00:00:00 2001 From: min486 Date: Sat, 8 Nov 2025 17:19:37 +0900 Subject: [PATCH 77/98] =?UTF-8?q?design:=20=EC=B9=B4=EB=93=9C=ED=98=95=20?= =?UTF-8?q?=EC=95=84=EC=9D=B4=ED=85=9C=20=ED=85=8D=EC=8A=A4=ED=8A=B8=20Cen?= =?UTF-8?q?ter=20=EC=A0=95=EB=A0=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/presentation/home/HomeScreen2.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt index 33e40f1..1539706 100644 --- a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt +++ b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt @@ -317,7 +317,7 @@ fun HomeCardImage( ) { Box( modifier = Modifier, - contentAlignment = Alignment.CenterStart + contentAlignment = Alignment.Center ) { AsyncImage( modifier = Modifier.size(100.dp), From 2ab0d79d9de75fb0ca18985ce14d8376ebee3687 Mon Sep 17 00:00:00 2001 From: min486 Date: Sat, 8 Nov 2025 17:49:16 +0900 Subject: [PATCH 78/98] =?UTF-8?q?fix:=20=ED=83=80=EC=9E=84=EB=9D=BC?= =?UTF-8?q?=EC=9D=B8=ED=98=95=20=EC=95=84=EC=9D=B4=ED=85=9C=20endDate=20?= =?UTF-8?q?=EC=97=86=EB=8A=94=20=EA=B2=BD=EC=9A=B0,=20=ED=91=9C=EC=8B=9C?= =?UTF-8?q?=20=EC=95=88=EB=90=98=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dnapp/presentation/home/HomeScreen2.kt | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt index 1539706..e90f30b 100644 --- a/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt +++ b/app/src/main/java/com/min/dnapp/presentation/home/HomeScreen2.kt @@ -382,8 +382,12 @@ fun TimelineSection( } TimelineItem( - record = record, - isYearStart = isYearStart + isYearStart = isYearStart, + startDateMillis = record.startDateMillis, + endDateMillis = if (record.endDateMillis == 0L) null else record.endDateMillis, + imageUrl = if (record.imageUrl.isEmpty()) null else record.imageUrl, + title = record.title, + placeName = record.selectedPlace?.title ) } @@ -414,12 +418,19 @@ fun YearHeader( @Composable fun TimelineItem( - record: TripRecord, - isYearStart: Boolean + isYearStart: Boolean, + startDateMillis: Long, + endDateMillis: Long?, + title: String, + placeName: String?, + imageUrl: String? ) { // 월.일 추출 (예: 07.25) - val startDate = record.startDateMillis.toDateString("MM.dd") - val endDate = record.endDateMillis.toDateString("MM.dd") + val startDate = startDateMillis.toDateString("MM.dd") + val endDate = endDateMillis?.toDateString("MM.dd") + + // 여행 날짜 텍스트 계산 + val dateText = endDate?.let { "$startDate ~ $endDate" } ?: startDate Row( modifier = Modifier.fillMaxWidth(), @@ -438,12 +449,12 @@ fun TimelineItem( ) { Spacer(Modifier.height(4.dp)) Text( - text = "$startDate ~ $endDate", + text = dateText, style = MomentoTheme.typography.body03, color = MomentoTheme.colors.grayW20 ) Text( - text = record.title, + text = title, style = MomentoTheme.typography.body02, color = MomentoTheme.colors.grayW20, maxLines = 1, @@ -457,9 +468,9 @@ fun TimelineItem( contentDescription = null ) Spacer(Modifier.width(6.dp)) - record.selectedPlace?.let { selectedPlace -> + placeName?.let { place -> Text( - text = selectedPlace.title, + text = place, style = MomentoTheme.typography.body03, color = MomentoTheme.colors.grayW20 ) @@ -468,10 +479,10 @@ fun TimelineItem( } } - if (record.imageUrl.isNotEmpty()) { + imageUrl?.let { image -> AsyncImage( modifier = Modifier.size(90.dp), - model = record.imageUrl, + model = image, contentDescription = null, contentScale = ContentScale.Crop ) From 7c71e283727c0caf0eb25f8fa1f56779dfe1dc81 Mon Sep 17 00:00:00 2001 From: min486 Date: Sat, 8 Nov 2025 19:25:07 +0900 Subject: [PATCH 79/98] =?UTF-8?q?feat:=20=EB=8B=89=EB=84=A4=EC=9E=84=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20Dialog=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dnapp/presentation/mypage/MypageScreen.kt | 66 ++++++++- .../mypage/component/NicknameUpdateDialog.kt | 128 ++++++++++++++++++ 2 files changed, 187 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/mypage/component/NicknameUpdateDialog.kt diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt index 5148b00..bb75810 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -27,6 +28,9 @@ import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults 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.painterResource @@ -38,6 +42,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavHostController import com.min.dnapp.R import com.min.dnapp.presentation.common.ProfileMapper +import com.min.dnapp.presentation.mypage.component.NicknameUpdateDialog import com.min.dnapp.presentation.mypage.component.ProfileImageDialog import com.min.dnapp.presentation.ui.component.UserBadge import com.min.dnapp.presentation.ui.icon.AppIcons @@ -56,6 +61,8 @@ fun MypageScreen( val showImageUpdateDialog by mypageViewModel.showImageUpdateDialog.collectAsStateWithLifecycle() val selectedImage by mypageViewModel.selectedImage.collectAsStateWithLifecycle() + var showNicknameUpdateDialog by remember { mutableStateOf(false) } + Scaffold( containerColor = MomentoTheme.colors.brownW90, topBar = { @@ -120,7 +127,8 @@ fun MypageScreen( nickname = data.user.nickname, recordCnt = data.user.recordCnt, stampCnt = data.user.stampCnt, - onClick = { mypageViewModel.openDialog() } + onImageClick = { mypageViewModel.openDialog() }, + onNicknameClick = { showNicknameUpdateDialog = true } ) Spacer(Modifier.height(20.dp)) @@ -153,6 +161,15 @@ fun MypageScreen( onConfirm = { mypageViewModel.updateProfileImage() } ) } + + // 닉네임 변경 모달창 + if (showNicknameUpdateDialog) { + NicknameUpdateDialog( + onDismiss = { showNicknameUpdateDialog = false }, + onCancel = { showNicknameUpdateDialog = false }, + onConfirm = { } + ) + } } @Composable @@ -163,7 +180,8 @@ fun MypageProfileSection( nickname: String, recordCnt: Int, stampCnt: Int, - onClick: () -> Unit + onImageClick: () -> Unit, + onNicknameClick: () -> Unit ) { Column( modifier = Modifier.fillMaxWidth(), @@ -172,7 +190,7 @@ fun MypageProfileSection( // 프로필 이미지 (수정 가능) UserProfileImage( profileImageName = profileImageName, - onClick = { onClick() } + onClick = { onImageClick() } ) Spacer(Modifier.height(12.dp)) @@ -186,10 +204,9 @@ fun MypageProfileSection( Spacer(Modifier.height(16.dp)) // 닉네임 - Text( - text = nickname, - style = MomentoTheme.typography.title01, - color = MomentoTheme.colors.grayW20 + UserNickname( + nickname = nickname, + onClick = { onNicknameClick() } ) Spacer(Modifier.height(28.dp)) @@ -242,6 +259,41 @@ fun UserProfileImage( } } +@Composable +fun UserNickname( + nickname: String, + onClick: () -> Unit +) { + Column( + modifier = Modifier + .clickable { onClick() } + .width(120.dp) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Spacer(Modifier.width(16.dp)) + Text( + text = nickname, + style = MomentoTheme.typography.title01, + color = MomentoTheme.colors.grayW20 + ) + Icon( + modifier = Modifier.size(16.dp), + imageVector = AppIcons.PenSmall, + contentDescription = null, + tint = MomentoTheme.colors.grayW60 + ) + } + + Spacer(Modifier.height(4.dp)) + + HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW60) + } +} + @Composable fun RecordAndStampNum( recordCnt: Int, diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/component/NicknameUpdateDialog.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/component/NicknameUpdateDialog.kt new file mode 100644 index 0000000..0325d6b --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/component/NicknameUpdateDialog.kt @@ -0,0 +1,128 @@ +package com.min.dnapp.presentation.mypage.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +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.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun NicknameUpdateDialog( + onDismiss: () -> Unit, + onCancel: () -> Unit, + onConfirm: () -> Unit +) { + var nickname by rememberSaveable { mutableStateOf("") } + + Dialog( + onDismissRequest = onDismiss + ) { + Surface( + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(16.dp), + color = MomentoTheme.colors.brownBg + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(20.dp), + ) { + Text( + text = "닉네임", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 + ) + + Spacer(Modifier.height(12.dp)) + + // 닉네임 입력 영역 + Box( + modifier = Modifier + .fillMaxWidth() + .height(40.dp) + .border(width = 1.dp, color = MomentoTheme.colors.grayW90, shape = RoundedCornerShape(5.dp)) + .background(color = MomentoTheme.colors.white) + .padding(start = 12.dp), + contentAlignment = Alignment.CenterStart + ) { + if (nickname.isEmpty()) { + Text( + text = "새 닉네임을 입력하세요.", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW60 + ) + } + BasicTextField( + modifier = Modifier.fillMaxWidth(), + value = nickname, + onValueChange = { newValue -> + nickname = newValue + }, + textStyle = MomentoTheme.typography.body02, + singleLine = true + ) + } + + Spacer(Modifier.height(20.dp)) + + // 버튼 영역 + Row( + modifier = Modifier.fillMaxWidth() + ) { + Box( + modifier = Modifier + .clickable { onCancel() } + .weight(1f) + .background(color = MomentoTheme.colors.white) + .border(width = 1.dp, color = MomentoTheme.colors.grayW60, shape = RoundedCornerShape(5.dp)) + .padding(vertical = 16.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "취소", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + } + + Spacer(Modifier.width(12.dp)) + + Box( + modifier = Modifier + .clickable { onConfirm() } + .weight(1f) + .background(color = MomentoTheme.colors.pinkBase, shape = RoundedCornerShape(5.dp)) + .padding(vertical = 16.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "저장", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + } + } + } + } + } +} From 5ae071704e157500801955ffd14c52e5c2250b33 Mon Sep 17 00:00:00 2001 From: min486 Date: Sun, 9 Nov 2025 15:40:02 +0900 Subject: [PATCH 80/98] =?UTF-8?q?feat:=20=EB=8B=89=EB=84=A4=EC=9E=84=20?= =?UTF-8?q?=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=82=AC=20=EB=B0=8F=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=EB=A9=94=EC=8B=9C=EC=A7=80=20=ED=91=9C?= =?UTF-8?q?=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dnapp/presentation/mypage/MypageScreen.kt | 9 ++- .../mypage/NicknameValidationState.kt | 8 +++ .../presentation/mypage/NicknameViewModel.kt | 69 +++++++++++++++++++ .../mypage/component/NicknameUpdateDialog.kt | 33 ++++++--- .../min/dnapp/presentation/ui/theme/Color.kt | 1 + 5 files changed, 108 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/mypage/NicknameValidationState.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/mypage/NicknameViewModel.kt diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt index bb75810..0ae5b5b 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt @@ -55,12 +55,15 @@ import com.min.dnapp.presentation.ui.theme.MomentoTheme @Composable fun MypageScreen( navController: NavHostController, - mypageViewModel: MypageViewModel = hiltViewModel() + mypageViewModel: MypageViewModel = hiltViewModel(), + nicknameViewModel: NicknameViewModel = hiltViewModel() ) { val uiState by mypageViewModel.uiState.collectAsStateWithLifecycle() val showImageUpdateDialog by mypageViewModel.showImageUpdateDialog.collectAsStateWithLifecycle() val selectedImage by mypageViewModel.selectedImage.collectAsStateWithLifecycle() + val nicknameState by nicknameViewModel.nicknameState.collectAsStateWithLifecycle() + var showNicknameUpdateDialog by remember { mutableStateOf(false) } Scaffold( @@ -165,6 +168,10 @@ fun MypageScreen( // 닉네임 변경 모달창 if (showNicknameUpdateDialog) { NicknameUpdateDialog( + state = nicknameState, + onValueChange = { newValue -> + nicknameViewModel.onNicknameChange(newValue) + }, onDismiss = { showNicknameUpdateDialog = false }, onCancel = { showNicknameUpdateDialog = false }, onConfirm = { } diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/NicknameValidationState.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/NicknameValidationState.kt new file mode 100644 index 0000000..27cf7f9 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/NicknameValidationState.kt @@ -0,0 +1,8 @@ +package com.min.dnapp.presentation.mypage + +data class NicknameValidationState( + val currentNickname: String = "", + val errorMessage: String? = null, + val isValid: Boolean = false, + val isSaving: Boolean = false +) diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/NicknameViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/NicknameViewModel.kt new file mode 100644 index 0000000..4763277 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/NicknameViewModel.kt @@ -0,0 +1,69 @@ +package com.min.dnapp.presentation.mypage + +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.update +import javax.inject.Inject + +@HiltViewModel +class NicknameViewModel @Inject constructor( + +) : ViewModel() { + + private val _nicknameState = MutableStateFlow(NicknameValidationState()) + val nicknameState: StateFlow = _nicknameState + + private val MIN_LENGTH = 2 + private val MAX_LENGTH = 10 + + // 한글, 영문, 숫자, .(마침표), _(언더만)만 허용 + private val ALLOWED_CHARS_REGEX = Regex("^[가-힣a-zA-Z0-9._]*$") + + /** + * 사용자의 입력에 따라 닉네임 검사 및 업데이트 + */ + fun onNicknameChange(newInput: String) { + + // 10자 초과 입력 차단 + val finalInput = if (newInput.length > MAX_LENGTH) { + newInput.substring(0, MAX_LENGTH) + } else { + newInput + } + Log.d("my", "onNicknameChange finalInput: $finalInput") + + val (isValid, errorMessage) = validateNickname(finalInput) + + _nicknameState.update { + it.copy( + currentNickname = finalInput, + errorMessage = errorMessage, + isValid = isValid + ) + } + } + + private fun validateNickname(nickname: String): Pair { + + // 빈 문자열인 경우 + if (nickname.isEmpty()) { + return Pair(false, null) + } + + // 문자 제한 검사 + if (!nickname.matches(ALLOWED_CHARS_REGEX)) { + return Pair(false, "한글, 영문, 숫자, .(마침표), _(언더바)만 가능합니다") + } + + // 글자수 제한 검사 + if (nickname.length < MIN_LENGTH) { + return Pair(false, "2~10자로 입력해주세요") + } + + // 모든 조건 통과 + return Pair(true, null) + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/component/NicknameUpdateDialog.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/component/NicknameUpdateDialog.kt index 0325d6b..eadef00 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/component/NicknameUpdateDialog.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/component/NicknameUpdateDialog.kt @@ -16,24 +16,22 @@ import androidx.compose.foundation.text.BasicTextField import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog +import com.min.dnapp.presentation.mypage.NicknameValidationState +import com.min.dnapp.presentation.ui.theme.ErrorRed import com.min.dnapp.presentation.ui.theme.MomentoTheme @Composable fun NicknameUpdateDialog( + state: NicknameValidationState, + onValueChange: (String) -> Unit, onDismiss: () -> Unit, onCancel: () -> Unit, onConfirm: () -> Unit ) { - var nickname by rememberSaveable { mutableStateOf("") } - Dialog( onDismissRequest = onDismiss ) { @@ -65,7 +63,7 @@ fun NicknameUpdateDialog( .padding(start = 12.dp), contentAlignment = Alignment.CenterStart ) { - if (nickname.isEmpty()) { + if (state.currentNickname.isEmpty()) { Text( text = "새 닉네임을 입력하세요.", style = MomentoTheme.typography.body02, @@ -74,15 +72,25 @@ fun NicknameUpdateDialog( } BasicTextField( modifier = Modifier.fillMaxWidth(), - value = nickname, + value = state.currentNickname, onValueChange = { newValue -> - nickname = newValue + onValueChange(newValue) }, textStyle = MomentoTheme.typography.body02, singleLine = true ) } + // 에러메시지 표시 + if (state.errorMessage != null) { + Spacer(Modifier.height(4.dp)) + Text( + text = state.errorMessage, + style = MomentoTheme.typography.body03, + color = ErrorRed + ) + } + Spacer(Modifier.height(20.dp)) // 버튼 영역 @@ -111,14 +119,17 @@ fun NicknameUpdateDialog( modifier = Modifier .clickable { onConfirm() } .weight(1f) - .background(color = MomentoTheme.colors.pinkBase, shape = RoundedCornerShape(5.dp)) + .background( + color = if (state.isValid) MomentoTheme.colors.pinkBase else MomentoTheme.colors.grayW80, + shape = RoundedCornerShape(5.dp) + ) .padding(vertical = 16.dp), contentAlignment = Alignment.Center ) { Text( text = "저장", style = MomentoTheme.typography.body01, - color = MomentoTheme.colors.grayW20 + color = if (state.isValid) MomentoTheme.colors.grayW20 else MomentoTheme.colors.white ) } } diff --git a/app/src/main/java/com/min/dnapp/presentation/ui/theme/Color.kt b/app/src/main/java/com/min/dnapp/presentation/ui/theme/Color.kt index d3f66fc..01ed4d2 100644 --- a/app/src/main/java/com/min/dnapp/presentation/ui/theme/Color.kt +++ b/app/src/main/java/com/min/dnapp/presentation/ui/theme/Color.kt @@ -46,3 +46,4 @@ val White = Color(0xFFFFFFFF) // 기타 val KakaoYellow = Color(0xFFFEE500) +val ErrorRed = Color(0xFFEF5350) From f99d14b07b693b80f8c51364f73118e9057c0923 Mon Sep 17 00:00:00 2001 From: min486 Date: Mon, 10 Nov 2025 20:22:11 +0900 Subject: [PATCH 81/98] =?UTF-8?q?feat:=20=EB=8B=89=EB=84=A4=EC=9E=84=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=EA=B8=B0=EB=8A=A5=20=EC=99=84=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/UserRepositoryImpl.kt | 19 ++ .../dnapp/domain/repository/UserRepository.kt | 1 + .../domain/usecase/UpdateNicknameUseCase.kt | 12 ++ .../dnapp/presentation/mypage/MypageScreen.kt | 14 +- .../presentation/mypage/MypageViewModel.kt | 90 +++++++++- .../presentation/mypage/NicknameViewModel.kt | 69 -------- .../mypage/component/NicknameUpdateDialog.kt | 162 ++++++++++-------- 7 files changed, 218 insertions(+), 149 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/domain/usecase/UpdateNicknameUseCase.kt delete mode 100644 app/src/main/java/com/min/dnapp/presentation/mypage/NicknameViewModel.kt diff --git a/app/src/main/java/com/min/dnapp/data/repository/UserRepositoryImpl.kt b/app/src/main/java/com/min/dnapp/data/repository/UserRepositoryImpl.kt index 48a2dd4..c8aafe4 100644 --- a/app/src/main/java/com/min/dnapp/data/repository/UserRepositoryImpl.kt +++ b/app/src/main/java/com/min/dnapp/data/repository/UserRepositoryImpl.kt @@ -57,4 +57,23 @@ class UserRepositoryImpl @Inject constructor( } } } + + override suspend fun updateNickname(nickname: String): Result { + val userId = currentUserId + val userDoc = firestore.collection("users").document(userId) + + val newNickname = mapOf( + "nickname" to nickname + ) + + return withContext(Dispatchers.IO) { + try { + userDoc.update(newNickname).await() + Result.success(Unit) + } catch (e: Exception) { + Log.e("record", "updateNickname error", e) + Result.failure(e) + } + } + } } diff --git a/app/src/main/java/com/min/dnapp/domain/repository/UserRepository.kt b/app/src/main/java/com/min/dnapp/domain/repository/UserRepository.kt index 8d388a3..b2d61bd 100644 --- a/app/src/main/java/com/min/dnapp/domain/repository/UserRepository.kt +++ b/app/src/main/java/com/min/dnapp/domain/repository/UserRepository.kt @@ -5,4 +5,5 @@ import com.min.dnapp.data.remote.dto.UserEntity interface UserRepository { suspend fun getUserData(uid: String): UserEntity suspend fun updateProfileImage(profileImageName: String): Result + suspend fun updateNickname(nickname: String): Result } diff --git a/app/src/main/java/com/min/dnapp/domain/usecase/UpdateNicknameUseCase.kt b/app/src/main/java/com/min/dnapp/domain/usecase/UpdateNicknameUseCase.kt new file mode 100644 index 0000000..5d35e1c --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/usecase/UpdateNicknameUseCase.kt @@ -0,0 +1,12 @@ +package com.min.dnapp.domain.usecase + +import com.min.dnapp.domain.repository.UserRepository +import javax.inject.Inject + +class UpdateNicknameUseCase @Inject constructor( + private val userRepository: UserRepository +) { + suspend operator fun invoke(nickname: String): Result { + return userRepository.updateNickname(nickname) + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt index 0ae5b5b..41171cf 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageScreen.kt @@ -55,14 +55,12 @@ import com.min.dnapp.presentation.ui.theme.MomentoTheme @Composable fun MypageScreen( navController: NavHostController, - mypageViewModel: MypageViewModel = hiltViewModel(), - nicknameViewModel: NicknameViewModel = hiltViewModel() + mypageViewModel: MypageViewModel = hiltViewModel() ) { val uiState by mypageViewModel.uiState.collectAsStateWithLifecycle() val showImageUpdateDialog by mypageViewModel.showImageUpdateDialog.collectAsStateWithLifecycle() val selectedImage by mypageViewModel.selectedImage.collectAsStateWithLifecycle() - - val nicknameState by nicknameViewModel.nicknameState.collectAsStateWithLifecycle() + val nicknameState by mypageViewModel.nicknameState.collectAsStateWithLifecycle() var showNicknameUpdateDialog by remember { mutableStateOf(false) } @@ -170,11 +168,15 @@ fun MypageScreen( NicknameUpdateDialog( state = nicknameState, onValueChange = { newValue -> - nicknameViewModel.onNicknameChange(newValue) + mypageViewModel.onNicknameChange(newValue) }, onDismiss = { showNicknameUpdateDialog = false }, onCancel = { showNicknameUpdateDialog = false }, - onConfirm = { } + onConfirm = { + mypageViewModel.updateNickname( + onSuccess = { showNicknameUpdateDialog = false } + ) + } ) } } diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageViewModel.kt index 259c1a6..be60c9a 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/MypageViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MypageViewModel.kt @@ -5,11 +5,13 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.min.dnapp.domain.usecase.GetCurrentUserIdUseCase import com.min.dnapp.domain.usecase.GetUserDataUseCase +import com.min.dnapp.domain.usecase.UpdateNicknameUseCase import com.min.dnapp.domain.usecase.UpdateProfileImageUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import javax.inject.Inject @@ -17,7 +19,8 @@ import javax.inject.Inject class MypageViewModel @Inject constructor( private val getCurrentUserIdUseCase: GetCurrentUserIdUseCase, private val getUserDataUseCase: GetUserDataUseCase, - private val updateProfileImageUseCase: UpdateProfileImageUseCase + private val updateProfileImageUseCase: UpdateProfileImageUseCase, + private val saveNicknameUseCase: UpdateNicknameUseCase ) : ViewModel() { private val _uiState = MutableStateFlow(MypageUiState.Loading) @@ -31,6 +34,15 @@ class MypageViewModel @Inject constructor( private val _selectedImage = MutableStateFlow(null) val selectedImage: StateFlow = _selectedImage.asStateFlow() + private val _nicknameState = MutableStateFlow(NicknameValidationState()) + val nicknameState: StateFlow = _nicknameState + + private val MIN_LENGTH = 2 + private val MAX_LENGTH = 10 + + // 한글, 영문, 숫자, .(마침표), _(언더만)만 허용 + private val ALLOWED_CHARS_REGEX = Regex("^[가-힣a-zA-Z0-9._]*$") + init { loadMyData() } @@ -102,4 +114,80 @@ class MypageViewModel @Inject constructor( } } } + + /** + * 사용자의 입력에 따라 닉네임 검사 및 업데이트 + */ + fun onNicknameChange(newInput: String) { + + // 10자 초과 입력 차단 + val finalInput = if (newInput.length > MAX_LENGTH) { + newInput.substring(0, MAX_LENGTH) + } else { + newInput + } + Log.d("my", "onNicknameChange finalInput: $finalInput") + + val (isValid, errorMessage) = validateNickname(finalInput) + + _nicknameState.update { + it.copy( + currentNickname = finalInput, + errorMessage = errorMessage, + isValid = isValid + ) + } + } + + private fun validateNickname(nickname: String): Pair { + + // 빈 문자열인 경우 + if (nickname.isEmpty()) { + return Pair(false, null) + } + + // 문자 제한 검사 + if (!nickname.matches(ALLOWED_CHARS_REGEX)) { + return Pair(false, "한글, 영문, 숫자, .(마침표), _(언더바)만 가능합니다") + } + + // 글자수 제한 검사 + if (nickname.length < MIN_LENGTH) { + return Pair(false, "2~10자로 입력해주세요") + } + + // 모든 조건 통과 + return Pair(true, null) + } + + /** + * 새로운 닉네임 저장 + */ + fun updateNickname(onSuccess: () -> Unit) { + viewModelScope.launch { + val nicknameState = _nicknameState.value + + if (!nicknameState.isValid || nicknameState.isSaving) { + return@launch + } + + // 저장 시작 + _nicknameState.update { it.copy(isSaving = true) } + + val newNickname = nicknameState.currentNickname + val result = saveNicknameUseCase(newNickname) + + result.onSuccess { + // 프로필 데이터 갱신 + loadMyData() + // Dialog 닫기 신호 전달 + onSuccess() + Log.d("my", "updateNickname 성공") + }.onFailure { exception -> + Log.e("my", "updateNickname 실패", exception) + } + + _nicknameState.update { it.copy(isSaving = false) } + } + } } diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/NicknameViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/NicknameViewModel.kt deleted file mode 100644 index 4763277..0000000 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/NicknameViewModel.kt +++ /dev/null @@ -1,69 +0,0 @@ -package com.min.dnapp.presentation.mypage - -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.update -import javax.inject.Inject - -@HiltViewModel -class NicknameViewModel @Inject constructor( - -) : ViewModel() { - - private val _nicknameState = MutableStateFlow(NicknameValidationState()) - val nicknameState: StateFlow = _nicknameState - - private val MIN_LENGTH = 2 - private val MAX_LENGTH = 10 - - // 한글, 영문, 숫자, .(마침표), _(언더만)만 허용 - private val ALLOWED_CHARS_REGEX = Regex("^[가-힣a-zA-Z0-9._]*$") - - /** - * 사용자의 입력에 따라 닉네임 검사 및 업데이트 - */ - fun onNicknameChange(newInput: String) { - - // 10자 초과 입력 차단 - val finalInput = if (newInput.length > MAX_LENGTH) { - newInput.substring(0, MAX_LENGTH) - } else { - newInput - } - Log.d("my", "onNicknameChange finalInput: $finalInput") - - val (isValid, errorMessage) = validateNickname(finalInput) - - _nicknameState.update { - it.copy( - currentNickname = finalInput, - errorMessage = errorMessage, - isValid = isValid - ) - } - } - - private fun validateNickname(nickname: String): Pair { - - // 빈 문자열인 경우 - if (nickname.isEmpty()) { - return Pair(false, null) - } - - // 문자 제한 검사 - if (!nickname.matches(ALLOWED_CHARS_REGEX)) { - return Pair(false, "한글, 영문, 숫자, .(마침표), _(언더바)만 가능합니다") - } - - // 글자수 제한 검사 - if (nickname.length < MIN_LENGTH) { - return Pair(false, "2~10자로 입력해주세요") - } - - // 모든 조건 통과 - return Pair(true, null) - } -} diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/component/NicknameUpdateDialog.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/component/NicknameUpdateDialog.kt index eadef00..0ef9266 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/component/NicknameUpdateDialog.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/component/NicknameUpdateDialog.kt @@ -10,9 +10,11 @@ import androidx.compose.foundation.layout.Spacer 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.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField +import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -40,99 +42,113 @@ fun NicknameUpdateDialog( shape = RoundedCornerShape(16.dp), color = MomentoTheme.colors.brownBg ) { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(20.dp), + Box( + contentAlignment = Alignment.Center ) { - Text( - text = "닉네임", - style = MomentoTheme.typography.title02, - color = MomentoTheme.colors.grayW20 - ) - - Spacer(Modifier.height(12.dp)) - - // 닉네임 입력 영역 - Box( + Column( modifier = Modifier .fillMaxWidth() - .height(40.dp) - .border(width = 1.dp, color = MomentoTheme.colors.grayW90, shape = RoundedCornerShape(5.dp)) - .background(color = MomentoTheme.colors.white) - .padding(start = 12.dp), - contentAlignment = Alignment.CenterStart + .padding(20.dp), ) { - if (state.currentNickname.isEmpty()) { - Text( - text = "새 닉네임을 입력하세요.", - style = MomentoTheme.typography.body02, - color = MomentoTheme.colors.grayW60 - ) - } - BasicTextField( - modifier = Modifier.fillMaxWidth(), - value = state.currentNickname, - onValueChange = { newValue -> - onValueChange(newValue) - }, - textStyle = MomentoTheme.typography.body02, - singleLine = true - ) - } - - // 에러메시지 표시 - if (state.errorMessage != null) { - Spacer(Modifier.height(4.dp)) Text( - text = state.errorMessage, - style = MomentoTheme.typography.body03, - color = ErrorRed + text = "닉네임", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 ) - } - Spacer(Modifier.height(20.dp)) + Spacer(Modifier.height(12.dp)) - // 버튼 영역 - Row( - modifier = Modifier.fillMaxWidth() - ) { + // 닉네임 입력 영역 Box( modifier = Modifier - .clickable { onCancel() } - .weight(1f) + .fillMaxWidth() + .height(40.dp) + .border(width = 1.dp, color = MomentoTheme.colors.grayW90, shape = RoundedCornerShape(5.dp)) .background(color = MomentoTheme.colors.white) - .border(width = 1.dp, color = MomentoTheme.colors.grayW60, shape = RoundedCornerShape(5.dp)) - .padding(vertical = 16.dp), - contentAlignment = Alignment.Center + .padding(start = 12.dp), + contentAlignment = Alignment.CenterStart ) { + if (state.currentNickname.isEmpty()) { + Text( + text = "새 닉네임을 입력하세요.", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW60 + ) + } + BasicTextField( + modifier = Modifier.fillMaxWidth(), + value = state.currentNickname, + onValueChange = { newValue -> + onValueChange(newValue) + }, + textStyle = MomentoTheme.typography.body02, + singleLine = true + ) + } + + // 에러메시지 표시 + if (state.errorMessage != null) { + Spacer(Modifier.height(4.dp)) Text( - text = "취소", - style = MomentoTheme.typography.body01, - color = MomentoTheme.colors.grayW20 + text = state.errorMessage, + style = MomentoTheme.typography.body03, + color = ErrorRed ) } - Spacer(Modifier.width(12.dp)) + Spacer(Modifier.height(20.dp)) - Box( - modifier = Modifier - .clickable { onConfirm() } - .weight(1f) - .background( - color = if (state.isValid) MomentoTheme.colors.pinkBase else MomentoTheme.colors.grayW80, - shape = RoundedCornerShape(5.dp) - ) - .padding(vertical = 16.dp), - contentAlignment = Alignment.Center + // 버튼 영역 + Row( + modifier = Modifier.fillMaxWidth() ) { - Text( - text = "저장", - style = MomentoTheme.typography.body01, - color = if (state.isValid) MomentoTheme.colors.grayW20 else MomentoTheme.colors.white - ) + Box( + modifier = Modifier + .clickable { onCancel() } + .weight(1f) + .background(color = MomentoTheme.colors.white) + .border(width = 1.dp, color = MomentoTheme.colors.grayW60, shape = RoundedCornerShape(5.dp)) + .padding(vertical = 16.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "취소", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + } + + Spacer(Modifier.width(12.dp)) + + Box( + modifier = Modifier + .clickable { + if (state.isValid) { onConfirm() } + } + .weight(1f) + .background( + color = if (state.isValid) MomentoTheme.colors.pinkBase else MomentoTheme.colors.grayW80, + shape = RoundedCornerShape(5.dp) + ) + .padding(vertical = 16.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "저장", + style = MomentoTheme.typography.body01, + color = if (state.isValid) MomentoTheme.colors.grayW20 else MomentoTheme.colors.white + ) + } } } + + if (state.isSaving) { + CircularProgressIndicator( + modifier = Modifier.size(40.dp), + color = MomentoTheme.colors.brownW20, + strokeWidth = 4.dp + ) + } } } } From 203d2c0a650f9148b53254c74de9e9ee283336da Mon Sep 17 00:00:00 2001 From: min486 Date: Tue, 11 Nov 2025 19:49:07 +0900 Subject: [PATCH 82/98] =?UTF-8?q?feat:=20=EA=B5=AD=EB=82=B4=20=EC=97=AC?= =?UTF-8?q?=ED=96=89=EC=A7=80=20=EA=B2=80=EC=83=89=20=EC=A7=84=ED=96=89=20?= =?UTF-8?q?=EC=8B=9C=20=EB=A1=9C=EB=94=A9=20=EC=9D=B8=EB=94=94=EC=BC=80?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/write/RecordWriteScreen.kt | 6 +++--- .../component/PlaceBottomSheetContent.kt | 21 ++++++++++++++----- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index 087fadd..aa7d651 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -432,8 +432,7 @@ fun RecordWriteScreen( shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp) ) { PlaceBottomSheetContent( - value = uiState.searchState.query, - places = uiState.searchState.places, + searchState = uiState.searchState, onValueChange = { newValue -> viewModel.updateQuery(newValue) }, @@ -764,7 +763,8 @@ fun WriteContentSection( Box( modifier = Modifier .fillMaxWidth() - .height(300.dp) +// .height(300.dp) + .height(280.dp) .background(color = MomentoTheme.colors.brownBg) .padding(16.dp) ) { diff --git a/app/src/main/java/com/min/dnapp/presentation/write/component/PlaceBottomSheetContent.kt b/app/src/main/java/com/min/dnapp/presentation/write/component/PlaceBottomSheetContent.kt index 353ce0d..aed456f 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/component/PlaceBottomSheetContent.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/component/PlaceBottomSheetContent.kt @@ -11,10 +11,12 @@ import androidx.compose.foundation.layout.Spacer 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.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -35,11 +37,11 @@ import com.min.dnapp.domain.model.LocalPlace import com.min.dnapp.presentation.ui.component.SelectButton import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.ui.theme.MomentoTheme +import com.min.dnapp.presentation.write.SearchState @Composable fun PlaceBottomSheetContent( - value: String, - places: List, + searchState: SearchState, onValueChange: (String) -> Unit, onSearch: () -> Unit, onClear: () -> Unit, @@ -74,7 +76,7 @@ fun PlaceBottomSheetContent( .border(width = 1.dp, color = MomentoTheme.colors.grayW80, shape = RoundedCornerShape(6.dp)) .padding(horizontal = 16.dp, vertical = 12.dp) ) { - if (value.isEmpty()) { + if (searchState.query.isEmpty()) { Text( text = "여행지를 입력해주세요", style = MomentoTheme.typography.body01, @@ -90,7 +92,7 @@ fun PlaceBottomSheetContent( onClear() } }, - value = value, + value = searchState.query, onValueChange = onValueChange, textStyle = MomentoTheme.typography.body01, singleLine = true, @@ -103,11 +105,20 @@ fun PlaceBottomSheetContent( Spacer(Modifier.height(20.dp)) + // 검색 진행 시 로딩 인디케이터 표시 + if (searchState.isLoading) { + CircularProgressIndicator( + modifier = Modifier.size(40.dp), + color = MomentoTheme.colors.brownW20, + strokeWidth = 4.dp + ) + } + // 검색 결과 목록 Column( modifier = Modifier.fillMaxWidth() ) { - places.forEach { item -> + searchState.places.forEach { item -> PlaceItem( placeName = item.title, placeCategory = item.category, From 2dd860b9ba92227f2544f45ce8ce4839ee01f247 Mon Sep 17 00:00:00 2001 From: min486 Date: Tue, 11 Nov 2025 21:45:48 +0900 Subject: [PATCH 83/98] =?UTF-8?q?fix:=20=EA=B5=AD=EB=82=B4/=ED=95=B4?= =?UTF-8?q?=EC=99=B8=20=EC=97=AC=ED=96=89=EC=A7=80=20=EC=A4=91=EB=B3=B5=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=20=EC=95=88=EB=90=98=EA=B2=8C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20=EA=B2=BD=EA=B3=A0=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/write/RecordWriteScreen.kt | 35 +++++- .../write/RecordWriteViewModel.kt | 15 ++- .../write/component/PlaceWarningDialog.kt | 115 ++++++++++++++++++ 3 files changed, 160 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/write/component/PlaceWarningDialog.kt diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index aa7d651..aa35d14 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -79,6 +79,7 @@ import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.ui.theme.MomentoTheme import com.min.dnapp.presentation.write.component.EmotionBottomSheetContent import com.min.dnapp.presentation.write.component.PlaceBottomSheetContent +import com.min.dnapp.presentation.write.component.PlaceWarningDialog import com.min.dnapp.presentation.write.component.ShareGuide import com.min.dnapp.presentation.write.component.WeatherBottomSheetContent import com.min.dnapp.util.toLocalDate @@ -109,6 +110,8 @@ fun RecordWriteScreen( // halfExpanded 상태 건너뛰기 skipPartiallyExpanded = true ) + // 저장된 여행지 삭제 경고 모달 + var showPlaceWarning by remember { mutableStateOf(false) } // Photo Picker 런처 등록 val singlePhotoPickerLauncher = rememberLauncherForActivityResult( @@ -278,9 +281,16 @@ fun RecordWriteScreen( selectedPlace = uiState.selectedPlace, overseasPlace = uiState.overseasPlace, onValueChange = { newValue -> + // 해외 여행지 입력 시, 국내 여행지 저장된 경우 + if (uiState.selectedPlace != null) { viewModel.clearSelectedPlace() } viewModel.updateOverseas(newValue) }, - onClick = { showPlaceBottomSheet = true } + onAddClick = { + // 국내 여행지 추가 클릭 시, 해외 여행지 저장된 경우 + if (uiState.overseasPlace.isNotEmpty()) { viewModel.clearOverseasPlace() } + showPlaceBottomSheet = true + }, + onWarningClick = { showPlaceWarning = true } ) Spacer(Modifier.height(40.dp)) @@ -445,6 +455,18 @@ fun RecordWriteScreen( ) } } + + // 해외 버튼 클릭 시 경고 모달 표시 (국내 여행지 저장된 경우) + if (showPlaceWarning) { + PlaceWarningDialog( + onDismiss = { showPlaceWarning = false }, + onCancel = { showPlaceWarning = false }, + onConfirm = { + viewModel.clearSelectedPlace() + showPlaceWarning = false + } + ) + } } @Composable @@ -613,7 +635,8 @@ fun WritePlaceSection( selectedPlace: LocalPlace?, overseasPlace: String, onValueChange: (String) -> Unit, - onClick: () -> Unit, + onAddClick: () -> Unit, + onWarningClick: () -> Unit, ) { val radioOptions = listOf("국내", "해외 (직접 입력)") var selectedCountry by remember { mutableStateOf("국내") } @@ -640,7 +663,11 @@ fun WritePlaceSection( RadioButton( modifier = Modifier.size(24.dp), selected = (text == selectedCountry), - onClick = { selectedCountry = text }, + onClick = { + // 해외 버튼 클릭 & 저장된 국내 여행지 있는 경우 + if (idx == 1 && selectedPlace != null) { onWarningClick() } + selectedCountry = text + }, colors = RadioButtonDefaults.colors( selectedColor = MomentoTheme.colors.greenW20, unselectedColor = MomentoTheme.colors.grayW80, @@ -664,7 +691,7 @@ fun WritePlaceSection( if (selectedCountry == "국내") { Row( - modifier = Modifier.clickable { onClick() }, + modifier = Modifier.clickable { onAddClick() }, verticalAlignment = Alignment.CenterVertically ) { Image( diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt index 666f9c5..fca3c72 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt @@ -16,7 +16,6 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow @@ -291,4 +290,18 @@ class RecordWriteViewModel @Inject constructor( return null } + + /** + * 저장된 국내 여행지 삭제 + */ + fun clearSelectedPlace() { + _uiState.update { it.copy(selectedPlace = null) } + } + + /** + * 저장된 해외 여행지 삭제 + */ + fun clearOverseasPlace() { + _uiState.update { it.copy(overseasPlace = "") } + } } diff --git a/app/src/main/java/com/min/dnapp/presentation/write/component/PlaceWarningDialog.kt b/app/src/main/java/com/min/dnapp/presentation/write/component/PlaceWarningDialog.kt new file mode 100644 index 0000000..4fd666a --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/write/component/PlaceWarningDialog.kt @@ -0,0 +1,115 @@ +package com.min.dnapp.presentation.write.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +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.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun PlaceWarningDialog( + onDismiss: () -> Unit, + onCancel: () -> Unit, + onConfirm: () -> Unit +) { + Dialog( + onDismissRequest = onDismiss + ) { + Surface( + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(16.dp), + color = MomentoTheme.colors.white + ) { + Column( + modifier = Modifier.padding(horizontal = 20.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(Modifier.height(20.dp)) + + Text( + text = "여행지를 변경하시겠어요?", + style = MomentoTheme.typography.title01, + color = MomentoTheme.colors.grayW20 + ) + + Spacer(Modifier.height(8.dp)) + + Text( + text = "해외 여행지를 입력하면 \n기존에 저장한 국내 여행지가 삭제됩니다.", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW20, + textAlign = TextAlign.Center, + ) + + Spacer(Modifier.height(20.dp)) + + // 취소/변경 버튼 + Row( + modifier = Modifier.fillMaxWidth() + ) { + Box( + modifier = Modifier + .clickable { onCancel() } + .weight(1f) + .background(color = MomentoTheme.colors.white) + .border(width = 1.dp, color = MomentoTheme.colors.grayW80, shape = RoundedCornerShape(5.dp)) + .padding(vertical = 16.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "취소", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + } + Spacer(Modifier.width(12.dp)) + Box( + modifier = Modifier + .clickable { onConfirm() } + .weight(1f) + .background( + color = MomentoTheme.colors.brownBase, + shape = RoundedCornerShape(5.dp) + ) + .padding(vertical = 16.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "변경", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.white + ) + } + } + + Spacer(Modifier.height(20.dp)) + } + } + } +} + +@Preview +@Composable +fun PlaceWarningDialogPreview() { + DngoTheme { +// PlaceWarningDialog() + } +} From d980a665b117b6591760ae653dd965c1275aea96 Mon Sep 17 00:00:00 2001 From: min486 Date: Tue, 11 Nov 2025 22:23:31 +0900 Subject: [PATCH 84/98] =?UTF-8?q?feat:=20=EC=84=A0=ED=83=9D=EB=90=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=82=AD=EC=A0=9C=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/write/RecordWriteScreen.kt | 45 ++++++++++++++----- .../write/RecordWriteViewModel.kt | 7 +++ 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt index aa35d14..ce564f0 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteScreen.kt @@ -18,6 +18,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width @@ -55,6 +56,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.draw.clip import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale @@ -74,6 +76,7 @@ import com.min.dnapp.presentation.ui.component.CustomSnackbar import com.min.dnapp.presentation.ui.icon.AppIcons import com.min.dnapp.presentation.ui.icon.appicons.Back import com.min.dnapp.presentation.ui.icon.appicons.Calendar +import com.min.dnapp.presentation.ui.icon.appicons.Delete import com.min.dnapp.presentation.ui.icon.appicons.Gallery import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.ui.theme.MomentoTheme @@ -301,7 +304,8 @@ fun RecordWriteScreen( recordContent = uiState.recordContent, onValueChange = { newValue -> viewModel.updateContent(newValue) - } + }, + onClick = { viewModel.clearSelectedImageUri() } ) } } @@ -776,7 +780,8 @@ fun WriteTitleSection( fun WriteContentSection( selectedImageUri: Uri?, recordContent: String, - onValueChange: (String) -> Unit + onValueChange: (String) -> Unit, + onClick: () -> Unit ) { Column( modifier = Modifier.fillMaxWidth() @@ -812,18 +817,38 @@ fun WriteContentSection( } // 선택된 이미지 selectedImageUri?.let { uri -> - Box( + Row( modifier = Modifier .fillMaxWidth() .background(color = MomentoTheme.colors.brownBg) - .padding(start = 16.dp, bottom = 16.dp) + .padding(start = 16.dp, bottom = 16.dp), ) { - AsyncImage( - model = uri, - contentDescription = null, - modifier = Modifier.size(72.dp), - contentScale = ContentScale.Crop - ) + Box( + contentAlignment = Alignment.TopEnd + ) { + AsyncImage( + modifier = Modifier + .size(72.dp) + .clip(RoundedCornerShape(5.dp)), + model = uri, + contentDescription = null, + contentScale = ContentScale.Crop + ) + + Box( + modifier = Modifier + .offset(x = 8.dp, y = (-8).dp) + .clickable { onClick() } + .background(color = MomentoTheme.colors.white, shape = CircleShape) + ) { + Icon( + modifier = Modifier.size(20.dp), + imageVector = AppIcons.Delete, + contentDescription = null, + tint = MomentoTheme.colors.grayW60 + ) + } + } } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt index fca3c72..d625acb 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/RecordWriteViewModel.kt @@ -304,4 +304,11 @@ class RecordWriteViewModel @Inject constructor( fun clearOverseasPlace() { _uiState.update { it.copy(overseasPlace = "") } } + + /** + * 선택된 이미지 삭제 + */ + fun clearSelectedImageUri() { + _uiState.update { it.copy(selectedImageUri = null) } + } } From bd9a5bcef30d225e4dc59863ed41bb5a833c8701 Mon Sep 17 00:00:00 2001 From: min486 Date: Wed, 12 Nov 2025 16:04:36 +0900 Subject: [PATCH 85/98] =?UTF-8?q?design:=20=EB=82=B4=20=EA=B8=B0=EB=A1=9D?= =?UTF-8?q?=20=EB=AA=A8=EC=95=84=EB=B3=B4=EA=B8=B0=20=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?UI=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/mypage/MyRecordScreen.kt | 207 +++++++++++++++++- .../mypage/component/MyRecordItem.kt | 40 ---- 2 files changed, 196 insertions(+), 51 deletions(-) delete mode 100644 app/src/main/java/com/min/dnapp/presentation/mypage/component/MyRecordItem.kt diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/MyRecordScreen.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/MyRecordScreen.kt index 2221318..0fcb3a9 100644 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/MyRecordScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/mypage/MyRecordScreen.kt @@ -1,10 +1,20 @@ package com.min.dnapp.presentation.mypage +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.aspectRatio 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.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.CenterAlignedTopAppBar @@ -19,14 +29,21 @@ import androidx.compose.runtime.Composable 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.res.painterResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavHostController -import com.min.dnapp.presentation.mypage.component.MyRecordItem +import coil3.compose.AsyncImage +import com.min.dnapp.R +import com.min.dnapp.presentation.common.EmotionMapper +import com.min.dnapp.presentation.common.WeatherMapper +import com.min.dnapp.presentation.home.YearHeader import com.min.dnapp.presentation.ui.icon.AppIcons import com.min.dnapp.presentation.ui.icon.appicons.Back import com.min.dnapp.presentation.ui.theme.MomentoTheme +import com.min.dnapp.util.toDateString @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -84,25 +101,193 @@ fun MyRecordScreen( LazyColumn( modifier = Modifier .padding(paddingValues) + .padding(horizontal = 20.dp) .fillMaxSize() ) { itemsIndexed(data.records) { idx, record -> - Box( - modifier = Modifier.padding(20.dp) - ) { - // 내 여행기록 아이템 - MyRecordItem( - record = record, - onClick = {} - ) + + // 현재 항목의 년도 + val currentYear = record.startDateMillis.toDateString("yyyy") + + // 직전 항목의 년도와 비교 + val previousYear = if (idx > 0) { + data.records[idx-1].startDateMillis.toDateString("yyyy") + } else { + null } - if (idx < data.records.size - 1) { - HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.grayW80) + // 년도별 첫번째 항목 여부 (1번째 항목인 경우 or 년도가 바뀌는 시점) + val isYearStart = (idx == 0) || (currentYear != previousYear) + + // 년도 표시 + if (isYearStart) { + Spacer(Modifier.height(20.dp)) + YearHeader(year = currentYear) + Spacer(Modifier.height(12.dp)) } + + // 날짜, 날씨+감정 + MyRecordItemHeaderSection( + startDateMillis = record.startDateMillis, + endDateMillis = if (record.endDateMillis == 0L) null else record.endDateMillis, + weatherName = record.weatherKey, + emotionName = record.emotionKey, + ) + + Spacer(Modifier.height(8.dp)) + + // 내 기록 아이템 + MyRecordItem( + title = record.title, + content = record.content, + placeName = record.selectedPlace?.title, + imageUrl = if (record.imageUrl.isEmpty()) null else record.imageUrl + ) + + Spacer(Modifier.height(20.dp)) } } } } } } + +@Composable +fun MyRecordItemHeaderSection( + startDateMillis: Long, + endDateMillis: Long?, + weatherName: String, + emotionName: String, +) { + val startDate = startDateMillis.toDateString("MM.dd") + val endDate = endDateMillis?.toDateString("MM.dd") + + // 여행 날짜 텍스트 계산 + val dateText = endDate?.let { "$startDate ~ $it" } ?: startDate + + // 날씨 & 감정 이미지 리소스로 변환 + val weatherImageResId = WeatherMapper.getWeatherImageResId(weatherName) + val emotionImageResId = EmotionMapper.getEmotionImageResId(emotionName) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + // 날짜 (08.20 ~ 08.22) + Text( + text = dateText, + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW20 + ) + + // 날씨 & 감정 + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "날씨", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW20 + ) + Spacer(Modifier.width(4.dp)) + Image( + modifier = Modifier.size(28.dp), + painter = painterResource(weatherImageResId), + contentDescription = null + ) + } + + Spacer(Modifier.width(8.dp)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "감정", + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW20 + ) + Spacer(Modifier.width(4.dp)) + Image( + modifier = Modifier.size(28.dp), + painter = painterResource(emotionImageResId), + contentDescription = null + ) + } + } + } +} + +@Composable +fun MyRecordItem( + title: String, + content: String, + placeName: String?, + imageUrl: String? +) { + Column( + modifier = Modifier + .fillMaxWidth() + .background(color = MomentoTheme.colors.brownW90) + .padding(16.dp) + ) { + // 여행 제목 + Text( + text = title, + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW20 + ) + + Spacer(Modifier.height(8.dp)) + + HorizontalDivider(thickness = 1.dp, color = MomentoTheme.colors.pinkBase) + + Spacer(Modifier.height(8.dp)) + + // 여행 장소 + placeName?.let { place -> + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(R.drawable.write_place), + contentDescription = null + ) + Spacer(Modifier.width(6.dp)) + Text( + text = place, + style = MomentoTheme.typography.body03 , + color = MomentoTheme.colors.grayW20 + ) + } + } + + Spacer(Modifier.height(8.dp)) + + // 여행 내용 + Text( + text = content, + style = MomentoTheme.typography.body02, + color = MomentoTheme.colors.grayW20 + ) + + // 여행 이미지 + imageUrl?.let { image -> + Spacer(Modifier.height(8.dp)) + + AsyncImage( + modifier = Modifier + .fillMaxWidth() + // 가로:세로 비율 1:1 + .aspectRatio(1f), + model = image, + contentDescription = null, + contentScale = ContentScale.Crop + ) + } + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/mypage/component/MyRecordItem.kt b/app/src/main/java/com/min/dnapp/presentation/mypage/component/MyRecordItem.kt deleted file mode 100644 index c4369ad..0000000 --- a/app/src/main/java/com/min/dnapp/presentation/mypage/component/MyRecordItem.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.min.dnapp.presentation.mypage.component - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview -import com.min.dnapp.domain.model.TripRecord -import com.min.dnapp.presentation.find.component.SharedRecordContentSection -import com.min.dnapp.presentation.ui.theme.DngoTheme - -@Composable -fun MyRecordItem( - record: TripRecord, - onClick: () -> Unit -) { - Column( - modifier = Modifier.fillMaxWidth() - ) { - // 기록 전체내용 - SharedRecordContentSection( - title = record.title, - content = record.content, - startDateMillis = record.startDateMillis, - endDateMillis = if (record.endDateMillis == 0L) null else record.endDateMillis, - weatherName = record.weatherKey, - emotionName = record.emotionKey, - placeName = record.selectedPlace?.title, - imageUrl = if (record.imageUrl.isEmpty()) null else record.imageUrl - ) - } -} - -@Preview -@Composable -fun MyRecordItemPreview() { - DngoTheme { -// MyRecordItem() - } -} From 0c87f33b26f3cd3c3bf62ccfaa7269ac163baae9 Mon Sep 17 00:00:00 2001 From: min486 Date: Wed, 12 Nov 2025 22:37:43 +0900 Subject: [PATCH 86/98] =?UTF-8?q?feat:=20=EB=88=84=EC=A0=81=20=EC=8A=A4?= =?UTF-8?q?=ED=83=AC=ED=94=84=20=EC=88=98=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?=EB=B1=83=EC=A7=80=20=EB=93=B1=EA=B8=89=20=EA=B2=B0=EC=A0=95=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/min/dnapp/domain/BadgeUtil.kt | 43 ++++++++ .../java/com/min/dnapp/domain/model/Badge.kt | 12 +++ .../usecase/GetBadgeDialogDataUseCase.kt | 11 +++ .../presentation/write/LevelUpViewModel.kt | 63 ++++++++++++ .../write/WriteFinishDialogState.kt | 9 ++ .../presentation/write/WriteFinishScreen.kt | 41 ++++---- .../write/component/LevelUpDialog.kt | 99 +++++++++++++++++++ 7 files changed, 260 insertions(+), 18 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/domain/BadgeUtil.kt create mode 100644 app/src/main/java/com/min/dnapp/domain/model/Badge.kt create mode 100644 app/src/main/java/com/min/dnapp/domain/usecase/GetBadgeDialogDataUseCase.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/write/LevelUpViewModel.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/write/WriteFinishDialogState.kt create mode 100644 app/src/main/java/com/min/dnapp/presentation/write/component/LevelUpDialog.kt diff --git a/app/src/main/java/com/min/dnapp/domain/BadgeUtil.kt b/app/src/main/java/com/min/dnapp/domain/BadgeUtil.kt new file mode 100644 index 0000000..422cc13 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/BadgeUtil.kt @@ -0,0 +1,43 @@ +package com.min.dnapp.domain + +import com.min.dnapp.R +import com.min.dnapp.domain.model.Badge + +val AllBadges = listOf( + Badge( + level = 1, + name = "새내기", + description = "다음 뱃지까지 5개 남았어요", + minStamp = 0, + nextBadgeRemainStamp = 5, + resId = R.drawable.badge_new, + ), + Badge( + level = 2, + name = "여린이", + description = "다음 뱃지까지 15개 남았어요", + minStamp = 5, + nextBadgeRemainStamp = 15, + resId = R.drawable.badge_bronze + ), + Badge( + level = 2, + name = "여행자", + description = "다음 뱃지까지 10개 남았어요", + minStamp = 20, + nextBadgeRemainStamp = 10, + resId = R.drawable.badge_silver + ), + Badge( + level = 3, + name = "마스터", + description = "최고 뱃지에 도달하셨어요", + minStamp = 30, + nextBadgeRemainStamp = 0, + resId = R.drawable.badge_gold + ) +) + +fun getNewBadgeData(totalStamp: Int): Badge? { + return AllBadges.firstOrNull { it.minStamp == totalStamp } +} diff --git a/app/src/main/java/com/min/dnapp/domain/model/Badge.kt b/app/src/main/java/com/min/dnapp/domain/model/Badge.kt new file mode 100644 index 0000000..3389226 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/model/Badge.kt @@ -0,0 +1,12 @@ +package com.min.dnapp.domain.model + +import androidx.annotation.DrawableRes + +data class Badge( + val level: Int, + val name: String, + val description: String, + val minStamp: Int, + val nextBadgeRemainStamp: Int, + @DrawableRes val resId: Int, +) diff --git a/app/src/main/java/com/min/dnapp/domain/usecase/GetBadgeDialogDataUseCase.kt b/app/src/main/java/com/min/dnapp/domain/usecase/GetBadgeDialogDataUseCase.kt new file mode 100644 index 0000000..e9b1f63 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/usecase/GetBadgeDialogDataUseCase.kt @@ -0,0 +1,11 @@ +package com.min.dnapp.domain.usecase + +import com.min.dnapp.domain.getNewBadgeData +import com.min.dnapp.domain.model.Badge +import javax.inject.Inject + +class GetBadgeDialogDataUseCase @Inject constructor() { + operator fun invoke(totalStamp: Int): Badge? { + return getNewBadgeData(totalStamp) + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/write/LevelUpViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/write/LevelUpViewModel.kt new file mode 100644 index 0000000..5a3720f --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/write/LevelUpViewModel.kt @@ -0,0 +1,63 @@ +package com.min.dnapp.presentation.write + +import android.util.Log +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.min.dnapp.domain.usecase.GetBadgeDialogDataUseCase +import com.min.dnapp.domain.usecase.GetCurrentUserIdUseCase +import com.min.dnapp.domain.usecase.GetUserDataUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class LevelUpViewModel @Inject constructor( + private val getCurrentUserIdUseCase: GetCurrentUserIdUseCase, + private val getUserDataUseCase: GetUserDataUseCase, + private val getBadgeDialogDataUseCase: GetBadgeDialogDataUseCase +) : ViewModel() { + + private val _dialogState = MutableStateFlow(WriteFinishDialogState.Hidden) + val dialogState: StateFlow = _dialogState.asStateFlow() + + init { + checkNewBadge() + } + + /** + * 새로운 뱃지 달성 여부 체크 + */ + fun checkNewBadge() { + viewModelScope.launch { + + // 사용자 ID 가져오기 + val uid = try { + getCurrentUserIdUseCase() ?: throw Exception("사용자 인증 정보 없음") + } catch (e: Exception) { + Log.e("write", "사용자 정보 조회 실패", e) + return@launch + } + + // 1초 지연 후 모달 표시 + delay(1000) + + val useData = getUserDataUseCase(uid) + val userStamp = useData.stampCnt + + val newBadge = getBadgeDialogDataUseCase(userStamp) + _dialogState.value = if (newBadge != null) { + WriteFinishDialogState.BadgeDialog(newBadge) + } else { + WriteFinishDialogState.StampDialog + } + } + } + + fun closeDialog() { + _dialogState.value = WriteFinishDialogState.Hidden + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishDialogState.kt b/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishDialogState.kt new file mode 100644 index 0000000..25ab12f --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishDialogState.kt @@ -0,0 +1,9 @@ +package com.min.dnapp.presentation.write + +import com.min.dnapp.domain.model.Badge + +sealed class WriteFinishDialogState { + data object Hidden: WriteFinishDialogState() + data object StampDialog: WriteFinishDialogState() + data class BadgeDialog(val badge: Badge): WriteFinishDialogState() +} diff --git a/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt index 2dcc4b4..b8f7c6b 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt @@ -16,33 +16,27 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect 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.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavHostController import com.min.dnapp.R import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.ui.theme.MomentoTheme +import com.min.dnapp.presentation.write.component.LevelUpDialog import com.min.dnapp.presentation.write.component.WriteStampDialog -import kotlinx.coroutines.delay @Composable fun WriteFinishScreen( - navController: NavHostController + navController: NavHostController, + viewModel: LevelUpViewModel = hiltViewModel() ) { - var showStampDialog by remember { mutableStateOf(false) } - - LaunchedEffect(Unit) { - delay(1000) - showStampDialog = true - } + val currentDialogState by viewModel.dialogState.collectAsStateWithLifecycle() Surface( modifier = Modifier @@ -101,12 +95,23 @@ fun WriteFinishScreen( } } - // 스탬프 지급 모달창 - if (showStampDialog) { - WriteStampDialog( - onDismiss = { showStampDialog = false }, - onConfirm = { showStampDialog = false } - ) + when (currentDialogState) { + is WriteFinishDialogState.BadgeDialog -> { + val data = currentDialogState as WriteFinishDialogState.BadgeDialog + + LevelUpDialog( + badge = data.badge, + onDismiss = { viewModel.closeDialog() }, + onConfirm = { viewModel.closeDialog() }, + ) + } + is WriteFinishDialogState.StampDialog -> { + WriteStampDialog( + onDismiss = { viewModel.closeDialog() }, + onConfirm = { viewModel.closeDialog() } + ) + } + is WriteFinishDialogState.Hidden -> {} } } diff --git a/app/src/main/java/com/min/dnapp/presentation/write/component/LevelUpDialog.kt b/app/src/main/java/com/min/dnapp/presentation/write/component/LevelUpDialog.kt new file mode 100644 index 0000000..c32d2cb --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/write/component/LevelUpDialog.kt @@ -0,0 +1,99 @@ +package com.min.dnapp.presentation.write.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +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.shape.RoundedCornerShape +import androidx.compose.material3.Surface +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.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import com.min.dnapp.domain.model.Badge +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun LevelUpDialog( + badge: Badge, + onDismiss: () -> Unit, + onConfirm: () -> Unit +) { + Dialog( + onDismissRequest = onDismiss + ) { + Surface( + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(16.dp), + color = MomentoTheme.colors.white + ) { + Column( + modifier = Modifier.padding(horizontal = 20.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(Modifier.height(20.dp)) + Text( + text = "${badge.name}가 된 것을 축하해요!", + style = MomentoTheme.typography.title01, + color = MomentoTheme.colors.grayW20 + ) + Spacer(Modifier.height(8.dp)) + Text( + text = "여행 기록 ${badge.minStamp}개 달성", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW60 + ) + Spacer(Modifier.height(20.dp)) + Image( + modifier = Modifier.size(160.dp), + painter = painterResource(badge.resId), + contentDescription = null + ) + Spacer(Modifier.height(20.dp)) + Text( + text = badge.description, + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.grayW20 + ) + Spacer(Modifier.height(20.dp)) + Box( + modifier = Modifier + .clickable { onConfirm() } + .fillMaxWidth() + .background( + color = MomentoTheme.colors.brownBase, + shape = RoundedCornerShape(10.dp) + ) + .padding(vertical = 16.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "확인했어요", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.white + ) + } + Spacer(Modifier.height(20.dp)) + } + } + } +} + +@Preview +@Composable +fun LevelUpDialogPreview() { + DngoTheme { +// LevelUpDialog() + } +} From f494bc646537f951a111ffc9ab6dc76230b7c73a Mon Sep 17 00:00:00 2001 From: min486 Date: Wed, 12 Nov 2025 23:18:34 +0900 Subject: [PATCH 87/98] =?UTF-8?q?feat:=20=EC=83=88=EB=A1=9C=EC=9A=B4=20?= =?UTF-8?q?=EB=B1=83=EC=A7=80=20=EB=8B=AC=EC=84=B1=20=EC=8B=9C,=20?= =?UTF-8?q?=EB=B1=83=EC=A7=80=20=EC=A0=95=EB=B3=B4=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/UserRepositoryImpl.kt | 21 ++++++++++++++ .../java/com/min/dnapp/domain/BadgeUtil.kt | 4 +-- .../dnapp/domain/repository/UserRepository.kt | 2 ++ .../domain/usecase/UpdateUserBadgeUseCase.kt | 13 +++++++++ ...lUpViewModel.kt => CheckBadgeViewModel.kt} | 29 +++++++++++++++---- .../presentation/write/WriteFinishScreen.kt | 2 +- 6 files changed, 62 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/domain/usecase/UpdateUserBadgeUseCase.kt rename app/src/main/java/com/min/dnapp/presentation/write/{LevelUpViewModel.kt => CheckBadgeViewModel.kt} (73%) diff --git a/app/src/main/java/com/min/dnapp/data/repository/UserRepositoryImpl.kt b/app/src/main/java/com/min/dnapp/data/repository/UserRepositoryImpl.kt index c8aafe4..44813c2 100644 --- a/app/src/main/java/com/min/dnapp/data/repository/UserRepositoryImpl.kt +++ b/app/src/main/java/com/min/dnapp/data/repository/UserRepositoryImpl.kt @@ -4,6 +4,7 @@ import android.util.Log import com.google.firebase.auth.FirebaseAuth import com.google.firebase.firestore.FirebaseFirestore import com.min.dnapp.data.remote.dto.UserEntity +import com.min.dnapp.domain.model.Badge import com.min.dnapp.domain.repository.UserRepository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.tasks.await @@ -76,4 +77,24 @@ class UserRepositoryImpl @Inject constructor( } } } + + override suspend fun updateBadge(badge: Badge): Result { + val userId = currentUserId + val userDoc = firestore.collection("users").document(userId) + + val newBadge = mapOf( + "badgeLv" to badge.level, + "badgeName" to badge.name + ) + + return withContext(Dispatchers.IO) { + try { + userDoc.update(newBadge).await() + Result.success(Unit) + } catch (e: Exception) { + Log.e("user", "updateBadge error", e) + Result.failure(e) + } + } + } } diff --git a/app/src/main/java/com/min/dnapp/domain/BadgeUtil.kt b/app/src/main/java/com/min/dnapp/domain/BadgeUtil.kt index 422cc13..e3f4a33 100644 --- a/app/src/main/java/com/min/dnapp/domain/BadgeUtil.kt +++ b/app/src/main/java/com/min/dnapp/domain/BadgeUtil.kt @@ -21,7 +21,7 @@ val AllBadges = listOf( resId = R.drawable.badge_bronze ), Badge( - level = 2, + level = 3, name = "여행자", description = "다음 뱃지까지 10개 남았어요", minStamp = 20, @@ -29,7 +29,7 @@ val AllBadges = listOf( resId = R.drawable.badge_silver ), Badge( - level = 3, + level = 4, name = "마스터", description = "최고 뱃지에 도달하셨어요", minStamp = 30, diff --git a/app/src/main/java/com/min/dnapp/domain/repository/UserRepository.kt b/app/src/main/java/com/min/dnapp/domain/repository/UserRepository.kt index b2d61bd..b06c3d9 100644 --- a/app/src/main/java/com/min/dnapp/domain/repository/UserRepository.kt +++ b/app/src/main/java/com/min/dnapp/domain/repository/UserRepository.kt @@ -1,9 +1,11 @@ package com.min.dnapp.domain.repository import com.min.dnapp.data.remote.dto.UserEntity +import com.min.dnapp.domain.model.Badge interface UserRepository { suspend fun getUserData(uid: String): UserEntity suspend fun updateProfileImage(profileImageName: String): Result suspend fun updateNickname(nickname: String): Result + suspend fun updateBadge(badge: Badge): Result } diff --git a/app/src/main/java/com/min/dnapp/domain/usecase/UpdateUserBadgeUseCase.kt b/app/src/main/java/com/min/dnapp/domain/usecase/UpdateUserBadgeUseCase.kt new file mode 100644 index 0000000..e00417a --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/usecase/UpdateUserBadgeUseCase.kt @@ -0,0 +1,13 @@ +package com.min.dnapp.domain.usecase + +import com.min.dnapp.domain.model.Badge +import com.min.dnapp.domain.repository.UserRepository +import javax.inject.Inject + +class UpdateUserBadgeUseCase @Inject constructor( + private val userRepository: UserRepository +) { + suspend operator fun invoke(badge: Badge): Result { + return userRepository.updateBadge(badge) + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/write/LevelUpViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/write/CheckBadgeViewModel.kt similarity index 73% rename from app/src/main/java/com/min/dnapp/presentation/write/LevelUpViewModel.kt rename to app/src/main/java/com/min/dnapp/presentation/write/CheckBadgeViewModel.kt index 5a3720f..3c17c45 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/LevelUpViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/CheckBadgeViewModel.kt @@ -6,6 +6,7 @@ import androidx.lifecycle.viewModelScope import com.min.dnapp.domain.usecase.GetBadgeDialogDataUseCase import com.min.dnapp.domain.usecase.GetCurrentUserIdUseCase import com.min.dnapp.domain.usecase.GetUserDataUseCase +import com.min.dnapp.domain.usecase.UpdateUserBadgeUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow @@ -15,10 +16,11 @@ import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel -class LevelUpViewModel @Inject constructor( +class CheckBadgeViewModel @Inject constructor( private val getCurrentUserIdUseCase: GetCurrentUserIdUseCase, private val getUserDataUseCase: GetUserDataUseCase, - private val getBadgeDialogDataUseCase: GetBadgeDialogDataUseCase + private val getBadgeDialogDataUseCase: GetBadgeDialogDataUseCase, + private val updateUserBadgeUseCase: UpdateUserBadgeUseCase ) : ViewModel() { private val _dialogState = MutableStateFlow(WriteFinishDialogState.Hidden) @@ -42,16 +44,31 @@ class LevelUpViewModel @Inject constructor( return@launch } - // 1초 지연 후 모달 표시 - delay(1000) - val useData = getUserDataUseCase(uid) val userStamp = useData.stampCnt - val newBadge = getBadgeDialogDataUseCase(userStamp) + + // 뱃지 업데이트 DB에 반영 + if (newBadge != null) { + val result = updateUserBadgeUseCase(newBadge) + + // DB 업데이트 실패 시 + if (result.isFailure) { + Log.e("user", "뱃지 DB 업데이트 실패: ${result.exceptionOrNull()}") + + _dialogState.value = WriteFinishDialogState.StampDialog + return@launch + } + } + + // 1초 지연 후 모달 표시 + delay(1000) + _dialogState.value = if (newBadge != null) { + // 뱃지 모달 표시 WriteFinishDialogState.BadgeDialog(newBadge) } else { + // 스탬프 모달 표시 WriteFinishDialogState.StampDialog } } diff --git a/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt b/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt index b8f7c6b..e24efe3 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/WriteFinishScreen.kt @@ -34,7 +34,7 @@ import com.min.dnapp.presentation.write.component.WriteStampDialog @Composable fun WriteFinishScreen( navController: NavHostController, - viewModel: LevelUpViewModel = hiltViewModel() + viewModel: CheckBadgeViewModel = hiltViewModel() ) { val currentDialogState by viewModel.dialogState.collectAsStateWithLifecycle() From 157d921a36a2482475fe0fac3a4b00bb9618dfe5 Mon Sep 17 00:00:00 2001 From: min486 Date: Thu, 13 Nov 2025 00:12:57 +0900 Subject: [PATCH 88/98] =?UTF-8?q?feat:=20LevelUpDialog=20-=20=EB=A1=9C?= =?UTF-8?q?=ED=8B=B0=20=EC=95=A0=EB=8B=88=EB=A9=94=EC=9D=B4=EC=85=98=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 2 + app/src/main/assets/fireworks.json | 1 + .../write/component/LevelUpDialog.kt | 117 ++++++++++++------ gradle/libs.versions.toml | 2 + 4 files changed, 81 insertions(+), 41 deletions(-) create mode 100644 app/src/main/assets/fireworks.json diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 218dc95..c9ab0fc 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -109,6 +109,8 @@ dependencies { // coil implementation(libs.coil) implementation(libs.coil.okhttp) + // lottie compose + implementation(libs.lottie.compose) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) diff --git a/app/src/main/assets/fireworks.json b/app/src/main/assets/fireworks.json new file mode 100644 index 0000000..4f133f9 --- /dev/null +++ b/app/src/main/assets/fireworks.json @@ -0,0 +1 @@ +{"v":"5.1.4","fr":60,"ip":0,"op":240,"w":375,"h":375,"nm":"Comp 2","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,1.083]},"o":{"x":[0.012,1],"y":[0,0]},"n":["0p833_1_0p012_0","0p833_1p083_1_0"],"t":0,"s":[0,1],"e":[93.75,1]},{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0.083]},"n":["0p667_1_0p167_0","0p667_1_0p167_0p083"],"t":15,"s":[93.75,1],"e":[0,0]},{"t":30}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"n":"0p833_0p833_0p333_0","t":0,"s":[-187.5,0],"e":[-93.75,0],"to":[15.625,0],"ti":[-31.25,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":15,"s":[-93.75,0],"e":[0,0],"to":[31.25,0],"ti":[-15.625,0]},{"t":30}],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.490196078431,0.698039215686,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":15,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.03,0.03,0.333],"y":[0,0,0]},"n":["0_1_0p03_0","0_1_0p03_0","0p667_1_0p333_0"],"t":36,"s":[0,0,100],"e":[100,100,100]},{"t":104}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":36,"s":[0,0],"e":[0,100],"to":[0,16.6666660308838],"ti":[0,-16.6666660308838]},{"t":104}],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":20,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.490196078431,0.698039215686,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-5.023,10.539],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.03,0.03],"y":[0,0]},"n":["0_1_0p03_0","0_1_0p03_0"],"t":36,"s":[60,0],"e":[0,100]},{"t":104}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"rp","c":{"a":0,"k":12,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":30,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false}],"ip":34,"op":105,"st":28,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":7.5,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.03,0.03,0.333],"y":[0,0,0]},"n":["0_1_0p03_0","0_1_0p03_0","0p667_1_0p333_0"],"t":32,"s":[0,0,100],"e":[100,100,100]},{"t":96}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":32,"s":[0,0],"e":[0,100],"to":[0,16.6666660308838],"ti":[0,-16.6666660308838]},{"t":96}],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":20,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.750827205882,0.852413042854,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-5.023,10.539],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.03,0.03],"y":[0,0]},"n":["0_1_0p03_0","0_1_0p03_0"],"t":32,"s":[60,0],"e":[0,100]},{"t":96}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"rp","c":{"a":0,"k":24,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":15,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false}],"ip":30,"op":98,"st":28,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.03,0.03,0.333],"y":[0,0,0]},"n":["0_1_0p03_0","0_1_0p03_0","0p667_1_0p333_0"],"t":28,"s":[0,0,100],"e":[100,100,100]},{"t":88}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":28,"s":[0,0],"e":[0,100],"to":[0,16.6666660308838],"ti":[0,-16.6666660308838]},{"t":88}],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":20,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.490196078431,0.698039215686,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-5.023,10.539],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.03,0.03],"y":[0,0]},"n":["0_1_0p03_0","0_1_0p03_0"],"t":28,"s":[60,0],"e":[0,100]},{"t":88}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"rp","c":{"a":0,"k":12,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":30,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false}],"ip":28,"op":91,"st":28,"bm":0}]},{"id":"comp_1","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,1.083]},"o":{"x":[0.012,1],"y":[0,0]},"n":["0p833_1_0p012_0","0p833_1p083_1_0"],"t":0,"s":[0,1],"e":[93.75,1]},{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0.083]},"n":["0p667_1_0p167_0","0p667_1_0p167_0p083"],"t":15,"s":[93.75,1],"e":[0,0]},{"t":30}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"n":"0p833_0p833_0p333_0","t":0,"s":[-187.5,0],"e":[-93.75,0],"to":[15.625,0],"ti":[-31.25,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":15,"s":[-93.75,0],"e":[0,0],"to":[31.25,0],"ti":[-15.625,0]},{"t":30}],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.486274509804,0.364705882353,0.929411764706,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":15,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.03,0.03,0.333],"y":[0,0,0]},"n":["0_1_0p03_0","0_1_0p03_0","0p667_1_0p333_0"],"t":36,"s":[0,0,100],"e":[100,100,100]},{"t":104}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":36,"s":[0,0],"e":[0,100],"to":[0,16.6666660308838],"ti":[0,-16.6666660308838]},{"t":104}],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":20,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.486274509804,0.364705882353,0.929411764706,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-5.023,10.539],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.03,0.03],"y":[0,0]},"n":["0_1_0p03_0","0_1_0p03_0"],"t":36,"s":[60,0],"e":[0,100]},{"t":104}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"rp","c":{"a":0,"k":12,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":30,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false}],"ip":34,"op":105,"st":28,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":7.5,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.03,0.03,0.333],"y":[0,0,0]},"n":["0_1_0p03_0","0_1_0p03_0","0p667_1_0p333_0"],"t":32,"s":[0,0,100],"e":[100,100,100]},{"t":96}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":32,"s":[0,0],"e":[0,100],"to":[0,16.6666660308838],"ti":[0,-16.6666660308838]},{"t":96}],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":20,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.643137254902,0.556862745098,0.952941176471,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-5.023,10.539],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.03,0.03],"y":[0,0]},"n":["0_1_0p03_0","0_1_0p03_0"],"t":32,"s":[60,0],"e":[0,100]},{"t":96}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"rp","c":{"a":0,"k":24,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":15,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false}],"ip":30,"op":98,"st":28,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.03,0.03,0.333],"y":[0,0,0]},"n":["0_1_0p03_0","0_1_0p03_0","0p667_1_0p333_0"],"t":28,"s":[0,0,100],"e":[100,100,100]},{"t":88}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":28,"s":[0,0],"e":[0,100],"to":[0,16.6666660308838],"ti":[0,-16.6666660308838]},{"t":88}],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":20,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.486274509804,0.364705882353,0.929411764706,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-5.023,10.539],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.03,0.03],"y":[0,0]},"n":["0_1_0p03_0","0_1_0p03_0"],"t":28,"s":[60,0],"e":[0,100]},{"t":88}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"rp","c":{"a":0,"k":12,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":30,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false}],"ip":28,"op":91,"st":28,"bm":0}]},{"id":"comp_2","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,1.083]},"o":{"x":[0.012,1],"y":[0,0]},"n":["0p833_1_0p012_0","0p833_1p083_1_0"],"t":0,"s":[0,1],"e":[93.75,1]},{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0.083]},"n":["0p667_1_0p167_0","0p667_1_0p167_0p083"],"t":15,"s":[93.75,1],"e":[0,0]},{"t":30}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"n":"0p833_0p833_0p333_0","t":0,"s":[-187.5,0],"e":[-93.75,0],"to":[15.625,0],"ti":[-31.25,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":15,"s":[-93.75,0],"e":[0,0],"to":[31.25,0],"ti":[-15.625,0]},{"t":30}],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.494117647059,0.839215686275,0.956862745098,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":15,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.03,0.03,0.333],"y":[0,0,0]},"n":["0_1_0p03_0","0_1_0p03_0","0p667_1_0p333_0"],"t":36,"s":[0,0,100],"e":[100,100,100]},{"t":104}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":36,"s":[0,0],"e":[0,100],"to":[0,16.6666660308838],"ti":[0,-16.6666660308838]},{"t":104}],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":20,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.494117647059,0.839215686275,0.956862745098,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-5.023,10.539],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.03,0.03],"y":[0,0]},"n":["0_1_0p03_0","0_1_0p03_0"],"t":36,"s":[60,0],"e":[0,100]},{"t":104}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"rp","c":{"a":0,"k":12,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":30,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false}],"ip":34,"op":105,"st":28,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":7.5,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.03,0.03,0.333],"y":[0,0,0]},"n":["0_1_0p03_0","0_1_0p03_0","0p667_1_0p333_0"],"t":32,"s":[0,0,100],"e":[100,100,100]},{"t":96}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":32,"s":[0,0],"e":[0,100],"to":[0,16.6666660308838],"ti":[0,-16.6666660308838]},{"t":96}],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":20,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.730839568493,0.892384906844,0.947457107843,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-5.023,10.539],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.03,0.03],"y":[0,0]},"n":["0_1_0p03_0","0_1_0p03_0"],"t":32,"s":[60,0],"e":[0,100]},{"t":96}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"rp","c":{"a":0,"k":24,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":15,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false}],"ip":30,"op":98,"st":28,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.03,0.03,0.333],"y":[0,0,0]},"n":["0_1_0p03_0","0_1_0p03_0","0p667_1_0p333_0"],"t":28,"s":[0,0,100],"e":[100,100,100]},{"t":88}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":28,"s":[0,0],"e":[0,100],"to":[0,16.6666660308838],"ti":[0,-16.6666660308838]},{"t":88}],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":20,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.494117647059,0.839215686275,0.956862745098,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-5.023,10.539],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.03,0.03],"y":[0,0]},"n":["0_1_0p03_0","0_1_0p03_0"],"t":28,"s":[60,0],"e":[0,100]},{"t":88}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"rp","c":{"a":0,"k":12,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":30,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false}],"ip":28,"op":91,"st":28,"bm":0}]},{"id":"comp_3","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,1.083]},"o":{"x":[0.012,1],"y":[0,0]},"n":["0p833_1_0p012_0","0p833_1p083_1_0"],"t":0,"s":[0,1],"e":[93.75,1]},{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0.083]},"n":["0p667_1_0p167_0","0p667_1_0p167_0p083"],"t":15,"s":[93.75,1],"e":[0,0]},{"t":30}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"n":"0p833_0p833_0p333_0","t":0,"s":[-187.5,0],"e":[-93.75,0],"to":[15.625,0],"ti":[-31.25,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":15,"s":[-93.75,0],"e":[0,0],"to":[31.25,0],"ti":[-15.625,0]},{"t":30}],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.717647058824,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":15,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.03,0.03,0.333],"y":[0,0,0]},"n":["0_1_0p03_0","0_1_0p03_0","0p667_1_0p333_0"],"t":36,"s":[0,0,100],"e":[100,100,100]},{"t":104}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":36,"s":[0,0],"e":[0,100],"to":[0,16.6666660308838],"ti":[0,-16.6666660308838]},{"t":104}],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":20,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.717647058824,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-5.023,10.539],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.03,0.03],"y":[0,0]},"n":["0_1_0p03_0","0_1_0p03_0"],"t":36,"s":[70,0],"e":[0,100]},{"t":104}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"rp","c":{"a":0,"k":12,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":30,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false}],"ip":34,"op":105,"st":28,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":7.5,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.03,0.03,0.333],"y":[0,0,0]},"n":["0_1_0p03_0","0_1_0p03_0","0p667_1_0p333_0"],"t":32,"s":[0,0,100],"e":[100,100,100]},{"t":96}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":32,"s":[0,0],"e":[0,100],"to":[0,16.6666660308838],"ti":[0,-16.6666660308838]},{"t":96}],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":20,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.82023788153,0.36334252451,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-5.023,10.539],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.03,0.03],"y":[0,0]},"n":["0_1_0p03_0","0_1_0p03_0"],"t":32,"s":[70,0],"e":[0,100]},{"t":96}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"rp","c":{"a":0,"k":24,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":15,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false}],"ip":30,"op":98,"st":28,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.03,0.03,0.333],"y":[0,0,0]},"n":["0_1_0p03_0","0_1_0p03_0","0p667_1_0p333_0"],"t":28,"s":[0,0,100],"e":[100,100,100]},{"t":88}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":28,"s":[0,0],"e":[0,100],"to":[0,16.6666660308838],"ti":[0,-16.6666660308838]},{"t":88}],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":20,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.717647058824,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-5.023,10.539],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.03,0.03],"y":[0,0]},"n":["0_1_0p03_0","0_1_0p03_0"],"t":28,"s":[70,0],"e":[0,100]},{"t":88}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"rp","c":{"a":0,"k":12,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":30,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false}],"ip":28,"op":91,"st":28,"bm":0}]},{"id":"comp_4","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,1.083]},"o":{"x":[0.012,1],"y":[0,0]},"n":["0p833_1_0p012_0","0p833_1p083_1_0"],"t":0,"s":[0,1],"e":[93.75,1]},{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0.083]},"n":["0p667_1_0p167_0","0p667_1_0p167_0p083"],"t":15,"s":[93.75,1],"e":[0,0]},{"t":30}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"n":"0p833_0p833_0p333_0","t":0,"s":[-187.5,0],"e":[-93.75,0],"to":[15.625,0],"ti":[-31.25,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":15,"s":[-93.75,0],"e":[0,0],"to":[31.25,0],"ti":[-15.625,0]},{"t":30}],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.839215686275,0.827450980392,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":15,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.03,0.03,0.333],"y":[0,0,0]},"n":["0_1_0p03_0","0_1_0p03_0","0p667_1_0p333_0"],"t":36,"s":[0,0,100],"e":[100,100,100]},{"t":104}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":36,"s":[0,0],"e":[0,100],"to":[0,16.6666660308838],"ti":[0,-16.6666660308838]},{"t":104}],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":20,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.839215686275,0.827450980392,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-5.023,10.539],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.03,0.03],"y":[0,0]},"n":["0_1_0p03_0","0_1_0p03_0"],"t":36,"s":[75,0],"e":[0,100]},{"t":104}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"rp","c":{"a":0,"k":12,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":30,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false}],"ip":34,"op":105,"st":28,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":7.5,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.03,0.03,0.333],"y":[0,0,0]},"n":["0_1_0p03_0","0_1_0p03_0","0p667_1_0p333_0"],"t":32,"s":[0,0,100],"e":[100,100,100]},{"t":96}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":32,"s":[0,0],"e":[0,100],"to":[0,16.6666660308838],"ti":[0,-16.6666660308838]},{"t":96}],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":20,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.408093830183,0.822411151961,0.816602998621,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-5.023,10.539],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.03,0.03],"y":[0,0]},"n":["0_1_0p03_0","0_1_0p03_0"],"t":32,"s":[75,0],"e":[0,100]},{"t":96}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"rp","c":{"a":0,"k":24,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":15,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false}],"ip":30,"op":98,"st":28,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.03,0.03,0.333],"y":[0,0,0]},"n":["0_1_0p03_0","0_1_0p03_0","0p667_1_0p333_0"],"t":28,"s":[0,0,100],"e":[100,100,100]},{"t":88}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":28,"s":[0,0],"e":[0,100],"to":[0,16.6666660308838],"ti":[0,-16.6666660308838]},{"t":88}],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":20,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.839215686275,0.827450980392,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-5.023,10.539],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.03,0.03],"y":[0,0]},"n":["0_1_0p03_0","0_1_0p03_0"],"t":28,"s":[75,0],"e":[0,100]},{"t":88}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"rp","c":{"a":0,"k":12,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":30,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false}],"ip":28,"op":91,"st":28,"bm":0}]},{"id":"comp_5","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,1.083]},"o":{"x":[0.012,1],"y":[0,0]},"n":["0p833_1_0p012_0","0p833_1p083_1_0"],"t":0,"s":[0,1],"e":[93.75,1]},{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0.083]},"n":["0p667_1_0p167_0","0p667_1_0p167_0p083"],"t":15,"s":[93.75,1],"e":[0,0]},{"t":30}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"n":"0p833_0p833_0p333_0","t":0,"s":[-187.5,0],"e":[-93.75,0],"to":[15.625,0],"ti":[-31.25,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":15,"s":[-93.75,0],"e":[0,0],"to":[31.25,0],"ti":[-15.625,0]},{"t":30}],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.443137258291,0.372549027205,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":15,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.03,0.03,0.333],"y":[0,0,0]},"n":["0_1_0p03_0","0_1_0p03_0","0p667_1_0p333_0"],"t":36,"s":[0,0,100],"e":[100,100,100]},{"t":104}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":36,"s":[0,0],"e":[0,100],"to":[0,16.6666660308838],"ti":[0,-16.6666660308838]},{"t":104}],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":20,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.443137258291,0.372549027205,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-5.023,10.539],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.03,0.03],"y":[0,0]},"n":["0_1_0p03_0","0_1_0p03_0"],"t":36,"s":[75,0],"e":[0,100]},{"t":104}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"rp","c":{"a":0,"k":12,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":30,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false}],"ip":34,"op":105,"st":28,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":7.5,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.03,0.03,0.333],"y":[0,0,0]},"n":["0_1_0p03_0","0_1_0p03_0","0p667_1_0p333_0"],"t":32,"s":[0,0,100],"e":[100,100,100]},{"t":96}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":32,"s":[0,0],"e":[0,100],"to":[0,16.6666660308838],"ti":[0,-16.6666660308838]},{"t":96}],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":20,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.607843160629,0.560784339905,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-5.023,10.539],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.03,0.03],"y":[0,0]},"n":["0_1_0p03_0","0_1_0p03_0"],"t":32,"s":[75,0],"e":[0,100]},{"t":96}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"rp","c":{"a":0,"k":24,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":15,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false}],"ip":30,"op":98,"st":28,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[187.5,187.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.03,0.03,0.333],"y":[0,0,0]},"n":["0_1_0p03_0","0_1_0p03_0","0p667_1_0p333_0"],"t":28,"s":[0,0,100],"e":[100,100,100]},{"t":88}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":2,"d":1,"pt":{"a":0,"k":3,"ix":3},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":28,"s":[0,0],"e":[0,100],"to":[0,16.6666660308838],"ti":[0,-16.6666660308838]},{"t":88}],"ix":4},"r":{"a":0,"k":0,"ix":5},"or":{"a":0,"k":20,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.443137258291,0.372549027205,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-5.023,10.539],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.03,0.03],"y":[0,0]},"n":["0_1_0p03_0","0_1_0p03_0"],"t":28,"s":[75,0],"e":[0,100]},{"t":88}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"rp","c":{"a":0,"k":12,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":2,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":30,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"Transform"},"nm":"Repeater 1","mn":"ADBE Vector Filter - Repeater","hd":false}],"ip":28,"op":91,"st":28,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Comp 7","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[307.473,158.568,0],"ix":2},"a":{"a":0,"k":[187.5,187.5,0],"ix":1},"s":{"a":0,"k":[50,50,100],"ix":6}},"ao":0,"w":375,"h":375,"ip":104,"op":224,"st":104,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Comp 6","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[79.867,175.707,0],"ix":2},"a":{"a":0,"k":[187.5,187.5,0],"ix":1},"s":{"a":0,"k":[60,60,100],"ix":6}},"ao":0,"w":375,"h":375,"ip":120,"op":240,"st":120,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"Comp 5","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[184.758,96.182,0],"ix":2},"a":{"a":0,"k":[187.5,187.5,0],"ix":1},"s":{"a":0,"k":[70,70,100],"ix":6}},"ao":0,"w":375,"h":375,"ip":90,"op":210,"st":90,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"Comp 4","refId":"comp_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[86.723,167.48,0],"ix":2},"a":{"a":0,"k":[187.5,187.5,0],"ix":1},"s":{"a":0,"k":[60,60,100],"ix":6}},"ao":0,"w":375,"h":375,"ip":25,"op":145,"st":25,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"Comp 3","refId":"comp_4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[286.906,216.84,0],"ix":2},"a":{"a":0,"k":[187.5,187.5,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"w":375,"h":375,"ip":16,"op":136,"st":16,"bm":0},{"ddd":0,"ind":6,"ty":0,"nm":"Comp 1","refId":"comp_5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[187.5,108.5,0],"ix":2},"a":{"a":0,"k":[187.5,187.5,0],"ix":1},"s":{"a":0,"k":[80,80,100],"ix":6}},"ao":0,"w":375,"h":375,"ip":0,"op":120,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/app/src/main/java/com/min/dnapp/presentation/write/component/LevelUpDialog.kt b/app/src/main/java/com/min/dnapp/presentation/write/component/LevelUpDialog.kt index c32d2cb..43d4341 100644 --- a/app/src/main/java/com/min/dnapp/presentation/write/component/LevelUpDialog.kt +++ b/app/src/main/java/com/min/dnapp/presentation/write/component/LevelUpDialog.kt @@ -14,12 +14,17 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog +import com.airbnb.lottie.compose.LottieAnimation +import com.airbnb.lottie.compose.LottieCompositionSpec +import com.airbnb.lottie.compose.animateLottieCompositionAsState +import com.airbnb.lottie.compose.rememberLottieComposition import com.min.dnapp.domain.model.Badge import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.ui.theme.MomentoTheme @@ -38,58 +43,88 @@ fun LevelUpDialog( shape = RoundedCornerShape(16.dp), color = MomentoTheme.colors.white ) { - Column( - modifier = Modifier.padding(horizontal = 20.dp), - horizontalAlignment = Alignment.CenterHorizontally + Box( + modifier = Modifier.fillMaxWidth() ) { - Spacer(Modifier.height(20.dp)) - Text( - text = "${badge.name}가 된 것을 축하해요!", - style = MomentoTheme.typography.title01, - color = MomentoTheme.colors.grayW20 - ) - Spacer(Modifier.height(8.dp)) - Text( - text = "여행 기록 ${badge.minStamp}개 달성", - style = MomentoTheme.typography.title02, - color = MomentoTheme.colors.grayW60 - ) - Spacer(Modifier.height(20.dp)) - Image( - modifier = Modifier.size(160.dp), - painter = painterResource(badge.resId), - contentDescription = null - ) - Spacer(Modifier.height(20.dp)) - Text( - text = badge.description, - style = MomentoTheme.typography.body01, - color = MomentoTheme.colors.grayW20 - ) - Spacer(Modifier.height(20.dp)) - Box( - modifier = Modifier - .clickable { onConfirm() } - .fillMaxWidth() - .background( - color = MomentoTheme.colors.brownBase, - shape = RoundedCornerShape(10.dp) - ) - .padding(vertical = 16.dp), - contentAlignment = Alignment.Center + Column( + modifier = Modifier.padding(horizontal = 20.dp), + horizontalAlignment = Alignment.CenterHorizontally ) { + Spacer(Modifier.height(20.dp)) + Text( + text = "${badge.name}가 된 것을 축하해요!", + style = MomentoTheme.typography.title01, + color = MomentoTheme.colors.grayW20 + ) + Spacer(Modifier.height(8.dp)) + Text( + text = "여행 기록 ${badge.minStamp}개 달성", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW60 + ) + Spacer(Modifier.height(20.dp)) + Image( + modifier = Modifier.size(160.dp), + painter = painterResource(badge.resId), + contentDescription = null + ) + Spacer(Modifier.height(20.dp)) Text( - text = "확인했어요", + text = badge.description, style = MomentoTheme.typography.body01, - color = MomentoTheme.colors.white + color = MomentoTheme.colors.grayW20 ) + Spacer(Modifier.height(20.dp)) + Box( + modifier = Modifier + .clickable { onConfirm() } + .fillMaxWidth() + .background( + color = MomentoTheme.colors.brownBase, + shape = RoundedCornerShape(10.dp) + ) + .padding(vertical = 16.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = "확인했어요", + style = MomentoTheme.typography.body01, + color = MomentoTheme.colors.white + ) + } + Spacer(Modifier.height(20.dp)) } - Spacer(Modifier.height(20.dp)) + + // Box 영역 전체 덮도록 설정 + LottieFireworksAnimation( + modifier = Modifier.matchParentSize() + ) } } } } +@Composable +fun LottieFireworksAnimation( + modifier: Modifier = Modifier +) { + val composition by rememberLottieComposition(spec = LottieCompositionSpec.Asset("fireworks.json")) + + // 애니메이션 1번만 재생 + val progress by animateLottieCompositionAsState( + composition = composition, + iterations = 1, + isPlaying = true, + restartOnPlay = false + ) + + LottieAnimation( + modifier = modifier, + composition = composition, + progress = progress + ) +} + @Preview @Composable fun LevelUpDialogPreview() { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 742dcbc..47cd16b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -21,6 +21,7 @@ retrofit = "3.0.0" kotlinSerialization = "1.9.0" okhttp = "5.0.0" coil = "3.1.0" +lottie = "6.6.9" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -55,6 +56,7 @@ kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serializa okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" } coil = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" } coil-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil" } +lottie-compose = { module = "com.airbnb.android:lottie-compose", version.ref = "lottie" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } From 8ad3670501317eb7531e3e2768024e360e741dfd Mon Sep 17 00:00:00 2001 From: min486 Date: Thu, 13 Nov 2025 17:35:11 +0900 Subject: [PATCH 89/98] =?UTF-8?q?design:=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=ED=99=94=EB=A9=B4=20UI=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 23 +++- .../presentation/init/AppInitViewModel.kt | 27 ++++ .../{onboarding => init}/OnboardingScreen.kt | 4 +- .../{onboarding => init}/OnboardingScreen2.kt | 4 +- .../{onboarding => init}/OnboardingScreen3.kt | 4 +- .../presentation/init/ProfileSelectScreen.kt | 119 ++++++++++++++++++ .../component/OnboardingButtonSection.kt | 2 +- 7 files changed, 171 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/init/AppInitViewModel.kt rename app/src/main/java/com/min/dnapp/presentation/{onboarding => init}/OnboardingScreen.kt (93%) rename app/src/main/java/com/min/dnapp/presentation/{onboarding => init}/OnboardingScreen2.kt (95%) rename app/src/main/java/com/min/dnapp/presentation/{onboarding => init}/OnboardingScreen3.kt (95%) create mode 100644 app/src/main/java/com/min/dnapp/presentation/init/ProfileSelectScreen.kt rename app/src/main/java/com/min/dnapp/presentation/{onboarding => init}/component/OnboardingButtonSection.kt (98%) diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index af1431f..ed89e3e 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -5,16 +5,12 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.WindowInsetsSides -import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.systemBars import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen -import androidx.core.view.WindowCompat import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.compose.NavHost @@ -26,6 +22,10 @@ import com.min.dnapp.presentation.bell.BellScreen import com.min.dnapp.presentation.find.FindDetailScreen import com.min.dnapp.presentation.find.FindScreen import com.min.dnapp.presentation.home.HomeScreen2 +import com.min.dnapp.presentation.init.OnboardingScreen +import com.min.dnapp.presentation.init.OnboardingScreen2 +import com.min.dnapp.presentation.init.OnboardingScreen3 +import com.min.dnapp.presentation.init.ProfileSelectScreen import com.min.dnapp.presentation.login.LoginScreen2 import com.min.dnapp.presentation.mypage.MyRecordScreen import com.min.dnapp.presentation.mypage.MypageScreen @@ -67,7 +67,8 @@ fun MomentoApp( val currentRoute = navBackStackEntry?.destination?.route ?: "home" val showBottomBar = when (currentRoute) { - "login", "bell", "find_detail", "record_write", "write_finish", "my_record", "setting" -> false + "login", "bell", "find_detail", "record_write", "write_finish", "my_record", "setting", + "onboarding", "onboarding2", "onboarding3", "profile_select" -> false else -> true } @@ -123,6 +124,18 @@ fun MomentoApp( composable("setting") { SettingScreen(navController = navController) } + composable("onboarding") { + OnboardingScreen() + } + composable("onboarding2") { + OnboardingScreen2() + } + composable("onboarding3") { + OnboardingScreen3() + } + composable("profile_select") { + ProfileSelectScreen() + } } } } diff --git a/app/src/main/java/com/min/dnapp/presentation/init/AppInitViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/init/AppInitViewModel.kt new file mode 100644 index 0000000..aa678bf --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/init/AppInitViewModel.kt @@ -0,0 +1,27 @@ +package com.min.dnapp.presentation.init + +import androidx.lifecycle.ViewModel +import com.min.dnapp.presentation.mypage.ProfileImageType +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 AppInitViewModel @Inject constructor( + +) : ViewModel() { + + // 선택된 프로필 이미지 + private val _selectedImage = MutableStateFlow(null) + val selectedImage: StateFlow = _selectedImage.asStateFlow() + + /** + * 프로필 이미지 선택 + */ + fun selectImage(image: ProfileImageType) { + // 선택된 이미지 다시 선택하면 해제 + _selectedImage.value = if (_selectedImage.value == image) null else image + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen.kt b/app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen.kt similarity index 93% rename from app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen.kt rename to app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen.kt index 1c5b3d6..b2424e6 100644 --- a/app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen.kt @@ -1,4 +1,4 @@ -package com.min.dnapp.presentation.onboarding +package com.min.dnapp.presentation.init import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement @@ -15,7 +15,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.min.dnapp.R -import com.min.dnapp.presentation.onboarding.component.OnboardingButtonSection +import com.min.dnapp.presentation.init.component.OnboardingButtonSection import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.ui.theme.MomentoTheme diff --git a/app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen2.kt b/app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen2.kt similarity index 95% rename from app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen2.kt rename to app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen2.kt index cbf2c55..219d862 100644 --- a/app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen2.kt +++ b/app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen2.kt @@ -1,4 +1,4 @@ -package com.min.dnapp.presentation.onboarding +package com.min.dnapp.presentation.init import androidx.compose.foundation.Image import androidx.compose.foundation.clickable @@ -22,7 +22,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.min.dnapp.R -import com.min.dnapp.presentation.onboarding.component.OnboardingButtonSection +import com.min.dnapp.presentation.init.component.OnboardingButtonSection import com.min.dnapp.presentation.ui.icon.AppIcons import com.min.dnapp.presentation.ui.icon.appicons.Back import com.min.dnapp.presentation.ui.theme.DngoTheme diff --git a/app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen3.kt b/app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen3.kt similarity index 95% rename from app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen3.kt rename to app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen3.kt index 9fad16c..1cf4fdc 100644 --- a/app/src/main/java/com/min/dnapp/presentation/onboarding/OnboardingScreen3.kt +++ b/app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen3.kt @@ -1,4 +1,4 @@ -package com.min.dnapp.presentation.onboarding +package com.min.dnapp.presentation.init import androidx.compose.foundation.Image import androidx.compose.foundation.clickable @@ -22,7 +22,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.min.dnapp.R -import com.min.dnapp.presentation.onboarding.component.OnboardingButtonSection +import com.min.dnapp.presentation.init.component.OnboardingButtonSection import com.min.dnapp.presentation.ui.icon.AppIcons import com.min.dnapp.presentation.ui.icon.appicons.Back import com.min.dnapp.presentation.ui.theme.DngoTheme diff --git a/app/src/main/java/com/min/dnapp/presentation/init/ProfileSelectScreen.kt b/app/src/main/java/com/min/dnapp/presentation/init/ProfileSelectScreen.kt new file mode 100644 index 0000000..f7593bf --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/init/ProfileSelectScreen.kt @@ -0,0 +1,119 @@ +package com.min.dnapp.presentation.init + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.min.dnapp.presentation.mypage.ProfileImageType +import com.min.dnapp.presentation.mypage.component.ProfileImageItem +import com.min.dnapp.presentation.ui.component.SelectButton +import com.min.dnapp.presentation.ui.theme.DngoTheme +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ProfileSelectScreen( + viewModel: AppInitViewModel = hiltViewModel() +) { + val selectedImage by viewModel.selectedImage.collectAsStateWithLifecycle() + + Scaffold( + containerColor = MomentoTheme.colors.brownBg, + topBar = { + CenterAlignedTopAppBar( + title = { + Text( + text = "프로필 설정", + style = MomentoTheme.typography.title02, + color = MomentoTheme.colors.grayW20 + ) + }, + colors = TopAppBarDefaults.centerAlignedTopAppBarColors( + containerColor = MomentoTheme.colors.brownBg + ) + ) + } + ) { paddingValues -> + Column( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize(), + verticalArrangement = Arrangement.SpaceBetween + ) { + // 프로필 이미지 목록 (8개) + val allImages = ProfileImageType.entries.toList() + + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + for (idx in 0 until allImages.size step 2) { + + // 처음 Row가 아니면, Row 위에 간격 추가 + if (idx > 0) { + Spacer(Modifier.height(16.dp)) + } + + Row( + horizontalArrangement = Arrangement.spacedBy(20.dp) + ) { + ProfileImageItem( + profileImageType = allImages[idx], + isSelected = selectedImage == allImages[idx], + onClick = { image -> viewModel.selectImage(image) } + ) + ProfileImageItem( + profileImageType = allImages[idx+1], + isSelected = selectedImage == allImages[idx+1], + onClick = { image -> viewModel.selectImage(image) } + ) + } + } + + Spacer(Modifier.height(20.dp)) + + Text( + text = "원하는 프로필을 선택해주세요!", + style = MomentoTheme.typography.title01, + color = MomentoTheme.colors.grayW20 + ) + } + + // 확인 버튼 + Column( + modifier = Modifier.padding(horizontal = 20.dp) + ) { + SelectButton( + enabled = selectedImage != null, + onConfirm = { } + ) + Spacer(Modifier.height(20.dp)) + } + } + } +} + +@Preview +@Composable +fun ProfileSelectScreenPreview() { + DngoTheme { + ProfileSelectScreen() + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/onboarding/component/OnboardingButtonSection.kt b/app/src/main/java/com/min/dnapp/presentation/init/component/OnboardingButtonSection.kt similarity index 98% rename from app/src/main/java/com/min/dnapp/presentation/onboarding/component/OnboardingButtonSection.kt rename to app/src/main/java/com/min/dnapp/presentation/init/component/OnboardingButtonSection.kt index 9ea1020..8a86ac2 100644 --- a/app/src/main/java/com/min/dnapp/presentation/onboarding/component/OnboardingButtonSection.kt +++ b/app/src/main/java/com/min/dnapp/presentation/init/component/OnboardingButtonSection.kt @@ -1,4 +1,4 @@ -package com.min.dnapp.presentation.onboarding.component +package com.min.dnapp.presentation.init.component import androidx.compose.foundation.background import androidx.compose.foundation.clickable From 7ff8b0d978598c8b5e8c08dda41bf4095e8c617d Mon Sep 17 00:00:00 2001 From: min486 Date: Thu, 13 Nov 2025 19:27:35 +0900 Subject: [PATCH 90/98] =?UTF-8?q?feat:=20=EC=95=B1=20=EC=B4=88=EA=B8=B0=20?= =?UTF-8?q?=EC=8B=9D=EB=B3=84=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?(DataStore=20=ED=99=9C=EC=9A=A9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 2 + .../datasource/AppPreferencesDataStore.kt | 58 +++++++++++++++++++ .../data/repository/AppInitRepositoryImpl.kt | 23 ++++++++ .../domain/repository/AppInitRepository.kt | 9 +++ .../domain/usecase/GetInitStatusUseCase.kt | 13 +++++ .../usecase/SetOnboardingCompletedUseCase.kt | 12 ++++ .../SetProfileSetupCompletedUseCase.kt | 12 ++++ .../presentation/init/AppInitViewModel.kt | 58 ++++++++++++++++++- gradle/libs.versions.toml | 2 + 9 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/min/dnapp/data/datasource/AppPreferencesDataStore.kt create mode 100644 app/src/main/java/com/min/dnapp/data/repository/AppInitRepositoryImpl.kt create mode 100644 app/src/main/java/com/min/dnapp/domain/repository/AppInitRepository.kt create mode 100644 app/src/main/java/com/min/dnapp/domain/usecase/GetInitStatusUseCase.kt create mode 100644 app/src/main/java/com/min/dnapp/domain/usecase/SetOnboardingCompletedUseCase.kt create mode 100644 app/src/main/java/com/min/dnapp/domain/usecase/SetProfileSetupCompletedUseCase.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c9ab0fc..e89ed37 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -111,6 +111,8 @@ dependencies { implementation(libs.coil.okhttp) // lottie compose implementation(libs.lottie.compose) + // preferences datastore + implementation(libs.datastore.preferences) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) diff --git a/app/src/main/java/com/min/dnapp/data/datasource/AppPreferencesDataStore.kt b/app/src/main/java/com/min/dnapp/data/datasource/AppPreferencesDataStore.kt new file mode 100644 index 0000000..b76409c --- /dev/null +++ b/app/src/main/java/com/min/dnapp/data/datasource/AppPreferencesDataStore.kt @@ -0,0 +1,58 @@ +package com.min.dnapp.data.datasource + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.core.IOException +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.booleanPreferencesKey +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.emptyPreferences +import androidx.datastore.preferences.preferencesDataStore +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.map +import javax.inject.Inject + +private val Context.dataStore: DataStore by preferencesDataStore(name = "app_init_prefs") + +class AppPreferencesDataStore @Inject constructor( + @ApplicationContext private val context: Context +) { + private object PreferencesKey { + // 온보딩 완료 여부 + val IS_ONBOARDING_COMPLETED = booleanPreferencesKey("is_onboarding_completed") + // 프로필 설정 완료 여부 + val IS_PROFILE_SETUP_COMPLETED = booleanPreferencesKey("is_profile_setup_completed") + } + + // 온보딩 완료 저장 + suspend fun setOnboardingCompleted(isCompleted: Boolean) { + context.dataStore.edit { preferences -> + preferences[PreferencesKey.IS_ONBOARDING_COMPLETED] = isCompleted + } + } + + // 프로필 설정 완료 저장 + suspend fun setProfileSetupCompleted(isCompleted: Boolean) { + context.dataStore.edit { preferences -> + preferences[PreferencesKey.IS_PROFILE_SETUP_COMPLETED] = isCompleted + } + } + + // 읽기 Flow + val initStatusFlow: Flow> = context.dataStore.data + .catch { exception -> + if (exception is IOException) { + emit(emptyPreferences()) + } else { + throw exception + } + } + .map { preferences -> + val onboarding = preferences[PreferencesKey.IS_ONBOARDING_COMPLETED] ?: false + val profile = preferences[PreferencesKey.IS_PROFILE_SETUP_COMPLETED] ?: false + // 온보딩 완료 상태, 프로필 설정 완료 상태 반환 + Pair(onboarding, profile) + } +} diff --git a/app/src/main/java/com/min/dnapp/data/repository/AppInitRepositoryImpl.kt b/app/src/main/java/com/min/dnapp/data/repository/AppInitRepositoryImpl.kt new file mode 100644 index 0000000..c28cfd9 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/data/repository/AppInitRepositoryImpl.kt @@ -0,0 +1,23 @@ +package com.min.dnapp.data.repository + +import com.min.dnapp.data.datasource.AppPreferencesDataStore +import com.min.dnapp.domain.repository.AppInitRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class AppInitRepositoryImpl @Inject constructor( + private val preferencesDataStore: AppPreferencesDataStore +) : AppInitRepository { + + override fun getInitStatus(): Flow> { + return preferencesDataStore.initStatusFlow + } + + override suspend fun setOnboardingCompleted() { + preferencesDataStore.setOnboardingCompleted(true) + } + + override suspend fun setProfileSetupCompleted() { + preferencesDataStore.setProfileSetupCompleted(true) + } +} diff --git a/app/src/main/java/com/min/dnapp/domain/repository/AppInitRepository.kt b/app/src/main/java/com/min/dnapp/domain/repository/AppInitRepository.kt new file mode 100644 index 0000000..b4a7b87 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/repository/AppInitRepository.kt @@ -0,0 +1,9 @@ +package com.min.dnapp.domain.repository + +import kotlinx.coroutines.flow.Flow + +interface AppInitRepository { + fun getInitStatus(): Flow> + suspend fun setOnboardingCompleted() + suspend fun setProfileSetupCompleted() +} diff --git a/app/src/main/java/com/min/dnapp/domain/usecase/GetInitStatusUseCase.kt b/app/src/main/java/com/min/dnapp/domain/usecase/GetInitStatusUseCase.kt new file mode 100644 index 0000000..a3e8360 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/usecase/GetInitStatusUseCase.kt @@ -0,0 +1,13 @@ +package com.min.dnapp.domain.usecase + +import com.min.dnapp.domain.repository.AppInitRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class GetInitStatusUseCase @Inject constructor( + private val appInitRepository: AppInitRepository +) { + operator fun invoke(): Flow> { + return appInitRepository.getInitStatus() + } +} diff --git a/app/src/main/java/com/min/dnapp/domain/usecase/SetOnboardingCompletedUseCase.kt b/app/src/main/java/com/min/dnapp/domain/usecase/SetOnboardingCompletedUseCase.kt new file mode 100644 index 0000000..0193d5d --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/usecase/SetOnboardingCompletedUseCase.kt @@ -0,0 +1,12 @@ +package com.min.dnapp.domain.usecase + +import com.min.dnapp.domain.repository.AppInitRepository +import javax.inject.Inject + +class SetOnboardingCompletedUseCase @Inject constructor( + private val appInitRepository: AppInitRepository +) { + suspend operator fun invoke() { + appInitRepository.setOnboardingCompleted() + } +} diff --git a/app/src/main/java/com/min/dnapp/domain/usecase/SetProfileSetupCompletedUseCase.kt b/app/src/main/java/com/min/dnapp/domain/usecase/SetProfileSetupCompletedUseCase.kt new file mode 100644 index 0000000..9864a1e --- /dev/null +++ b/app/src/main/java/com/min/dnapp/domain/usecase/SetProfileSetupCompletedUseCase.kt @@ -0,0 +1,12 @@ +package com.min.dnapp.domain.usecase + +import com.min.dnapp.domain.repository.AppInitRepository +import javax.inject.Inject + +class SetProfileSetupCompletedUseCase @Inject constructor( + private val appInitRepository: AppInitRepository +){ + suspend operator fun invoke() { + appInitRepository.setProfileSetupCompleted() + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/init/AppInitViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/init/AppInitViewModel.kt index aa678bf..6103ad8 100644 --- a/app/src/main/java/com/min/dnapp/presentation/init/AppInitViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/init/AppInitViewModel.kt @@ -1,22 +1,60 @@ package com.min.dnapp.presentation.init import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.min.dnapp.domain.usecase.GetInitStatusUseCase +import com.min.dnapp.domain.usecase.SetOnboardingCompletedUseCase +import com.min.dnapp.domain.usecase.SetProfileSetupCompletedUseCase import com.min.dnapp.presentation.mypage.ProfileImageType import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch import javax.inject.Inject +enum class InitRoute { + LOADING, + ONBOARDING, + PROFILE_SETUP, + MAIN +} + +data class InitUiState( + val route: InitRoute = InitRoute.LOADING +) + @HiltViewModel class AppInitViewModel @Inject constructor( - + getInitStatusUseCase: GetInitStatusUseCase, + private val setOnboardingCompletedUseCase: SetOnboardingCompletedUseCase, + private val setProfileSetupCompletedUseCase: SetProfileSetupCompletedUseCase ) : ViewModel() { // 선택된 프로필 이미지 private val _selectedImage = MutableStateFlow(null) val selectedImage: StateFlow = _selectedImage.asStateFlow() + private val _uiState = MutableStateFlow(InitUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + + init { + viewModelScope.launch { + getInitStatusUseCase().collect { (isOnboardingCompleted, isProfileSetupCompleted) -> + val nextRoute = when { + // 2단계 완료 + isProfileSetupCompleted -> InitRoute.MAIN + // 1단계 완료 + isOnboardingCompleted -> InitRoute.PROFILE_SETUP + // 둘다 완료되지 않음 + else -> InitRoute.ONBOARDING + } + _uiState.update { it.copy(route = nextRoute) } + } + } + } + /** * 프로필 이미지 선택 */ @@ -24,4 +62,22 @@ class AppInitViewModel @Inject constructor( // 선택된 이미지 다시 선택하면 해제 _selectedImage.value = if (_selectedImage.value == image) null else image } + + /** + * 온보딩 3개 완료 후 호출 + */ + fun onOnboardingFinished() { + viewModelScope.launch { + setOnboardingCompletedUseCase() + } + } + + /** + * 프로필 선택 완료 후 호출 + */ + fun onProfileSetupFinished() { + viewModelScope.launch { + setProfileSetupCompletedUseCase() + } + } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 47cd16b..fc2e661 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -22,6 +22,7 @@ kotlinSerialization = "1.9.0" okhttp = "5.0.0" coil = "3.1.0" lottie = "6.6.9" +datastore = "1.1.7" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -57,6 +58,7 @@ okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version. coil = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" } coil-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil" } lottie-compose = { module = "com.airbnb.android:lottie-compose", version.ref = "lottie" } +datastore-preferences = { module = "androidx.datastore:datastore-preferences" , version.ref = "datastore" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } From 0c8dae0b90e5ceba00495221fe9e9d422e3a0f4a Mon Sep 17 00:00:00 2001 From: min486 Date: Thu, 13 Nov 2025 22:31:10 +0900 Subject: [PATCH 91/98] =?UTF-8?q?feat:=20=EC=95=B1=20=EC=B4=88=EA=B8=B0=20?= =?UTF-8?q?=EC=8B=A4=ED=96=89=20=EC=8B=9C,=20=EC=98=A8=EB=B3=B4=EB=94=A9/?= =?UTF-8?q?=ED=94=84=EB=A1=9C=ED=95=84=EC=84=A4=EC=A0=95=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/min/dnapp/MainActivity.kt | 50 +++++----- .../com/min/dnapp/data/di/RepositoryModule.kt | 8 ++ .../dnapp/presentation/init/LoadingScreen.kt | 33 +++++++ .../presentation/init/OnboardingScreen.kt | 14 ++- .../presentation/init/OnboardingScreen2.kt | 13 ++- .../presentation/init/OnboardingScreen3.kt | 13 ++- ...eSelectScreen.kt => ProfileSetupScreen.kt} | 9 +- .../init/component/OnboardingButtonSection.kt | 38 ++++---- .../dnapp/presentation/login/LoginScreen2.kt | 9 +- .../presentation/navigation/AppInitHost.kt | 94 +++++++++++++++++++ 10 files changed, 221 insertions(+), 60 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/init/LoadingScreen.kt rename app/src/main/java/com/min/dnapp/presentation/init/{ProfileSelectScreen.kt => ProfileSetupScreen.kt} (95%) create mode 100644 app/src/main/java/com/min/dnapp/presentation/navigation/AppInitHost.kt diff --git a/app/src/main/java/com/min/dnapp/MainActivity.kt b/app/src/main/java/com/min/dnapp/MainActivity.kt index ed89e3e..6e1fdb0 100644 --- a/app/src/main/java/com/min/dnapp/MainActivity.kt +++ b/app/src/main/java/com/min/dnapp/MainActivity.kt @@ -22,14 +22,11 @@ import com.min.dnapp.presentation.bell.BellScreen import com.min.dnapp.presentation.find.FindDetailScreen import com.min.dnapp.presentation.find.FindScreen import com.min.dnapp.presentation.home.HomeScreen2 -import com.min.dnapp.presentation.init.OnboardingScreen -import com.min.dnapp.presentation.init.OnboardingScreen2 -import com.min.dnapp.presentation.init.OnboardingScreen3 -import com.min.dnapp.presentation.init.ProfileSelectScreen import com.min.dnapp.presentation.login.LoginScreen2 import com.min.dnapp.presentation.mypage.MyRecordScreen import com.min.dnapp.presentation.mypage.MypageScreen import com.min.dnapp.presentation.mypage.SettingScreen +import com.min.dnapp.presentation.navigation.AppInitHost import com.min.dnapp.presentation.ui.component.MomentoBottomNav import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.write.RecordWriteScreen @@ -60,16 +57,18 @@ fun MomentoApp( appStartViewModel: AppStartViewModel = hiltViewModel() ) { val isLogin by appStartViewModel.isLogin.collectAsStateWithLifecycle() - val startDestination = if (isLogin) "home" else "login" + val startDestination = if (isLogin) "init_host" else "login" + // root navigation 담당 val navController = rememberNavController() + + // root navigation 경로 val navBackStackEntry by navController.currentBackStackEntryAsState() - val currentRoute = navBackStackEntry?.destination?.route ?: "home" + val currentRoute = navBackStackEntry?.destination?.route ?: startDestination val showBottomBar = when (currentRoute) { - "login", "bell", "find_detail", "record_write", "write_finish", "my_record", "setting", - "onboarding", "onboarding2", "onboarding3", "profile_select" -> false - else -> true + "home", "find", "my" -> true + else -> false } Scaffold( @@ -95,8 +94,26 @@ fun MomentoApp( startDestination = startDestination ) { composable("login") { - LoginScreen2(navController = navController) + LoginScreen2( + navController = navController, + onLoginSuccess = { + navController.navigate("init_host") { + popUpTo("login") { inclusive = true } + } + } + ) } + + composable("init_host") { + AppInitHost( + onInitComplete = { + navController.navigate("home") { + popUpTo("init_host") { inclusive = true } + } + } + ) + } + composable("home") { HomeScreen2(navController = navController) } @@ -106,6 +123,7 @@ fun MomentoApp( composable("my") { MypageScreen(navController = navController) } + composable("bell") { BellScreen(navController = navController) } @@ -124,18 +142,6 @@ fun MomentoApp( composable("setting") { SettingScreen(navController = navController) } - composable("onboarding") { - OnboardingScreen() - } - composable("onboarding2") { - OnboardingScreen2() - } - composable("onboarding3") { - OnboardingScreen3() - } - composable("profile_select") { - ProfileSelectScreen() - } } } } diff --git a/app/src/main/java/com/min/dnapp/data/di/RepositoryModule.kt b/app/src/main/java/com/min/dnapp/data/di/RepositoryModule.kt index 8d71d5d..2bb6e47 100644 --- a/app/src/main/java/com/min/dnapp/data/di/RepositoryModule.kt +++ b/app/src/main/java/com/min/dnapp/data/di/RepositoryModule.kt @@ -1,9 +1,11 @@ package com.min.dnapp.data.di +import com.min.dnapp.data.repository.AppInitRepositoryImpl import com.min.dnapp.data.repository.AuthRepositoryImpl import com.min.dnapp.data.repository.LocalSearchRepositoryImpl import com.min.dnapp.data.repository.RecordRepositoryImpl import com.min.dnapp.data.repository.UserRepositoryImpl +import com.min.dnapp.domain.repository.AppInitRepository import com.min.dnapp.domain.repository.AuthRepository import com.min.dnapp.domain.repository.LocalSearchRepository import com.min.dnapp.domain.repository.RecordRepository @@ -41,4 +43,10 @@ abstract class RepositoryModule { abstract fun bindUserRepository( userRepositoryImpl: UserRepositoryImpl ): UserRepository + + @Binds + @Singleton + abstract fun bindAppInitRepository( + appInitRepositoryImpl: AppInitRepositoryImpl + ): AppInitRepository } diff --git a/app/src/main/java/com/min/dnapp/presentation/init/LoadingScreen.kt b/app/src/main/java/com/min/dnapp/presentation/init/LoadingScreen.kt new file mode 100644 index 0000000..92efd05 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/init/LoadingScreen.kt @@ -0,0 +1,33 @@ +package com.min.dnapp.presentation.init + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.size +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.min.dnapp.presentation.ui.theme.MomentoTheme + +@Composable +fun LoadingScreen() { + Surface( + modifier = Modifier.fillMaxSize(), + color = MomentoTheme.colors.brownBg + ) { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + CircularProgressIndicator( + modifier = Modifier.size(40.dp), + color = MomentoTheme.colors.brownW20, + strokeWidth = 4.dp + ) + } + } +} diff --git a/app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen.kt b/app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen.kt index b2424e6..d41a875 100644 --- a/app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen.kt @@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -20,9 +21,13 @@ import com.min.dnapp.presentation.ui.theme.DngoTheme import com.min.dnapp.presentation.ui.theme.MomentoTheme @Composable -fun OnboardingScreen() { +fun OnboardingScreen( + onFinish: () -> Unit +) { Surface( - modifier = Modifier.fillMaxSize(), + modifier = Modifier + .systemBarsPadding() + .fillMaxSize(), color = MomentoTheme.colors.brownW90 ) { Column( @@ -41,8 +46,9 @@ fun OnboardingScreen() { } OnboardingButtonSection( + onboardingNum = 1, title = "모멘토와 함께하는 따뜻하고 진솔한 공간. \n제목, 날짜, 장소, 감정을 \n입력하여 내 기록을 남겨보세요.", - onClick = {} + onClick = { onFinish() } ) } } @@ -52,6 +58,6 @@ fun OnboardingScreen() { @Composable fun OnboardingScreenPreview() { DngoTheme { - OnboardingScreen() +// OnboardingScreen() } } diff --git a/app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen2.kt b/app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen2.kt index 219d862..c63a77d 100644 --- a/app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen2.kt +++ b/app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen2.kt @@ -21,6 +21,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController import com.min.dnapp.R import com.min.dnapp.presentation.init.component.OnboardingButtonSection import com.min.dnapp.presentation.ui.icon.AppIcons @@ -30,7 +31,10 @@ import com.min.dnapp.presentation.ui.theme.MomentoTheme @OptIn(ExperimentalMaterial3Api::class) @Composable -fun OnboardingScreen2() { +fun OnboardingScreen2( + navController: NavHostController, + onFinish: () -> Unit +) { Scaffold( containerColor = MomentoTheme.colors.brownW90, topBar = { @@ -39,7 +43,7 @@ fun OnboardingScreen2() { navigationIcon = { Icon( modifier = Modifier - .clickable { } + .clickable { navController.popBackStack() } .padding(16.dp), imageVector = AppIcons.Back, contentDescription = null @@ -69,8 +73,9 @@ fun OnboardingScreen2() { } OnboardingButtonSection( + onboardingNum = 2, title = "여행을 기록할 때마다 스탬프가 적립돼요. \n하나의 기록이 모여 나만의 컬렉션이 완성됩니다. \n", - onClick = {} + onClick = { onFinish() } ) } } @@ -80,6 +85,6 @@ fun OnboardingScreen2() { @Composable fun OnboardingScreen2Preview() { DngoTheme { - OnboardingScreen2() +// OnboardingScreen2() } } diff --git a/app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen3.kt b/app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen3.kt index 1cf4fdc..5296fa8 100644 --- a/app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen3.kt +++ b/app/src/main/java/com/min/dnapp/presentation/init/OnboardingScreen3.kt @@ -21,6 +21,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController import com.min.dnapp.R import com.min.dnapp.presentation.init.component.OnboardingButtonSection import com.min.dnapp.presentation.ui.icon.AppIcons @@ -30,7 +31,10 @@ import com.min.dnapp.presentation.ui.theme.MomentoTheme @OptIn(ExperimentalMaterial3Api::class) @Composable -fun OnboardingScreen3() { +fun OnboardingScreen3( + navController: NavHostController, + onFinish: () -> Unit +) { Scaffold( containerColor = MomentoTheme.colors.brownW90, topBar = { @@ -39,7 +43,7 @@ fun OnboardingScreen3() { navigationIcon = { Icon( modifier = Modifier - .clickable { } + .clickable { navController.popBackStack() } .padding(16.dp), imageVector = AppIcons.Back, contentDescription = null @@ -69,8 +73,9 @@ fun OnboardingScreen3() { } OnboardingButtonSection( + onboardingNum = 3, title = "솔직한 기록을 다른 사람과 가볍게 나누기 \n공감과 영감을 주고받는 공간입니다. \n", - onClick = {} + onClick = { onFinish() } ) } } @@ -80,6 +85,6 @@ fun OnboardingScreen3() { @Composable fun OnboardingScreen3Preview() { DngoTheme { - OnboardingScreen3() +// OnboardingScreen3() } } diff --git a/app/src/main/java/com/min/dnapp/presentation/init/ProfileSelectScreen.kt b/app/src/main/java/com/min/dnapp/presentation/init/ProfileSetupScreen.kt similarity index 95% rename from app/src/main/java/com/min/dnapp/presentation/init/ProfileSelectScreen.kt rename to app/src/main/java/com/min/dnapp/presentation/init/ProfileSetupScreen.kt index f7593bf..741e980 100644 --- a/app/src/main/java/com/min/dnapp/presentation/init/ProfileSelectScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/init/ProfileSetupScreen.kt @@ -29,8 +29,9 @@ import com.min.dnapp.presentation.ui.theme.MomentoTheme @OptIn(ExperimentalMaterial3Api::class) @Composable -fun ProfileSelectScreen( - viewModel: AppInitViewModel = hiltViewModel() +fun ProfileSetupScreen( + viewModel: AppInitViewModel = hiltViewModel(), + onFinish: () -> Unit ) { val selectedImage by viewModel.selectedImage.collectAsStateWithLifecycle() @@ -102,7 +103,7 @@ fun ProfileSelectScreen( ) { SelectButton( enabled = selectedImage != null, - onConfirm = { } + onConfirm = { onFinish() } ) Spacer(Modifier.height(20.dp)) } @@ -114,6 +115,6 @@ fun ProfileSelectScreen( @Composable fun ProfileSelectScreenPreview() { DngoTheme { - ProfileSelectScreen() +// ProfileSetupScreen() } } diff --git a/app/src/main/java/com/min/dnapp/presentation/init/component/OnboardingButtonSection.kt b/app/src/main/java/com/min/dnapp/presentation/init/component/OnboardingButtonSection.kt index 8a86ac2..03dc659 100644 --- a/app/src/main/java/com/min/dnapp/presentation/init/component/OnboardingButtonSection.kt +++ b/app/src/main/java/com/min/dnapp/presentation/init/component/OnboardingButtonSection.kt @@ -10,7 +10,6 @@ import androidx.compose.foundation.layout.Spacer 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.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape @@ -24,6 +23,7 @@ import com.min.dnapp.presentation.ui.theme.MomentoTheme @Composable fun OnboardingButtonSection( + onboardingNum: Int, title: String, onClick: () -> Unit ) { @@ -38,7 +38,6 @@ fun OnboardingButtonSection( ) { Spacer(Modifier.height(40.dp)) Text( -// text = "모멘토와 함께하는 따뜻하고 진솔한 공간. \n제목, 날짜, 장소, 감정을 \n입력하여 내 기록을 남겨보세요.", text = title, style = MomentoTheme.typography.body01, color = MomentoTheme.colors.black, @@ -53,23 +52,16 @@ fun OnboardingButtonSection( verticalAlignment = Alignment.CenterVertically ) { Row { - Box( - modifier = Modifier - .width(16.dp) - .height(8.dp) - .background(color = MomentoTheme.colors.pinkBase, shape = RoundedCornerShape(20.dp)) + OnboardingIndicator( + isActive = onboardingNum == 1 ) Spacer(Modifier.width(4.dp)) - Box( - modifier = Modifier - .size(8.dp) - .background(color = MomentoTheme.colors.pinkW40, shape = CircleShape) + OnboardingIndicator( + isActive = onboardingNum == 2 ) Spacer(Modifier.width(4.dp)) - Box( - modifier = Modifier - .size(8.dp) - .background(color = MomentoTheme.colors.pinkW40, shape = CircleShape) + OnboardingIndicator( + isActive = onboardingNum == 3 ) } Box( @@ -89,5 +81,19 @@ fun OnboardingButtonSection( Spacer(Modifier.height(20.dp)) } } +} -} \ No newline at end of file +@Composable +private fun OnboardingIndicator(isActive: Boolean) { + val indicatorColor = if (isActive) MomentoTheme.colors.pinkBase else MomentoTheme.colors.pinkW40 + val indicatorShape = if (isActive) RoundedCornerShape(20.dp) else CircleShape + val indicatorWidth = if (isActive) 16.dp else 8.dp + val indicatorHeight = 8.dp + + Box( + modifier = Modifier + .width(indicatorWidth) + .height(indicatorHeight) + .background(color = indicatorColor, shape = indicatorShape) + ) +} diff --git a/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt b/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt index 37ee538..f12372f 100644 --- a/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt +++ b/app/src/main/java/com/min/dnapp/presentation/login/LoginScreen2.kt @@ -43,7 +43,8 @@ import com.min.dnapp.presentation.ui.theme.MomentoTheme @Composable fun LoginScreen2( navController: NavHostController, - viewModel: LoginViewModel = hiltViewModel() + viewModel: LoginViewModel = hiltViewModel(), + onLoginSuccess: () -> Unit ) { val context = LocalContext.current val isLoading by viewModel.isLoading.collectAsStateWithLifecycle() @@ -64,11 +65,7 @@ fun LoginScreen2( onClick = { viewModel.onKakaoLoginClicked( context = context, - onSuccess = { - navController.navigate("home") { - popUpTo("login") { inclusive = true } - } - }, + onSuccess = { onLoginSuccess() }, onFailure = { } diff --git a/app/src/main/java/com/min/dnapp/presentation/navigation/AppInitHost.kt b/app/src/main/java/com/min/dnapp/presentation/navigation/AppInitHost.kt new file mode 100644 index 0000000..2936a6d --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/navigation/AppInitHost.kt @@ -0,0 +1,94 @@ +package com.min.dnapp.presentation.navigation + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.navigation +import androidx.navigation.compose.rememberNavController +import com.min.dnapp.presentation.init.AppInitViewModel +import com.min.dnapp.presentation.init.InitRoute +import com.min.dnapp.presentation.init.LoadingScreen +import com.min.dnapp.presentation.init.OnboardingScreen +import com.min.dnapp.presentation.init.OnboardingScreen2 +import com.min.dnapp.presentation.init.OnboardingScreen3 +import com.min.dnapp.presentation.init.ProfileSetupScreen + +@Composable +fun AppInitHost( + appInitViewModel: AppInitViewModel = hiltViewModel(), + onInitComplete: () -> Unit +) { + val uiState by appInitViewModel.uiState.collectAsStateWithLifecycle() + + // nested navigation 담당 (인증 후) + val navController = rememberNavController() + + // 초기 상태에 따라 시작 경로 결정 + val startDestination = when (uiState.route) { + InitRoute.LOADING -> "loading" + InitRoute.ONBOARDING -> "onboarding_flow" + InitRoute.PROFILE_SETUP -> "profile_setup" + InitRoute.MAIN -> { + // 1번만 실행 + LaunchedEffect(Unit) { + onInitComplete() + } + // NavHost 렌더링 중단 + return + } + } + + NavHost( + navController = navController, + startDestination = startDestination + ) { + composable("loading") { + LoadingScreen() + } + + navigation( + startDestination = "onboarding", + route = "onboarding_flow" + ) { + composable("onboarding") { + OnboardingScreen( + onFinish = { + navController.navigate("onboarding2") + } + ) + } + composable("onboarding2") { + OnboardingScreen2( + navController = navController, + onFinish = { + navController.navigate("onboarding3") + } + ) + } + composable("onboarding3") { + OnboardingScreen3( + navController = navController, + onFinish = { + appInitViewModel.onOnboardingFinished() + navController.navigate("profile_setup") { + popUpTo("onboarding_flow") { inclusive = true } + } + } + ) + } + } + + composable("profile_setup") { + ProfileSetupScreen( + onFinish = { + appInitViewModel.onProfileSetupFinished() + onInitComplete() + } + ) + } + } +} From 46ead07867c0a7eaf7cae2e74cf2ca34807d45be Mon Sep 17 00:00:00 2001 From: min486 Date: Fri, 14 Nov 2025 15:04:57 +0900 Subject: [PATCH 92/98] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90?= =?UTF-8?q?=EA=B0=80=20=EC=84=A0=ED=83=9D=ED=95=9C=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=95=84=20=EC=A0=80=EC=9E=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/init/AppInitViewModel.kt | 54 ++++++++++++++----- .../presentation/init/ProfileSetupScreen.kt | 26 ++++++++- .../dnapp/presentation/init/SaveImageState.kt | 8 +++ .../presentation/navigation/AppInitHost.kt | 1 - 4 files changed, 75 insertions(+), 14 deletions(-) create mode 100644 app/src/main/java/com/min/dnapp/presentation/init/SaveImageState.kt diff --git a/app/src/main/java/com/min/dnapp/presentation/init/AppInitViewModel.kt b/app/src/main/java/com/min/dnapp/presentation/init/AppInitViewModel.kt index 6103ad8..0273343 100644 --- a/app/src/main/java/com/min/dnapp/presentation/init/AppInitViewModel.kt +++ b/app/src/main/java/com/min/dnapp/presentation/init/AppInitViewModel.kt @@ -1,10 +1,12 @@ package com.min.dnapp.presentation.init +import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.min.dnapp.domain.usecase.GetInitStatusUseCase import com.min.dnapp.domain.usecase.SetOnboardingCompletedUseCase import com.min.dnapp.domain.usecase.SetProfileSetupCompletedUseCase +import com.min.dnapp.domain.usecase.UpdateProfileImageUseCase import com.min.dnapp.presentation.mypage.ProfileImageType import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow @@ -29,15 +31,20 @@ data class InitUiState( class AppInitViewModel @Inject constructor( getInitStatusUseCase: GetInitStatusUseCase, private val setOnboardingCompletedUseCase: SetOnboardingCompletedUseCase, - private val setProfileSetupCompletedUseCase: SetProfileSetupCompletedUseCase + private val setProfileSetupCompletedUseCase: SetProfileSetupCompletedUseCase, + private val updateProfileImageUseCase: UpdateProfileImageUseCase ) : ViewModel() { + private val _uiState = MutableStateFlow(InitUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + // 선택된 프로필 이미지 private val _selectedImage = MutableStateFlow(null) val selectedImage: StateFlow = _selectedImage.asStateFlow() - private val _uiState = MutableStateFlow(InitUiState()) - val uiState: StateFlow = _uiState.asStateFlow() + // 프로필 저장 상태 + private val _saveImageState = MutableStateFlow(SaveImageState.Init) + val saveImageState: StateFlow = _saveImageState.asStateFlow() init { viewModelScope.launch { @@ -55,14 +62,6 @@ class AppInitViewModel @Inject constructor( } } - /** - * 프로필 이미지 선택 - */ - fun selectImage(image: ProfileImageType) { - // 선택된 이미지 다시 선택하면 해제 - _selectedImage.value = if (_selectedImage.value == image) null else image - } - /** * 온보딩 3개 완료 후 호출 */ @@ -75,9 +74,40 @@ class AppInitViewModel @Inject constructor( /** * 프로필 선택 완료 후 호출 */ - fun onProfileSetupFinished() { + private fun onProfileSetupFinished() { viewModelScope.launch { setProfileSetupCompletedUseCase() } } + + /** + * 프로필 이미지 선택 + */ + fun selectImage(image: ProfileImageType) { + // 선택된 이미지 다시 선택하면 해제 + _selectedImage.value = if (_selectedImage.value == image) null else image + } + + /** + * 프로필 이미지 저장 + */ + fun saveProfileImage() { + viewModelScope.launch { + _selectedImage.value?.let { image -> + + // 로딩 시작 + _saveImageState.value = SaveImageState.Loading + + val result = updateProfileImageUseCase(image.key) + + result.onSuccess { + onProfileSetupFinished() + _saveImageState.value = SaveImageState.Success + }.onFailure { exception -> + Log.e("init", "saveProfileImage 실패", exception) + _saveImageState.value = SaveImageState.Error("이미지 저장 실패") + } + } + } + } } diff --git a/app/src/main/java/com/min/dnapp/presentation/init/ProfileSetupScreen.kt b/app/src/main/java/com/min/dnapp/presentation/init/ProfileSetupScreen.kt index 741e980..3796175 100644 --- a/app/src/main/java/com/min/dnapp/presentation/init/ProfileSetupScreen.kt +++ b/app/src/main/java/com/min/dnapp/presentation/init/ProfileSetupScreen.kt @@ -1,6 +1,7 @@ package com.min.dnapp.presentation.init 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 @@ -8,7 +9,9 @@ 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.material3.CenterAlignedTopAppBar +import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Text @@ -34,6 +37,7 @@ fun ProfileSetupScreen( onFinish: () -> Unit ) { val selectedImage by viewModel.selectedImage.collectAsStateWithLifecycle() + val saveImageState by viewModel.saveImageState.collectAsStateWithLifecycle() Scaffold( containerColor = MomentoTheme.colors.brownBg, @@ -103,12 +107,32 @@ fun ProfileSetupScreen( ) { SelectButton( enabled = selectedImage != null, - onConfirm = { onFinish() } + onConfirm = { viewModel.saveProfileImage() } ) Spacer(Modifier.height(20.dp)) } } } + + when (saveImageState) { + is SaveImageState.Loading -> { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator( + modifier = Modifier.size(40.dp), + color = MomentoTheme.colors.brownW20, + strokeWidth = 4.dp + ) + } + } + is SaveImageState.Success -> { onFinish() } + is SaveImageState.Error -> {} + else -> { + // Init 또는 Success + } + } } @Preview diff --git a/app/src/main/java/com/min/dnapp/presentation/init/SaveImageState.kt b/app/src/main/java/com/min/dnapp/presentation/init/SaveImageState.kt new file mode 100644 index 0000000..a8e4ff0 --- /dev/null +++ b/app/src/main/java/com/min/dnapp/presentation/init/SaveImageState.kt @@ -0,0 +1,8 @@ +package com.min.dnapp.presentation.init + +sealed class SaveImageState { + data object Init : SaveImageState() + data object Loading : SaveImageState() + data object Success : SaveImageState() + data class Error(val message: String) : SaveImageState() +} diff --git a/app/src/main/java/com/min/dnapp/presentation/navigation/AppInitHost.kt b/app/src/main/java/com/min/dnapp/presentation/navigation/AppInitHost.kt index 2936a6d..eaa6e44 100644 --- a/app/src/main/java/com/min/dnapp/presentation/navigation/AppInitHost.kt +++ b/app/src/main/java/com/min/dnapp/presentation/navigation/AppInitHost.kt @@ -85,7 +85,6 @@ fun AppInitHost( composable("profile_setup") { ProfileSetupScreen( onFinish = { - appInitViewModel.onProfileSetupFinished() onInitComplete() } ) From 1b40270177bd65457d35a3f3d9cb44326d6c1587 Mon Sep 17 00:00:00 2001 From: min486 Date: Fri, 14 Nov 2025 16:02:21 +0900 Subject: [PATCH 93/98] =?UTF-8?q?feat:=20Firebase=20Crashlytics=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 2 ++ build.gradle.kts | 3 ++- gradle/libs.versions.toml | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e89ed37..de771d4 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -19,6 +19,7 @@ plugins { alias(libs.plugins.ksp) alias(libs.plugins.hilt) alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.firebase.crashlytics) } android { @@ -86,6 +87,7 @@ dependencies { // firebase implementation(platform(libs.firebase.bom)) + implementation(libs.firebase.crashlytics) implementation(libs.firebase.analytics) implementation(libs.firebase.auth) implementation(libs.firebase.firestore) diff --git a/build.gradle.kts b/build.gradle.kts index 4708b68..0bee734 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,4 +6,5 @@ plugins { alias(libs.plugins.google.services) apply false alias(libs.plugins.ksp) apply false alias(libs.plugins.hilt) apply false -} \ No newline at end of file + alias(libs.plugins.firebase.crashlytics) apply false +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fc2e661..c44dc68 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,6 +11,7 @@ activityCompose = "1.10.1" composeBom = "2025.05.00" google = "4.4.3" firebaseBom = "34.1.0" +crashlytics = "3.0.6" kakao = "2.21.6" nav = "2.9.3" hilt = "2.56.2" @@ -41,6 +42,7 @@ androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit androidx-material3 = { group = "androidx.compose.material3", name = "material3" } firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebaseBom" } +firebase-crashlytics = { module = "com.google.firebase:firebase-crashlytics-ndk" } firebase-analytics = { module = "com.google.firebase:firebase-analytics" } firebase-auth = { module = "com.google.firebase:firebase-auth" } firebase-firestore = { module = "com.google.firebase:firebase-firestore" } @@ -68,3 +70,4 @@ google-services = { id = "com.google.gms.google-services", version.ref = "google hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } +firebase-crashlytics = { id = "com.google.firebase.crashlytics", version.ref = "crashlytics" } From e36818fe8dff4276f72caccff8fd14a448f3f7bc Mon Sep 17 00:00:00 2001 From: min486 Date: Sat, 15 Nov 2025 18:35:54 +0900 Subject: [PATCH 94/98] =?UTF-8?q?feat:=20=ED=94=84=EB=A1=9C=EC=A0=9D?= =?UTF-8?q?=ED=8A=B8=20Java=2017=EB=A1=9C=20=EC=97=85=EA=B7=B8=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index de771d4..9924ef5 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -59,11 +59,11 @@ android { } } compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = "11" + jvmTarget = "17" } buildFeatures { compose = true From 57b8bf804572b9616cb9bd5c2d65f662992941fc Mon Sep 17 00:00:00 2001 From: min486 Date: Sat, 15 Nov 2025 23:51:56 +0900 Subject: [PATCH 95/98] =?UTF-8?q?feat:=20CI/CD=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20release?= =?UTF-8?q?=20=EC=84=9C=EB=AA=85=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/cd_release.yml | 60 ++++++++++++++++++++++++++++++++ .github/workflows/ci_build.yml | 38 ++++++++++++++++++++ app/build.gradle.kts | 19 ++++++++++ 3 files changed, 117 insertions(+) create mode 100644 .github/workflows/cd_release.yml create mode 100644 .github/workflows/ci_build.yml diff --git a/.github/workflows/cd_release.yml b/.github/workflows/cd_release.yml new file mode 100644 index 0000000..c12d935 --- /dev/null +++ b/.github/workflows/cd_release.yml @@ -0,0 +1,60 @@ +name: Android CD Release + +on: + push: + branches: + - master # master 브랜치에 push 될 때 실행 + +jobs: + release: + runs-on: ubuntu-latest + + # Secrets를 환경 변수로 정의하여 run 스크립트에서 $변수 형태로 사용 가능 + env: + KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }} + KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }} + KEY_ALIAS: ${{ secrets.KEY_ALIAS }} + KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }} + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + + - name: Make gradlew executable + run: chmod +x ./gradlew + + # Secrets에서 Base64 문자열을 디코딩하여 app/keystore.jks 파일로 저장 + - name: Decode Keystore File + # base64 -d 명령어를 사용하여 복호화 + run: echo "$KEYSTORE_BASE64" | base64 -d > app/keystore.jks + + # 서명에 필요한 비밀번호와 별칭 정보를 signing.properties 파일로 생성 + - name: Set up Signing Properties + run: | + echo "storeFile=keystore.jks" > ./signing.properties + echo "storePassword=$KEYSTORE_PASSWORD" >> ./signing.properties + echo "keyAlias=$KEY_ALIAS" >> ./signing.properties + echo "keyPassword=$KEY_PASSWORD" >> ./signing.properties + + # 릴리즈 AAB 빌드 실행 + - name: Build Release AAB + # 프로젝트 설정을 통해 서명된다 + run: ./gradlew bundleRelease + + # GitHub Release 생성 및 고정 메시지 적용 + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + # Git Tag가 푸시될 때만 Release를 생성 (예: v1.0.0) + if: startsWith(github.ref, 'refs/tags/') + with: + # 빌드된 AAB 파일 업로드 + files: app/build/outputs/bundle/release/app-release.aab + name: Release ${{ github.ref_name }} + body: | + 더 나은 모멘토를 위해 버그를 수정하고, 사용성을 개선했어요 \ No newline at end of file diff --git a/.github/workflows/ci_build.yml b/.github/workflows/ci_build.yml new file mode 100644 index 0000000..080adc6 --- /dev/null +++ b/.github/workflows/ci_build.yml @@ -0,0 +1,38 @@ +name: Android CI Build + +on: + push: + branches: + - develop # develop 브랜치에 push 될 때 실행 + pull_request: + branches: + - develop # develop 브랜치로 PR이 열리거나 업데이트 될 때 실행 + + +jobs: + build: + runs-on: ubuntu-latest # 워크플로우를 실행할 가상 환경 + + steps: + - name: Checkout Code + uses: actions/checkout@v4 # GitHub 저장소 코드를 워크스페이스로 가져오기 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + + - name: Make gradlew executable + run: chmod +x ./gradlew # gradlew 파일에 실행 권한 부여 + + - name: Build Debug APK + run: ./gradlew assembleDebug # 디버그 APK 빌드 명령어 실행 + + # 빌드된 APK 아티팩트 저장 + - name: Upload APK Artifact + uses: actions/upload-artifact@v4 + with: + name: dngo-app-debug + path: app/build/outputs/apk/debug/app-debug.apk + retention-days: 90 \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9924ef5..1626930 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -11,6 +11,13 @@ if (propertiesFile.exists()) { propertiesFile.inputStream().use { properties.load(it) } } +// CI/CD 서명 설정 파일 로드 +val signingProps = Properties() +val signingPropsFile = project.rootProject.file("signing.properties") +if (signingPropsFile.exists()) { + signingPropsFile.inputStream().use { signingProps.load(it) } +} + plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) @@ -49,6 +56,16 @@ android { buildConfigField("String", "NAVER_CLIENT_SECRET", "\"${naverClientSecret}\"") } + // CI/CD 서명 설정 + signingConfigs { + create("release") { + storeFile = if (signingProps.containsKey("storeFile")) file("app/${signingProps["storeFile"] as String}") else null + storePassword = signingProps["storePassword"] as String? + keyAlias = signingProps["keyAlias"] as String? + keyPassword = signingProps["keyPassword"] as String? + } + } + buildTypes { release { isMinifyEnabled = false @@ -56,6 +73,8 @@ android { getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) + // release 빌드 타입에 서명 설정 적용 + signingConfig = signingConfigs.getByName("release") } } compileOptions { From 11054c934af1c6004d63100a0aa62ce63baf281a Mon Sep 17 00:00:00 2001 From: min486 Date: Sun, 16 Nov 2025 13:15:03 +0900 Subject: [PATCH 96/98] =?UTF-8?q?fix:=20CI=20=EB=B9=8C=EB=93=9C=20?= =?UTF-8?q?=EC=8B=A4=ED=8C=A8=20=EC=88=98=EC=A0=95=20(local.properties?= =?UTF-8?q?=EC=97=90=20=ED=82=A4=20=EA=B0=92=20=EC=A3=BC=EC=9E=85)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci_build.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/ci_build.yml b/.github/workflows/ci_build.yml index 080adc6..4746cec 100644 --- a/.github/workflows/ci_build.yml +++ b/.github/workflows/ci_build.yml @@ -13,6 +13,11 @@ jobs: build: runs-on: ubuntu-latest # 워크플로우를 실행할 가상 환경 + env: + KAKAO_NATIVE_APP_KEY: ${{ secrets.KAKAO_NATIVE_APP_KEY }} + NAVER_CLIENT_ID: ${{ secrets.NAVER_CLIENT_ID }} + NAVER_CLIENT_SECRET: ${{ secrets.NAVER_CLIENT_SECRET }} + steps: - name: Checkout Code uses: actions/checkout@v4 # GitHub 저장소 코드를 워크스페이스로 가져오기 @@ -26,6 +31,13 @@ jobs: - name: Make gradlew executable run: chmod +x ./gradlew # gradlew 파일에 실행 권한 부여 + # Secrets를 사용하여 local.properties 파일 생성 + - name: Create local.properties for CI + run: | + echo "kakao.native.app.key=$KAKAO_NATIVE_APP_KEY" > local.properties + echo "naver.client.id=$NAVER_CLIENT_ID" >> local.properties + echo "naver.client.secret=$NAVER_CLIENT_SECRET" >> local.properties + - name: Build Debug APK run: ./gradlew assembleDebug # 디버그 APK 빌드 명령어 실행 From 1aced58ff2f5e52c1762062524fe5914267dd932 Mon Sep 17 00:00:00 2001 From: min486 Date: Sun, 16 Nov 2025 14:22:44 +0900 Subject: [PATCH 97/98] =?UTF-8?q?fix:=20Firebase=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EB=94=94=EC=BD=94=EB=94=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci_build.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci_build.yml b/.github/workflows/ci_build.yml index 4746cec..80e6fff 100644 --- a/.github/workflows/ci_build.yml +++ b/.github/workflows/ci_build.yml @@ -14,6 +14,7 @@ jobs: runs-on: ubuntu-latest # 워크플로우를 실행할 가상 환경 env: + GOOGLE_SERVICES_BASE64: ${{ secrets.GOOGLE_SERVICES_BASE64 }} KAKAO_NATIVE_APP_KEY: ${{ secrets.KAKAO_NATIVE_APP_KEY }} NAVER_CLIENT_ID: ${{ secrets.NAVER_CLIENT_ID }} NAVER_CLIENT_SECRET: ${{ secrets.NAVER_CLIENT_SECRET }} @@ -31,6 +32,9 @@ jobs: - name: Make gradlew executable run: chmod +x ./gradlew # gradlew 파일에 실행 권한 부여 + - name: Decode Google Services File + run: echo "$GOOGLE_SERVICES_BASE64" | base64 -d > app/google-services.json + # Secrets를 사용하여 local.properties 파일 생성 - name: Create local.properties for CI run: | From a436bcc22bec4895ad285d78a2e174955626abd9 Mon Sep 17 00:00:00 2001 From: min486 Date: Sun, 16 Nov 2025 14:37:32 +0900 Subject: [PATCH 98/98] =?UTF-8?q?chore:=20=EB=B2=84=EC=A0=84=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=202.0=20(10)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1626930..f34d9ac 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -37,8 +37,8 @@ android { applicationId = "com.min.dnapp" minSdk = 30 targetSdk = 36 - versionCode = 6 - versionName = "1.6" + versionCode = 10 + versionName = "2.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"