diff --git a/.gitignore b/.gitignore index 56cc6425e..ec4c59d52 100644 --- a/.gitignore +++ b/.gitignore @@ -82,4 +82,4 @@ lint/intermediates/ lint/generated/ lint/outputs/ lint/tmp/ -# lint/reports/ +# lint/reports/ \ No newline at end of file diff --git a/android/.idea/.gitignore b/android/.idea/.gitignore new file mode 100644 index 000000000..26d33521a --- /dev/null +++ b/android/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/android/.idea/.name b/android/.idea/.name new file mode 100644 index 000000000..e152c8212 --- /dev/null +++ b/android/.idea/.name @@ -0,0 +1 @@ +mediproject \ No newline at end of file diff --git a/android/.idea/compiler.xml b/android/.idea/compiler.xml new file mode 100644 index 000000000..b589d56e9 --- /dev/null +++ b/android/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/android/.idea/gradle.xml b/android/.idea/gradle.xml new file mode 100644 index 000000000..9458d8dd5 --- /dev/null +++ b/android/.idea/gradle.xml @@ -0,0 +1,56 @@ + + + + + + + \ No newline at end of file diff --git a/android/.idea/inspectionProfiles/Project_Default.xml b/android/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 000000000..44ca2d9b0 --- /dev/null +++ b/android/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,41 @@ + + + + \ No newline at end of file diff --git a/android/.idea/jarRepositories.xml b/android/.idea/jarRepositories.xml new file mode 100644 index 000000000..fdc392fe8 --- /dev/null +++ b/android/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/android/.idea/kotlinc.xml b/android/.idea/kotlinc.xml new file mode 100644 index 000000000..9a55c2de1 --- /dev/null +++ b/android/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/android/.idea/misc.xml b/android/.idea/misc.xml new file mode 100644 index 000000000..ab874d476 --- /dev/null +++ b/android/.idea/misc.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/android/.idea/navEditor.xml b/android/.idea/navEditor.xml new file mode 100644 index 000000000..46a4e1aae --- /dev/null +++ b/android/.idea/navEditor.xml @@ -0,0 +1,65 @@ + + + + + + \ No newline at end of file diff --git a/android/apikey.properties b/android/apikey.properties new file mode 100644 index 000000000..9f1389d4d --- /dev/null +++ b/android/apikey.properties @@ -0,0 +1,9 @@ +# 이 파일은 .gitignore에 추가되어 있어서 git에 올라가지 않는다. +dataGoKrServiceKey=T2nJm9zlOA0Z7Dut%2BThT6Jp0Itn0zZw80AUP3uMdOWlZJR1gVPkx9p1t8etuSW1kWsSNrGGHKdxbwr1IUlt%2Baw%3D%3D +dataGoKrBaseUrl=https://apis.data.go.kr/1471000/ +awsUrl=http://winocreative.synology.me:33000/ +vertexEndpointUrl=https://us-central1-aiplatform.googleapis.com/v1/projects/balmy-nuance-380605/locations/us-central1/endpoints/1063583985826791424:predict +SIGNED_STORE_FILE=secretkey/medikey.jks +SIGNED_STORE_PASSWORD=pamspams1 +SIGNED_KEY_ALIAS=medikey +SIGNED_KEY_PASSWORD=pamspams1 \ No newline at end of file diff --git a/android/app/.gitignore b/android/app/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/android/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/android/app/README.md b/android/app/README.md new file mode 100644 index 000000000..1a1b28d3c --- /dev/null +++ b/android/app/README.md @@ -0,0 +1,5 @@ +## App module + +* ### 구성 + * MainActivty + * Application class \ No newline at end of file diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts new file mode 100644 index 000000000..f60b439ad --- /dev/null +++ b/android/app/build.gradle.kts @@ -0,0 +1,104 @@ +import org.jetbrains.kotlin.konan.properties.Properties + +plugins { + id("mediproject.android.application") + id("mediproject.android.hilt") + id("androidx.navigation.safeargs.kotlin") + alias(libs.plugins.gms) + alias(libs.plugins.firebase.crashlytics) +} + +android { + signingConfigs { + val properties = Properties() + properties.load(project.rootProject.file("/apikey.properties").bufferedReader()) + create("release") { + storeFile = project.rootProject.file(properties["SIGNED_STORE_FILE"] as String) + storePassword = properties["SIGNED_STORE_PASSWORD"] as String + keyAlias = properties["SIGNED_KEY_ALIAS"] as String + keyPassword = properties["SIGNED_KEY_PASSWORD"] as String + } + } + + defaultConfig { + applicationId = "com.android.mediproject" + versionCode = 1 + versionName = "1.0.0-alpha01" + + vectorDrawables { + useSupportLibrary = true + } + + buildTypes { + debug { + + } + release { + isMinifyEnabled = true + proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro", + "proguard-glide.pro", + "proguard-okhttp3.pro", + "proguard-room.pro", + "proguard-retrofit2.pro") + signingConfig = signingConfigs.getByName("release") + } + } + } + namespace = "com.android.mediproject" + + lint { + checkDependencies = true + ignoreTestSources = true + } + +} + +hilt { + enableAggregatingTask = true +} + +dependencies { + implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar")))) + + implementation(project(":core:common")) + implementation(project(":core:data")) + implementation(project(":core:ui")) + implementation(project(":core:model")) + implementation(project(":core:database")) + implementation(project(":core:domain")) + implementation(project(":core:network")) + + implementation(project(":feature:interestedmedicine")) + implementation(project(":feature:home")) + implementation(project(":feature:intro")) + implementation(project(":feature:comments")) + implementation(project(":feature:search")) + implementation(project(":feature:mypage")) + + implementation(project(":feature:setting")) + implementation(project(":feature:penalties")) + implementation(project(":feature:medicine")) + implementation(project(":feature:news")) + implementation(project(":feature:camera")) + + implementation(libs.bundles.lifecycles) + implementation(libs.bundles.materials) + implementation(libs.bundles.composes) + implementation(libs.bundles.navigations) + implementation(libs.bundles.kotlins) + implementation(libs.bundles.workManagers) + implementation(libs.bundles.glides) + implementation(libs.androidx.splash) + kapt(libs.bundles.glides.kapt) + + implementation(libs.firebase.crashlytics) + implementation(libs.firebase.analytics) + + /* + androidTestImplementation(libs.bundles.testUIs) + testImplementation(libs.bundles.testUIs) + androidTestUtil(libs.androidx.test.orchestrator) + + */ +} \ No newline at end of file diff --git a/android/app/debug/output-metadata.json b/android/app/debug/output-metadata.json new file mode 100644 index 000000000..81da20561 --- /dev/null +++ b/android/app/debug/output-metadata.json @@ -0,0 +1,20 @@ +{ + "version": 3, + "artifactType": { + "type": "APK", + "kind": "Directory" + }, + "applicationId": "com.android.mediproject", + "variantName": "debug", + "elements": [ + { + "type": "SINGLE", + "filters": [], + "attributes": [], + "versionCode": 1, + "versionName": "1.0.0-alpha01", + "outputFile": "app-debug.apk" + } + ], + "elementType": "File" +} \ No newline at end of file diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 000000000..eabad396a --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,47 @@ +{ + "project_info": { + "project_number": "898493131497", + "project_id": "medilenz-7276b", + "storage_bucket": "medilenz-7276b.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:898493131497:android:884db09c3cf16cd030de78", + "android_client_info": { + "package_name": "com.android.mediproject" + } + }, + "oauth_client": [ + { + "client_id": "898493131497-kq7nsheeco98msah8hl0ptcioh8pebbg.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.android.mediproject", + "certificate_hash": "52585fe9fb7f05d0d0c0e3f443c35613e00c29b1" + } + }, + { + "client_id": "898493131497-lnipe3n8n22d5242pir050annu2adj14.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyBiQ7pa6mtYgTHbovjr6kndPzc19-MMfIo" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "898493131497-lnipe3n8n22d5242pir050annu2adj14.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/app/proguard-glide.pro b/android/app/proguard-glide.pro new file mode 100644 index 000000000..1d231b30b --- /dev/null +++ b/android/app/proguard-glide.pro @@ -0,0 +1,11 @@ +-keep public class * implements com.bumptech.glide.module.GlideModule +-keep class * extends com.bumptech.glide.module.AppGlideModule { + (...); +} +-keep public enum com.bumptech.glide.load.ImageHeaderParser$** { + **[] $VALUES; + public *; +} +-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder { + *** rewind(); +} \ No newline at end of file diff --git a/android/app/proguard-okhttp3.pro b/android/app/proguard-okhttp3.pro new file mode 100644 index 000000000..ee738b77a --- /dev/null +++ b/android/app/proguard-okhttp3.pro @@ -0,0 +1,3 @@ +-dontwarn okhttp3.** +-dontwarn okio.** +-dontnote okhttp3.** \ No newline at end of file diff --git a/android/app/proguard-retrofit2.pro b/android/app/proguard-retrofit2.pro new file mode 100644 index 000000000..a56ee242b --- /dev/null +++ b/android/app/proguard-retrofit2.pro @@ -0,0 +1,45 @@ +# Begin: Proguard rules for retrofit2 + +# Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and +# EnclosingMethod is required to use InnerClasses. +-keepattributes Signature, InnerClasses, EnclosingMethod + +# Retrofit does reflection on method and parameter annotations. +-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations + +# Keep annotation default values (e.g., retrofit2.http.Field.encoded). +-keepattributes AnnotationDefault + +# Retain service method parameters when optimizing. +-keepclassmembers,allowshrinking,allowobfuscation interface * { + @retrofit2.http.* ; +} + +# Ignore annotation used for build tooling. +-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement.* + +# Ignore JSR 305 annotations for embedding nullability information. +-dontwarn javax.annotation.** + +# Guarded by a NoClassDefFoundError try/catch and only used when on the classpath. +-dontwarn kotlin.Unit + +# Top-level functions that can only be used by Kotlin. +-dontwarn retrofit2.KotlinExtensions +-dontwarn retrofit2.KotlinExtensions$* + +# With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy +# and replaces all potential values with null. Explicitly keeping the interfaces prevents this. +-if interface * { @retrofit2.http.* ; } +-keep,allowobfuscation interface <1> + +# Keep generic signature of Call, Response (R8 full mode strips signatures from non-kept items). +-keep,allowobfuscation,allowshrinking interface retrofit2.Call +-keep,allowobfuscation,allowshrinking class retrofit2.Response + +# With R8 full mode generic signatures are stripped for classes that are not +# kept. Suspend functions are wrapped in continuations where the type argument +# is used. +-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation + +# End: Proguard rules for retrofit2 \ No newline at end of file diff --git a/android/app/proguard-room.pro b/android/app/proguard-room.pro new file mode 100644 index 000000000..42a2b2691 --- /dev/null +++ b/android/app/proguard-room.pro @@ -0,0 +1,3 @@ +-keep class * extends androidx.room.RoomDatabase +-keep @androidx.room.Entity class * +-dontwarn androidx.room.paging.** \ No newline at end of file diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro new file mode 100644 index 000000000..122ed34d0 --- /dev/null +++ b/android/app/proguard-rules.pro @@ -0,0 +1,64 @@ +# 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,RuntimeVisibleAnnotations,AnnotationDefault + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +#keep +-keep public class * { public protected *; } +-keep class com.luckycatlabs.sunrisesunset.** { *;} +-keepclassmembers class * extends com.google.protobuf.GeneratedMessageLite* { + ; +} + + +# Keep `Companion` object fields of serializable classes. +# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects. +-if @kotlinx.serialization.Serializable class ** +-keepclassmembers class <1> { + static <1>$Companion Companion; +} + +# Keep `serializer()` on companion objects (both default and named) of serializable classes. +-if @kotlinx.serialization.Serializable class ** { + static **$* *; +} +-keepclassmembers class <2>$<3> { + kotlinx.serialization.KSerializer serializer(...); +} + +# Keep `INSTANCE.serializer()` of serializable objects. +-if @kotlinx.serialization.Serializable class ** { + public static ** INSTANCE; +} +-keepclassmembers class <1> { + public static <1> INSTANCE; + kotlinx.serialization.KSerializer serializer(...); +} + +-dontwarn org.bouncycastle.jsse.BCSSLParameters +-dontwarn org.bouncycastle.jsse.BCSSLSocket +-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider +-dontwarn org.conscrypt.Conscrypt$Version +-dontwarn org.conscrypt.Conscrypt +-dontwarn org.conscrypt.ConscryptHostnameVerifier +-dontwarn org.openjsse.javax.net.ssl.SSLParameters +-dontwarn org.openjsse.javax.net.ssl.SSLSocket +-dontwarn org.openjsse.net.ssl.OpenJSSE +-dontwarn org.tensorflow.lite.gpu.** \ No newline at end of file diff --git a/android/app/release/output-metadata.json b/android/app/release/output-metadata.json new file mode 100644 index 000000000..5840e38bd --- /dev/null +++ b/android/app/release/output-metadata.json @@ -0,0 +1,20 @@ +{ + "version": 3, + "artifactType": { + "type": "APK", + "kind": "Directory" + }, + "applicationId": "com.android.mediproject", + "variantName": "release", + "elements": [ + { + "type": "SINGLE", + "filters": [], + "attributes": [], + "versionCode": 1, + "versionName": "1.0.0-alpha01", + "outputFile": "app-release.apk" + } + ], + "elementType": "File" +} \ No newline at end of file diff --git a/android/app/src/androidTest/java/com/android/mediproject/ExampleInstrumentedTest.kt b/android/app/src/androidTest/java/com/android/mediproject/ExampleInstrumentedTest.kt new file mode 100644 index 000000000..6ebd3b0e2 --- /dev/null +++ b/android/app/src/androidTest/java/com/android/mediproject/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.android.mediproject + +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.android.mediproject", appContext.packageName) + } +} \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..32b51daf4 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/ic_medilenz-playstore.png b/android/app/src/main/ic_medilenz-playstore.png new file mode 100644 index 000000000..906ae0a4f Binary files /dev/null and b/android/app/src/main/ic_medilenz-playstore.png differ diff --git a/android/app/src/main/java/com/android/mediproject/DevDialogFragment.kt b/android/app/src/main/java/com/android/mediproject/DevDialogFragment.kt new file mode 100644 index 000000000..453c10b99 --- /dev/null +++ b/android/app/src/main/java/com/android/mediproject/DevDialogFragment.kt @@ -0,0 +1,38 @@ +package com.android.mediproject + +import android.os.Bundle +import android.text.Html +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.text.toSpannable +import com.android.mediproject.databinding.ViewDevStateBinding +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class DevDialogFragment : BottomSheetDialogFragment() { + + private var _binding: ViewDevStateBinding? = null + + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View = ViewDevStateBinding.inflate(layoutInflater, container, false).also { + _binding = it + }.root + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.apply { + val text = Html.fromHtml(getString(R.string.messageDevelopment), Html.FROM_HTML_MODE_COMPACT).toSpannable() + messageTextView.text = text + } + + binding.okButton.setOnClickListener { + dismiss() + } + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/android/mediproject/MainActivity.kt b/android/app/src/main/java/com/android/mediproject/MainActivity.kt new file mode 100644 index 000000000..875029bcf --- /dev/null +++ b/android/app/src/main/java/com/android/mediproject/MainActivity.kt @@ -0,0 +1,169 @@ +package com.android.mediproject + +import android.animation.ObjectAnimator +import android.os.Build +import android.view.View +import android.view.ViewGroup.MarginLayoutParams +import android.view.ViewTreeObserver +import android.view.animation.AnticipateInterpolator +import androidx.activity.viewModels +import androidx.core.animation.doOnEnd +import androidx.core.net.toUri +import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen +import androidx.core.view.isVisible +import androidx.core.view.marginBottom +import androidx.core.view.updateLayoutParams +import androidx.navigation.NavController +import androidx.navigation.fragment.NavHostFragment +import androidx.navigation.ui.setupWithNavController +import com.android.mediproject.core.common.uiutil.LayoutController +import com.android.mediproject.core.common.uiutil.SystemBarStyler +import com.android.mediproject.core.network.InternetNetworkListener +import com.android.mediproject.core.ui.WindowViewModel +import com.android.mediproject.core.ui.base.BaseActivity +import com.android.mediproject.databinding.ActivityMainBinding +import dagger.hilt.android.AndroidEntryPoint +import repeatOnStarted +import javax.inject.Inject + +@AndroidEntryPoint +class MainActivity : BaseActivity(ActivityMainBinding::inflate), LayoutController { + + private val windowViewModel: WindowViewModel by viewModels() + + @Inject lateinit var systemBarStyler: SystemBarStyler + + @Inject lateinit var internetNetworkListener: InternetNetworkListener + + companion object { + const val VISIBLE = 0 + const val INVISIBLE = 1 + } + + override val activityViewModel: MainViewModel by viewModels() + private lateinit var navController: NavController + + override fun afterBinding() { + systemBarStyler.init(this, window, this::changeFragmentContainerHeight) + systemBarStyler.setStyle(SystemBarStyler.StatusBarColor.WHITE, SystemBarStyler.NavigationBarColor.BLACK) + + internetNetworkListener.activityLifeCycle = this.lifecycle + internetNetworkListener.networkStateCallback = InternetNetworkListener.NetworkStateCallback { isConnected -> + if (!isConnected) { + NetworkStateDialogFragment().show(supportFragmentManager, NetworkStateDialogFragment::class.java.name) + } + } + + //SDK 31이상일 때 Splash가 소소하게 사라지는 이펙트 입니다. 추후 걸리적거리면 삭제해도 됌 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + splashScreen.setOnExitAnimationListener { splashScreenView -> + ObjectAnimator.ofFloat(splashScreenView, View.ALPHA, 1f, 0f).run { + interpolator = AnticipateInterpolator() + duration = 1000L + doOnEnd { splashScreenView.remove() } + start() + } + } + } + + binding.apply { + val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragmentContainerView) as NavHostFragment + navController = navHostFragment.navController + + bottomNav.apply { + itemIconTintList = null + setupWithNavController(navController) + background = null + menu.getItem(2).isEnabled = false + } + R.array.hideBottomNavDestinationIds + setDestinationListener() + + viewModel = activityViewModel.apply { + repeatOnStarted { eventFlow.collect { handleEvent(it) } } + } + + root.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener { + override fun onPreDraw(): Boolean { + if (bottomNav.marginBottom == 0) { + systemBarStyler.changeMode(emptyList(), + listOf(SystemBarStyler.ChangeView(bottomNav, SystemBarStyler.SpacingType.MARGIN))) + return true + } + + if (bottomAppBar.height > 0 && bottomNav.marginBottom == systemBarStyler.navigationBarHeightPx) { + root.viewTreeObserver.removeOnPreDrawListener(this) + windowViewModel.bottomNavHeightInPx = bottomAppBar.height + this@MainActivity.changeFragmentContainerHeight(false) + } + return true + } + }) + + DevDialogFragment().show(supportFragmentManager, DevDialogFragment::class.java.name) + } + } + + + override fun setSplash() { + installSplashScreen() + } + + + private val hideBottomNavDestinationIds: Set by lazy { + resources.obtainTypedArray(R.array.hideBottomNavDestinationIds).let { typedArray -> + val destinationIds = mutableSetOf() + for (i in 0 until typedArray.length()) { + destinationIds.add(typedArray.getResourceId(i, 0)) + } + typedArray.recycle() + destinationIds + } + } + + + /** + * <2번째 방법> + * + * 1번째 방법은 nav_graph.xml 에서 destination 에서 argument 를 추가해주고 + * + * 2번째 방법은 navController.addOnDestinationChangedListener 에서 + * + * destination.id 를 통해 destination 을 구분하고 + * + * argument 를 통해 bottomNav 를 숨길지 말지 결정한다. + */ + private fun setDestinationListener() = navController.addOnDestinationChangedListener { _, destination, arg -> + log(arg.toString()) + bottomVisible(destination.id !in hideBottomNavDestinationIds) + } + + private fun bottomVisible(visible: Boolean) { + log(visible.toString()) + binding.cameraFAB.isVisible = visible + binding.bottomAppBar.isVisible = visible + this.changeFragmentContainerHeight(!visible) + } + + fun handleEvent(event: MainViewModel.MainEvent) = when (event) { + is MainViewModel.MainEvent.AICamera -> navController.navigate("medilens://main/camera_nav".toUri()) + } + + /** + * fragmentContainerView의 높이를 조정해주는 함수 + * + * CoordinatorLayout으로 인해 fragmentContainerView의 높이가 앱 전체의 높이로 되어있는데 + * isFull true를 전달받으면 fragmentContainerView의 bottom좌표가 bottomNav의 top좌표가 되고, + * isFull false를 전달받으면 fragmentContainerView의 bottom좌표가 앱 전체의 bottom좌표가 된다. + * + * @param isFull true: 전체화면, false: 전체화면X + */ + override fun changeFragmentContainerHeight(isFull: Boolean) { + if (windowViewModel.bottomNavHeight.value > 0) { + binding.fragmentContainerView.updateLayoutParams { + bottomMargin = if (!isFull) (windowViewModel.bottomNavHeight.value) else 0 + } + } + } + +} \ No newline at end of file diff --git a/android/app/src/main/java/com/android/mediproject/MainViewModel.kt b/android/app/src/main/java/com/android/mediproject/MainViewModel.kt new file mode 100644 index 000000000..da470c158 --- /dev/null +++ b/android/app/src/main/java/com/android/mediproject/MainViewModel.kt @@ -0,0 +1,31 @@ +package com.android.mediproject + +import MutableEventFlow +import androidx.lifecycle.viewModelScope +import asEventFlow +import com.android.mediproject.core.domain.sign.GetAccountStateUseCase +import com.android.mediproject.core.ui.base.BaseViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class MainViewModel @Inject constructor( + private val getAccountStateUseCase: GetAccountStateUseCase, +) : BaseViewModel() { + private val _eventFlow = MutableEventFlow() + val eventFlow = _eventFlow.asEventFlow() + + fun event(event: MainEvent) = viewModelScope.launch { _eventFlow.emit(event) } + fun aicamera() = event(MainEvent.AICamera()) + + init { + viewModelScope.launch { + getAccountStateUseCase.loadAccountState() + } + } + + sealed class MainEvent { + data class AICamera(val unit: Unit? = null) : MainEvent() + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/android/mediproject/MediApplication.kt b/android/app/src/main/java/com/android/mediproject/MediApplication.kt new file mode 100644 index 000000000..ed4f1d147 --- /dev/null +++ b/android/app/src/main/java/com/android/mediproject/MediApplication.kt @@ -0,0 +1,10 @@ +package com.android.mediproject + +import android.app.Application +import dagger.hilt.android.HiltAndroidApp + + +@HiltAndroidApp +class MediApplication : Application() { + +} \ No newline at end of file diff --git a/android/app/src/main/java/com/android/mediproject/NetworkStateDialogFragment.kt b/android/app/src/main/java/com/android/mediproject/NetworkStateDialogFragment.kt new file mode 100644 index 000000000..95bc1993d --- /dev/null +++ b/android/app/src/main/java/com/android/mediproject/NetworkStateDialogFragment.kt @@ -0,0 +1,31 @@ +package com.android.mediproject + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.android.mediproject.databinding.ViewNetworkStateBinding +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class NetworkStateDialogFragment : BottomSheetDialogFragment() { + + private var _binding: ViewNetworkStateBinding? = null + + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View = ViewNetworkStateBinding.inflate(layoutInflater, container, false).also { + _binding = it + }.root + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + binding.okButton.setOnClickListener { + dismiss() + requireActivity().finish() + } + } +} \ No newline at end of file diff --git a/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 000000000..2b068d114 --- /dev/null +++ b/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/camera.xml b/android/app/src/main/res/drawable/camera.xml new file mode 100644 index 000000000..946bd15a0 --- /dev/null +++ b/android/app/src/main/res/drawable/camera.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/home.xml b/android/app/src/main/res/drawable/home.xml new file mode 100644 index 000000000..34e0f6ff8 --- /dev/null +++ b/android/app/src/main/res/drawable/home.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/android/app/src/main/res/drawable/home_blue.xml b/android/app/src/main/res/drawable/home_blue.xml new file mode 100644 index 000000000..bf8a09ddf --- /dev/null +++ b/android/app/src/main/res/drawable/home_blue.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/android/app/src/main/res/drawable/ic_launcher_background.xml b/android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000..07d5da9cb --- /dev/null +++ b/android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/drawable/menu_selector_home_color.xml b/android/app/src/main/res/drawable/menu_selector_home_color.xml new file mode 100644 index 000000000..1f465194e --- /dev/null +++ b/android/app/src/main/res/drawable/menu_selector_home_color.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/menu_selector_mypage_color.xml b/android/app/src/main/res/drawable/menu_selector_mypage_color.xml new file mode 100644 index 000000000..a067f8ed0 --- /dev/null +++ b/android/app/src/main/res/drawable/menu_selector_mypage_color.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/menu_selector_news_color.xml b/android/app/src/main/res/drawable/menu_selector_news_color.xml new file mode 100644 index 000000000..22a4ad7bb --- /dev/null +++ b/android/app/src/main/res/drawable/menu_selector_news_color.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/menu_selector_setting_color.xml b/android/app/src/main/res/drawable/menu_selector_setting_color.xml new file mode 100644 index 000000000..2ad7c3ef2 --- /dev/null +++ b/android/app/src/main/res/drawable/menu_selector_setting_color.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/menu_selector_text_color.xml b/android/app/src/main/res/drawable/menu_selector_text_color.xml new file mode 100644 index 000000000..088dc4534 --- /dev/null +++ b/android/app/src/main/res/drawable/menu_selector_text_color.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/mypage.xml b/android/app/src/main/res/drawable/mypage.xml new file mode 100644 index 000000000..4eacc80b5 --- /dev/null +++ b/android/app/src/main/res/drawable/mypage.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/mypage_blue.xml b/android/app/src/main/res/drawable/mypage_blue.xml new file mode 100644 index 000000000..2437b1da5 --- /dev/null +++ b/android/app/src/main/res/drawable/mypage_blue.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/news.xml b/android/app/src/main/res/drawable/news.xml new file mode 100644 index 000000000..4a2bf5a73 --- /dev/null +++ b/android/app/src/main/res/drawable/news.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/news_blue.xml b/android/app/src/main/res/drawable/news_blue.xml new file mode 100644 index 000000000..fcb1bd17a --- /dev/null +++ b/android/app/src/main/res/drawable/news_blue.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/setting.xml b/android/app/src/main/res/drawable/setting.xml new file mode 100644 index 000000000..8f8be8740 --- /dev/null +++ b/android/app/src/main/res/drawable/setting.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/setting_blue.xml b/android/app/src/main/res/drawable/setting_blue.xml new file mode 100644 index 000000000..92ba14f96 --- /dev/null +++ b/android/app/src/main/res/drawable/setting_blue.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/layout/activity_main.xml b/android/app/src/main/res/layout/activity_main.xml new file mode 100644 index 000000000..feea95b55 --- /dev/null +++ b/android/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/view_dev_state.xml b/android/app/src/main/res/layout/view_dev_state.xml new file mode 100644 index 000000000..60abd0a6a --- /dev/null +++ b/android/app/src/main/res/layout/view_dev_state.xml @@ -0,0 +1,31 @@ + + + + + +