diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 1d25749ae..000000000 --- a/.editorconfig +++ /dev/null @@ -1,13 +0,0 @@ -root = true - -[*] -charset = utf-8 -indent_size = 4 -indent_style = space -max_line_length = 150 -insert_final_newline = true -trim_trailing_whitespace = true - -[*.{kt,kts}] -ij_kotlin_allow_trailing_comma = true -ij_kotlin_allow_trailing_comma_on_call_site = true \ No newline at end of file diff --git a/.github/workflows/android-ci.yml b/.github/workflows/android-ci.yml index f2b0195ef..24b0c6cb0 100644 --- a/.github/workflows/android-ci.yml +++ b/.github/workflows/android-ci.yml @@ -21,10 +21,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: set up JDK 21 + - name: set up JDK 17 uses: actions/setup-java@v4 with: - java-version: '21' + java-version: '17' distribution: 'temurin' cache: gradle @@ -49,9 +49,9 @@ jobs: # run: | # echo '${{ secrets.GOOGLE_SERVICES }}' >> ./app/google-services.json - - name: Code style checks - run: | - ./gradlew detekt --continue +# - name: Code style checks +# run: | +# ./gradlew detekt --continue - name: Run build - run: ./gradlew buildDebug --stacktrace + run: ./gradlew buildDebug --stacktrace \ No newline at end of file diff --git a/.github/workflows/discord_push_event_notify.yml b/.github/workflows/discord_push_event_notify.yml deleted file mode 100644 index 89193ffa9..000000000 --- a/.github/workflows/discord_push_event_notify.yml +++ /dev/null @@ -1,81 +0,0 @@ -name: Discord Push Notify - -on: - push: - branches: - - main - - develop - -jobs: - notify: - runs-on: ubuntu-latest - - steps: - - name: Send push to Discord (Embed) - env: - DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} - run: | - set -e - - # ---- push info ---- - REF=$(jq -r '.ref' "$GITHUB_EVENT_PATH") - BRANCH="${REF#refs/heads/}" - - REPO_URL=$(jq -r '.repository.html_url' "$GITHUB_EVENT_PATH") - URL=$(jq -r '.compare // .repository.html_url' "$GITHUB_EVENT_PATH") - TIMESTAMP=$(jq -r '.head_commit.timestamp // empty' "$GITHUB_EVENT_PATH") - - COUNT=$(jq -r '.commits | length' "$GITHUB_EVENT_PATH") - - # "• [hash] — message" (hash는 링크) - COMMITS=$(jq -r --arg repo_url "$REPO_URL" ' - (.commits // [])[:20] - | map( - "• [" + (.id[0:7]) + "](" + ($repo_url + "/commit/" + .id) + ") — " + - ((.message | split("\n")[0]) | gsub("\r";"")) - ) - | join("\n") - ' "$GITHUB_EVENT_PATH") - - TITLE="🚀 New Push · [${BRANCH}] · ${COUNT} commits" - - if [ -z "$COMMITS" ]; then - DESC=$(printf "총 %s개 커밋\n(커밋 정보 없음)" "$COUNT") - else - DESC=$(printf "총 %s개 커밋\n%s" "$COUNT" "$COMMITS") - fi - - payload=$(jq -n \ - --arg username "네키 디스코드 알림 봇" \ - --arg avatar "https://i.ifh.cc/PbdkGM.jpg" \ - --arg title "$TITLE" \ - --arg url "$URL" \ - --arg desc "$DESC" \ - --arg ts "$TIMESTAMP" \ - --argjson color 3066993 \ - '{ - username: $username, - avatar_url: $avatar, - embeds: [ - { - title: $title, - url: $url, - description: $desc, - color: $color - } - ] - } - | (if ($ts|length) > 0 then .embeds[0].timestamp = $ts else . end) - ') - - resp=$(curl -sS -X POST -H "Content-Type: application/json" -d "$payload" \ - -w "\nHTTP_STATUS:%{http_code}\n" \ - "$DISCORD_WEBHOOK_URL" || true) - - echo "$resp" - - status=$(echo "$resp" | sed -n 's/HTTP_STATUS://p') - if [ -z "$status" ] || [ "$status" -ge 400 ]; then - echo "Discord webhook failed" - exit 1 - fi diff --git a/.github/workflows/discord_review_event_notify.yml b/.github/workflows/discord_review_event_notify.yml deleted file mode 100644 index c424591c3..000000000 --- a/.github/workflows/discord_review_event_notify.yml +++ /dev/null @@ -1,182 +0,0 @@ -name: Discord PR Review - -on: - pull_request_review: - types: [submitted] - issue_comment: - types: [created] - -jobs: - notify: - if: | - github.actor != 'coderabbitai[bot]' && - github.actor != 'coderabbitai' && - (github.event_name != 'issue_comment' || github.event.issue.pull_request) - runs-on: ubuntu-latest - - steps: - - name: Send PR activity to Discord (Embed) - env: - DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - set -e - - EVENT="$GITHUB_EVENT_NAME" - REPO=$(jq -r '.repository.full_name' "$GITHUB_EVENT_PATH") - - truncate_lines () { - local text="$1" - local max="$2" - echo "$text" | awk -v max="$max" 'NR<=max {print} NR==max {exit}' - } - - truncate_chars () { - local s="$1" - local n="$2" - if [ "${#s}" -gt "$n" ]; then - echo "${s:0:$n}…" - else - echo "$s" - fi - } - - quote_block () { - # 각 줄을 "> "로 감싸서 Discord 인용문 만들기 - echo "$1" | sed 's/^/> /' - } - - TITLE="" - DESC="" - URL="" - COLOR=7506394 - TIMESTAMP="" - - if [ "$EVENT" = "pull_request_review" ]; then - PR_NUMBER=$(jq -r '.pull_request.number' "$GITHUB_EVENT_PATH") - PR_TITLE=$(jq -r '.pull_request.title' "$GITHUB_EVENT_PATH") - PR_URL=$(jq -r '.pull_request.html_url' "$GITHUB_EVENT_PATH") - - REVIEWER=$(jq -r '.review.user.login' "$GITHUB_EVENT_PATH") - STATE=$(jq -r '.review.state' "$GITHUB_EVENT_PATH") - REVIEW_BODY=$(jq -r '.review.body // ""' "$GITHUB_EVENT_PATH") - - REVIEW_ID=$(jq -r '.review.id' "$GITHUB_EVENT_PATH") - TIMESTAMP=$(jq -r '.review.submitted_at // empty' "$GITHUB_EVENT_PATH") - - # state별 컬러 - case "$STATE" in - approved|APPROVED) COLOR=5763719 ;; - changes_requested|CHANGES_REQUESTED) COLOR=15548997 ;; - commented|COMMENTED) COLOR=3447003 ;; - dismissed|DISMISSED) COLOR=9807270 ;; - *) COLOR=7506394 ;; - esac - - # ✅ 타이틀: 2줄 - TITLE=$(printf "📝 PR Review · %s\n[#%s] — “%s”" "$STATE" "$PR_NUMBER" "$PR_TITLE") - URL="$PR_URL" - - # ✅ 리뷰 본문: 있으면 2~4줄만, 없으면 아예 출력 안 함 - REVIEW_SNIP="" - if [ -n "$REVIEW_BODY" ] && [ "$REVIEW_BODY" != "null" ]; then - REVIEW_SNIP=$(truncate_lines "$REVIEW_BODY" 4) - fi - - # 인라인 코멘트 가져오기 (파일 경로 제거, 코멘트만) - COMMENTS_JSON=$(curl -sS -L \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer $GITHUB_TOKEN" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - "https://api.github.com/repos/$REPO/pulls/$PR_NUMBER/reviews/$REVIEW_ID/comments?per_page=100") - - INLINE_COMMENTS=$(echo "$COMMENTS_JSON" | jq -r ' - if type=="array" and length>0 then - .[:10] | map(.body | gsub("\r";"")) | join("\n\n---\n\n") - else - "" - end - ') - - QUOTED_INLINE="" - if [ -n "$INLINE_COMMENTS" ]; then - QUOTED_INLINE=$(quote_block "$INLINE_COMMENTS") - fi - - # ✅ Description 조립 - DESC=$(printf "Reviewer: %s" "$REVIEWER") - - if [ -n "$REVIEW_SNIP" ]; then - DESC=$(printf "%s\n\n%s" "$DESC" "$REVIEW_SNIP") - fi - - if [ -n "$QUOTED_INLINE" ]; then - DESC=$(printf "%s\n\n**💬 Comments**\n%s" "$DESC" "$QUOTED_INLINE") - fi - - DESC=$(truncate_chars "$DESC" 3800) - - elif [ "$EVENT" = "issue_comment" ]; then - PR_NUMBER=$(jq -r '.issue.number' "$GITHUB_EVENT_PATH") - PR_TITLE=$(jq -r '.issue.title' "$GITHUB_EVENT_PATH") - ISSUE_URL=$(jq -r '.issue.html_url' "$GITHUB_EVENT_PATH") - - COMMENTER=$(jq -r '.comment.user.login' "$GITHUB_EVENT_PATH") - COMMENT_BODY=$(jq -r '.comment.body // ""' "$GITHUB_EVENT_PATH") - TIMESTAMP=$(jq -r '.comment.created_at // empty' "$GITHUB_EVENT_PATH") - - COLOR=15105570 - - TITLE=$(printf "💬 PR Comment\n[#%s] — “%s”" "$PR_NUMBER" "$PR_TITLE") - URL="$ISSUE_URL" - - if [ -z "$COMMENT_BODY" ] || [ "$COMMENT_BODY" = "null" ]; then - COMMENT_BODY="" - fi - - DESC=$(printf "Commenter: %s" "$COMMENTER") - - if [ -n "$COMMENT_BODY" ]; then - DESC=$(printf "%s\n\n%s" "$DESC" "$(quote_block "$COMMENT_BODY")") - fi - - DESC=$(truncate_chars "$DESC" 3800) - - else - exit 0 - fi - - payload=$(jq -n \ - --arg username "네키 디스코드 알림 봇" \ - --arg avatar "https://i.ifh.cc/PbdkGM.jpg" \ - --arg title "$TITLE" \ - --arg url "$URL" \ - --arg desc "$DESC" \ - --arg ts "$TIMESTAMP" \ - --argjson color "$COLOR" \ - '{ - username: $username, - avatar_url: $avatar, - embeds: [ - { - title: $title, - url: $url, - description: $desc, - color: $color - } - ] - } - | (if ($ts|length) > 0 then .embeds[0].timestamp = $ts else . end) - ') - - resp=$(curl -sS -X POST -H "Content-Type: application/json" -d "$payload" \ - -w "\nHTTP_STATUS:%{http_code}\n" \ - "$DISCORD_WEBHOOK_URL" || true) - - echo "$resp" - - status=$(echo "$resp" | sed -n 's/HTTP_STATUS://p') - if [ -z "$status" ] || [ "$status" -ge 400 ]; then - echo "Discord webhook failed" - exit 1 - fi diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 09d4680a9..fe2278788 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,17 +1,5 @@ -import java.util.Properties -import kotlin.apply - plugins { alias(libs.plugins.neki.android.application) - alias(libs.plugins.neki.android.application.compose) - alias(libs.plugins.oss.licenses) -} - -val localPropertiesFile = project.rootProject.file("local.properties") -val properties = Properties().apply { - if (localPropertiesFile.exists()) { - load(localPropertiesFile.inputStream()) - } } android { @@ -20,61 +8,25 @@ android { buildFeatures { buildConfig = true } - - defaultConfig { - buildConfigField("String", "NAVER_MAP_CLIENT_ID", properties["NAVER_MAP_CLIENT_ID"].toString()) - manifestPlaceholders["KAKAO_NATIVE_APP_KEY"] = buildConfigField( - "String", - "KAKAO_NATIVE_APP_KEY", - properties["KAKAO_NATIVE_APP_KEY"].toString() - ) - } - - signingConfigs { - create("release") { - storeFile = rootProject.file("neki_key_store.jks") - storePassword = properties["STORE_PASSWORD"].toString() - keyAlias = properties["KEY_ALIAS"].toString() - keyPassword = properties["KEY_PASSWORD"].toString() - } - } - buildTypes { - getByName("release") { - isMinifyEnabled = true - signingConfig = signingConfigs.getByName("release") - proguardFiles( - getDefaultProguardFile("proguard-android-optimize.txt"), - "proguard-rules.pro", - ) - } - } - } dependencies { implementation(projects.core.common) implementation(projects.core.dataApi) implementation(projects.core.data) + implementation(projects.core.domain) + implementation(projects.core.model) + implementation(projects.core.designsystem) + implementation(projects.feature.sample.impl) + implementation(projects.feature.sample.api) + + implementation(projects.core.common) + implementation(projects.core.data) + implementation(projects.core.dataApi) implementation(projects.core.designsystem) implementation(projects.core.domain) implementation(projects.core.model) - implementation(projects.core.navigation) - implementation(projects.core.ui) - implementation(projects.feature.auth.api) - implementation(projects.feature.auth.impl) - implementation(projects.feature.pose.api) - implementation(projects.feature.pose.impl) - implementation(projects.feature.archive.api) - implementation(projects.feature.archive.impl) - implementation(projects.feature.map.api) - implementation(projects.feature.map.impl) - implementation(projects.feature.mypage.api) - implementation(projects.feature.mypage.impl) - implementation(projects.feature.photoUpload.api) - implementation(projects.feature.photoUpload.impl) implementation(libs.timber) - implementation(libs.androidx.activity.compose) - implementation(libs.androidx.navigation3.ui) -} +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 9aa01c402..481bb4348 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -5,191 +5,17 @@ # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html -# Keep line number information for debugging stack traces. --keepattributes SourceFile,LineNumberTable --renamesourcefileattribute SourceFile - -# ======================== -# Project Classes -# ======================== --keep class com.neki.android.** { *; } --keepclassmembers class com.neki.android.** { *; } - -# ======================== -# Kotlin -# ======================== --keep class kotlin.Metadata { *; } --keepattributes RuntimeVisibleAnnotations --keepattributes *Annotation* - -# Kotlin Coroutines --keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {} --keepnames class kotlinx.coroutines.CoroutineExceptionHandler {} --keepclassmembers class kotlinx.coroutines.** { - volatile ; -} --keepclassmembernames class kotlinx.** { - volatile ; -} - -# ======================== -# Ktor -# ======================== --keep class io.ktor.** { *; } --keepclassmembers class io.ktor.** { *; } --dontwarn io.ktor.** - -# ======================== -# kotlinx.serialization -# ======================== --keepattributes *Annotation*, InnerClasses --dontnote kotlinx.serialization.AnnotationsKt - --keepclassmembers @kotlinx.serialization.Serializable class ** { - *** Companion; -} --if @kotlinx.serialization.Serializable class ** --keepclassmembers class <1>$Companion { - kotlinx.serialization.KSerializer serializer(...); -} --if @kotlinx.serialization.Serializable class ** { - static **$* *; -} --keepclassmembers class <2>$<3> { - kotlinx.serialization.KSerializer serializer(...); -} --if @kotlinx.serialization.Serializable class ** { - public static ** INSTANCE; -} --keepclassmembers class <1> { - public static <1> INSTANCE; - kotlinx.serialization.KSerializer serializer(...); -} --keepclassmembers class * { - @kotlinx.serialization.SerialName ; -} --keep,includedescriptorclasses class com.neki.android.**$$serializer { *; } --keepclassmembers class com.neki.android.** { - *** Companion; -} - -# ======================== -# Kakao SDK -# ======================== --keep class com.kakao.sdk.** { *; } --keepclassmembers class com.kakao.sdk.** { *; } --dontwarn com.kakao.sdk.** - -# Kakao SDK enums (TokenNotFound 등) --keepclassmembers enum com.kakao.sdk.** { - public static **[] values(); - public static ** valueOf(java.lang.String); - ; -} - -# ======================== -# Hilt / Dagger -# ======================== --keep class dagger.** { *; } --keep class javax.inject.** { *; } --keep class * extends dagger.hilt.android.internal.managers.ComponentSupplier { *; } --keep class * extends dagger.hilt.android.internal.managers.ViewComponentManager$FragmentContextWrapper { *; } --keepclassmembers class * { - @dagger.hilt.* ; - @dagger.hilt.* ; - @javax.inject.* ; - @javax.inject.* ; -} --dontwarn dagger.internal.codegen.** --dontwarn dagger.hilt.internal.** - -# ======================== -# Android / Jetpack -# ======================== -# Lifecycle --keep class androidx.lifecycle.** { *; } --keepclassmembers class * implements androidx.lifecycle.LifecycleObserver { - (...); -} - -# Navigation --keep class androidx.navigation.** { *; } - -# Compose --keep class androidx.compose.** { *; } --dontwarn androidx.compose.** - -# DataStore --keep class androidx.datastore.** { *; } --keepclassmembers class * extends com.google.protobuf.GeneratedMessageLite { - ; -} - -# Paging --keep class androidx.paging.** { *; } - -# ======================== -# Enums (General) -# ======================== --keepclassmembers enum * { - public static **[] values(); - public static ** valueOf(java.lang.String); - ; -} - -# ======================== -# Timber -# ======================== --dontwarn org.jetbrains.annotations.** - -# ======================== -# OSS Licenses -# ======================== --keep class com.google.android.gms.oss.licenses.** { *; } - -# ======================== -# Coil -# ======================== --keep class coil3.** { *; } --dontwarn coil3.** - -# ======================== -# Naver Maps -# ======================== --keep class com.naver.maps.** { *; } --dontwarn com.naver.maps.** - -# ======================== -# OkHttp (used by Coil) -# ======================== --dontwarn okhttp3.** --dontwarn okio.** --keep class okhttp3.** { *; } --keep class okio.** { *; } - -# ======================== -# ML Kit Barcode -# ======================== --keep class com.google.mlkit.** { *; } --dontwarn com.google.mlkit.** - -# ======================== -# Play Services -# ======================== --keep class com.google.android.gms.** { *; } --dontwarn com.google.android.gms.** - -# ======================== -# CameraX -# ======================== --keep class androidx.camera.** { *; } --dontwarn androidx.camera.** - -# ======================== -# Missing class warnings suppression -# ======================== --dontwarn java.lang.invoke.StringConcatFactory --dontwarn org.slf4j.** --dontwarn org.bouncycastle.** --dontwarn org.conscrypt.** --dontwarn org.openjsse.** +# 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/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f442abbee..f892cf440 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,13 +1,7 @@ - - - - - - - + @@ -29,29 +23,7 @@ - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/app/src/main/java/com/neki/android/app/MainActivity.kt b/app/src/main/java/com/neki/android/app/MainActivity.kt deleted file mode 100644 index 9116b7619..000000000 --- a/app/src/main/java/com/neki/android/app/MainActivity.kt +++ /dev/null @@ -1,101 +0,0 @@ -package com.neki.android.app - -import android.os.Bundle -import android.widget.Toast -import androidx.activity.ComponentActivity -import androidx.activity.compose.setContent -import androidx.activity.enableEdgeToEdge -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.remember -import androidx.core.view.WindowCompat -import androidx.lifecycle.lifecycleScope -import androidx.navigation3.runtime.entryProvider -import com.neki.android.core.dataapi.auth.AuthEvent -import com.neki.android.core.dataapi.auth.AuthEventManager -import com.neki.android.core.designsystem.ui.theme.NekiTheme -import com.neki.android.core.navigation.EntryProviderInstaller -import com.neki.android.core.navigation.NavigatorImpl -import com.neki.android.core.navigation.result.LocalResultEventBus -import com.neki.android.core.navigation.result.ResultEventBus -import com.neki.android.core.navigation.root.RootNavKey -import com.neki.android.core.navigation.root.RootNavigationState -import com.neki.android.core.navigation.toEntries -import com.neki.android.feature.auth.impl.LoginRoute -import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.launch -import javax.inject.Inject - -@AndroidEntryPoint -class MainActivity : ComponentActivity() { - - @Inject - lateinit var rootNavigationState: RootNavigationState - - @Inject - lateinit var navigator: NavigatorImpl - - @Inject - lateinit var entryProviderScopes: Set<@JvmSuppressWildcards EntryProviderInstaller> - - @Inject - lateinit var authEventManager: AuthEventManager - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - enableEdgeToEdge() - WindowCompat.setDecorFitsSystemWindows(window, false) - - setContent { - NekiTheme { - val resultBus = remember { ResultEventBus() } - NekiTheme { - CompositionLocalProvider(LocalResultEventBus provides resultBus) { - when (rootNavigationState.currentRootKey) { - RootNavKey.Login -> { - LoginRoute( - navigateToMain = { navigator.navigateRoot(RootNavKey.Main) }, - ) - } - - RootNavKey.Main -> { - MainScreen( - currentKey = navigator.state.currentKey, - currentTopLevelKey = navigator.state.currentTopLevelKey, - topLevelKeys = navigator.state.topLevelKeys, - entries = navigator.state.toEntries( - entryProvider = entryProvider { - entryProviderScopes.forEach { builder -> this.builder() } - }, - ), - onTabSelected = { navigator.navigate(it) }, - onBack = { navigator.goBack() }, - navigateToLogin = { navigator.navigateRoot(RootNavKey.Login) }, - ) - } - } - } - } - } - } - observeAuthEvents() - } - - private fun observeAuthEvents() { - lifecycleScope.launch { - authEventManager.authEvent.collect { event -> - when (event) { - AuthEvent.RefreshTokenExpired -> { - Toast.makeText( - this@MainActivity, - "RefreshToken이 만료되었습니다.", - Toast.LENGTH_SHORT, - ).show() - - navigator.navigateRoot(RootNavKey.Login) - } - } - } - } - } -} diff --git a/app/src/main/java/com/neki/android/app/MainScreen.kt b/app/src/main/java/com/neki/android/app/MainScreen.kt deleted file mode 100644 index 028ce52cf..000000000 --- a/app/src/main/java/com/neki/android/app/MainScreen.kt +++ /dev/null @@ -1,55 +0,0 @@ -package com.neki.android.app - -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.navigationBarsPadding -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Scaffold -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.snapshots.SnapshotStateList -import androidx.compose.ui.Modifier -import androidx.navigation3.runtime.NavEntry -import androidx.navigation3.runtime.NavKey -import androidx.navigation3.ui.NavDisplay -import com.neki.android.app.ui.BottomNavigationBar -import com.neki.android.feature.map.api.MapNavKey - -@Composable -fun MainScreen( - currentKey: NavKey, - currentTopLevelKey: NavKey, - topLevelKeys: Set, - entries: SnapshotStateList>, - onTabSelected: (NavKey) -> Unit, - onBack: () -> Unit, - navigateToLogin: () -> Unit, -) { - val shouldShowBottomBar by remember(currentKey) { - mutableStateOf(currentKey in topLevelKeys) - } - - Scaffold( - modifier = Modifier - .fillMaxSize() - .navigationBarsPadding(), - bottomBar = { - BottomNavigationBar( - visible = shouldShowBottomBar, - currentTab = currentTopLevelKey, - currentKey = currentKey, - onTabSelected = { onTabSelected(it.navKey) }, - ) - }, - ) { innerPadding -> - NavDisplay( - modifier = Modifier.padding( - if (currentKey == MapNavKey.Map) PaddingValues(bottom = innerPadding.calculateBottomPadding()) else innerPadding, - ), - entries = entries, - onBack = onBack, - ) - } -} diff --git a/app/src/main/java/com/neki/android/app/NekiApplication.kt b/app/src/main/java/com/neki/android/app/NekiApplication.kt index f42f5e762..3f2fad624 100644 --- a/app/src/main/java/com/neki/android/app/NekiApplication.kt +++ b/app/src/main/java/com/neki/android/app/NekiApplication.kt @@ -1,29 +1,24 @@ package com.neki.android.app import android.app.Application -import com.kakao.sdk.common.KakaoSdk -import com.naver.maps.map.NaverMapSdk import dagger.hilt.android.HiltAndroidApp import timber.log.Timber @HiltAndroidApp -class NekiApplication : Application() { +class NekiApplication: Application() { override fun onCreate() { super.onCreate() if (BuildConfig.DEBUG) { Timber.plant(Timber.DebugTree()) } else { - Timber.plant( - object : Timber.Tree() { - override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { - // 여기는 Release일 때 로그를 남기지 않고 어딘가로 전송 ? - } - }, - ) + Timber.plant(object : Timber.Tree() { + override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { + // 여기는 Release일 때 로그를 남기지 않고 어딘가로 전송 ? + + } + }) } - NaverMapSdk.getInstance(this).client = NaverMapSdk.NcpKeyClient(BuildConfig.NAVER_MAP_CLIENT_ID) - KakaoSdk.init(this, BuildConfig.KAKAO_NATIVE_APP_KEY) } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/neki/android/app/navigation/TopLevelNavItem.kt b/app/src/main/java/com/neki/android/app/navigation/TopLevelNavItem.kt deleted file mode 100644 index 9fcc9a4ee..000000000 --- a/app/src/main/java/com/neki/android/app/navigation/TopLevelNavItem.kt +++ /dev/null @@ -1,47 +0,0 @@ -package com.neki.android.app.navigation - -import androidx.annotation.DrawableRes -import androidx.annotation.StringRes -import androidx.navigation3.runtime.NavKey -import com.neki.android.app.R -import com.neki.android.feature.archive.api.ArchiveNavKey -import com.neki.android.feature.map.api.MapNavKey -import com.neki.android.feature.mypage.api.MyPageNavKey -import com.neki.android.feature.pose.api.PoseNavKey - -enum class TopLevelNavItem( - @DrawableRes val selectedIconRes: Int, - @DrawableRes val unselectedIconRes: Int, - @StringRes val iconStringRes: Int, - val navKey: NavKey, -) { - ARCHIVE( - selectedIconRes = R.drawable.ic_nav_archive_selected, - unselectedIconRes = R.drawable.ic_nav_archive_unselected, - iconStringRes = R.string.top_level_nav_archive, - navKey = ArchiveNavKey.Archive, - ), - POSE_RECOMMEND( - selectedIconRes = R.drawable.ic_nav_pose_selected, - unselectedIconRes = R.drawable.ic_nav_pose_unselected, - iconStringRes = R.string.top_level_nav_pose, - navKey = PoseNavKey.PoseMain, - ), - MAP( - selectedIconRes = R.drawable.ic_nav_map_selected, - unselectedIconRes = R.drawable.ic_nav_map_unselected, - iconStringRes = R.string.top_level_nav_map, - navKey = MapNavKey.Map, - ), - MYPAGE( - selectedIconRes = R.drawable.ic_nav_mypage_selected, - unselectedIconRes = R.drawable.ic_nav_mypage_unselected, - iconStringRes = R.string.top_level_nav_mypage, - navKey = MyPageNavKey.MyPage, - ), - ; - - companion object { - val startTopLevelItem = ARCHIVE - } -} diff --git a/app/src/main/java/com/neki/android/app/navigation/di/AppModule.kt b/app/src/main/java/com/neki/android/app/navigation/di/AppModule.kt deleted file mode 100644 index 9c9f65551..000000000 --- a/app/src/main/java/com/neki/android/app/navigation/di/AppModule.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.neki.android.app.navigation.di - -import com.neki.android.core.navigation.Navigator -import com.neki.android.core.navigation.NavigatorImpl -import dagger.Binds -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.android.components.ActivityRetainedComponent - -@Module -@InstallIn(ActivityRetainedComponent::class) -internal interface AppModule { - - @Binds - fun bindsNavigator( - impl: NavigatorImpl, - ): Navigator -} diff --git a/app/src/main/java/com/neki/android/app/navigation/di/NavigationModule.kt b/app/src/main/java/com/neki/android/app/navigation/di/NavigationModule.kt deleted file mode 100644 index f28a13f8a..000000000 --- a/app/src/main/java/com/neki/android/app/navigation/di/NavigationModule.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.neki.android.app.navigation.di - -import com.neki.android.app.navigation.keys.START_NAV_KEY -import com.neki.android.app.navigation.keys.START_ROOT_NAV_KEY -import com.neki.android.app.navigation.keys.TOP_LEVEL_NAV_KEYS -import com.neki.android.core.navigation.NavigationState -import com.neki.android.core.navigation.root.RootNavigationState -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.components.ActivityRetainedComponent -import dagger.hilt.android.scopes.ActivityRetainedScoped - -@Module -@InstallIn(ActivityRetainedComponent::class) -internal object NavigationModule { - - @Provides - @ActivityRetainedScoped - fun providesNavigationState(): NavigationState { - return NavigationState( - startKey = START_NAV_KEY, - topLevelKeys = TOP_LEVEL_NAV_KEYS.toSet(), - ) - } - - @Provides - @ActivityRetainedScoped - fun providesRootNavigationState(): RootNavigationState { - return RootNavigationState( - startKey = START_ROOT_NAV_KEY, - ) - } -} diff --git a/app/src/main/java/com/neki/android/app/navigation/keys/Keys.kt b/app/src/main/java/com/neki/android/app/navigation/keys/Keys.kt deleted file mode 100644 index 50a2d285c..000000000 --- a/app/src/main/java/com/neki/android/app/navigation/keys/Keys.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.neki.android.app.navigation.keys - -import com.neki.android.app.navigation.TopLevelNavItem -import com.neki.android.core.navigation.root.RootNavKey -import com.neki.android.feature.archive.api.ArchiveNavKey - -internal val START_ROOT_NAV_KEY = RootNavKey.Login -internal val START_NAV_KEY = ArchiveNavKey.Archive -internal val TOP_LEVEL_NAV_KEYS = TopLevelNavItem.entries.map { it.navKey } diff --git a/app/src/main/java/com/neki/android/app/ui/BottomNavigationBar.kt b/app/src/main/java/com/neki/android/app/ui/BottomNavigationBar.kt deleted file mode 100644 index ff8d77400..000000000 --- a/app/src/main/java/com/neki/android/app/ui/BottomNavigationBar.kt +++ /dev/null @@ -1,120 +0,0 @@ -package com.neki.android.app.ui - -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.slideInVertically -import androidx.compose.animation.slideOutVertically -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.navigationBarsPadding -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -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.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.graphics.vector.ImageVector -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.res.vectorResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.navigation3.runtime.NavKey -import com.neki.android.app.navigation.TopLevelNavItem -import com.neki.android.core.designsystem.modifier.tabbarShadow -import com.neki.android.core.designsystem.ui.theme.NekiTheme - -@Composable -fun BottomNavigationBar( - visible: Boolean, - currentKey: NavKey, - currentTab: NavKey, - tabs: List = TopLevelNavItem.entries, - onTabSelected: (TopLevelNavItem) -> Unit, -) { - AnimatedVisibility( - visible = visible, - enter = slideInVertically { it }, - exit = slideOutVertically { it }, - ) { - Surface( - modifier = Modifier - .navigationBarsPadding() - .fillMaxWidth() - .tabbarShadow(), - color = NekiTheme.colorScheme.white, - ) { - Row( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 19.5.dp, vertical = 2.dp), - horizontalArrangement = Arrangement.spacedBy(16.dp), - ) { - tabs.forEach { tab -> - BottomNavigationBarItem( - modifier = Modifier.weight(1f), - selected = tab.navKey == currentTab, - tab = tab, - onClick = { if (tab.navKey != currentKey) onTabSelected(tab) }, - ) - } - } - } - } -} - -@Composable -fun BottomNavigationBarItem( - selected: Boolean, - tab: TopLevelNavItem, - modifier: Modifier = Modifier, - onClick: () -> Unit = {}, -) { - val icon = if (selected) tab.selectedIconRes else tab.unselectedIconRes - val iconColor = if (selected) NekiTheme.colorScheme.gray800 else NekiTheme.colorScheme.gray200 - val textColor = if (selected) NekiTheme.colorScheme.gray800 else NekiTheme.colorScheme.gray500 - - Surface( - modifier = modifier, - onClick = onClick, - color = NekiTheme.colorScheme.white, - ) { - Column( - modifier = Modifier.padding(vertical = 1.dp), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(4.dp), - ) { - Icon( - modifier = Modifier.size(26.dp), - imageVector = ImageVector.vectorResource(icon), - contentDescription = stringResource(tab.iconStringRes), - tint = iconColor, - ) - Text( - text = stringResource(tab.iconStringRes), - color = textColor, - style = NekiTheme.typography.caption12SemiBold, - ) - } - } -} - -@Preview -@Composable -private fun BottomNavigationBarPreview() { - var currentTab by remember { mutableStateOf(TopLevelNavItem.ARCHIVE) } - NekiTheme { - BottomNavigationBar( - visible = true, - tabs = TopLevelNavItem.entries, - currentTab = currentTab.navKey, - currentKey = currentTab.navKey, - ) { currentTab = it } - } -} diff --git a/app/src/main/res/drawable/ic_nav_archive_selected.xml b/app/src/main/res/drawable/ic_nav_archive_selected.xml deleted file mode 100644 index cbc544202..000000000 --- a/app/src/main/res/drawable/ic_nav_archive_selected.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_nav_archive_unselected.xml b/app/src/main/res/drawable/ic_nav_archive_unselected.xml deleted file mode 100644 index 3326a37a8..000000000 --- a/app/src/main/res/drawable/ic_nav_archive_unselected.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_nav_map_selected.xml b/app/src/main/res/drawable/ic_nav_map_selected.xml deleted file mode 100644 index bf9d67933..000000000 --- a/app/src/main/res/drawable/ic_nav_map_selected.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_nav_map_unselected.xml b/app/src/main/res/drawable/ic_nav_map_unselected.xml deleted file mode 100644 index f8fa1da48..000000000 --- a/app/src/main/res/drawable/ic_nav_map_unselected.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_nav_mypage_selected.xml b/app/src/main/res/drawable/ic_nav_mypage_selected.xml deleted file mode 100644 index 4d4e83f92..000000000 --- a/app/src/main/res/drawable/ic_nav_mypage_selected.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_nav_mypage_unselected.xml b/app/src/main/res/drawable/ic_nav_mypage_unselected.xml deleted file mode 100644 index b633e5435..000000000 --- a/app/src/main/res/drawable/ic_nav_mypage_unselected.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_nav_pose_selected.xml b/app/src/main/res/drawable/ic_nav_pose_selected.xml deleted file mode 100644 index ef5d248c5..000000000 --- a/app/src/main/res/drawable/ic_nav_pose_selected.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_nav_pose_unselected.xml b/app/src/main/res/drawable/ic_nav_pose_unselected.xml deleted file mode 100644 index 61143f466..000000000 --- a/app/src/main/res/drawable/ic_nav_pose_unselected.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/icon_nav_archive_selected.xml b/app/src/main/res/drawable/icon_nav_archive_selected.xml deleted file mode 100644 index fb9e6f13f..000000000 --- a/app/src/main/res/drawable/icon_nav_archive_selected.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/icon_nav_archive_unselected.xml b/app/src/main/res/drawable/icon_nav_archive_unselected.xml deleted file mode 100644 index e70c42e65..000000000 --- a/app/src/main/res/drawable/icon_nav_archive_unselected.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/icon_nav_map_selected.xml b/app/src/main/res/drawable/icon_nav_map_selected.xml deleted file mode 100644 index 2196191b8..000000000 --- a/app/src/main/res/drawable/icon_nav_map_selected.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/icon_nav_map_unselected.xml b/app/src/main/res/drawable/icon_nav_map_unselected.xml deleted file mode 100644 index f92a513d4..000000000 --- a/app/src/main/res/drawable/icon_nav_map_unselected.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/icon_nav_mypage_selected.xml b/app/src/main/res/drawable/icon_nav_mypage_selected.xml deleted file mode 100644 index 92f7c657c..000000000 --- a/app/src/main/res/drawable/icon_nav_mypage_selected.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/icon_nav_mypage_unselected.xml b/app/src/main/res/drawable/icon_nav_mypage_unselected.xml deleted file mode 100644 index b5be1485d..000000000 --- a/app/src/main/res/drawable/icon_nav_mypage_unselected.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/icon_nav_pose_selected.xml b/app/src/main/res/drawable/icon_nav_pose_selected.xml deleted file mode 100644 index 1a0d4868b..000000000 --- a/app/src/main/res/drawable/icon_nav_pose_selected.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/icon_nav_pose_unselected.xml b/app/src/main/res/drawable/icon_nav_pose_unselected.xml deleted file mode 100644 index 93dc71333..000000000 --- a/app/src/main/res/drawable/icon_nav_pose_unselected.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a82505ad5..820454ae5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,9 +1,3 @@ Neki - - 포즈 - 아카이빙 - 네컷지도 - 마이 - - + \ 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 208d2f239..3a126b0e1 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,13 +1,5 @@ - + - - - - +