From ceda88bf5e580387b1db6e34cd9c46f383250f1b Mon Sep 17 00:00:00 2001 From: bhindor <82446373+bhindor@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:18:52 +0900 Subject: [PATCH 01/21] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20::=20set=20main?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kr/ac/anu/mumu/presentation/main/MainActivity.kt | 2 ++ .../kr/ac/anu/mumu/presentation/main/MainViewModel.kt | 9 +++++++++ 2 files changed, 11 insertions(+) create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/main/MainViewModel.kt diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/MainActivity.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/MainActivity.kt index 7901e6c..fdc3286 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/main/MainActivity.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/MainActivity.kt @@ -5,8 +5,10 @@ import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat +import dagger.hilt.android.AndroidEntryPoint import kr.ac.anu.mumu.R +@AndroidEntryPoint class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/MainViewModel.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/MainViewModel.kt new file mode 100644 index 0000000..951029d --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/MainViewModel.kt @@ -0,0 +1,9 @@ +package kr.ac.anu.mumu.presentation.main + +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class MainViewModel @Inject constructor() : ViewModel() { +} \ No newline at end of file From 937e8853b621148cfe76f288b36536f6971ea9c0 Mon Sep 17 00:00:00 2001 From: bhindor <82446373+bhindor@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:19:21 +0900 Subject: [PATCH 02/21] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20::=20set=20logo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 111c250..5ded846 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -9,9 +9,9 @@ android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" - android:icon="@mipmap/ic_launcher" + android:icon="@drawable/mumu_logo" android:label="@string/app_name" - android:roundIcon="@mipmap/ic_launcher_round" + android:roundIcon="@drawable/mumu_logo" android:supportsRtl="true" android:theme="@style/Theme.Mumu" android:usesCleartextTraffic="true" From 1b7c567076b208d4d2fd6f2f00292c7814e49593 Mon Sep 17 00:00:00 2001 From: bhindor <82446373+bhindor@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:19:29 +0900 Subject: [PATCH 03/21] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20::=20add=20homeFragm?= =?UTF-8?q?ent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/kr/ac/anu/mumu/presentation/main/HomeFragment.kt | 6 ++++++ app/src/main/res/layout/fragment_home.xml | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/main/HomeFragment.kt create mode 100644 app/src/main/res/layout/fragment_home.xml diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/HomeFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HomeFragment.kt new file mode 100644 index 0000000..711f616 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HomeFragment.kt @@ -0,0 +1,6 @@ +package kr.ac.anu.mumu.presentation.main + +import androidx.fragment.app.Fragment + +class HomeFragment: Fragment() { +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml new file mode 100644 index 0000000..77d9ef6 --- /dev/null +++ b/app/src/main/res/layout/fragment_home.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file From 3e08c9dbddda2274634e90ce9253f377fe3b8ed8 Mon Sep 17 00:00:00 2001 From: bhindor <82446373+bhindor@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:19:50 +0900 Subject: [PATCH 04/21] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20::=20myFragment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/kr/ac/anu/mumu/presentation/main/MyFragment.kt | 6 ++++++ app/src/main/res/layout/fragment_my.xml | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/main/MyFragment.kt create mode 100644 app/src/main/res/layout/fragment_my.xml diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/MyFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/MyFragment.kt new file mode 100644 index 0000000..23d97b1 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/MyFragment.kt @@ -0,0 +1,6 @@ +package kr.ac.anu.mumu.presentation.main + +import androidx.fragment.app.Fragment + +class MyFragment : Fragment() { +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_my.xml b/app/src/main/res/layout/fragment_my.xml new file mode 100644 index 0000000..77d9ef6 --- /dev/null +++ b/app/src/main/res/layout/fragment_my.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file From 9114402c04d79c2df4eb1fad3c45ca4ca8062976 Mon Sep 17 00:00:00 2001 From: bhindor <82446373+bhindor@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:20:02 +0900 Subject: [PATCH 05/21] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20::=20add=20hospital?= =?UTF-8?q?=5Ffragment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kr/ac/anu/mumu/presentation/main/HospitalFragment.kt | 6 ++++++ app/src/main/res/layout/fragment_hospital.xml | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/main/HospitalFragment.kt create mode 100644 app/src/main/res/layout/fragment_hospital.xml diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/HospitalFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HospitalFragment.kt new file mode 100644 index 0000000..f32ea7c --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HospitalFragment.kt @@ -0,0 +1,6 @@ +package kr.ac.anu.mumu.presentation.main + +import androidx.fragment.app.Fragment + +class HospitalFragment : Fragment() { +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_hospital.xml b/app/src/main/res/layout/fragment_hospital.xml new file mode 100644 index 0000000..77d9ef6 --- /dev/null +++ b/app/src/main/res/layout/fragment_hospital.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file From d7498bc83695ca767db1864ae8318911eba67ca4 Mon Sep 17 00:00:00 2001 From: bhindor <82446373+bhindor@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:20:09 +0900 Subject: [PATCH 06/21] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20::=20add=20menu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/drawable/ic_home.xml | 13 +++++++++++++ app/src/main/res/drawable/ic_hospital.xml | 9 +++++++++ app/src/main/res/drawable/ic_user.xml | 9 +++++++++ app/src/main/res/menu/main_menu.xml | 17 +++++++++++++++++ 4 files changed, 48 insertions(+) create mode 100644 app/src/main/res/drawable/ic_home.xml create mode 100644 app/src/main/res/drawable/ic_hospital.xml create mode 100644 app/src/main/res/drawable/ic_user.xml create mode 100644 app/src/main/res/menu/main_menu.xml 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..3ac74ad --- /dev/null +++ b/app/src/main/res/drawable/ic_home.xml @@ -0,0 +1,13 @@ + + + diff --git a/app/src/main/res/drawable/ic_hospital.xml b/app/src/main/res/drawable/ic_hospital.xml new file mode 100644 index 0000000..d1bd8ec --- /dev/null +++ b/app/src/main/res/drawable/ic_hospital.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_user.xml b/app/src/main/res/drawable/ic_user.xml new file mode 100644 index 0000000..492d428 --- /dev/null +++ b/app/src/main/res/drawable/ic_user.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/menu/main_menu.xml b/app/src/main/res/menu/main_menu.xml new file mode 100644 index 0000000..2fb9d5c --- /dev/null +++ b/app/src/main/res/menu/main_menu.xml @@ -0,0 +1,17 @@ + + + + + + + + \ No newline at end of file From 942ccc2a7a002562a798336b107e1b4b41583f3a Mon Sep 17 00:00:00 2001 From: bhindor <82446373+bhindor@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:20:17 +0900 Subject: [PATCH 07/21] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20::=20bottom=20nav=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/res/color/selector_bottom_nav.xml | 6 +++++ .../main/res/navigation/nav_graph_main.xml | 23 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 app/src/main/res/color/selector_bottom_nav.xml create mode 100644 app/src/main/res/navigation/nav_graph_main.xml diff --git a/app/src/main/res/color/selector_bottom_nav.xml b/app/src/main/res/color/selector_bottom_nav.xml new file mode 100644 index 0000000..0bab02d --- /dev/null +++ b/app/src/main/res/color/selector_bottom_nav.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_graph_main.xml b/app/src/main/res/navigation/nav_graph_main.xml new file mode 100644 index 0000000..43dbe2c --- /dev/null +++ b/app/src/main/res/navigation/nav_graph_main.xml @@ -0,0 +1,23 @@ + + + + + + + + + + \ No newline at end of file From 9442973daae29fa65d3dcec890239f5149f3af54 Mon Sep 17 00:00:00 2001 From: bhindor <82446373+bhindor@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:20:57 +0900 Subject: [PATCH 08/21] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20::=20mainActivity=20?= =?UTF-8?q?=EB=B7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/layout/activity_main.xml | 62 +++++++++++++++++++++-- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index a75041f..7af65b3 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -5,15 +5,69 @@ android:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" + android:background="@color/white" tools:context=".presentation.main.MainActivity"> - + + + + + + + + + + + app:menu="@menu/main_menu" + app:paddingBottomSystemWindowInsets="false" /> \ No newline at end of file From f80f15eeff863063a0fd7b6c5201a3ead1addfdf Mon Sep 17 00:00:00 2001 From: bhindor <82446373+bhindor@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:21:05 +0900 Subject: [PATCH 09/21] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20::=20nav=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mumu/presentation/main/HomeFragment.kt | 26 +++++++++++++++++++ .../presentation/main/HospitalFragment.kt | 24 +++++++++++++++++ .../mumu/presentation/main/MainActivity.kt | 20 +++++++++++++- .../anu/mumu/presentation/main/MyFragment.kt | 24 +++++++++++++++++ 4 files changed, 93 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/HomeFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HomeFragment.kt index 711f616..a0b8fc9 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/main/HomeFragment.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HomeFragment.kt @@ -1,6 +1,32 @@ package kr.ac.anu.mumu.presentation.main +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup import androidx.fragment.app.Fragment +import dagger.hilt.android.AndroidEntryPoint +import kr.ac.anu.mumu.databinding.FragmentHomeBinding +@AndroidEntryPoint class HomeFragment: Fragment() { + + private var _binding: FragmentHomeBinding? = null + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentHomeBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + } \ No newline at end of file diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/HospitalFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HospitalFragment.kt index f32ea7c..410521b 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/main/HospitalFragment.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HospitalFragment.kt @@ -1,6 +1,30 @@ package kr.ac.anu.mumu.presentation.main +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup import androidx.fragment.app.Fragment +import dagger.hilt.android.AndroidEntryPoint +import kr.ac.anu.mumu.databinding.FragmentHospitalBinding +@AndroidEntryPoint class HospitalFragment : Fragment() { + + private var _binding: FragmentHospitalBinding? = null + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentHospitalBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } } \ No newline at end of file diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/MainActivity.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/MainActivity.kt index fdc3286..7255dd5 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/main/MainActivity.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/MainActivity.kt @@ -5,19 +5,37 @@ import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat +import androidx.core.view.updatePadding +import androidx.navigation.fragment.NavHostFragment +import androidx.navigation.ui.setupWithNavController import dagger.hilt.android.AndroidEntryPoint import kr.ac.anu.mumu.R +import kr.ac.anu.mumu.databinding.ActivityMainBinding @AndroidEntryPoint class MainActivity : AppCompatActivity() { + + private lateinit var binding: ActivityMainBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() - setContentView(R.layout.activity_main) + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) insets } + + val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment_main) as NavHostFragment + val navController = navHostFragment.navController + + binding.bottomNav.setupWithNavController(navController) + + ViewCompat.setOnApplyWindowInsetsListener(binding.bottomNav) { view, windowInsets -> + view.updatePadding(bottom = 0) + windowInsets + } } } diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/MyFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/MyFragment.kt index 23d97b1..4ebf0c1 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/main/MyFragment.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/MyFragment.kt @@ -1,6 +1,30 @@ package kr.ac.anu.mumu.presentation.main +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup import androidx.fragment.app.Fragment +import dagger.hilt.android.AndroidEntryPoint +import kr.ac.anu.mumu.databinding.FragmentMyBinding +@AndroidEntryPoint class MyFragment : Fragment() { + + private var _binding: FragmentMyBinding? = null + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentMyBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } } \ No newline at end of file From a0487973ab3b185b647bb74920dde441f7951aae Mon Sep 17 00:00:00 2001 From: bhindor <82446373+bhindor@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:21:12 +0900 Subject: [PATCH 10/21] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20::=20home=20?= =?UTF-8?q?=EB=B7=B0=20=EC=A4=91=EA=B0=84=20=EC=A7=80=EC=A0=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../anu/mumu/presentation/main/MyFragment.kt | 2 +- app/src/main/res/drawable/bg_pill_mint.xml | 13 ++ app/src/main/res/drawable/dog.jpg | Bin 0 -> 200815 bytes app/src/main/res/drawable/ic_diary.png | Bin 0 -> 290 bytes app/src/main/res/drawable/ic_foot.png | Bin 0 -> 602 bytes app/src/main/res/drawable/ic_history.png | Bin 0 -> 773 bytes app/src/main/res/drawable/ic_man.png | Bin 0 -> 477 bytes app/src/main/res/drawable/ic_woman.png | Bin 0 -> 560 bytes app/src/main/res/layout/fragment_home.xml | 190 +++++++++++++++++- app/src/main/res/values/themes.xml | 4 + 10 files changed, 207 insertions(+), 2 deletions(-) create mode 100644 app/src/main/res/drawable/bg_pill_mint.xml create mode 100644 app/src/main/res/drawable/dog.jpg create mode 100644 app/src/main/res/drawable/ic_diary.png create mode 100644 app/src/main/res/drawable/ic_foot.png create mode 100644 app/src/main/res/drawable/ic_history.png create mode 100644 app/src/main/res/drawable/ic_man.png create mode 100644 app/src/main/res/drawable/ic_woman.png diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/MyFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/MyFragment.kt index 4ebf0c1..1d3484d 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/main/MyFragment.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/MyFragment.kt @@ -10,7 +10,7 @@ import kr.ac.anu.mumu.databinding.FragmentMyBinding @AndroidEntryPoint class MyFragment : Fragment() { - + private var _binding: FragmentMyBinding? = null private val binding get() = _binding!! diff --git a/app/src/main/res/drawable/bg_pill_mint.xml b/app/src/main/res/drawable/bg_pill_mint.xml new file mode 100644 index 0000000..6f6ef23 --- /dev/null +++ b/app/src/main/res/drawable/bg_pill_mint.xml @@ -0,0 +1,13 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dog.jpg b/app/src/main/res/drawable/dog.jpg new file mode 100644 index 0000000000000000000000000000000000000000..455c843cd5abe06044f0064bb4eb1a85e9c8cc3f GIT binary patch literal 200815 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
    0vzbM(`A?-g29nHgfDuoNBHW(t9vk&sDD9rXo| zEqU7MlYyzvI1>8^Q-A;}*d%n<%kommR=|shSo>j0rd1no6t*_sbL**>k3ywWM-gk}wI9RUqzibtP!$pUhdSE+DSxBCyIpA0QFJHbM_A`VB$h zQ^!|WXf)CJE3(;=IHQPie%qBip3-9|pyQC#o^*MCAx4ySB^JNVD|e)VBgQ)r)MFGS zijAZ!TaVLFy)v_G*Gi;&2$s-J4c>Zgh}#2hnr|N7ZM^4`w2GoCN~`01R4fS*%vvzQSjS8p<5g=Gmi?JxNc@Fk zMk!#Hz{!wCNF0}rKV3&{d{+xIvLr1snBtAe3ckc(5H@l2I*Z9z@fCcP$mDqI!5WpZ zO2lc+riF$3eOq@w$^vZ4>@rOk5#3!v6prOKb5z5#;N6YO{#!OJzrnw?b`*WrUT2(20%# zBQ4iZQNJ@-46I?dd)qQR%+kDElMH0b{)#pe^E7}qAV8D#cFiQy7hE6NsD^1(8lR8oO)q4=-Zd)Pk%v0hy8+LtKJ6yPO$H%NpbYH^9~0 zhmw?5%yyk&LdYIGWk_B{`L;_9&(}*2gsNS@*l2kF0L7>;&Z{+VAAZC|K0i~*tw^ddIgcFiwsj>7eok9*;T~#~a#p9t zDyafvk2ID=83dj3dh7g;_|x$@XW{&F@_XF7oxbPa$3E=m^y#XP7_)NP&i1UlA-g3d z*jj{M)&1@Q^sGKzc#H-2{|Q>YEgg+ z#Bzi&IL6r5!tfuD*SceDLoo#!yla5d!7CBEH=y4-lC&3XLF3(777*;LLy*19xl_r3 z>!@nUTGwQDh_y6|C6*#faVpsMkNfm)dBV}9Rc4Y9(HPPfU8ERnJUsqG z$u}cL+yxtoI`EP!Kn_?|+yV&FRPmLj@sRd}C*#(`JY2Z|{5`njcgLosSzO31OxGt zfnZlSR356p{{Xh5uSdnfQD@+h&X5P5BCf9PTNn(AJ=^0;479BID@e)~-qFIC``oa6 z3;<56)2;axxAIn4$t6=PtzHy`bHuZIG0#@~bly^(lS)`sVq_Tz>xmn<2?_&mojuz% zYstV!i{z4ZNaO_Luq0ia$?5dhjqLb?<0F~uDQINw$uW>^DVX76SN{NqP8DM{qInFl z6j5T^GN=%hP^~KGukp}ZraBd@R+D*2ifWL8(nmB&AMO#)+BqNg(+Moql4hPXNgdKC zCP?yHTM#*3?21R+M!c0PF@KSj87sQ1%Pn~-Z~?1ViCFtwjFF6L8`VD(sFPTJ-8!B_ z$J2_uH6cZMlR_AUTWqJOJc-V#Pgn7;7SYvMro5$%TQV#~f*?r8y;QE)&ZDQ~JVbsn z>1ke8@>L=pDa$DfUJ0cp$I8Yr%#rldz26p#J({z^O=~LA6jdz|5uxF^>ACu9>aUG~ zJhh+75~TK^jQ5wu*$j){;4#4ln| zNd(b(I#Z>2k*mkWGbljiQa}%>#=NDE$o$2`@@)Wiy zqesknFO3bkS@AGEe zHv64hh~nrsQ|NTiKauj2giOga{zgdVk%r~tl)8+zc%RT}S*w0G;OtpgoBn6d0q00o zQfAhYZdJ$ zIBzOez2qjA46Ncxal^-f8v~qbI`dVEPaOnnJPCO_)@s;7BMBVkOp}yJ4kRa$#x~T* zthW4QnJ+3Z4+dDO83Pq#+c?<$HSwdL=hm=|J$x^9VTp$+d4|Uh*xZk&O(TfovSF}W zxm>YAh}=-ds<{W-zCg#Wh;q#fy7GYJU~I+yoYW16`|2y+F2fi}?@EY9OhgPTfJ)#I zj=9vP-J3L@AVRSrSckjqkr$z0I`6K~ka+oG9r0i=Uyx%!H(*%h$lIn)xO0iwgSUOS ziCBd%#rIe1wnnA3B(Z#7ak@DKI*H6DpU|g zH9v{`Ps_&()-~Yr5yv_>j>%@_898Ce6lyBoQ_IaX{zc(7YuZC%w5bZPX%;mu2={dL z)5|Q1_UDJV(Ptx$!@CF{V#K5nrx?^-=oxCo9Fdk~JZE`=x=)-PzNfBrS!?+@NRmlS zy1cdz60j*CVX$T+j>lH~Z{z+F%n>D{I#`k;TuA~DIlRsmKFlMce_nNK%Km@lesmTU zC-`+HMytd6V}3bY6R{XNj)&q@slnr*12HT~S|5(1-O1cT8>n5+sXa5P+6z*;%_nvW zba`+?7|S>aF}6RRr17vU)n}9zNUPQ`#>oU=GfgNS`!D+Hrg3;JyIf+{% z4xEU_z-lYLV$|L~IMVDk0k4!jx6e5`U^HLvt1V{TJCahUCR)7FWtgMz?ctk|Vn;93 zYFK<Zw@Qn;^O1vyJEIj~0+2it><^;^r` zuJycFimb89SpMNk=)j_XMh*l{A(jYu5ZXD4kypN~o9e9ZC9Bun7@ z6&YW{#3Lb5@A>8iq*9CyVGc*rQP=#d&v<%vZirSN4fy;=$$6L;Jfc}Vm6DZfvCbbL z5seykt3wUR6=DAXAr;u8e-R#PDflOPSqwtobh?w9eCyO-;UCDCOKA1b|YiuCR|}wFKIi2uZ+Kt znT=`dJP@~ZnAu@S?917a00Vl=Ca4aRLcBzU6}LpBY&=@sWE9~HSMh14|CZf zMklU0-~;MaK=jn&tqU`$Ej_8DhbdkuH&CZI%7dP|{CD!-%lw~*{2#{o*izjJS8W#j zhTn@0tpZ$8IAk zFglHRi#}Wans^AVP=$^&r+ee{=X{{Yrs z`blPm+2XF=2kQ1hBM zW=y&sI8H%0k<<`%AC#j7KRqqShSo5+jZB%zyAPDEL9S!_H9}G zr^kPfu*g9`Co!~)8OHwrZUGv!&-iEKKaMS{F{95v!@L&ctOPke;PLv@I>~anM)Az zGJ(kTCsVg@U1ka_!194&zr1ANV5)(!{SLcyR$B40BRy)Z8~gZ#G%LS&BZ)$jO#So!NXFjoNuKyV_H5P@dw00i3yc3#@up1T4`p6 z5wu5Qchr@r#c#I+1x4#onAFD^5`-t;=X7V;KzS zKHxKr^;gLLN93*fYjMZ$cAluFWZpE=OuaokWQ{sggR8CK+Sj z-TwfKN?@YRTeOfrdO3g+*yAM9GDugD*ymMa^7i~?q@gFr_%+!evXhK(oeLatgn~Bu z>MFi7#7fG+f?B&OK6_)JS^JF9wrnx!Wl!@RtKD#)6P{FjyT5Wr{tbj@_!*s&o|>?>c<6iF@Q^$ z*Mgn1wxgl>7m@KkT6d4VVuy~LRPeT*KiaPYMI)QntM?=af%cLC^wbl6QTYdo2~l8r zUyXi0NoYq^l0GoP&>iKptB>3sy>$_(9s0gPz&2(R*=XlxELKq`A_f5&G$~R)Lc(xEFum{?SNYv@*ZdNZ_hs^ZzC;;UJn~AFxisPm^6Y))ckaDO%!Ps zSu((bx!2`0*NgtAen;gzjFx;aRH6z z`50rCc!Z2>S+ngq{yJ*3?XPaj0csfnv~1CmVwy6gOPJUXYivm0Z5aOmBeCRvE4|`t zRQDQ=&a@sNu02*@G0GPZbN<9$^8jxYM1{{T*ZCh&X(UnHNN*z+D*C@j?zl9QkFhKSy2!Sy@Z)S z7{*5WspR}j>uIC~C4r_#lvv3o7mTu&4BKzFrlf$^v*Y~TACp#iW>k*6v$)I5%ef8| z;Q%L)-$@m8idBYVB1t-yoVzJ2?g0A$`+kE+Jfu*Tn1p*UDUIv`r;K+QwpNU7pIv;) z^1Ll9@o_k3H8n0A@8~mLnZC5?G#o;f+!y;A{I7}c3^80U8swHe6zNv#Lvq!aM+??Oa;iw^10pHd zG7bL#hLs_B3c>#XAp=a1!9vApBjjrPGbD~VXMTrmS6V(eSicO9QU$tag1^RWmh8ea zC5#eruoxf1Qp;DtTbRPK2}>lE>7i^ytpsg_G4?t)snu9-wBB>exq&B%3!0Sy{lQve z823dQjOU@(j+TJ;Cq?J~z9jft%fk$pAqaNuq{{RvG8o%Oy4uiQFf@t8DWr@L; z0VLwcbIo~VVCPqSzvjMw$Vy^)uSw(nXov`~78OXxMm;f|MMfHyC9wYhy3bDd{!hraiuu+RtX8egD5Q3TLC*-U z?hvR7F`!|iFP5GUDO$U`q~z5R_P==ilvI%jJC9SHS(oykCF8y<%&i4l(KK?aG2&7{ zOKeHpeRN{{YM=Q#kgL`UCS2DDaNWLVimI^BuA++XkRA;nTQa;JAyLd=orzCy(f>DuZT|qDl_Q!okEq8i3};omf8rHt z`ENOL#rB`_KRC%>yuu>lqSZ4m_=?pT*}L*(c#L|DS^U5AFUzO={{Zs{m`C91i5_nk z<1edy-afEpjhQzK%(8JEHREVrvi?KzA2|a>`aC^8B$06xkH_{*W=cp@)SQc{8zxs4Iek)yse1o{$t}O0}Bma z=rsR~o@cjTQSyW_m=IuJa~2O&-dc!wCl40FC)*HKvfPs-2#08YOw zM|G!e8wP*JJoHQoJyBGatqKGnh8#{#oj)@16fJm}B^B)cL*j$AOVy;17(!PsJWG~bi|0MqX&Yr+0kMk>+CuY@$)&9FuvNyxZO*GVhq*6?^KEGq zUEpEy_JFFX3)_IUBZOltq~iqYuZ#S$`SIybxptBJd{qAcC)>s;+DA@N%@OvWsMCd2 z65Nb5QXy5yZ+yHL+@W0?t}}zzQQz^Ml(R)3kKufUhFFRRW@+PPS!6Q-_ve0tR^gI( zYTS;nCMjf2&?-P6InOP>U9^ZAG%zwvbBIwKs++S$=Og<1dV{I4=b(ZYgu`MHh}*PB z9?WXl<0^l|H_6nHS46SnYr^wIF?O+OoibK6lb0f7&+z){xk-D_Gy+KZ7|R5aobYKF z5Uht{JvDJwv&ZElQSszi)+Kah0k}uq21hv{Je}mc5Y+#~6w0%5w5tkSg&!qx*kDzMd+uq`j=kDV9F?l1ySr zq2wH^F!~TRP2!@|>sUrfXLx3<62UMgv#D|sC26yV0Bx$4JdEB;&UthZ$20>iW5yL_ zSu-(S4-}Z{2`4&LujfaOtWZNW8n)I8vCON_jIZ70+jHzu>gQJcFXCVQ>6xT3LF8G4 zvdb55fR&0Bkr=O1PN<(N<}7)*t+FV28d+kd=Ljks^&orhfrP*kNS?zC;&Si87T6iEmLxq>}L+IyC~hscrRNs7j-wIX3SRtjVa z+=6F5fa*5!f-3hc$i`XE-fO-XvS--bhW`LvNhF^#-^+r>8w%Xu;~M~@KMR6XT}?Dnzvp*B^(x`Q!Njh9jq~ZM=rL;C#a1?(lt-9# z3>iP|+fYsBd_5>F#a^?t&=St-$O*;cxSY!ZH?oaX57ZxX!O%n#&iy*;xUw{mIXt7DJ~F{89@@qT7~)CK5PEg`=}nm6ogkUs1p|p$0`|`= z4Zzs%{I!*qHSWT!y_}R*Y;i8z@F9rlp=a_5K5?PW%LBPQo!WP9X(V|$BkQ)Ij!W`O zBrOz>qgQiP01q7f+e9X20OTL9@YHrb3i%rm7indgWcaZ&wmG%|S7i;iU9@dUU?pi0 zqeZJc(ASP=#vzqMD9a*%7B?vGWFt!sRmgAI3N+9T|rC4#}yS$ z<$5h(Ghg_!yK{FyLo0U+5HX!SGv;i?B=UBz`I&ZGwA;283PMtJTIFh|+VvfACUgYF<(N&C2LYQPIryii4 zc`qw^^3|pwe;Y!~(iM3nun3MRqyXjeqykRh?sed;c?Yu7!{t-Rc?(81AjZ|Z2^%{h z?hZSs$;PVDuku=rZ#8b>v)BtX@?A!ZNo}%F%i42+oGAYQO$h4Vk~%eKlC1UPXrz)A zh;!zk6<|3&b{db&#pYvQA>ysYSI9*01pfdfGxPj|1hR zr*UZow#g7;Ub`2CnH}Jg18TiX*zB6>86nFy||?D==@{x_^8aTLld3wajyRWjh@_6c=TU`MNjvUcEi6Ed8J79IT^slrMF|o z$9AP4jpfBu75vQ!q(8GIK%}*Z&<58r6}&@^W@A35qKGSCth@0i0*9jau<7ifI{Jo+ADAir%Q7cmeoApf|ktX%7BuzC`pu;1O>+} zzNe;jAC~d=@#E~!SRwJw5n`n7!#&q3q|As8=dPxD5-pHs3*U{hI}MWU$2^Y@;l8g` zusdcNh$`A*dtJsLD<4L|>N@_KwH(kzBv7$Lh64DSMjU06+@V#N@ATKow=KG{K%m!# zyqOiyj4Gi<_sY&g5_SVlDNNJbOG)xx0JP6UU5mcfvBOoUk<)9a1VI$zkTO_5{KxmAj|gD?UaLjlmlYQ}O;n{XtQMhlYoZmMap?JcP*c zG_VE3p=@C7j)z_){G^q92amC3d{mZYV*W-%QcZHvNC9ky-v=X7_>O&_adWoA?!r0t}dS?9BP3(6%S zglesYIL2}Y4m2XYRxgaXjwKT*X{$)2$!zlbKxW1|gQu~25-=n@Paa!1 z+o9++Jvap$Ih(o8(*X(<9n!Hs4k%=At6&m+HG1SzPkw(WQ{q#g?FDKw!a~TC#=x1q z-_)al(4OTZax%eDV?g0b4j~y8m3@b)#&soDt0htw0cys3(O8En(km$9vAHJ%>Kih% zq}6}3CDM%<0Fn!Z;N`MTt-FDDu?i%8;m({k2^n~x$&Dr>`o88HXkt3(LWO8qaTg_Q zqpz%Qo%Ykg<)xd*#w1rY=x~qTpr}V;zWgxBKc=FcD%y=Hw{n$O`xC_vA@4S#nR{}f z0B0j3(^FXS!R2Hi#ZnpDw1O;`WodB7hWj10Q^Dh#t;I8yo3?XLb<@{ zsmQB5QrZW#Ad!`x!C}rv47>5+{KlrGZe^0FZZ9p?8ER5DdRhgF;KM6`a(4h@LR;73 zuV2Zs@~<4Ku9DykK#>j~8v_IAG)&Oco})~wPG1tSpDPRz%F;7fAK7#uVS(IaV^Jkp zZP(=@w~kmL_ZS(AOBJR?!{ndhHQK3Pvnrl5%q-$5Lxb&gB&y_WHB?DBp=Za=XIWD` zr!&dhc(WG8ii`~UYQt2KtXT2Yq>js2i@V+V0AUz`#z^auN4OjvM7Lm$Zz*0Tyn;3q z9jYXNm;|saOe2tW1dwzrts&WRTD)-O>_Isspm_iRiV@dXjbxJL%1ce=lyYvza5nOd z`NjuNO(Wi!MA6U`?c10G6o}1;VOByOy_iY%I1JpkCtnWye>=xX+p86YC4V5Qw84!& zJ=es6Tpw^G0=kl)kMi-^t!jAZuU6ZFu|o(suOMT@7fqWTPOf;X)V@8FDPoa<9d|(9 z-q|AqkU85)+KwiUO^{5g+V>n#YrI<9tv_rZ(VS3kV3zozWg!1;z#jch`Qq z+_nDzFD_xQaO*28g=rfDjAgf8hlv^APix9f_3B~LA0I*Z+)_bBkjxxKhR8eaN9&}g zNz$CkCA(qel_i$NbYQWp!ZPQ&!M4@Am(+OQ3vab3@>ZXW!dRTN@x*b-W1bcSZT9Q@ zoCsyT6zbDT#v@kLz~*+3pY)jWOLaKY$sd?nlQf9ce04J$O6XL&cg#n&@Vsbvt6&4G z6u%cq>$}M;21SkIvDz4DnGAeD5)6aXV^3qv&w3DtF}p(P7&|UY=MF|UCtfP$81Gr~ zo?71vjc3}B!wD$!F2Hb;AcA!od7JU2S9zDkQ?13PKORQzyU2u)j9X&gO?gK19z1v& zF3UAXAzEt=6O4+knPApWP&UccZyWe8;k7GEGD0Kr_c#QJ)!0iinORvTD!D$J=_LG? zSpNXXHHzyE>FjsBa>k*1lha7{7J}tKKGJn&$A`TXu+vAqAd)x=FO6tNy;4MB$T=jQ zqgMQ%nEbVDc^N8Kw+&w#FDZ;o7QU`1Ho2 zUnk{WGfu>H3;~+Ni4~X@!cCbM3lYvUkTIlZtq)}Os+8jinVF6efWaYUJq9}GUQRl* zH43mz3w9DEGY=mCG0Mu$07+z#fn(H#)n;fXKPnWCv97$ChIrSOVF)d?;$Up@)W8g zQm&~SD;eR5V@6z($&4Mh(TbHc@e3O~Q8!@9C5IRRj}h8nH|5moTQ=sJ?fGK(-xZ!< zJBChZ(UBYd#~TCG>ZM-X-Y?{|AR%{N(?T-9zEqBTR@a?_!bDq14mKBO5Nqx(MKau0R8*Z)h9(>Uj;AySHL$@+u

    C;kLM|p0DnkxbDslqZ)@m!peewq>=a1A4=LxQleB}1^>dvG-!+cJD} zW^)qq9nN3^S&Na%E++$Sxz*XBfQV#_R+-~w_9S`a@qlm{!Pht@m$Ian5;Jk=rFmfE zIr{1RWqbXq^I3{p7%b99#gwwba!y$XLDxEAedU>6PSi58km`<30Y=yoar);?W_hNy zYItl<8Z(IEqsX$WAz(q_1cjwXpMEOqXKa{ul{K*yiDJxU30vz1U53FRBl!a z9m^``kQnKWS>rXOlFYrvM@$tJhZT{>{{VF!?E30R+HcukxUz&|8#sLJpKq?7D$p;+ zz<0DaVZnl`0tV&!<2cYn@0W;yJd9tAszyi+k`E9FA581w#TAK#z{p1lQK}YBeWjTR z9Hdi{dLLa#w$*+(i-?Xmzj0y!@lhr+{JJ*!Kd|WS$X7f7jS%G+mB-zW(^B~8dR%5Sctwki?KMJmgCfjH|F7(5>|K(^rB<7ZN#R$`n%= zn~a8G$Yd2PS0jIJkV`yqz>3jWkxIPQod+hAguy&P+>Q3mgHyK86n&x>vW}h3Az5;B zBu#_6eKo>ccD!eqSt^>7Q?nz-ENi=@qC?u;U>pzQsNlM(U$(*}zS)*(!Vo)+Hal^Z z&M-InY8v${8!*QjIV?!w!}@Se0DScI)S|3!cv*#>)d?bJU)mv>C>g;CAsNDsxYUQo zQ$OQ;g^O<$I1*2q$gBd^nbZf3c{5<1oOH(EZyil#X`L(;kebjeGPf3x2P-c!3H9~R z@*X~fQF%K)G^E~B$;??}T(jY0-;$3_OXClbi^y77`_`kZ13|}uuUa&WX9)3tP6lzL z@rsf7UmI7PHBu*k-&vML56MW(l8u1=TB^QU-RjU@Ra+Kjc}0qi0&#_VaxexJB=I@M z`)Zwk#u`r}#nvyEViph=!!K;MI2MR+>y1MP<;e`zBzCP(vnX(U2`iOka`^S z)hNOb#=I?9#SsIeFOjnfVI{g;s=Q#G*QPV5Xn1Q4VFZ1(@~2S)^s; zm?LsG#-~djPFj*&W9^Dk(Ij{;gPfHEJ$-bi#mODyjzwtMqb(!xY`ZBS`<75Z)K|R2 zRIL!Swo-p8prX5bNRbzbWhlpOx8GDDffhz!dG?W&A0T_->O?21{RX8~le>vi5i4d$ z&i?K4O5^?YKhKZ04qyv_9heX9Xa4{YIR09i)mrg9q7p(A$33;!g&=^y5B1a%I>!<) z79Ks=%B2E4NA2OpOq}ohH8;l`5p(S0%OEfuM&N;sO!kzT(!n3bOds2`C@i_hMcCxy zR;O64PZUE97=`$>?bSiS1wUNq$s|$1LSWNG@?bj`+0-z`>yDa|SQUa2i`23+NQd4I z1_E*VXgt!zJa9Uxgm9IjXFa&)V9D+Q+XQ~Pl1tZXJjHm-Sn(kw9D;Vxalr&{uNwu0 zZ-8HzRc7KMPqfHWfjs{JU51-9X@o9PlAcV!DLfRr5(4d>p1QQKc>YTt87{PK7ZDO* zzijf{{dH61`1Bt-V$CNdc8a^GXpDw1+({d8^g0w!0bIWLKzu~^5KNcxN=Q0ceyAs46zR-8od8dxD#Tcw&AQqNY zi#U)dIU||JuASyZYK)b;lR5`MGhtZEf-w$HxD0QNR#@73VEIh;UM6pg+ju|;Tmywb zt&n=_#r$gV*s8|CThc#8O1C=byf%Ymu>DM~$OJC;1tRPds zEU_Q~9z%c*BRzDIMI~!7EH-Z>O)oI9G3?l;vK(@m(RRrFF{;+;(vp7_`ObinB={5 zV6IAM-^daH#+j+N$7hBYo+QGmOB$4RP*3%<4Tnr=ppq)`A#LTb!YMcD#lT`n^aD~v zA_lC6KaQ{5?W>FzE6I*z$lFkf5#ogKw9?2yFFJp2xC%?GV;@cPt2U9vXogF6)OV{y z$B3D+jwL|I7&+Bw{IyztAgjv0QP+XFPqreCe`Z82Aw$) zs{nT=eSCvvC@4)ViC(NAnVk{)YZ9WcDf{yw}G*?S&JFqSUP7;#m1W?++S zM^FjW^pRE@VT`PxhY$q^bs!F92SK);^+~N;w2Fz|nD)Ymk0Uo6;jjiUKi5w^l{Tjs zk*lH-;fkU>vI5urlI2Mx0o?PJ9b@3Uvn|!K*&>oKbEFiv>~fV)p#4QfeJV!#Gcja zNXB&~%aTV>O8{DnA{S9&CjG~ey(48C=hsjG)<7x07}hG(Ek`7lFRo)RJ!suI=OX~V zF}T?1OBtWa0+B@`B&AubNLUjbpz<-t#B4h1c&bHc)kIkhh!^{&Q-(k=14x<26V&z8 z59H+*Ey!@9Ifr^BQINC8_V3Vvzt>n=HEPWYs-sm^&4~Ero<>iNw zgU7G$3ksg`(BPIM8OFSQ`rbChC?t$DG0vovMcEG`Fe7YiF|gFO+(lN@gPS4tp>^G3 zQI#QF^~cjoXoiYKCP#_b7})N40^ibc(?QGe0I88wg&|nrkf4?a2O~~l0(d1Dj7S3> zM;!-If^{U*);WIUpabo0P0Jj2ARO)b=y7>Wv({N%Fmj5y;};S(3;w#5E6pWQ86EbS zav2w?DUFn`Olrk=7}}{+vY@cf8%rYs(ltdm>Tg4NiP8fhGej zI^3`;n4LpQ6S!mhF1tQBZa3?xC|-noR*FP|M&tuH$OJat{#n=^P@Kl$jFP2>3eAAh zg-+NWyc_AHN@eQa4-~X*XLhq6?sjK{Vb3)i^vKk)$#G$~0(Kq(orIT@0A@tM9gz7d zchIM9RZ8TgC59k?%VC(mcaRtuOoP*G>g9U#yfzs=EqM8cj92FJlNn%D@+2#rO;$lH zG^8j19TbN-K6qSAMxH&81XelbMfYeW(=^1!*L1+9FCypLZhUq zB7XN8@^;;X;K?5q>nMyaFg-Og-GjRBP*t8r0x?^c6>wOQ-UJXnplV2K#8lT~YtaStvDIl<8rczAqOAWg@+Z9A48M+cb&z$HLCeMY=&#yg&W%SvUiScH<2R*qZ_ z03bwHIRG*1`s!#rl?hhVXtO9x=0XUzKd9 zM2N6F<2WE-V^V%UN-X=0A8Ws?P3DOC}jtN=IULY?%{O8}l407zqx5lpfv z2_iJ-iptA_g1tb}cIJ6xum1oqRbr8t!&nt}h1V_2utB~twxzQT{{ZpEY1N}Vo3@~V z+!Mu+T><_C9X&dW728iFlGu@FYccjuzByq-p36Iox2~QG_hgJp%`lOHX-KZcu^Des zk4?spkP{h`E;-CdW+<#XS7irH zd1%%}SY8;^h-RKM8vfXHBrzoJThwc@@uKWwv++Aex7+2z!v9$na6@A@2d)Yg2&@>8v5D9vj1l*k|zz+CV?(cC|9 zJO2PZ3BD9otSLvOCVOH&**v6@Ab91r>%OD8f5}(zG0cWR6?a9E-B&EdVI7s&4oty&0u8J}UkwYJAlECC( z{V+8!fdz$u3pA4R2qOUU0XAdA4F3Q<2C$+_%fOiuL&alkY!K{nhidXXL&fs7xWNoQ_4TXCK zXhE*URb)`ZlthrEC>?z@ach3fy6n3s1aWx4A`^}b3+Fnf%?vZgZgUi|#)ah&>|3}u zE6kImFH7OOq{@+U2&O1o_W62qU^W=k^E{OC9I?d%I}4km8X>*vLCo4WhWS1a`y4k2^E3j zId^c(o{Cfq@&Qj>N#mlNwS=^@Rar+KO&Bqi4mRS;)AiSOfQSHW{Nl@jRHnP45JVY^>GFDlg1}9+IY^paCjkFJvMH51g znUA^TQ-)lG_Z3mTrM=>$Sy_Z>U5)Inx;Wqii!@+_{SaB>MK z2;We{&-&<09Epmg5X;R= z%tH{eF4;uj+vj~HdD1R5+PoCN!kGj|l%3K&xdf4_63k(U#-$x1VaCiV{mRPN>SJPZ zPTG-YooiLJiW%Z%21#*<>#qA2^e17eHAOhS1N@5Z7sgA4WPf3lf~B*K#yV;rB~E1V zzC2IZl@XS(p0YE1i6srh$AQ<>j15O`#nO+NPb_CrUUY zn!jygh!-)i98o|c-NYU7>!DhIF;B#J+p?n?@F=h3rmY(1*fMNLvp>1Y`&T>a%#`6i zTEy;=!{jW=ZW!f;A|~R*9%|Uwj=eoK-MLCjW=Rq`8VOzqD%W)77iyy6P)7I;PuE?$ zo>3?A6-;JI&=pmzh`+NOtb_>*M~#n7T#8?iwpqtz>mJ-~7(vL%#|qd`dTJS9cXsy{ z3nMI#m0`1=XawqdHR7`)3eRSCIc0_zi7x8oVUBf7n^DIr$~medM`%=Ygf8ojYIn{y z15rY&BMS1%%5fnh<2KGlaLjX^fz^9nYs+);)1Li50ana%+xc}$%?Nscv%GH@QpA06 z*Ir3HSB1Oc7Uw?gn3Ll(!U*RhEW_B0He7FwFZr)EKgF!@rJC(eIe7BLQHbm7 zuHX2x{x{^~{GY>o{0{GTIpLgoeKV+%D7jZwN51l*c&E8<+1snJ#jawP{EXk_lV} zrDlotWBoXVRk>Q*vmEkO70g9vX1GpbMh3k)92&mN+ zQcPwhZcoK}QH=$xkNW|lIpNp8}i3RL6TNpI7AEKiuF zkfOT~aN`Fbc2pc6OlT~1p_OaQS)N?CD5Q&$h09@rxX#%+YfTMf1ag>~A%$iveex$F zIUYSf+g7Vk`7y=9Ipk|n0cc5p%qrya5D!)9rN12}c7{#`<{S*1fx%EPatY2xg@+lL zSFj`;vkd%cHXQlbmd1 z zVH`o3)Rh}BZ$L&z5I>fxUGdh1n!>Yr2_E8;1lJ<>wRm>qv5|m%8&b{YEEp=>h5ko@ zU=qbAcQPc(APNdtm2d{*h}G0KJb#0Qq)F;eGVrh=jd%!^2pDHzHpXy%nz0me)blrE zcCKWUhyMVWnEM$Ru^<*+o`+9!0>!wiv^}JentHiExfB2%+)%h2cEKR&X(ti1r{H=dSult$5DdvOzbFjMZgVog`v%2$%Uh8S+-JyO3I46HbZve|V#>i*IiRafSdnc>I-xR1%v+ZS z8xCI4ow2CAXX5@2PYG6$a~F_G!5Tg+pgqZ#h;(d|jGT>4`7h-jV!hwVO1G9{pY>qVS(Ohln&HzKe^d5H~^ysPfuNc?0@r6bNHVJ{D;K<0GH*CJ&s&6-Ou%B zIn<&Rj#ESq5@g6!md7RL+%vyjQl&htMf*}nmh1lXmLzD`lzEJt6X-Q$csh3K)Jtfx z`72^R&4|FuDUF6*TzgJ>6R9tGKP`UKxs2DZMHq*6V4PqJhT{IyF^5h@B4>gQ5w2| zCm7uJd(V;X+kE8WG!oPIQP)uWiJs(gaj2)SM4 zNcSW3#*wc1QDvebo~%eCpAx^nJeT^28o2b*%|luHa~W8$nQFt`MJhlClk5gCbt*Em z#VwYSIf}N?HtAk7=#ldMHDau_UTJ}4OyzjQ0OC_5VY8j~(^skjSdmJZWl|lsB!(an zfxe}K_EK=I#bb?S=Ob>Uv*Q^ZF{q`nA%QC(43WgFjUZj*DIQys5Ir-mmuidLu_-a0 z;*fxC#g!Wjq!Yf{WLAZ1vKbm263R$Fx1K+6+i$L%K^dzCUz13mcEdT&P5{m|I|N%Y z5=zKhiibr6GN}L(g>$xgX=hvM&Pbe?Q3#MTF3zEpDJXa92-I>`A3EG_TFsc3_ZXPF zGPHo>eght(I<4coW-iqN#y5z~0pkE;GD(~j&!_4&1ZY>tTxc?}S9gtwXv1S}Ae9G9k|CG2>^>o7JQNP3u~sAz zkEW@r((T7$zj{b=y`|s}0ka=_fs^U3%(PWI{{XctG2rrd2aBlbg(H09uA#2cySx|V zdl8a5WmPzZepozk!_!oxuMY~-IYQB^FhGm;uO$PFzi;!?Sg|6fHj-{I1a2yz@r{AQ z4`>IbqOtJhiqM)?MhF7GF~#4hJW8m}qcT)?f0D72j)6hW2r7d;|h?z zpJ~Gor9mFLty#r+ZAl`VJXkA0!v%Pfst!lpzSz{Fi$@5ohy0Y$Vov!AK!J;33}Yi6 zx+x8XM2fUBK#b%xj_SqGaSf77bkajDV8S#5o>YR{5_*qmCvROj?F5}

    dyScO$qF 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_diary.png b/app/src/main/res/drawable/ic_diary.png new file mode 100644 index 0000000000000000000000000000000000000000..75dcace6e7cf785233b9403dd70b8df0555a0af5 GIT binary patch literal 290 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9GG!XV7ZFl!D-1!HlL zyA#8@b22Z19F}xPUq=Rpjs4tz5?O)#?Vc`I>K>{=va_X;OEQmGX1-Fm%lz&_*JG|f@DTpsE$Oq~&+ zeS&fg?QFN(ZW0jt4=gP{$K!DTTQd`|=Xn;v6musI*o3l`B-$bi@P5Bp6W1{+WO)rna>GV7RDEo3_d-F(&_`=C;(%u#O#cB@b*On4Ib zj^%~}_~dnADeSa;+4I^ut^cDr4lAY@Gf z%KDxHCti$B4d*sM2O_$*S>y~BQ#Cq~?14-j)=%6n^J=yFC>zuZ(h>JbLmfsJz$vpJ zlc3plDlnQb7k3IM=B5IR=<41yY$#-v+&GG%I_Yj3>4g2Kh>>1V2Q5sqN{^ zVsDJGiHY(_i1p6SH?yp8)6V%wA>~akFhdDP!nEH)4f#8 z`cb^}f6e+kw)J90nHP$%=5XkooJo@a?(tN&+hI{z-+ey=IpSE$5;CRV=?1$7HgRp_ zybg5dlSU2ri&7bAM;Q!(^;unOyjK$?v#r zz+wf&=K9$ofqYB&D2cVczr83b>G$0+hhmU^HV`GlDg!Mj=bB^t1#x_1cM~-51k6oL z0tkp5ylFU`-)p=m$UZP4ukRstPjU3GRqCO4Ji(#xq7|Ye$vEaypFMqIierrzf^MIN zoSAEwP^0NQizP{#d*y^b>Hh%+lv?LL{NQeWUU}A0Z|qVUniNVtCCk8dG0o>XQ9Q0R zLX^E{=pcU3rV6>2NLpc^5zh6RMzYqik~GbFOasZQGdzJ3Bcm<3^e1dGQrfx0xjMGe zgw9a|1tY61;imZ+$gEICVKI}6?HPHlQ5_01TcrIPb~V=Tx|f?Qid^x=go+#0aBqfG zk+Y5^m(I)sNLI#x6dT9OmbiI5?wqyB#dFrN`aCGJ>8A1r_2P$?9Jd>aD?H)D67vEi zy%9aM((}DX$@UykMaAOq$YILIL)HlSicCz+!hj0J^R%O)(tz#1}pPDgrl=Ru-x9nlddMqto!Uy^W@Aar`UT63Z)iFd;W(PT)00000NkvXXu0mjf DI`w6n literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_man.png b/app/src/main/res/drawable/ic_man.png new file mode 100644 index 0000000000000000000000000000000000000000..a753cc8fc29e4f29d7e4fd4c2a8ae8f20ea57d8c GIT binary patch literal 477 zcmV<30V4j1P)A+4b@XaKEUyLIRujE<}Z;g6WTuOBpXC|_S167`>C zS&ztgWX|?Vh&FK-%DDyWPOe%lp|X+R^wQtScWp0>-r~SMv5DKQi|q3m;2wx}5>rcH z>ddi_)h&{3PO|RFgJDjPtmftc10!`A zN++++<=Wb1BGTm7G6C~MV%K`$1e8{ND}s4iCa7IJnI?*9qI|adC=5iPvETLX1^@s6IQ*`u00009a7bBm000XU z000XU0RWnu7ytkO0drDELIAGL9O(c600d`2O+f$vv5yP= z-oYPPdV11ICM+R+88xAz7T6rgYix~#A()1U%vDmW=kxv)0<)|N^VycbbF2fa4k}wh zR2v5Z7ySMJM#H-eI| zz4Y~|C&9O1ZeSv6feT8rQ4CF)uP8}&_Iv9pustGraOLo!f>v#(in^PE3wU({8&7nk zKy2$~ppVj!{@A2wsn9q>dFgoDT#Hx*-GfdrE&I69E;3m)O>Z8E zXI~bmJKe&S1dBv|M_U&;0IX99P8`J5&8_nA%6KWpOO6MO;mTD!kywW?$Q0000 + android:layout_height="match_parent" + android:background="@color/white"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 328ba4a..57dadef 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -6,4 +6,8 @@ \ No newline at end of file From e88dba3fb70aa18dad4597578041014e962f1705 Mon Sep 17 00:00:00 2001 From: bhindor <82446373+bhindor@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:21:46 +0900 Subject: [PATCH 11/21] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20::=20home=20?= =?UTF-8?q?=EB=B7=B0=20=EB=A7=88=EB=AC=B4=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit only view 인기 게시글 부분 수정될수 있음 --- app/src/main/res/drawable/bg_post_box.xml | 11 + app/src/main/res/drawable/ic_empty_heart.png | Bin 0 -> 568 bytes app/src/main/res/drawable/ic_heart.png | Bin 0 -> 422 bytes app/src/main/res/layout/fragment_home.xml | 234 +++++++++++++++++++ 4 files changed, 245 insertions(+) create mode 100644 app/src/main/res/drawable/bg_post_box.xml create mode 100644 app/src/main/res/drawable/ic_empty_heart.png create mode 100644 app/src/main/res/drawable/ic_heart.png diff --git a/app/src/main/res/drawable/bg_post_box.xml b/app/src/main/res/drawable/bg_post_box.xml new file mode 100644 index 0000000..0ebd6ef --- /dev/null +++ b/app/src/main/res/drawable/bg_post_box.xml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_empty_heart.png b/app/src/main/res/drawable/ic_empty_heart.png new file mode 100644 index 0000000000000000000000000000000000000000..84a0c10a09ed8c4367c11171b71e01dab11cd384 GIT binary patch literal 568 zcmV-80>}M{P)~$1XAl9w>1>h3ZoSmn#HTd8YnGr{n*K8!>UxILFYq(n`&M zvR~8Frq6&#PA2)T>(dN8%^KliV?)L_PNOTOY{1bGt|f*c&t^28PQymT$d zy1QI7_$AUh#tcLyh`q4u@F0w}k8%ufCtsh;hDUKcwzbtq)&Oy;#$aGpL0L!+f~~YF zlZ*i_7CSwQ8XdGX+zZ92gQy^>l`@csV^LZm<@3V3-7%ES-gU=0pl;203-W%V+fwXNjXn>Dv91`gEU$T)mohL+-au9e?j?isCa4Xy zio{D9NE4e*cZF@0iA1O~4{vcx8Kg|0toYp!Ce&*1r|<>73EehIX!@4`0000K)k ze4kV$#~X;$KBlhbnAYo$ia}ZV?+>m=!GCx*z!EOcA{8ibUODlt)|TK)=a-p{}UEt8Q3a6 zAkcswm+%I#AG~Z6*Ba*a(QFIa-;<7EblYwD^uHqL{nDFEBQoI5F01hvAT=}D_ QGXMYp07*qoM6N<$f{2>33;+NC literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index c1d1c22..05a4361 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -191,4 +191,238 @@ app:layout_constraintStart_toStartOf="@id/layout_menu_buttons" app:layout_constraintTop_toBottomOf="@id/layout_menu_buttons" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From ebfc82fbada80d4d00a55bc6c7ccf30dd827231a Mon Sep 17 00:00:00 2001 From: bhindor <82446373+bhindor@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:21:53 +0900 Subject: [PATCH 12/21] =?UTF-8?q?=F0=9F=8E=A8=20::=20color=20change?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mumu/presentation/join/AccountFragment.kt | 2 +- .../mumu/presentation/join/AddressFragment.kt | 2 +- .../anu/mumu/presentation/join/FinishFragment.kt | 2 +- .../anu/mumu/presentation/login/LoginActivity.kt | 2 +- app/src/main/res/color/selector_bottom_nav.xml | 2 +- app/src/main/res/drawable/bg_pill_mint.xml | 2 +- app/src/main/res/drawable/btn_disabled.xml | 2 +- app/src/main/res/drawable/btn_enabled.xml | 2 +- .../main/res/drawable/btn_join_background.xml | 2 +- app/src/main/res/layout/activity_login.xml | 2 +- app/src/main/res/layout/activity_main.xml | 2 +- app/src/main/res/layout/fragment_home.xml | 16 ++++++++-------- app/src/main/res/layout/fragment_terms.xml | 8 ++++---- app/src/main/res/values/colors.xml | 12 ++++++------ 14 files changed, 29 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/join/AccountFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/join/AccountFragment.kt index 53d45db..4beb0cf 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/join/AccountFragment.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/join/AccountFragment.kt @@ -87,7 +87,7 @@ class AccountFragment : Fragment() { if (start != -1) { context?.let { ctx -> - val color = ContextCompat.getColor(ctx, R.color.mumumint_300) + val color = ContextCompat.getColor(ctx, R.color.mumu_300) spannable.setSpan( ForegroundColorSpan(color), diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/join/AddressFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/join/AddressFragment.kt index afb8663..56d329b 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/join/AddressFragment.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/join/AddressFragment.kt @@ -65,7 +65,7 @@ class AddressFragment : Fragment() { val end = start + targetWord.length if (start != -1) { - val color = ContextCompat.getColor(requireContext(), R.color.mumumint_300) + val color = ContextCompat.getColor(requireContext(), R.color.mumu_300) spannable.setSpan( ForegroundColorSpan(color), diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/join/FinishFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/join/FinishFragment.kt index 7cd2df2..ffc5e84 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/join/FinishFragment.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/join/FinishFragment.kt @@ -41,7 +41,7 @@ class FinishFragment : Fragment() { if (start != -1) { // requireContext()를 사용하여 안전하게 색상 가져오기 - val color = ContextCompat.getColor(requireContext(), R.color.mumumint_300) + val color = ContextCompat.getColor(requireContext(), R.color.mumu_300) spannable.setSpan( ForegroundColorSpan(color), diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/login/LoginActivity.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/login/LoginActivity.kt index 5d1dd44..e46dba0 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/login/LoginActivity.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/login/LoginActivity.kt @@ -57,7 +57,7 @@ class LoginActivity : AppCompatActivity() { val end = start + targetWord.length if (start != -1) { - val color = ContextCompat.getColor(this, R.color.mumumint_300) + val color = ContextCompat.getColor(this, R.color.mumu_300) spannable.setSpan( ForegroundColorSpan(color), diff --git a/app/src/main/res/color/selector_bottom_nav.xml b/app/src/main/res/color/selector_bottom_nav.xml index 0bab02d..084c2c3 100644 --- a/app/src/main/res/color/selector_bottom_nav.xml +++ b/app/src/main/res/color/selector_bottom_nav.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_pill_mint.xml b/app/src/main/res/drawable/bg_pill_mint.xml index 6f6ef23..61c35d8 100644 --- a/app/src/main/res/drawable/bg_pill_mint.xml +++ b/app/src/main/res/drawable/bg_pill_mint.xml @@ -6,7 +6,7 @@ + android:color="@color/mumu_300" /> diff --git a/app/src/main/res/drawable/btn_disabled.xml b/app/src/main/res/drawable/btn_disabled.xml index 375755b..3333edc 100644 --- a/app/src/main/res/drawable/btn_disabled.xml +++ b/app/src/main/res/drawable/btn_disabled.xml @@ -3,6 +3,6 @@ android:shape="rectangle"> - + \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_enabled.xml b/app/src/main/res/drawable/btn_enabled.xml index 3fce4ed..cb29bec 100644 --- a/app/src/main/res/drawable/btn_enabled.xml +++ b/app/src/main/res/drawable/btn_enabled.xml @@ -3,6 +3,6 @@ android:shape="rectangle"> - + \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_join_background.xml b/app/src/main/res/drawable/btn_join_background.xml index ab4e216..1fe1b95 100644 --- a/app/src/main/res/drawable/btn_join_background.xml +++ b/app/src/main/res/drawable/btn_join_background.xml @@ -5,6 +5,6 @@ + android:color="@color/mumu_150" /> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index 779ee7a..56f4247 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -94,7 +94,7 @@ android:background="@drawable/btn_join_background" android:fontFamily="@font/pretendard_semibold" android:text="회원가입" - android:textColor="@color/mumumint_250" + android:textColor="@color/mumu_250" android:textSize="@dimen/body_4" app:layout_constraintEnd_toEndOf="@id/btn_login" app:layout_constraintStart_toStartOf="@id/btn_login" diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 7af65b3..01b1f42 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -31,7 +31,7 @@ android:layout_marginStart="8dp" android:fontFamily="@font/pretendard_semibold" android:text="Mumu" - android:textColor="@color/mumumint_300" + android:textColor="@color/mumu_300" android:textSize="@dimen/body_1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toEndOf="@id/iv_logo" diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 05a4361..26bf505 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -18,7 +18,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:shapeAppearanceOverlay="@style/CircleImage" - app:strokeColor="@color/mumumint_300" + app:strokeColor="@color/mumu_300" app:strokeWidth="2dp" /> + app:tint="@color/mumu_300" /> @@ -117,7 +117,7 @@ android:layout_width="24dp" android:layout_height="24dp" android:src="@drawable/ic_diary" - app:tint="@color/mumumint_300" /> + app:tint="@color/mumu_300" /> @@ -215,7 +215,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:shapeAppearanceOverlay="@style/CircleImage" - app:strokeColor="@color/mumumint_300" + app:strokeColor="@color/mumu_300" app:strokeWidth="2dp" /> @@ -99,7 +99,7 @@ android:text="개인정보 취급방침 (필수)" android:textColor="@color/mumugray_400" android:textSize="@dimen/body_4" - app:buttonTint="@color/mumumint_300" + app:buttonTint="@color/mumu_300" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/cb_terms" /> @@ -133,7 +133,7 @@ android:text="마케팅 수신 동의 (선택)" android:textColor="@color/mumugray_400" android:textSize="@dimen/body_4" - app:buttonTint="@color/mumumint_300" + app:buttonTint="@color/mumu_300" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/cb_privacy" /> diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 88c8551..35ca88d 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -3,12 +3,12 @@ #262626 #FFFFFF - #80CBC4 - #97D3CE - #AFDCD8 - #C6E4E1 - #DEEDEB - #E9F0F0 + #FFC13B + #FDCB60 + #FBD685 + #F9E0AB + #F7EBD0 + #F6EFE2 #F5F5F5 #E9E9EA From ec32c12fb5e19a6a11a5677f9f80daeb8ee00765 Mon Sep 17 00:00:00 2001 From: bhindor <82446373+bhindor@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:22:33 +0900 Subject: [PATCH 13/21] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20::=20add=20menu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/drawable/ic_diary.xml | 9 +++++++++ app/src/main/res/drawable/ic_message.xml | 9 +++++++++ app/src/main/res/menu/main_menu.xml | 9 +++++++++ app/src/main/res/navigation/nav_graph_main.xml | 6 ++++++ 4 files changed, 33 insertions(+) create mode 100644 app/src/main/res/drawable/ic_diary.xml create mode 100644 app/src/main/res/drawable/ic_message.xml diff --git a/app/src/main/res/drawable/ic_diary.xml b/app/src/main/res/drawable/ic_diary.xml new file mode 100644 index 0000000..a90c972 --- /dev/null +++ b/app/src/main/res/drawable/ic_diary.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_message.xml b/app/src/main/res/drawable/ic_message.xml new file mode 100644 index 0000000..26107c3 --- /dev/null +++ b/app/src/main/res/drawable/ic_message.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/menu/main_menu.xml b/app/src/main/res/menu/main_menu.xml index 2fb9d5c..99cd1fc 100644 --- a/app/src/main/res/menu/main_menu.xml +++ b/app/src/main/res/menu/main_menu.xml @@ -5,11 +5,20 @@ android:icon="@drawable/ic_hospital" android:title="병원" /> + + + + + + + Date: Wed, 26 Aug 2026 14:23:55 +0900 Subject: [PATCH 14/21] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20::=20add=20diary=20f?= =?UTF-8?q?ragment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mumu/presentation/main/DiaryFragment.kt | 31 +++++++++++++++++++ app/src/main/res/layout/fragment_diary.xml | 9 ++++++ 2 files changed, 40 insertions(+) create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/main/DiaryFragment.kt create mode 100644 app/src/main/res/layout/fragment_diary.xml diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/DiaryFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/DiaryFragment.kt new file mode 100644 index 0000000..9b0bf2a --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/DiaryFragment.kt @@ -0,0 +1,31 @@ +package kr.ac.anu.mumu.presentation.main + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import kr.ac.anu.mumu.databinding.FragmentDiaryBinding +import kr.ac.anu.mumu.presentation.join.JoinViewModel + +class DiaryFragment : Fragment() { + private var _binding: FragmentDiaryBinding? = null + private val binding get() = _binding!! + private val viewModel: JoinViewModel by activityViewModels() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentDiaryBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_diary.xml b/app/src/main/res/layout/fragment_diary.xml new file mode 100644 index 0000000..9c463cc --- /dev/null +++ b/app/src/main/res/layout/fragment_diary.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file From 62e8858dde3234c71a1e5edb8cd6ed7c5201f5ac Mon Sep 17 00:00:00 2001 From: bhindor <82446373+bhindor@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:24:38 +0900 Subject: [PATCH 15/21] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20::=20add=20community?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mumu/presentation/main/CommFragment.kt | 31 +++++++++++++++++++ app/src/main/res/layout/fragment_comm.xml | 7 +++++ 2 files changed, 38 insertions(+) create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/main/CommFragment.kt create mode 100644 app/src/main/res/layout/fragment_comm.xml diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/CommFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/CommFragment.kt new file mode 100644 index 0000000..02ed13b --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/CommFragment.kt @@ -0,0 +1,31 @@ +package kr.ac.anu.mumu.presentation.main + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import kr.ac.anu.mumu.databinding.FragmentCommBinding +import kr.ac.anu.mumu.presentation.join.JoinViewModel + +class CommFragment : Fragment() { + private var _binding: FragmentCommBinding? = null + private val binding get() = _binding!! + private val viewModel: JoinViewModel by activityViewModels() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentCommBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_comm.xml b/app/src/main/res/layout/fragment_comm.xml new file mode 100644 index 0000000..3728533 --- /dev/null +++ b/app/src/main/res/layout/fragment_comm.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file From 17a1dbba73d3fb15ddf054a64c017eedf7e93477 Mon Sep 17 00:00:00 2001 From: bhindor <82446373+bhindor@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:24:46 +0900 Subject: [PATCH 16/21] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20::=20post=20view?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 2 + .../mumu/presentation/main/HomeFragment.kt | 53 ++ .../mumu/presentation/main/PostFragment.kt | 28 ++ .../{bg_pill_mint.xml => bg_btn_analyze.xml} | 7 +- app/src/main/res/drawable/bg_btn_write.xml | 8 + app/src/main/res/drawable/bg_pill_yellow.xml | 11 + app/src/main/res/drawable/bg_post_box.xml | 2 +- app/src/main/res/drawable/dog_foot.png | Bin 0 -> 5112 bytes app/src/main/res/drawable/ic_diary.png | Bin 290 -> 0 bytes app/src/main/res/drawable/ic_heart.png | Bin 422 -> 1615 bytes app/src/main/res/layout/fragment_home.xml | 454 +++++++----------- app/src/main/res/layout/fragment_post.xml | 18 + app/src/main/res/layout/item_post.xml | 18 + gradle/libs.versions.toml | 4 + 14 files changed, 308 insertions(+), 297 deletions(-) create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/main/PostFragment.kt rename app/src/main/res/drawable/{bg_pill_mint.xml => bg_btn_analyze.xml} (70%) create mode 100644 app/src/main/res/drawable/bg_btn_write.xml create mode 100644 app/src/main/res/drawable/bg_pill_yellow.xml create mode 100644 app/src/main/res/drawable/dog_foot.png delete mode 100644 app/src/main/res/drawable/ic_diary.png create mode 100644 app/src/main/res/layout/fragment_post.xml create mode 100644 app/src/main/res/layout/item_post.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3dbbbf2..c47fe98 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -48,6 +48,8 @@ dependencies { implementation(libs.material) implementation(libs.androidx.activity) implementation(libs.androidx.constraintlayout) + implementation(libs.navigation.fragment.ktx) + implementation(libs.navigation.ui.ktx) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/HomeFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HomeFragment.kt index a0b8fc9..3f01da1 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/main/HomeFragment.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HomeFragment.kt @@ -4,8 +4,12 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import dagger.hilt.android.AndroidEntryPoint +import kr.ac.anu.mumu.R import kr.ac.anu.mumu.databinding.FragmentHomeBinding @AndroidEntryPoint @@ -23,6 +27,55 @@ class HomeFragment: Fragment() { return binding.root } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + if (savedInstanceState == null) { + setTabActive(isPeedActive = true) + replaceFragment(PostFragment()) + } + + binding.btnPeed.setOnClickListener { + setTabActive(isPeedActive = true) + replaceFragment(PostFragment()) + } + + binding.btnHistory.setOnClickListener { + setTabActive(isPeedActive = false) + replaceFragment(HistoryFragment()) + } + } + + private fun replaceFragment(fragment: Fragment) { + childFragmentManager.beginTransaction() + .replace(binding.fragmentContainer.id, fragment) + .commit() + } + + private fun setTabActive(isPeedActive: Boolean) { + val activeColor = ContextCompat.getColor(requireContext(), R.color.mumu_300) + val inactiveColor = ContextCompat.getColor(requireContext(), R.color.mumugray_150) + + val peedIcon = binding.btnPeed.getChildAt(0) as ImageView + val peedText = binding.btnPeed.getChildAt(1) as TextView + val historyIcon = binding.btnHistory.getChildAt(0) as ImageView + val historyText = binding.btnHistory.getChildAt(1) as TextView + + if (isPeedActive) { + peedIcon.setColorFilter(activeColor) + peedText.setTextColor(activeColor) + + historyIcon.setColorFilter(inactiveColor) + historyText.setTextColor(inactiveColor) + } else { + peedIcon.setColorFilter(inactiveColor) + peedText.setTextColor(inactiveColor) + + historyIcon.setColorFilter(activeColor) + historyText.setTextColor(activeColor) + } + } + override fun onDestroyView() { super.onDestroyView() _binding = null diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/PostFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/PostFragment.kt new file mode 100644 index 0000000..d124b7f --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/PostFragment.kt @@ -0,0 +1,28 @@ +package kr.ac.anu.mumu.presentation.main + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import kr.ac.anu.mumu.databinding.FragmentPostBinding + +class PostFragment : Fragment() { + + private var _binding: FragmentPostBinding? = null + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentPostBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_pill_mint.xml b/app/src/main/res/drawable/bg_btn_analyze.xml similarity index 70% rename from app/src/main/res/drawable/bg_pill_mint.xml rename to app/src/main/res/drawable/bg_btn_analyze.xml index 61c35d8..67b296e 100644 --- a/app/src/main/res/drawable/bg_pill_mint.xml +++ b/app/src/main/res/drawable/bg_btn_analyze.xml @@ -1,13 +1,8 @@ - - - + - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_btn_write.xml b/app/src/main/res/drawable/bg_btn_write.xml new file mode 100644 index 0000000..9492222 --- /dev/null +++ b/app/src/main/res/drawable/bg_btn_write.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_pill_yellow.xml b/app/src/main/res/drawable/bg_pill_yellow.xml new file mode 100644 index 0000000..89f259b --- /dev/null +++ b/app/src/main/res/drawable/bg_pill_yellow.xml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_post_box.xml b/app/src/main/res/drawable/bg_post_box.xml index 0ebd6ef..15ff3d9 100644 --- a/app/src/main/res/drawable/bg_post_box.xml +++ b/app/src/main/res/drawable/bg_post_box.xml @@ -6,6 +6,6 @@ android:width="1dp" android:color="@color/mumugray_100" /> - + \ No newline at end of file diff --git a/app/src/main/res/drawable/dog_foot.png b/app/src/main/res/drawable/dog_foot.png new file mode 100644 index 0000000000000000000000000000000000000000..465d287389002ba006da55e849628375c38c3551 GIT binary patch literal 5112 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 byaE0I4lj3H`J<{c00000NkvXXu0mjf;*+Zx diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 26bf505..b1a3048 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -5,66 +5,176 @@ android:layout_height="match_parent" android:background="@color/white"> - - + app:layout_constraintTop_toTopOf="parent"> - + app:layout_constraintTop_toTopOf="parent" + app:shapeAppearanceOverlay="@style/CircleImage" + app:strokeColor="@color/mumu_300" + app:strokeWidth="2dp" /> + android:textSize="@dimen/body_4" + app:layout_constraintBottom_toBottomOf="@id/iv_post_profile" + app:layout_constraintStart_toEndOf="@id/iv_post_profile" + app:layout_constraintTop_toTopOf="@id/iv_post_profile" /> + + + + + + + + + + + app:layout_constraintTop_toTopOf="@id/tv_pet_name"> + + + + + + + + + + + app:layout_constraintTop_toBottomOf="@id/btn_analyze"> + android:src="@drawable/ic_history" + app:tint="@color/mumugray_150" /> @@ -179,250 +289,14 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + app:layout_constraintEnd_toEndOf="@id/layout_pet_profile" + app:layout_constraintStart_toStartOf="@id/layout_pet_profile" + app:layout_constraintTop_toBottomOf="@id/layout_menu_buttons" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_post.xml b/app/src/main/res/layout/fragment_post.xml new file mode 100644 index 0000000..715ee39 --- /dev/null +++ b/app/src/main/res/layout/fragment_post.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_post.xml b/app/src/main/res/layout/item_post.xml new file mode 100644 index 0000000..f335351 --- /dev/null +++ b/app/src/main/res/layout/item_post.xml @@ -0,0 +1,18 @@ + + + + + \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6ec3a43..ab4e9b3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,6 +16,8 @@ activity = "1.12.1" constraintlayout = "2.2.1" navigationFragmentKtx = "2.9.7" retrofit2 = "2.9.0" +navigationFragmentKtxVersion = "2.9.8" +navigationUiKtx = "2.9.8" [libraries] androidx-activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activityKtx" } @@ -37,6 +39,8 @@ material = { group = "com.google.android.material", name = "material", version.r androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" } androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } retrofit2 = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit2" } +navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigationFragmentKtxVersion" } +navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigationUiKtx" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } From 5a435e952447ba380b7b277f111872911983c366 Mon Sep 17 00:00:00 2001 From: bhindor <82446373+bhindor@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:24:53 +0900 Subject: [PATCH 17/21] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20::=20add=20history?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mumu/data/mapper/AnalysisHistoryDto.kt | 33 +++++++++ .../kr/ac/anu/mumu/data/model/HistoryDtos.kt | 25 +++++++ .../anu/mumu/domain/model/AnalysisHistory.kt | 9 +++ .../mumu/presentation/main/HistoryFragment.kt | 66 ++++++++++++++++++ .../main/adapter/HistoryAdapter.kt | 61 +++++++++++++++++ app/src/main/res/layout/fragment_history.xml | 31 +++++++++ app/src/main/res/layout/item_history.xml | 67 +++++++++++++++++++ app/src/main/res/values/colors.xml | 3 + 8 files changed, 295 insertions(+) create mode 100644 app/src/main/java/kr/ac/anu/mumu/data/mapper/AnalysisHistoryDto.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/data/model/HistoryDtos.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/domain/model/AnalysisHistory.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryFragment.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/main/adapter/HistoryAdapter.kt create mode 100644 app/src/main/res/layout/fragment_history.xml create mode 100644 app/src/main/res/layout/item_history.xml diff --git a/app/src/main/java/kr/ac/anu/mumu/data/mapper/AnalysisHistoryDto.kt b/app/src/main/java/kr/ac/anu/mumu/data/mapper/AnalysisHistoryDto.kt new file mode 100644 index 0000000..abafad0 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/data/mapper/AnalysisHistoryDto.kt @@ -0,0 +1,33 @@ +package kr.ac.anu.mumu.data.mapper + +import kr.ac.anu.mumu.data.model.AnalysisHistoryDto +import kr.ac.anu.mumu.domain.model.AnalysisHistory +import java.text.SimpleDateFormat +import java.util.Locale + +fun AnalysisHistoryDto.toDomain(): AnalysisHistory { + val formattedDate = try { + val parser = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()) + val formatter = SimpleDateFormat("yyyy.MM.dd", Locale.getDefault()) + val parsedDate = parser.parse(this.analyzedAt) + parsedDate?.let { formatter.format(it) } ?: this.analyzedAt + } catch (e: Exception) { + this.analyzedAt + } + + val isNormal = this.status == "정상" || this.resultLabel?.uppercase() == "NORMAL" + + val joinedBehavior = if (this.suspectedItems.isNullOrEmpty()) { + "없음" + } else { + this.suspectedItems.joinToString(", ") + } + + return AnalysisHistory( + id = this.analysisId, + isNormal = isNormal, + behaviorText = joinedBehavior, + probability = this.confidence, + date = formattedDate + ) +} \ No newline at end of file diff --git a/app/src/main/java/kr/ac/anu/mumu/data/model/HistoryDtos.kt b/app/src/main/java/kr/ac/anu/mumu/data/model/HistoryDtos.kt new file mode 100644 index 0000000..c79b946 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/data/model/HistoryDtos.kt @@ -0,0 +1,25 @@ +package kr.ac.anu.mumu.data.model + +data class BaseResponse( + val success: Boolean, + val message: String, + val data: T +) + +data class PaginatedData( + val content: List, + val page: Int, + val size: Int, + val totalElements: Long, + val totalPages: Int +) + +data class AnalysisHistoryDto( + val analysisId: Long, + val type: String, + val status: String, + val resultLabel: String?, + val suspectedItems: List?, + val confidence: Int, + val analyzedAt: String +) \ No newline at end of file diff --git a/app/src/main/java/kr/ac/anu/mumu/domain/model/AnalysisHistory.kt b/app/src/main/java/kr/ac/anu/mumu/domain/model/AnalysisHistory.kt new file mode 100644 index 0000000..9f84896 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/domain/model/AnalysisHistory.kt @@ -0,0 +1,9 @@ +package kr.ac.anu.mumu.domain.model + +data class AnalysisHistory( + val id: Long, + val isNormal: Boolean, + val behaviorText: String, + val probability: Int, + val date: String +) \ No newline at end of file diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryFragment.kt new file mode 100644 index 0000000..047b7df --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryFragment.kt @@ -0,0 +1,66 @@ +package kr.ac.anu.mumu.presentation.main + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import kr.ac.anu.mumu.databinding.FragmentHistoryBinding +import kr.ac.anu.mumu.domain.model.AnalysisHistory +import kr.ac.anu.mumu.presentation.main.adapter.HistoryAdapter + +class HistoryFragment : Fragment() { + + private var _binding: FragmentHistoryBinding? = null + private val binding get() = _binding!! + + // 어댑터 전역 변수 선언 + private lateinit var historyAdapter: HistoryAdapter + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentHistoryBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + // 1. 리사이클러뷰와 어댑터 연결 + setupRecyclerView() + + // 2. 데이터 불러오기 (테스트용) + // 실제로는 ViewModel에서 서버 데이터를 관찰(observe)하고 변경될 때 submitList를 호출합니다. + loadDummyData() + } + + private fun setupRecyclerView() { + historyAdapter = HistoryAdapter() + binding.rvHistory.apply { + adapter = historyAdapter + // XML에 app:layoutManager를 설정해 두었다면 아래 줄은 생략해도 됩니다. + layoutManager = LinearLayoutManager(requireContext()) + } + } + + private fun loadDummyData() { + // 방금 만든 도메인 모델 형태에 맞춰 임시 데이터를 만듭니다. + val dummyData = listOf( + AnalysisHistory(id = 1L, isNormal = false, behaviorText = "자세 비정상, 발바닥 이상", probability = 72, date = "2026.04.15"), + AnalysisHistory(id = 2L, isNormal = true, behaviorText = "자세 비정상, 절뚝거림", probability = 72, date = "2026.04.15"), + AnalysisHistory(id = 3L, isNormal = true, behaviorText = "자세 비정상, 절뚝거림", probability = 72, date = "2026.04.15") + ) + + // 생성한 데이터를 어댑터에 넘겨서 화면에 그려지게 합니다. + historyAdapter.submitList(dummyData) + } + + override fun onDestroyView() { + super.onDestroyView() + // 메모리 누수 방지 + _binding = null + } +} \ No newline at end of file diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/adapter/HistoryAdapter.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/adapter/HistoryAdapter.kt new file mode 100644 index 0000000..c59ba25 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/adapter/HistoryAdapter.kt @@ -0,0 +1,61 @@ +package kr.ac.anu.mumu.presentation.main.adapter + +import android.graphics.Color +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView +import kr.ac.anu.mumu.R +import kr.ac.anu.mumu.databinding.ItemHistoryBinding +import kr.ac.anu.mumu.domain.model.AnalysisHistory + +class HistoryAdapter( + private var items: List = emptyList() // 초기값은 빈 리스트 +) : RecyclerView.Adapter() { + + // 외부(프래그먼트나 뷰모델)에서 데이터를 업데이트할 때 호출할 함수 + fun submitList(newItems: List) { + items = newItems + notifyDataSetChanged() // 데이터가 바뀌었음을 리사이클러뷰에 알림 + } + + inner class HistoryViewHolder(private val binding: ItemHistoryBinding) : + RecyclerView.ViewHolder(binding.root) { + + fun bind(item: AnalysisHistory) { + val context = binding.root.context + + // 1. 공통 데이터 바인딩 + binding.tvDate.text = item.date + binding.tvProbability.text = "확률 : ${item.probability}%" + + // 2. 상태(정상/비정상)에 따른 동적 UI 변경 + if (item.isNormal) { + // 정상: 초록색 테두리 + val greenColor = ContextCompat.getColor(context, R.color.mumu_300) + binding.cardResult.strokeColor = greenColor + binding.tvResultStatus.text = "검사결과 : 정상" + binding.tvDescription.text = "검사목록 : ${item.behaviorText}" + } else { + // 비정상: 빨간색 테두리 + val redColor = Color.parseColor("#FF5252") // 또는 colors.xml에 정의한 색상 사용 + binding.cardResult.strokeColor = redColor + binding.tvResultStatus.text = "검사결과 : 비정상" + binding.tvDescription.text = "의심행동 : ${item.behaviorText}" + } + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HistoryViewHolder { + val binding = ItemHistoryBinding.inflate( + LayoutInflater.from(parent.context), parent, false + ) + return HistoryViewHolder(binding) + } + + override fun onBindViewHolder(holder: HistoryViewHolder, position: Int) { + holder.bind(items[position]) + } + + override fun getItemCount(): Int = items.size +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_history.xml b/app/src/main/res/layout/fragment_history.xml new file mode 100644 index 0000000..080353c --- /dev/null +++ b/app/src/main/res/layout/fragment_history.xml @@ -0,0 +1,31 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_history.xml b/app/src/main/res/layout/item_history.xml new file mode 100644 index 0000000..35f22a4 --- /dev/null +++ b/app/src/main/res/layout/item_history.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 35ca88d..296f994 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -21,4 +21,7 @@ #F44355 #4B88FF + + #DF7171 + #88BA47 \ No newline at end of file From 279a5c8139f995c78094c366a089746bd4b53eec Mon Sep 17 00:00:00 2001 From: bhindor Date: Wed, 26 Aug 2026 16:10:16 +0900 Subject: [PATCH 18/21] =?UTF-8?q?feat:=20=EC=84=9C=EB=B2=84=20=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=20=EA=B3=84=EC=95=BD=20=EB=B0=8F=20=EC=84=B8=EC=85=98?= =?UTF-8?q?=20=EC=A0=80=EC=9E=A5=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../anu/mumu/data/datasource/AuthService.kt | 2 +- .../ac/anu/mumu/data/local/SessionManager.kt | 31 +++++++++++++++++++ .../kr/ac/anu/mumu/data/model/AuthDtos.kt | 26 ++++++---------- .../java/kr/ac/anu/mumu/data/model/JoinDto.kt | 18 ++++------- .../data/repository/JoinRepositoryImpl.kt | 4 +-- .../data/repository/LoginRepositoryImpl.kt | 18 +++++++---- .../java/kr/ac/anu/mumu/domain/model/User.kt | 7 ++--- .../mumu/presentation/join/JoinViewModel.kt | 5 +-- 8 files changed, 65 insertions(+), 46 deletions(-) create mode 100644 app/src/main/java/kr/ac/anu/mumu/data/local/SessionManager.kt diff --git a/app/src/main/java/kr/ac/anu/mumu/data/datasource/AuthService.kt b/app/src/main/java/kr/ac/anu/mumu/data/datasource/AuthService.kt index 8c3d418..3968755 100644 --- a/app/src/main/java/kr/ac/anu/mumu/data/datasource/AuthService.kt +++ b/app/src/main/java/kr/ac/anu/mumu/data/datasource/AuthService.kt @@ -7,6 +7,6 @@ import retrofit2.http.Body import retrofit2.http.POST interface AuthService { - @POST("/api/users/login") + @POST("/api/auth/login") suspend fun login(@Body request: LoginRequest): Response } diff --git a/app/src/main/java/kr/ac/anu/mumu/data/local/SessionManager.kt b/app/src/main/java/kr/ac/anu/mumu/data/local/SessionManager.kt new file mode 100644 index 0000000..522e1d5 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/data/local/SessionManager.kt @@ -0,0 +1,31 @@ +package kr.ac.anu.mumu.data.local + +import android.content.Context +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class SessionManager @Inject constructor( + @ApplicationContext context: Context +) { + private val preferences = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE) + + val accessToken: String? + get() = preferences.getString(KEY_ACCESS_TOKEN, null) + + fun saveTokens(accessToken: String, refreshToken: String, tokenType: String) { + preferences.edit() + .putString(KEY_ACCESS_TOKEN, accessToken) + .putString(KEY_REFRESH_TOKEN, refreshToken) + .putString(KEY_TOKEN_TYPE, tokenType) + .apply() + } + + private companion object { + const val PREFERENCES_NAME = "mumu_session" + const val KEY_ACCESS_TOKEN = "access_token" + const val KEY_REFRESH_TOKEN = "refresh_token" + const val KEY_TOKEN_TYPE = "token_type" + } +} diff --git a/app/src/main/java/kr/ac/anu/mumu/data/model/AuthDtos.kt b/app/src/main/java/kr/ac/anu/mumu/data/model/AuthDtos.kt index 01e8b01..7b07c19 100644 --- a/app/src/main/java/kr/ac/anu/mumu/data/model/AuthDtos.kt +++ b/app/src/main/java/kr/ac/anu/mumu/data/model/AuthDtos.kt @@ -1,28 +1,20 @@ package kr.ac.anu.mumu.data.model -import com.google.gson.annotations.SerializedName - data class LoginRequest( - @SerializedName("id") - val id: String, - @SerializedName("password") - val pw: String + val loginId: String, + val password: String, + val deviceType: String = "android", + val deviceInfo: String? = null ) data class LoginResponse( val success: Boolean, val message: String, - val token: String, - val user: UserDto + val data: TokenDto ) -data class UserDto( - @SerializedName("user_id") - val userId: Int, - val id: String, - val name: String, - val phone: String?, - @SerializedName("profile_image") - val profileImage: String?, - val role: String +data class TokenDto( + val accessToken: String, + val refreshToken: String, + val tokenType: String ) diff --git a/app/src/main/java/kr/ac/anu/mumu/data/model/JoinDto.kt b/app/src/main/java/kr/ac/anu/mumu/data/model/JoinDto.kt index 314dbd8..865642c 100644 --- a/app/src/main/java/kr/ac/anu/mumu/data/model/JoinDto.kt +++ b/app/src/main/java/kr/ac/anu/mumu/data/model/JoinDto.kt @@ -1,29 +1,23 @@ package kr.ac.anu.mumu.data.model -import com.google.gson.annotations.SerializedName - data class JoinRequest( - val id: String, + val loginId: String, val password: String, val name: String, val phone: String, - val address: String, - @SerializedName("detail_address") val detailAddress: String, - @SerializedName("postal_code") val postalCode: String, - @SerializedName("terms_agreed") val termsAgreed: Boolean, - @SerializedName("privacy_agreed") val privacyAgreed: Boolean, - @SerializedName("marketing_agreed") val marketingAgreed: Boolean + val termsAgreed: Boolean, + val privacyAgreed: Boolean, + val marketingAgreed: Boolean ) data class JoinResponse( val success: Boolean, val message: String, - val token: String?, - val user: UserDto? + val data: UserDto? ) { data class UserDto( val userId: Int, - val id: String, + val loginId: String, val name: String, val phone: String ) diff --git a/app/src/main/java/kr/ac/anu/mumu/data/repository/JoinRepositoryImpl.kt b/app/src/main/java/kr/ac/anu/mumu/data/repository/JoinRepositoryImpl.kt index 4313d7d..4111bba 100644 --- a/app/src/main/java/kr/ac/anu/mumu/data/repository/JoinRepositoryImpl.kt +++ b/app/src/main/java/kr/ac/anu/mumu/data/repository/JoinRepositoryImpl.kt @@ -12,12 +12,12 @@ class JoinRepositoryImpl @Inject constructor( override suspend fun register(request: JoinRequest): Result { return try { val response = joinService.registerUser(request) - if (response.isSuccessful) { + if (response.isSuccessful && response.body()?.success == true) { Result.success(Unit) } else { val errorString = response.errorBody()?.string() val errorMessage = try { - JSONObject(errorString ?: "").getString("error") + JSONObject(errorString ?: "").optString("message", "회원가입에 실패했습니다.") } catch (e: Exception) { "회원가입에 실패했습니다." } diff --git a/app/src/main/java/kr/ac/anu/mumu/data/repository/LoginRepositoryImpl.kt b/app/src/main/java/kr/ac/anu/mumu/data/repository/LoginRepositoryImpl.kt index 27749cc..8ebbc0c 100644 --- a/app/src/main/java/kr/ac/anu/mumu/data/repository/LoginRepositoryImpl.kt +++ b/app/src/main/java/kr/ac/anu/mumu/data/repository/LoginRepositoryImpl.kt @@ -1,28 +1,34 @@ package kr.ac.anu.mumu.data.repository import kr.ac.anu.mumu.data.datasource.AuthService +import kr.ac.anu.mumu.data.local.SessionManager import kr.ac.anu.mumu.data.model.LoginRequest import kr.ac.anu.mumu.domain.model.User import kr.ac.anu.mumu.domain.repository.LoginRepository import javax.inject.Inject class LoginRepositoryImpl @Inject constructor( - private val authService: AuthService + private val authService: AuthService, + private val sessionManager: SessionManager ) : LoginRepository { override suspend fun login(id: String, pw: String): Result { return try { - val response = authService.login(LoginRequest(id, pw)) + val response = authService.login(LoginRequest(loginId = id, password = pw)) if (response.isSuccessful && response.body() != null) { val result = response.body()!! if (result.success) { + sessionManager.saveTokens( + accessToken = result.data.accessToken, + refreshToken = result.data.refreshToken, + tokenType = result.data.tokenType + ) val domainUser = User( - name = result.user.name, - token = result.token, - profileImage = result.user.profileImage, - role = result.user.role + accessToken = result.data.accessToken, + refreshToken = result.data.refreshToken, + tokenType = result.data.tokenType ) Result.success(domainUser) } else { diff --git a/app/src/main/java/kr/ac/anu/mumu/domain/model/User.kt b/app/src/main/java/kr/ac/anu/mumu/domain/model/User.kt index 8056a13..c6469c9 100644 --- a/app/src/main/java/kr/ac/anu/mumu/domain/model/User.kt +++ b/app/src/main/java/kr/ac/anu/mumu/domain/model/User.kt @@ -1,8 +1,7 @@ package kr.ac.anu.mumu.domain.model data class User( - val name: String, - val token: String, - val profileImage: String?, - val role: String + val accessToken: String, + val refreshToken: String, + val tokenType: String ) diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/join/JoinViewModel.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/join/JoinViewModel.kt index 55d2428..18a4357 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/join/JoinViewModel.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/join/JoinViewModel.kt @@ -207,13 +207,10 @@ class JoinViewModel @Inject constructor( viewModelScope.launch { val request = JoinRequest( - id = inputId.value ?: "", + loginId = inputId.value ?: "", password = inputPw.value ?: "", name = inputName.value ?: "", phone = inputPhoneNum.value ?: "", - address = inputAddress.value ?: "", - detailAddress = inputDetailAddress.value ?: "", - postalCode = inputPostalCode.value ?: "", termsAgreed = isTermsAgreed.value ?: false, privacyAgreed = isPrivacyAgreed.value ?: false, marketingAgreed = isMarketingAgreed.value ?: false From f98255ab47951768d2cb613d0066b1e5660234b9 Mon Sep 17 00:00:00 2001 From: bhindor Date: Wed, 26 Aug 2026 16:10:48 +0900 Subject: [PATCH 19/21] =?UTF-8?q?feat:=20=ED=96=89=EB=8F=99=20=EB=B6=84?= =?UTF-8?q?=EC=84=9D=20=EB=B0=8F=20=EB=B6=84=EC=84=9D=20=EB=82=B4=EC=97=AD?= =?UTF-8?q?=20=EC=84=9C=EB=B2=84=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 17 +- .../mumu/data/datasource/AnalysisService.kt | 27 +++ .../mumu/data/datasource/HistoryService.kt | 20 ++ .../ac/anu/mumu/data/datasource/PetService.kt | 11 ++ .../mumu/data/mapper/AnalysisHistoryDto.kt | 36 ++-- .../kr/ac/anu/mumu/data/model/AnalysisDtos.kt | 21 ++ .../kr/ac/anu/mumu/data/model/HistoryDtos.kt | 8 +- .../data/repository/AnalysisRepositoryImpl.kt | 179 ++++++++++++++++++ .../data/repository/HistoryRepositoryImpl.kt | 55 ++++++ .../java/kr/ac/anu/mumu/di/NetworkModule.kt | 50 ++++- .../kr/ac/anu/mumu/di/RepositoryModule.kt | 17 ++ .../anu/mumu/domain/model/AnalysisHistory.kt | 5 +- .../domain/model/BehaviorAnalysisResult.kt | 10 + .../domain/repository/AnalysisRepository.kt | 7 + .../domain/repository/HistoryRepository.kt | 8 + .../analysis/AnalysisCaptureFragment.kt | 113 +++++++++++ .../presentation/analysis/AnalysisContract.kt | 12 ++ .../analysis/AnalysisLoadingFragment.kt | 91 +++++++++ .../analysis/AnalysisResultFragment.kt | 76 ++++++++ .../analysis/AnalysisStartFragment.kt | 41 ++++ .../analysis/AnalysisUploadFragment.kt | 102 ++++++++++ .../analysis/AnalysisViewModel.kt | 38 ++++ .../main/HistoryDetailFragment.kt | 77 ++++++++ .../main/HistoryDetailViewModel.kt | 47 +++++ .../mumu/presentation/main/HistoryFragment.kt | 69 +++++-- .../presentation/main/HistoryViewModel.kt | 44 +++++ .../mumu/presentation/main/HomeFragment.kt | 11 +- .../mumu/presentation/main/MainActivity.kt | 23 +++ .../main/adapter/HistoryAdapter.kt | 38 ++-- .../drawable/bg_analysis_circle_outline.xml | 5 + .../drawable/bg_analysis_circle_primary.xml | 4 + .../main/res/drawable/bg_analysis_header.xml | 6 + .../main/res/drawable/bg_analysis_item.xml | 6 + .../main/res/drawable/bg_analysis_panel.xml | 6 + .../main/res/drawable/bg_analysis_primary.xml | 5 + .../res/drawable/bg_analysis_secondary.xml | 5 + .../main/res/drawable/bg_analysis_video.xml | 5 + app/src/main/res/layout/activity_main.xml | 34 +++- .../res/layout/fragment_analysis_capture.xml | 94 +++++++++ .../res/layout/fragment_analysis_loading.xml | 94 +++++++++ .../res/layout/fragment_analysis_result.xml | 121 ++++++++++++ .../res/layout/fragment_analysis_start.xml | 87 +++++++++ .../res/layout/fragment_analysis_upload.xml | 102 ++++++++++ app/src/main/res/layout/fragment_history.xml | 63 +++++- .../res/layout/fragment_history_detail.xml | 136 +++++++++++++ app/src/main/res/layout/item_history.xml | 6 +- .../main/res/navigation/nav_graph_main.xml | 63 +++++- app/src/main/res/values/themes.xml | 12 +- app/src/main/res/xml/file_paths.xml | 6 + 49 files changed, 2035 insertions(+), 78 deletions(-) create mode 100644 app/src/main/java/kr/ac/anu/mumu/data/datasource/AnalysisService.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/data/datasource/HistoryService.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/data/datasource/PetService.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/data/model/AnalysisDtos.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/data/repository/AnalysisRepositoryImpl.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/data/repository/HistoryRepositoryImpl.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/domain/model/BehaviorAnalysisResult.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/domain/repository/AnalysisRepository.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/domain/repository/HistoryRepository.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisCaptureFragment.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisContract.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisLoadingFragment.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisResultFragment.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisStartFragment.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisUploadFragment.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisViewModel.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryDetailFragment.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryDetailViewModel.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryViewModel.kt create mode 100644 app/src/main/res/drawable/bg_analysis_circle_outline.xml create mode 100644 app/src/main/res/drawable/bg_analysis_circle_primary.xml create mode 100644 app/src/main/res/drawable/bg_analysis_header.xml create mode 100644 app/src/main/res/drawable/bg_analysis_item.xml create mode 100644 app/src/main/res/drawable/bg_analysis_panel.xml create mode 100644 app/src/main/res/drawable/bg_analysis_primary.xml create mode 100644 app/src/main/res/drawable/bg_analysis_secondary.xml create mode 100644 app/src/main/res/drawable/bg_analysis_video.xml create mode 100644 app/src/main/res/layout/fragment_analysis_capture.xml create mode 100644 app/src/main/res/layout/fragment_analysis_loading.xml create mode 100644 app/src/main/res/layout/fragment_analysis_result.xml create mode 100644 app/src/main/res/layout/fragment_analysis_start.xml create mode 100644 app/src/main/res/layout/fragment_analysis_upload.xml create mode 100644 app/src/main/res/layout/fragment_history_detail.xml create mode 100644 app/src/main/res/xml/file_paths.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5ded846..244d0f4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,6 +4,12 @@ + + + + + + + + + @@ -33,4 +48,4 @@ android:exported="false" /> - \ No newline at end of file + diff --git a/app/src/main/java/kr/ac/anu/mumu/data/datasource/AnalysisService.kt b/app/src/main/java/kr/ac/anu/mumu/data/datasource/AnalysisService.kt new file mode 100644 index 0000000..80dac51 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/data/datasource/AnalysisService.kt @@ -0,0 +1,27 @@ +package kr.ac.anu.mumu.data.datasource + +import kr.ac.anu.mumu.data.model.AnalysisDetailDto +import kr.ac.anu.mumu.data.model.AnalysisTriggerDto +import kr.ac.anu.mumu.data.model.BaseResponse +import okhttp3.MultipartBody +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Multipart +import retrofit2.http.POST +import retrofit2.http.Part +import retrofit2.http.Path +import retrofit2.http.Query + +interface AnalysisService { + @Multipart + @POST("/api/behavior-analyses") + suspend fun triggerBehaviorAnalysis( + @Query("petId") petId: Long, + @Part video: MultipartBody.Part + ): Response> + + @GET("/api/behavior-analyses/{id}") + suspend fun getBehaviorAnalysis( + @Path("id") analysisId: Long + ): Response> +} diff --git a/app/src/main/java/kr/ac/anu/mumu/data/datasource/HistoryService.kt b/app/src/main/java/kr/ac/anu/mumu/data/datasource/HistoryService.kt new file mode 100644 index 0000000..eabbad9 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/data/datasource/HistoryService.kt @@ -0,0 +1,20 @@ +package kr.ac.anu.mumu.data.datasource + +import kr.ac.anu.mumu.data.model.AnalysisHistoryDto +import kr.ac.anu.mumu.data.model.BaseResponse +import kr.ac.anu.mumu.data.model.PaginatedData +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Path +import retrofit2.http.Query + +interface HistoryService { + @GET("/api/pets/{petId}/analyses") + suspend fun getAnalysisHistory( + @Path("petId") petId: Long, + @Query("type") type: String = "behavior", + @Query("status") status: String = "completed", + @Query("page") page: Int = 0, + @Query("size") size: Int = 50 + ): Response>> +} diff --git a/app/src/main/java/kr/ac/anu/mumu/data/datasource/PetService.kt b/app/src/main/java/kr/ac/anu/mumu/data/datasource/PetService.kt new file mode 100644 index 0000000..8ac62a7 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/data/datasource/PetService.kt @@ -0,0 +1,11 @@ +package kr.ac.anu.mumu.data.datasource + +import kr.ac.anu.mumu.data.model.BaseResponse +import kr.ac.anu.mumu.data.model.PetDto +import retrofit2.Response +import retrofit2.http.GET + +interface PetService { + @GET("/api/pets") + suspend fun getMyPets(): Response>> +} diff --git a/app/src/main/java/kr/ac/anu/mumu/data/mapper/AnalysisHistoryDto.kt b/app/src/main/java/kr/ac/anu/mumu/data/mapper/AnalysisHistoryDto.kt index abafad0..11499ec 100644 --- a/app/src/main/java/kr/ac/anu/mumu/data/mapper/AnalysisHistoryDto.kt +++ b/app/src/main/java/kr/ac/anu/mumu/data/mapper/AnalysisHistoryDto.kt @@ -2,32 +2,34 @@ package kr.ac.anu.mumu.data.mapper import kr.ac.anu.mumu.data.model.AnalysisHistoryDto import kr.ac.anu.mumu.domain.model.AnalysisHistory -import java.text.SimpleDateFormat -import java.util.Locale +import java.time.OffsetDateTime +import java.time.format.DateTimeFormatter +import kotlin.math.roundToInt fun AnalysisHistoryDto.toDomain(): AnalysisHistory { - val formattedDate = try { - val parser = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()) - val formatter = SimpleDateFormat("yyyy.MM.dd", Locale.getDefault()) - val parsedDate = parser.parse(this.analyzedAt) - parsedDate?.let { formatter.format(it) } ?: this.analyzedAt - } catch (e: Exception) { - this.analyzedAt - } + val formattedDate = analyzedAt?.let { value -> + runCatching { + OffsetDateTime.parse(value).format(DateTimeFormatter.ofPattern("yyyy.MM.dd")) + }.getOrDefault(value.take(10).replace('-', '.')) + } ?: "-" - val isNormal = this.status == "정상" || this.resultLabel?.uppercase() == "NORMAL" + val probability = confidence?.roundToInt()?.coerceIn(0, 100) ?: 0 + val isNormal = resultLabel.equals("NORMAL", ignoreCase = true) || + resultLabel == "정상" || + (suspectedItems.isNullOrEmpty() && probability < 50) - val joinedBehavior = if (this.suspectedItems.isNullOrEmpty()) { - "없음" + val joinedBehavior = if (suspectedItems.isNullOrEmpty()) { + if (isNormal) "특이 행동 없음" else resultLabel ?: "분석 결과 확인" } else { - this.suspectedItems.joinToString(", ") + suspectedItems.joinToString(", ") } return AnalysisHistory( id = this.analysisId, isNormal = isNormal, behaviorText = joinedBehavior, - probability = this.confidence, - date = formattedDate + probability = probability, + date = formattedDate, + resultLabel = resultLabel ) -} \ No newline at end of file +} diff --git a/app/src/main/java/kr/ac/anu/mumu/data/model/AnalysisDtos.kt b/app/src/main/java/kr/ac/anu/mumu/data/model/AnalysisDtos.kt new file mode 100644 index 0000000..146c834 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/data/model/AnalysisDtos.kt @@ -0,0 +1,21 @@ +package kr.ac.anu.mumu.data.model + +data class AnalysisTriggerDto( + val analysisId: Long, + val status: String +) + +data class AnalysisDetailDto( + val analysisId: Long, + val type: String?, + val status: String, + val resultLabel: String?, + val suspectedItems: List?, + val confidence: Double?, + val analyzedAt: String? +) + +data class PetDto( + val petId: Long, + val name: String? +) diff --git a/app/src/main/java/kr/ac/anu/mumu/data/model/HistoryDtos.kt b/app/src/main/java/kr/ac/anu/mumu/data/model/HistoryDtos.kt index c79b946..6b1557b 100644 --- a/app/src/main/java/kr/ac/anu/mumu/data/model/HistoryDtos.kt +++ b/app/src/main/java/kr/ac/anu/mumu/data/model/HistoryDtos.kt @@ -3,7 +3,7 @@ package kr.ac.anu.mumu.data.model data class BaseResponse( val success: Boolean, val message: String, - val data: T + val data: T? ) data class PaginatedData( @@ -20,6 +20,6 @@ data class AnalysisHistoryDto( val status: String, val resultLabel: String?, val suspectedItems: List?, - val confidence: Int, - val analyzedAt: String -) \ No newline at end of file + val confidence: Double?, + val analyzedAt: String? +) diff --git a/app/src/main/java/kr/ac/anu/mumu/data/repository/AnalysisRepositoryImpl.kt b/app/src/main/java/kr/ac/anu/mumu/data/repository/AnalysisRepositoryImpl.kt new file mode 100644 index 0000000..c282203 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/data/repository/AnalysisRepositoryImpl.kt @@ -0,0 +1,179 @@ +package kr.ac.anu.mumu.data.repository + +import android.content.Context +import android.net.Uri +import android.provider.OpenableColumns +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.withContext +import kr.ac.anu.mumu.data.datasource.AnalysisService +import kr.ac.anu.mumu.data.datasource.PetService +import kr.ac.anu.mumu.data.model.AnalysisDetailDto +import kr.ac.anu.mumu.domain.model.BehaviorAnalysisResult +import kr.ac.anu.mumu.domain.repository.AnalysisRepository +import okhttp3.MediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.File +import javax.inject.Inject +import kotlin.math.roundToInt + +class AnalysisRepositoryImpl @Inject constructor( + @ApplicationContext private val context: Context, + private val analysisService: AnalysisService, + private val petService: PetService +) : AnalysisRepository { + + override suspend fun analyzeBehavior(videoUri: String): Result { + return withContext(Dispatchers.IO) { + runCatching { + val petId = getPrimaryPetId() + val uri = Uri.parse(videoUri) + val videoPart = createVideoPart(uri) + + try { + val triggerResponse = analysisService.triggerBehaviorAnalysis(petId, videoPart) + val triggerBody = triggerResponse.body() + if (!triggerResponse.isSuccessful || triggerBody?.success != true) { + error(triggerBody?.message ?: "분석 요청에 실패했습니다. (${triggerResponse.code()})") + } + val analysisId = triggerBody.data?.analysisId + ?: error("서버가 분석 ID를 반환하지 않았습니다.") + pollResult(analysisId, videoUri) + } finally { + videoPart.body().let { body -> + if (body is FileRequestBody) body.file.delete() + } + } + } + } + } + + private suspend fun getPrimaryPetId(): Long { + val response = petService.getMyPets() + val body = response.body() + if (!response.isSuccessful || body?.success != true) { + error(body?.message ?: "반려동물 정보를 불러오지 못했습니다. (${response.code()})") + } + return body.data?.firstOrNull()?.petId + ?: error("분석할 반려동물을 먼저 등록해 주세요.") + } + + private fun createVideoPart(uri: Uri): MultipartBody.Part { + val metadata = readMetadata(uri) + if (metadata.size != null && metadata.size > MAX_VIDEO_BYTES) { + error("영상은 100MB 이하만 업로드할 수 있습니다.") + } + + val extension = metadata.name.substringAfterLast('.', "mp4").lowercase() + if (extension !in SUPPORTED_EXTENSIONS) { + error("mp4, avi, mov, mkv 영상만 분석할 수 있습니다.") + } + + val temporaryFile = File.createTempFile("mumu-behavior-", ".$extension", context.cacheDir) + try { + val input = context.contentResolver.openInputStream(uri) + ?: error("선택한 영상을 열 수 없습니다.") + input.use { source -> + temporaryFile.outputStream().use(source::copyTo) + } + if (temporaryFile.length() > MAX_VIDEO_BYTES) { + error("영상은 100MB 이하만 업로드할 수 있습니다.") + } + + val mediaType = MediaType.parse(context.contentResolver.getType(uri) ?: "video/$extension") + val requestBody = FileRequestBody(mediaType, temporaryFile) + return MultipartBody.Part.createFormData("video", metadata.name, requestBody) + } catch (error: Throwable) { + temporaryFile.delete() + throw error + } + } + + private fun readMetadata(uri: Uri): VideoMetadata { + val projection = arrayOf(OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE) + context.contentResolver.query(uri, projection, null, null, null)?.use { cursor -> + if (cursor.moveToFirst()) { + val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME) + val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE) + val name = if (nameIndex >= 0) cursor.getString(nameIndex) else null + val size = if (sizeIndex >= 0 && !cursor.isNull(sizeIndex)) cursor.getLong(sizeIndex) else null + return VideoMetadata(name ?: "behavior-video.mp4", size) + } + } + return VideoMetadata("behavior-video.mp4", null) + } + + private suspend fun pollResult(analysisId: Long, videoUri: String): BehaviorAnalysisResult { + repeat(MAX_POLL_ATTEMPTS) { + val response = analysisService.getBehaviorAnalysis(analysisId) + val body = response.body() + if (!response.isSuccessful || body?.success != true) { + error(body?.message ?: "분석 결과를 불러오지 못했습니다. (${response.code()})") + } + + val detail = body.data ?: error("분석 결과가 비어 있습니다.") + when (detail.status.uppercase()) { + "COMPLETED" -> return detail.toResult(videoUri) + "FAILED" -> error("영상 분석에 실패했습니다. 다른 영상으로 다시 시도해 주세요.") + } + delay(POLL_INTERVAL_MILLIS) + } + error("분석 시간이 오래 걸리고 있습니다. 잠시 후 내역에서 결과를 확인해 주세요.") + } + + private fun AnalysisDetailDto.toResult(videoUri: String): BehaviorAnalysisResult { + val probability = confidence?.roundToInt()?.coerceIn(0, 100) ?: 0 + val items = suspectedItems.orEmpty().filter(String::isNotBlank) + val label = resultLabel.orEmpty() + val isNormal = label.equals("NORMAL", ignoreCase = true) || + label == "정상" || + (items.isEmpty() && probability < NORMAL_THRESHOLD) + val behavior = if (isNormal) { + "특이 행동 없음" + } else { + items.joinToString(", ").ifBlank { label.ifBlank { "이상 행동 의심" } } + } + val reason = if (isNormal) { + "분석 영상에서 뚜렷한 이상 행동이 감지되지 않았습니다." + } else { + "AI 분석에서 $behavior 패턴이 감지되었습니다." + } + val recommendation = if (isNormal) { + "현재 상태를 계속 관찰하고 새로운 이상 행동이 보이면 다시 분석해 주세요." + } else { + "같은 행동이 반복되면 가까운 동물병원에서 정밀 검사를 받아보세요." + } + + return BehaviorAnalysisResult( + videoUri = videoUri, + isNormal = isNormal, + probability = probability, + suspectedBehavior = behavior, + reason = reason, + recommendation = recommendation + ) + } + + private class FileRequestBody( + contentType: MediaType?, + val file: File + ) : RequestBody() { + private val delegate = RequestBody.create(contentType, file) + + override fun contentType(): MediaType? = delegate.contentType() + override fun contentLength(): Long = delegate.contentLength() + override fun writeTo(sink: okio.BufferedSink) = delegate.writeTo(sink) + } + + private data class VideoMetadata(val name: String, val size: Long?) + + private companion object { + const val MAX_VIDEO_BYTES = 100L * 1024L * 1024L + const val MAX_POLL_ATTEMPTS = 60 + const val POLL_INTERVAL_MILLIS = 5_000L + const val NORMAL_THRESHOLD = 50 + val SUPPORTED_EXTENSIONS = setOf("mp4", "avi", "mov", "mkv") + } +} diff --git a/app/src/main/java/kr/ac/anu/mumu/data/repository/HistoryRepositoryImpl.kt b/app/src/main/java/kr/ac/anu/mumu/data/repository/HistoryRepositoryImpl.kt new file mode 100644 index 0000000..1714d56 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/data/repository/HistoryRepositoryImpl.kt @@ -0,0 +1,55 @@ +package kr.ac.anu.mumu.data.repository + +import kr.ac.anu.mumu.data.datasource.AnalysisService +import kr.ac.anu.mumu.data.datasource.HistoryService +import kr.ac.anu.mumu.data.datasource.PetService +import kr.ac.anu.mumu.data.mapper.toDomain +import kr.ac.anu.mumu.data.model.AnalysisHistoryDto +import kr.ac.anu.mumu.domain.model.AnalysisHistory +import kr.ac.anu.mumu.domain.repository.HistoryRepository +import javax.inject.Inject + +class HistoryRepositoryImpl @Inject constructor( + private val historyService: HistoryService, + private val analysisService: AnalysisService, + private val petService: PetService +) : HistoryRepository { + + override suspend fun getBehaviorHistory(): Result> = runCatching { + val petId = getPrimaryPetId() + val response = historyService.getAnalysisHistory(petId) + val body = response.body() + if (!response.isSuccessful || body?.success != true) { + error(body?.message ?: "분석 내역을 불러오지 못했습니다. (${response.code()})") + } + body.data?.content.orEmpty().map(AnalysisHistoryDto::toDomain) + } + + override suspend fun getBehaviorDetail(analysisId: Long): Result = runCatching { + val response = analysisService.getBehaviorAnalysis(analysisId) + val body = response.body() + if (!response.isSuccessful || body?.success != true) { + error(body?.message ?: "분석 상세 정보를 불러오지 못했습니다. (${response.code()})") + } + val detail = body.data ?: error("분석 상세 정보가 비어 있습니다.") + AnalysisHistoryDto( + analysisId = detail.analysisId, + type = detail.type.orEmpty(), + status = detail.status, + resultLabel = detail.resultLabel, + suspectedItems = detail.suspectedItems, + confidence = detail.confidence, + analyzedAt = detail.analyzedAt + ).toDomain() + } + + private suspend fun getPrimaryPetId(): Long { + val response = petService.getMyPets() + val body = response.body() + if (!response.isSuccessful || body?.success != true) { + error(body?.message ?: "반려동물 정보를 불러오지 못했습니다. (${response.code()})") + } + return body.data?.firstOrNull()?.petId + ?: error("분석 내역을 확인할 반려동물을 먼저 등록해 주세요.") + } +} diff --git a/app/src/main/java/kr/ac/anu/mumu/di/NetworkModule.kt b/app/src/main/java/kr/ac/anu/mumu/di/NetworkModule.kt index 8c979fb..d44ff47 100644 --- a/app/src/main/java/kr/ac/anu/mumu/di/NetworkModule.kt +++ b/app/src/main/java/kr/ac/anu/mumu/di/NetworkModule.kt @@ -4,10 +4,16 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import kr.ac.anu.mumu.data.datasource.AnalysisService import kr.ac.anu.mumu.data.datasource.AuthService +import kr.ac.anu.mumu.data.datasource.HistoryService import kr.ac.anu.mumu.data.datasource.JoinService +import kr.ac.anu.mumu.data.datasource.PetService +import kr.ac.anu.mumu.data.local.SessionManager +import okhttp3.OkHttpClient import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory +import java.util.concurrent.TimeUnit import javax.inject.Singleton @Module @@ -15,9 +21,31 @@ import javax.inject.Singleton object NetworkModule { @Provides @Singleton - fun provideRetrofit(): Retrofit { + fun provideOkHttpClient(sessionManager: SessionManager): OkHttpClient { + return OkHttpClient.Builder() + .addInterceptor { chain -> + val token = sessionManager.accessToken + val request = if (token.isNullOrBlank()) { + chain.request() + } else { + chain.request().newBuilder() + .header("Authorization", "Bearer $token") + .build() + } + chain.proceed(request) + } + .connectTimeout(30, TimeUnit.SECONDS) + .writeTimeout(2, TimeUnit.MINUTES) + .readTimeout(2, TimeUnit.MINUTES) + .build() + } + + @Provides + @Singleton + fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit { return Retrofit.Builder() - .baseUrl("https://keagan-slipperier-bewilderedly.ngrok-free.dev") // 서버 주소 + .baseUrl("http://13.125.155.32:8080/") + .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build() } @@ -33,4 +61,22 @@ object NetworkModule { fun provideJoinService(retrofit: Retrofit): JoinService { return retrofit.create(JoinService::class.java) } + + @Provides + @Singleton + fun provideAnalysisService(retrofit: Retrofit): AnalysisService { + return retrofit.create(AnalysisService::class.java) + } + + @Provides + @Singleton + fun providePetService(retrofit: Retrofit): PetService { + return retrofit.create(PetService::class.java) + } + + @Provides + @Singleton + fun provideHistoryService(retrofit: Retrofit): HistoryService { + return retrofit.create(HistoryService::class.java) + } } diff --git a/app/src/main/java/kr/ac/anu/mumu/di/RepositoryModule.kt b/app/src/main/java/kr/ac/anu/mumu/di/RepositoryModule.kt index 8591104..78060a4 100644 --- a/app/src/main/java/kr/ac/anu/mumu/di/RepositoryModule.kt +++ b/app/src/main/java/kr/ac/anu/mumu/di/RepositoryModule.kt @@ -4,8 +4,12 @@ import dagger.Binds import dagger.Module import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import kr.ac.anu.mumu.data.repository.AnalysisRepositoryImpl +import kr.ac.anu.mumu.data.repository.HistoryRepositoryImpl import kr.ac.anu.mumu.data.repository.JoinRepositoryImpl import kr.ac.anu.mumu.data.repository.LoginRepositoryImpl +import kr.ac.anu.mumu.domain.repository.AnalysisRepository +import kr.ac.anu.mumu.domain.repository.HistoryRepository import kr.ac.anu.mumu.domain.repository.JoinRepository import kr.ac.anu.mumu.domain.repository.LoginRepository import javax.inject.Singleton @@ -13,6 +17,19 @@ import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) abstract class RepositoryModule { + + @Binds + @Singleton + abstract fun bindAnalysisRepository( + analysisRepositoryImpl: AnalysisRepositoryImpl + ): AnalysisRepository + + @Binds + @Singleton + abstract fun bindHistoryRepository( + historyRepositoryImpl: HistoryRepositoryImpl + ): HistoryRepository + @Binds @Singleton abstract fun bindLoginRepository( diff --git a/app/src/main/java/kr/ac/anu/mumu/domain/model/AnalysisHistory.kt b/app/src/main/java/kr/ac/anu/mumu/domain/model/AnalysisHistory.kt index 9f84896..511f4ae 100644 --- a/app/src/main/java/kr/ac/anu/mumu/domain/model/AnalysisHistory.kt +++ b/app/src/main/java/kr/ac/anu/mumu/domain/model/AnalysisHistory.kt @@ -5,5 +5,6 @@ data class AnalysisHistory( val isNormal: Boolean, val behaviorText: String, val probability: Int, - val date: String -) \ No newline at end of file + val date: String, + val resultLabel: String? +) diff --git a/app/src/main/java/kr/ac/anu/mumu/domain/model/BehaviorAnalysisResult.kt b/app/src/main/java/kr/ac/anu/mumu/domain/model/BehaviorAnalysisResult.kt new file mode 100644 index 0000000..62f5763 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/domain/model/BehaviorAnalysisResult.kt @@ -0,0 +1,10 @@ +package kr.ac.anu.mumu.domain.model + +data class BehaviorAnalysisResult( + val videoUri: String, + val isNormal: Boolean, + val probability: Int, + val suspectedBehavior: String, + val reason: String, + val recommendation: String +) diff --git a/app/src/main/java/kr/ac/anu/mumu/domain/repository/AnalysisRepository.kt b/app/src/main/java/kr/ac/anu/mumu/domain/repository/AnalysisRepository.kt new file mode 100644 index 0000000..5bc0d32 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/domain/repository/AnalysisRepository.kt @@ -0,0 +1,7 @@ +package kr.ac.anu.mumu.domain.repository + +import kr.ac.anu.mumu.domain.model.BehaviorAnalysisResult + +interface AnalysisRepository { + suspend fun analyzeBehavior(videoUri: String): Result +} diff --git a/app/src/main/java/kr/ac/anu/mumu/domain/repository/HistoryRepository.kt b/app/src/main/java/kr/ac/anu/mumu/domain/repository/HistoryRepository.kt new file mode 100644 index 0000000..b052384 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/domain/repository/HistoryRepository.kt @@ -0,0 +1,8 @@ +package kr.ac.anu.mumu.domain.repository + +import kr.ac.anu.mumu.domain.model.AnalysisHistory + +interface HistoryRepository { + suspend fun getBehaviorHistory(): Result> + suspend fun getBehaviorDetail(analysisId: Long): Result +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisCaptureFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisCaptureFragment.kt new file mode 100644 index 0000000..cee8a5b --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisCaptureFragment.kt @@ -0,0 +1,113 @@ +package kr.ac.anu.mumu.presentation.analysis + +import android.net.Uri +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.content.FileProvider +import androidx.core.os.bundleOf +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.findNavController +import kr.ac.anu.mumu.R +import kr.ac.anu.mumu.databinding.FragmentAnalysisCaptureBinding +import java.io.File + +class AnalysisCaptureFragment : Fragment() { + + private var _binding: FragmentAnalysisCaptureBinding? = null + private val binding get() = _binding!! + private var selectedVideoUri: Uri? = null + private var pendingCaptureUri: Uri? = null + + private val captureVideo = registerForActivityResult(ActivityResultContracts.CaptureVideo()) { saved -> + if (saved) { + pendingCaptureUri?.let(::showVideo) + } else { + Toast.makeText(requireContext(), "영상 촬영이 취소되었습니다.", Toast.LENGTH_SHORT).show() + } + pendingCaptureUri = null + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentAnalysisCaptureBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + savedInstanceState?.getString(STATE_SELECTED_VIDEO)?.let { showVideo(Uri.parse(it)) } + + binding.btnRecord.setOnClickListener { + val uri = createVideoUri() + pendingCaptureUri = uri + captureVideo.launch(uri) + } + binding.btnRetake.setOnClickListener { + val uri = createVideoUri() + pendingCaptureUri = uri + captureVideo.launch(uri) + } + binding.btnAnalyzeVideo.setOnClickListener { + selectedVideoUri?.let { uri -> + findNavController().navigate( + R.id.action_analysisCaptureFragment_to_analysisLoadingFragment, + bundleOf(ARG_VIDEO_URI to uri.toString()) + ) + } + } + binding.videoPreview.setOnClickListener { + if (binding.videoPreview.isPlaying) binding.videoPreview.pause() else binding.videoPreview.start() + } + } + + private fun createVideoUri(): Uri { + val directory = File(requireContext().cacheDir, "analysis-videos").apply { mkdirs() } + val file = File.createTempFile("mumu-analysis-", ".mp4", directory) + return FileProvider.getUriForFile( + requireContext(), + "${requireContext().packageName}.fileprovider", + file + ) + } + + private fun showVideo(uri: Uri) { + selectedVideoUri = uri + binding.tvCaptureGuide.visibility = View.GONE + binding.videoPreview.visibility = View.VISIBLE + binding.videoPreview.setVideoURI(uri) + binding.videoPreview.setOnPreparedListener { player -> + player.isLooping = true + binding.videoPreview.start() + } + binding.btnRecord.visibility = View.INVISIBLE + binding.btnRetake.visibility = View.VISIBLE + binding.btnAnalyzeVideo.visibility = View.VISIBLE + } + + override fun onSaveInstanceState(outState: Bundle) { + selectedVideoUri?.let { outState.putString(STATE_SELECTED_VIDEO, it.toString()) } + super.onSaveInstanceState(outState) + } + + override fun onPause() { + binding.videoPreview.pause() + super.onPause() + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + private companion object { + const val STATE_SELECTED_VIDEO = "selected_video" + } +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisContract.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisContract.kt new file mode 100644 index 0000000..b3a1c97 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisContract.kt @@ -0,0 +1,12 @@ +package kr.ac.anu.mumu.presentation.analysis + +import kr.ac.anu.mumu.domain.model.BehaviorAnalysisResult + +internal const val ARG_VIDEO_URI = "analysis_video_uri" + +sealed interface AnalysisUiState { + data object Idle : AnalysisUiState + data class Loading(val videoUri: String) : AnalysisUiState + data class Success(val result: BehaviorAnalysisResult) : AnalysisUiState + data class Error(val videoUri: String, val message: String) : AnalysisUiState +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisLoadingFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisLoadingFragment.kt new file mode 100644 index 0000000..7523974 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisLoadingFragment.kt @@ -0,0 +1,91 @@ +package kr.ac.anu.mumu.presentation.analysis + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import androidx.navigation.fragment.findNavController +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch +import kr.ac.anu.mumu.R +import kr.ac.anu.mumu.databinding.FragmentAnalysisLoadingBinding + +@AndroidEntryPoint +class AnalysisLoadingFragment : Fragment() { + + private var _binding: FragmentAnalysisLoadingBinding? = null + private val binding get() = _binding!! + private val viewModel: AnalysisViewModel by activityViewModels() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentAnalysisLoadingBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val videoUri = requireArguments().getString(ARG_VIDEO_URI).orEmpty() + require(videoUri.isNotBlank()) { "분석할 영상 URI가 필요합니다." } + viewModel.analyze(videoUri) + + binding.btnWriteDiary.setOnClickListener { + findNavController().navigate(R.id.diaryFragment) + } + binding.btnLater.setOnClickListener { + findNavController().popBackStack(R.id.homeFragment, false) + } + binding.btnRetry.setOnClickListener { + binding.btnRetry.visibility = View.GONE + binding.progressAnalysis.visibility = View.VISIBLE + binding.btnWriteDiary.visibility = View.VISIBLE + binding.btnLater.visibility = View.VISIBLE + binding.tvLoadingMessage.text = "mumu가 열심히 분석하고 있어요!..." + viewModel.analyze(videoUri) + } + + viewLifecycleOwner.lifecycleScope.launch { + viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.uiState.collect { state -> + when (state) { + is AnalysisUiState.Loading -> { + binding.progressAnalysis.visibility = View.VISIBLE + binding.btnRetry.visibility = View.GONE + binding.btnWriteDiary.visibility = View.VISIBLE + binding.btnLater.visibility = View.VISIBLE + } + is AnalysisUiState.Success -> { + if (findNavController().currentDestination?.id == R.id.analysisLoadingFragment) { + findNavController().navigate( + R.id.action_analysisLoadingFragment_to_analysisResultFragment + ) + } + } + is AnalysisUiState.Error -> { + binding.progressAnalysis.visibility = View.GONE + binding.tvLoadingMessage.text = state.message + binding.btnRetry.visibility = View.VISIBLE + binding.btnWriteDiary.visibility = View.GONE + binding.btnLater.visibility = View.GONE + } + AnalysisUiState.Idle -> Unit + } + } + } + } + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisResultFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisResultFragment.kt new file mode 100644 index 0000000..9989df3 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisResultFragment.kt @@ -0,0 +1,76 @@ +package kr.ac.anu.mumu.presentation.analysis + +import android.net.Uri +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.navigation.fragment.findNavController +import dagger.hilt.android.AndroidEntryPoint +import kr.ac.anu.mumu.R +import kr.ac.anu.mumu.databinding.FragmentAnalysisResultBinding +import kr.ac.anu.mumu.domain.model.BehaviorAnalysisResult + +@AndroidEntryPoint +class AnalysisResultFragment : Fragment() { + + private var _binding: FragmentAnalysisResultBinding? = null + private val binding get() = _binding!! + private val viewModel: AnalysisViewModel by activityViewModels() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentAnalysisResultBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val state = viewModel.uiState.value + if (state !is AnalysisUiState.Success) { + findNavController().popBackStack(R.id.homeFragment, false) + return + } + bindResult(state.result) + + binding.btnHome.setOnClickListener { + findNavController().popBackStack(R.id.homeFragment, false) + } + binding.videoResult.setOnClickListener { + if (binding.videoResult.isPlaying) binding.videoResult.pause() else binding.videoResult.start() + } + } + + private fun bindResult(result: BehaviorAnalysisResult) { + val status = if (result.isNormal) "정상" else "비정상" + val statusColor = if (result.isNormal) R.color.cardgreen else R.color.cardred + + binding.tvResultStatus.text = "분석결과: $status" + binding.tvResultStatus.setTextColor(ContextCompat.getColor(requireContext(), statusColor)) + binding.tvProbability.text = "${result.probability}% 확률" + binding.tvSuspectedBehavior.text = result.suspectedBehavior + binding.tvReason.text = "이유 : ${result.reason}\n\n추천 방향성 : ${result.recommendation}" + binding.videoResult.setVideoURI(Uri.parse(result.videoUri)) + binding.videoResult.setOnPreparedListener { player -> + player.isLooping = true + binding.videoResult.start() + } + } + + override fun onPause() { + binding.videoResult.pause() + super.onPause() + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisStartFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisStartFragment.kt new file mode 100644 index 0000000..954b307 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisStartFragment.kt @@ -0,0 +1,41 @@ +package kr.ac.anu.mumu.presentation.analysis + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.findNavController +import kr.ac.anu.mumu.R +import kr.ac.anu.mumu.databinding.FragmentAnalysisStartBinding + +class AnalysisStartFragment : Fragment() { + + private var _binding: FragmentAnalysisStartBinding? = null + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentAnalysisStartBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.btnCapture.setOnClickListener { + findNavController().navigate(R.id.action_analysisStartFragment_to_analysisCaptureFragment) + } + binding.btnUpload.setOnClickListener { + findNavController().navigate(R.id.action_analysisStartFragment_to_analysisUploadFragment) + } + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisUploadFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisUploadFragment.kt new file mode 100644 index 0000000..b32fb3f --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisUploadFragment.kt @@ -0,0 +1,102 @@ +package kr.ac.anu.mumu.presentation.analysis + +import android.database.Cursor +import android.net.Uri +import android.os.Bundle +import android.provider.OpenableColumns +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.os.bundleOf +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.findNavController +import kr.ac.anu.mumu.R +import kr.ac.anu.mumu.databinding.FragmentAnalysisUploadBinding + +class AnalysisUploadFragment : Fragment() { + + private var _binding: FragmentAnalysisUploadBinding? = null + private val binding get() = _binding!! + private var selectedVideoUri: Uri? = null + + private val selectVideo = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> + uri?.let(::showVideo) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentAnalysisUploadBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val restoredUri = savedInstanceState?.getString(STATE_SELECTED_VIDEO)?.let(Uri::parse) + if (restoredUri != null) showVideo(restoredUri) + + binding.btnSelectVideo.setOnClickListener { selectVideo.launch("video/*") } + binding.btnAnalyzeVideo.setOnClickListener { + selectedVideoUri?.let { uri -> + findNavController().navigate( + R.id.action_analysisUploadFragment_to_analysisLoadingFragment, + bundleOf(ARG_VIDEO_URI to uri.toString()) + ) + } + } + + if (savedInstanceState == null) selectVideo.launch("video/*") + } + + private fun showVideo(uri: Uri) { + selectedVideoUri = uri + binding.videoPreview.visibility = View.VISIBLE + binding.videoPreview.setVideoURI(uri) + binding.videoPreview.setOnPreparedListener { player -> + player.isLooping = true + binding.videoPreview.start() + } + binding.tvSelectedFile.text = getDisplayName(uri) ?: "선택한 영상" + binding.btnSelectVideo.text = "다른 영상 선택" + binding.btnAnalyzeVideo.visibility = View.VISIBLE + } + + private fun getDisplayName(uri: Uri): String? { + var cursor: Cursor? = null + return try { + cursor = requireContext().contentResolver.query( + uri, + arrayOf(OpenableColumns.DISPLAY_NAME), + null, + null, + null + ) + if (cursor?.moveToFirst() == true) cursor.getString(0) else null + } finally { + cursor?.close() + } + } + + override fun onSaveInstanceState(outState: Bundle) { + selectedVideoUri?.let { outState.putString(STATE_SELECTED_VIDEO, it.toString()) } + super.onSaveInstanceState(outState) + } + + override fun onPause() { + binding.videoPreview.pause() + super.onPause() + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + private companion object { + const val STATE_SELECTED_VIDEO = "selected_video" + } +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisViewModel.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisViewModel.kt new file mode 100644 index 0000000..5ad103b --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/analysis/AnalysisViewModel.kt @@ -0,0 +1,38 @@ +package kr.ac.anu.mumu.presentation.analysis + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +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 kr.ac.anu.mumu.domain.repository.AnalysisRepository +import javax.inject.Inject + +@HiltViewModel +class AnalysisViewModel @Inject constructor( + private val analysisRepository: AnalysisRepository +) : ViewModel() { + + private val _uiState = MutableStateFlow(AnalysisUiState.Idle) + val uiState: StateFlow = _uiState.asStateFlow() + + fun analyze(videoUri: String) { + val currentState = _uiState.value + if (currentState is AnalysisUiState.Loading && currentState.videoUri == videoUri) return + if (currentState is AnalysisUiState.Success && currentState.result.videoUri == videoUri) return + + viewModelScope.launch { + _uiState.value = AnalysisUiState.Loading(videoUri) + analysisRepository.analyzeBehavior(videoUri) + .onSuccess { result -> _uiState.value = AnalysisUiState.Success(result) } + .onFailure { error -> + _uiState.value = AnalysisUiState.Error( + videoUri = videoUri, + message = error.message ?: "분석 중 오류가 발생했습니다." + ) + } + } + } +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryDetailFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryDetailFragment.kt new file mode 100644 index 0000000..e142409 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryDetailFragment.kt @@ -0,0 +1,77 @@ +package kr.ac.anu.mumu.presentation.main + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch +import kr.ac.anu.mumu.R +import kr.ac.anu.mumu.databinding.FragmentHistoryDetailBinding +import kr.ac.anu.mumu.domain.model.AnalysisHistory + +@AndroidEntryPoint +class HistoryDetailFragment : Fragment() { + + private var _binding: FragmentHistoryDetailBinding? = null + private val binding get() = _binding!! + private val viewModel: HistoryDetailViewModel by viewModels() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentHistoryDetailBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + binding.btnRetry.setOnClickListener { viewModel.loadDetail() } + + viewLifecycleOwner.lifecycleScope.launch { + viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.uiState.collect(::render) + } + } + } + + private fun render(state: HistoryDetailUiState) { + binding.progressDetail.visibility = if (state is HistoryDetailUiState.Loading) View.VISIBLE else View.GONE + binding.layoutContent.visibility = if (state is HistoryDetailUiState.Success) View.VISIBLE else View.GONE + binding.layoutError.visibility = if (state is HistoryDetailUiState.Error) View.VISIBLE else View.GONE + + when (state) { + HistoryDetailUiState.Loading -> Unit + is HistoryDetailUiState.Success -> bindItem(state.item) + is HistoryDetailUiState.Error -> binding.tvError.text = state.message + } + } + + private fun bindItem(item: AnalysisHistory) { + val status = if (item.isNormal) "정상" else "비정상" + val color = if (item.isNormal) R.color.cardgreen else R.color.cardred + binding.tvResultStatus.text = "분석결과: $status" + binding.tvResultStatus.setTextColor(ContextCompat.getColor(requireContext(), color)) + binding.tvProbability.text = "${item.probability}% 확률" + binding.tvDate.text = item.date + binding.tvSuspectedBehavior.text = item.behaviorText + binding.tvReason.text = if (item.isNormal) { + "분석 영상에서 뚜렷한 이상 행동이 감지되지 않았습니다." + } else { + "AI 분석에서 ${item.behaviorText} 패턴이 감지되었습니다." + } + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryDetailViewModel.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryDetailViewModel.kt new file mode 100644 index 0000000..cd8e93e --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryDetailViewModel.kt @@ -0,0 +1,47 @@ +package kr.ac.anu.mumu.presentation.main + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +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 kr.ac.anu.mumu.domain.model.AnalysisHistory +import kr.ac.anu.mumu.domain.repository.HistoryRepository +import javax.inject.Inject + +sealed interface HistoryDetailUiState { + data object Loading : HistoryDetailUiState + data class Success(val item: AnalysisHistory) : HistoryDetailUiState + data class Error(val message: String) : HistoryDetailUiState +} + +@HiltViewModel +class HistoryDetailViewModel @Inject constructor( + savedStateHandle: SavedStateHandle, + private val historyRepository: HistoryRepository +) : ViewModel() { + + private val analysisId: Long = checkNotNull(savedStateHandle["analysisId"]) + private val _uiState = MutableStateFlow(HistoryDetailUiState.Loading) + val uiState: StateFlow = _uiState.asStateFlow() + + init { + loadDetail() + } + + fun loadDetail() { + viewModelScope.launch { + _uiState.value = HistoryDetailUiState.Loading + historyRepository.getBehaviorDetail(analysisId) + .onSuccess { item -> _uiState.value = HistoryDetailUiState.Success(item) } + .onFailure { error -> + _uiState.value = HistoryDetailUiState.Error( + error.message ?: "분석 상세 정보를 불러오지 못했습니다." + ) + } + } + } +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryFragment.kt index 047b7df..5da1ea3 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryFragment.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryFragment.kt @@ -5,21 +5,30 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch +import kr.ac.anu.mumu.R import kr.ac.anu.mumu.databinding.FragmentHistoryBinding -import kr.ac.anu.mumu.domain.model.AnalysisHistory import kr.ac.anu.mumu.presentation.main.adapter.HistoryAdapter +@AndroidEntryPoint class HistoryFragment : Fragment() { private var _binding: FragmentHistoryBinding? = null private val binding get() = _binding!! - // 어댑터 전역 변수 선언 private lateinit var historyAdapter: HistoryAdapter + private val viewModel: HistoryViewModel by viewModels() override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, + inflater: LayoutInflater, + container: ViewGroup?, savedInstanceState: Bundle? ): View { _binding = FragmentHistoryBinding.inflate(inflater, container, false) @@ -29,38 +38,56 @@ class HistoryFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - // 1. 리사이클러뷰와 어댑터 연결 setupRecyclerView() - - // 2. 데이터 불러오기 (테스트용) - // 실제로는 ViewModel에서 서버 데이터를 관찰(observe)하고 변경될 때 submitList를 호출합니다. - loadDummyData() + observeHistory() + binding.btnRetry.setOnClickListener { viewModel.loadHistory() } } private fun setupRecyclerView() { - historyAdapter = HistoryAdapter() + historyAdapter = HistoryAdapter { item -> + findNavController().navigate( + R.id.analysisHistoryDetailFragment, + Bundle().apply { putLong("analysisId", item.id) } + ) + } binding.rvHistory.apply { adapter = historyAdapter - // XML에 app:layoutManager를 설정해 두었다면 아래 줄은 생략해도 됩니다. layoutManager = LinearLayoutManager(requireContext()) } } - private fun loadDummyData() { - // 방금 만든 도메인 모델 형태에 맞춰 임시 데이터를 만듭니다. - val dummyData = listOf( - AnalysisHistory(id = 1L, isNormal = false, behaviorText = "자세 비정상, 발바닥 이상", probability = 72, date = "2026.04.15"), - AnalysisHistory(id = 2L, isNormal = true, behaviorText = "자세 비정상, 절뚝거림", probability = 72, date = "2026.04.15"), - AnalysisHistory(id = 3L, isNormal = true, behaviorText = "자세 비정상, 절뚝거림", probability = 72, date = "2026.04.15") - ) + private fun observeHistory() { + viewLifecycleOwner.lifecycleScope.launch { + viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.uiState.collect { state -> render(state) } + } + } + } + + private fun render(state: HistoryUiState) { + binding.progressHistory.visibility = if (state is HistoryUiState.Loading) View.VISIBLE else View.GONE + binding.layoutError.visibility = if (state is HistoryUiState.Error) View.VISIBLE else View.GONE - // 생성한 데이터를 어댑터에 넘겨서 화면에 그려지게 합니다. - historyAdapter.submitList(dummyData) + when (state) { + HistoryUiState.Loading -> { + binding.rvHistory.visibility = View.GONE + binding.tvEmpty.visibility = View.GONE + } + is HistoryUiState.Success -> { + historyAdapter.submitList(state.items) + binding.rvHistory.visibility = if (state.items.isEmpty()) View.GONE else View.VISIBLE + binding.tvEmpty.visibility = if (state.items.isEmpty()) View.VISIBLE else View.GONE + } + is HistoryUiState.Error -> { + binding.rvHistory.visibility = View.GONE + binding.tvEmpty.visibility = View.GONE + binding.tvError.text = state.message + } + } } override fun onDestroyView() { super.onDestroyView() - // 메모리 누수 방지 _binding = null } -} \ No newline at end of file +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryViewModel.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryViewModel.kt new file mode 100644 index 0000000..5d0c0e5 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HistoryViewModel.kt @@ -0,0 +1,44 @@ +package kr.ac.anu.mumu.presentation.main + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +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 kr.ac.anu.mumu.domain.model.AnalysisHistory +import kr.ac.anu.mumu.domain.repository.HistoryRepository +import javax.inject.Inject + +sealed interface HistoryUiState { + data object Loading : HistoryUiState + data class Success(val items: List) : HistoryUiState + data class Error(val message: String) : HistoryUiState +} + +@HiltViewModel +class HistoryViewModel @Inject constructor( + private val historyRepository: HistoryRepository +) : ViewModel() { + + private val _uiState = MutableStateFlow(HistoryUiState.Loading) + val uiState: StateFlow = _uiState.asStateFlow() + + init { + loadHistory() + } + + fun loadHistory() { + viewModelScope.launch { + _uiState.value = HistoryUiState.Loading + historyRepository.getBehaviorHistory() + .onSuccess { items -> _uiState.value = HistoryUiState.Success(items) } + .onFailure { error -> + _uiState.value = HistoryUiState.Error( + error.message ?: "분석 내역을 불러오지 못했습니다." + ) + } + } + } +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/HomeFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HomeFragment.kt index 3f01da1..03301e2 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/main/HomeFragment.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HomeFragment.kt @@ -8,12 +8,13 @@ import android.widget.ImageView import android.widget.TextView import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment +import androidx.navigation.fragment.findNavController import dagger.hilt.android.AndroidEntryPoint import kr.ac.anu.mumu.R import kr.ac.anu.mumu.databinding.FragmentHomeBinding @AndroidEntryPoint -class HomeFragment: Fragment() { +class HomeFragment : Fragment() { private var _binding: FragmentHomeBinding? = null private val binding get() = _binding!! @@ -44,6 +45,10 @@ class HomeFragment: Fragment() { setTabActive(isPeedActive = false) replaceFragment(HistoryFragment()) } + + binding.btnAnalyze.setOnClickListener { + findNavController().navigate(R.id.action_homeFragment_to_analysisStartFragment) + } } private fun replaceFragment(fragment: Fragment) { @@ -80,6 +85,4 @@ class HomeFragment: Fragment() { super.onDestroyView() _binding = null } - - -} \ No newline at end of file +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/MainActivity.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/MainActivity.kt index 7255dd5..ccccbb1 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/main/MainActivity.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/MainActivity.kt @@ -1,6 +1,7 @@ package kr.ac.anu.mumu.presentation.main import android.os.Bundle +import android.view.View import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity import androidx.core.view.ViewCompat @@ -33,6 +34,28 @@ class MainActivity : AppCompatActivity() { binding.bottomNav.setupWithNavController(navController) + val analysisDestinations = setOf( + R.id.analysisStartFragment, + R.id.analysisCaptureFragment, + R.id.analysisUploadFragment, + R.id.analysisLoadingFragment, + R.id.analysisResultFragment, + R.id.analysisHistoryDetailFragment + ) + + binding.btnBack.setOnClickListener { + navController.navigateUp() + } + + navController.addOnDestinationChangedListener { _, destination, _ -> + val isAnalysisDestination = destination.id in analysisDestinations + binding.btnBack.visibility = if (isAnalysisDestination) View.VISIBLE else View.GONE + binding.ivLogo.visibility = if (isAnalysisDestination) View.GONE else View.VISIBLE + binding.tvMumu.visibility = if (isAnalysisDestination) View.GONE else View.VISIBLE + binding.tvAnalysisMumu.visibility = if (isAnalysisDestination) View.VISIBLE else View.GONE + binding.bottomNav.visibility = if (isAnalysisDestination) View.GONE else View.VISIBLE + } + ViewCompat.setOnApplyWindowInsetsListener(binding.bottomNav) { view, windowInsets -> view.updatePadding(bottom = 0) windowInsets diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/adapter/HistoryAdapter.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/adapter/HistoryAdapter.kt index c59ba25..4b35e4f 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/main/adapter/HistoryAdapter.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/adapter/HistoryAdapter.kt @@ -1,23 +1,18 @@ package kr.ac.anu.mumu.presentation.main.adapter -import android.graphics.Color import android.view.LayoutInflater import android.view.ViewGroup import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import kr.ac.anu.mumu.R import kr.ac.anu.mumu.databinding.ItemHistoryBinding import kr.ac.anu.mumu.domain.model.AnalysisHistory class HistoryAdapter( - private var items: List = emptyList() // 초기값은 빈 리스트 -) : RecyclerView.Adapter() { - - // 외부(프래그먼트나 뷰모델)에서 데이터를 업데이트할 때 호출할 함수 - fun submitList(newItems: List) { - items = newItems - notifyDataSetChanged() // 데이터가 바뀌었음을 리사이클러뷰에 알림 - } + private val onClick: (AnalysisHistory) -> Unit +) : ListAdapter(HistoryDiffCallback) { inner class HistoryViewHolder(private val binding: ItemHistoryBinding) : RecyclerView.ViewHolder(binding.root) { @@ -25,37 +20,42 @@ class HistoryAdapter( fun bind(item: AnalysisHistory) { val context = binding.root.context - // 1. 공통 데이터 바인딩 binding.tvDate.text = item.date binding.tvProbability.text = "확률 : ${item.probability}%" - // 2. 상태(정상/비정상)에 따른 동적 UI 변경 if (item.isNormal) { - // 정상: 초록색 테두리 - val greenColor = ContextCompat.getColor(context, R.color.mumu_300) + val greenColor = ContextCompat.getColor(context, R.color.cardgreen) binding.cardResult.strokeColor = greenColor binding.tvResultStatus.text = "검사결과 : 정상" binding.tvDescription.text = "검사목록 : ${item.behaviorText}" } else { - // 비정상: 빨간색 테두리 - val redColor = Color.parseColor("#FF5252") // 또는 colors.xml에 정의한 색상 사용 + val redColor = ContextCompat.getColor(context, R.color.cardred) binding.cardResult.strokeColor = redColor binding.tvResultStatus.text = "검사결과 : 비정상" binding.tvDescription.text = "의심행동 : ${item.behaviorText}" } + binding.root.setOnClickListener { onClick(item) } } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HistoryViewHolder { val binding = ItemHistoryBinding.inflate( - LayoutInflater.from(parent.context), parent, false + LayoutInflater.from(parent.context), + parent, + false ) return HistoryViewHolder(binding) } override fun onBindViewHolder(holder: HistoryViewHolder, position: Int) { - holder.bind(items[position]) + holder.bind(getItem(position)) } - override fun getItemCount(): Int = items.size -} \ No newline at end of file + private object HistoryDiffCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: AnalysisHistory, newItem: AnalysisHistory): Boolean = + oldItem.id == newItem.id + + override fun areContentsTheSame(oldItem: AnalysisHistory, newItem: AnalysisHistory): Boolean = + oldItem == newItem + } +} diff --git a/app/src/main/res/drawable/bg_analysis_circle_outline.xml b/app/src/main/res/drawable/bg_analysis_circle_outline.xml new file mode 100644 index 0000000..70bf13d --- /dev/null +++ b/app/src/main/res/drawable/bg_analysis_circle_outline.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/bg_analysis_circle_primary.xml b/app/src/main/res/drawable/bg_analysis_circle_primary.xml new file mode 100644 index 0000000..b9d67db --- /dev/null +++ b/app/src/main/res/drawable/bg_analysis_circle_primary.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/src/main/res/drawable/bg_analysis_header.xml b/app/src/main/res/drawable/bg_analysis_header.xml new file mode 100644 index 0000000..683a1e1 --- /dev/null +++ b/app/src/main/res/drawable/bg_analysis_header.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/src/main/res/drawable/bg_analysis_item.xml b/app/src/main/res/drawable/bg_analysis_item.xml new file mode 100644 index 0000000..6e712c5 --- /dev/null +++ b/app/src/main/res/drawable/bg_analysis_item.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/src/main/res/drawable/bg_analysis_panel.xml b/app/src/main/res/drawable/bg_analysis_panel.xml new file mode 100644 index 0000000..4fde999 --- /dev/null +++ b/app/src/main/res/drawable/bg_analysis_panel.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/src/main/res/drawable/bg_analysis_primary.xml b/app/src/main/res/drawable/bg_analysis_primary.xml new file mode 100644 index 0000000..3b2feb8 --- /dev/null +++ b/app/src/main/res/drawable/bg_analysis_primary.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/bg_analysis_secondary.xml b/app/src/main/res/drawable/bg_analysis_secondary.xml new file mode 100644 index 0000000..1f15749 --- /dev/null +++ b/app/src/main/res/drawable/bg_analysis_secondary.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/bg_analysis_video.xml b/app/src/main/res/drawable/bg_analysis_video.xml new file mode 100644 index 0000000..36dbc16 --- /dev/null +++ b/app/src/main/res/drawable/bg_analysis_video.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 01b1f42..6c7d021 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -11,9 +11,24 @@ + + + + - \ No newline at end of file + diff --git a/app/src/main/res/layout/fragment_analysis_capture.xml b/app/src/main/res/layout/fragment_analysis_capture.xml new file mode 100644 index 0000000..83eaf13 --- /dev/null +++ b/app/src/main/res/layout/fragment_analysis_capture.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_analysis_loading.xml b/app/src/main/res/layout/fragment_analysis_loading.xml new file mode 100644 index 0000000..b357af5 --- /dev/null +++ b/app/src/main/res/layout/fragment_analysis_loading.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_analysis_result.xml b/app/src/main/res/layout/fragment_analysis_result.xml new file mode 100644 index 0000000..d934149 --- /dev/null +++ b/app/src/main/res/layout/fragment_analysis_result.xml @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_analysis_start.xml b/app/src/main/res/layout/fragment_analysis_start.xml new file mode 100644 index 0000000..ad484b3 --- /dev/null +++ b/app/src/main/res/layout/fragment_analysis_start.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_analysis_upload.xml b/app/src/main/res/layout/fragment_analysis_upload.xml new file mode 100644 index 0000000..04c7f0c --- /dev/null +++ b/app/src/main/res/layout/fragment_analysis_upload.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_history.xml b/app/src/main/res/layout/fragment_history.xml index 080353c..8d767e9 100644 --- a/app/src/main/res/layout/fragment_history.xml +++ b/app/src/main/res/layout/fragment_history.xml @@ -28,4 +28,65 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toBottomOf="@id/tv_detail_page" /> - \ No newline at end of file + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_history_detail.xml b/app/src/main/res/layout/fragment_history_detail.xml new file mode 100644 index 0000000..8a6d17b --- /dev/null +++ b/app/src/main/res/layout/fragment_history_detail.xml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/item_history.xml b/app/src/main/res/layout/item_history.xml index 35f22a4..2d334cf 100644 --- a/app/src/main/res/layout/item_history.xml +++ b/app/src/main/res/layout/item_history.xml @@ -5,6 +5,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="8dp" + android:clickable="true" + android:focusable="true" + android:foreground="?attr/selectableItemBackground" app:cardCornerRadius="@dimen/radius_1" app:cardElevation="0dp" app:strokeColor="@color/cardred" @@ -30,7 +33,6 @@ android:id="@+id/tv_date" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginEnd="16dp" android:fontFamily="@font/pretendard_medium" android:text="2026.07.02" android:textColor="@color/mumugray_400" @@ -64,4 +66,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/navigation/nav_graph_main.xml b/app/src/main/res/navigation/nav_graph_main.xml index 743e236..9b560f2 100644 --- a/app/src/main/res/navigation/nav_graph_main.xml +++ b/app/src/main/res/navigation/nav_graph_main.xml @@ -19,11 +19,70 @@ + tools:layout="@layout/fragment_home"> + + - \ 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 57dadef..9bc8422 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -10,4 +10,14 @@ - \ No newline at end of file + + + diff --git a/app/src/main/res/xml/file_paths.xml b/app/src/main/res/xml/file_paths.xml new file mode 100644 index 0000000..dae037f --- /dev/null +++ b/app/src/main/res/xml/file_paths.xml @@ -0,0 +1,6 @@ + + + + From 0a8d97bab7cf38b334d1ae0591149515a204090a Mon Sep 17 00:00:00 2001 From: bhindor Date: Wed, 26 Aug 2026 16:33:20 +0900 Subject: [PATCH 20/21] =?UTF-8?q?feat:=20=ED=99=88=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EA=B8=80=20=EB=AA=A9=EB=A1=9D=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 | 2 + .../mumu/data/datasource/CommunityService.kt | 16 +++++ .../anu/mumu/data/model/CommunityPostDto.kt | 19 ++++++ .../data/repository/AnalysisRepositoryImpl.kt | 8 ++- .../repository/CommunityRepositoryImpl.kt | 26 ++++++++ .../java/kr/ac/anu/mumu/di/NetworkModule.kt | 7 ++ .../kr/ac/anu/mumu/di/RepositoryModule.kt | 8 +++ .../ac/anu/mumu/domain/model/CommunityPost.kt | 7 ++ .../domain/repository/CommunityRepository.kt | 7 ++ .../mumu/presentation/main/PostFragment.kt | 55 +++++++++++++++- .../mumu/presentation/main/PostViewModel.kt | 44 +++++++++++++ .../presentation/main/adapter/PostAdapter.kt | 51 ++++++++++++++ .../main/adapter/PostGridSpacingDecoration.kt | 36 ++++++++++ app/src/main/res/layout/fragment_post.xml | 66 ++++++++++++++++++- app/src/main/res/layout/item_post.xml | 8 +-- gradle/libs.versions.toml | 3 + 16 files changed, 352 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/kr/ac/anu/mumu/data/datasource/CommunityService.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/data/model/CommunityPostDto.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/data/repository/CommunityRepositoryImpl.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/domain/model/CommunityPost.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/domain/repository/CommunityRepository.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/main/PostViewModel.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/main/adapter/PostAdapter.kt create mode 100644 app/src/main/java/kr/ac/anu/mumu/presentation/main/adapter/PostGridSpacingDecoration.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c47fe98..a6fb3e4 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -48,6 +48,8 @@ dependencies { implementation(libs.material) implementation(libs.androidx.activity) implementation(libs.androidx.constraintlayout) + implementation(libs.coil) + implementation(libs.coil.network.okhttp) implementation(libs.navigation.fragment.ktx) implementation(libs.navigation.ui.ktx) testImplementation(libs.junit) diff --git a/app/src/main/java/kr/ac/anu/mumu/data/datasource/CommunityService.kt b/app/src/main/java/kr/ac/anu/mumu/data/datasource/CommunityService.kt new file mode 100644 index 0000000..b6e2926 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/data/datasource/CommunityService.kt @@ -0,0 +1,16 @@ +package kr.ac.anu.mumu.data.datasource + +import kr.ac.anu.mumu.data.model.BaseResponse +import kr.ac.anu.mumu.data.model.CommunityPostDto +import kr.ac.anu.mumu.data.model.PaginatedData +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Query + +interface CommunityService { + @GET("/api/community") + suspend fun getPosts( + @Query("page") page: Int = 0, + @Query("size") size: Int = 50 + ): Response>> +} diff --git a/app/src/main/java/kr/ac/anu/mumu/data/model/CommunityPostDto.kt b/app/src/main/java/kr/ac/anu/mumu/data/model/CommunityPostDto.kt new file mode 100644 index 0000000..da47c2c --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/data/model/CommunityPostDto.kt @@ -0,0 +1,19 @@ +package kr.ac.anu.mumu.data.model + +data class CommunityPostDto( + val communityId: Long, + val userId: Long, + val petId: Long?, + val category: String, + val title: String, + val content: String, + val hashtags: List?, + val viewCount: Int, + val likeCount: Int, + val commentCount: Int, + val bookmarkCount: Int, + val isBest: Boolean, + val createdAt: String, + val updatedAt: String, + val thumbnailUrl: String? +) diff --git a/app/src/main/java/kr/ac/anu/mumu/data/repository/AnalysisRepositoryImpl.kt b/app/src/main/java/kr/ac/anu/mumu/data/repository/AnalysisRepositoryImpl.kt index c282203..52805ad 100644 --- a/app/src/main/java/kr/ac/anu/mumu/data/repository/AnalysisRepositoryImpl.kt +++ b/app/src/main/java/kr/ac/anu/mumu/data/repository/AnalysisRepositoryImpl.kt @@ -13,8 +13,10 @@ import kr.ac.anu.mumu.data.model.AnalysisDetailDto import kr.ac.anu.mumu.domain.model.BehaviorAnalysisResult import kr.ac.anu.mumu.domain.repository.AnalysisRepository import okhttp3.MediaType +import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MultipartBody import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody import java.io.File import javax.inject.Inject import kotlin.math.roundToInt @@ -42,7 +44,7 @@ class AnalysisRepositoryImpl @Inject constructor( ?: error("서버가 분석 ID를 반환하지 않았습니다.") pollResult(analysisId, videoUri) } finally { - videoPart.body().let { body -> + videoPart.body.let { body -> if (body is FileRequestBody) body.file.delete() } } @@ -82,7 +84,7 @@ class AnalysisRepositoryImpl @Inject constructor( error("영상은 100MB 이하만 업로드할 수 있습니다.") } - val mediaType = MediaType.parse(context.contentResolver.getType(uri) ?: "video/$extension") + val mediaType = (context.contentResolver.getType(uri) ?: "video/$extension").toMediaTypeOrNull() val requestBody = FileRequestBody(mediaType, temporaryFile) return MultipartBody.Part.createFormData("video", metadata.name, requestBody) } catch (error: Throwable) { @@ -160,7 +162,7 @@ class AnalysisRepositoryImpl @Inject constructor( contentType: MediaType?, val file: File ) : RequestBody() { - private val delegate = RequestBody.create(contentType, file) + private val delegate = file.asRequestBody(contentType) override fun contentType(): MediaType? = delegate.contentType() override fun contentLength(): Long = delegate.contentLength() diff --git a/app/src/main/java/kr/ac/anu/mumu/data/repository/CommunityRepositoryImpl.kt b/app/src/main/java/kr/ac/anu/mumu/data/repository/CommunityRepositoryImpl.kt new file mode 100644 index 0000000..d5a9b58 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/data/repository/CommunityRepositoryImpl.kt @@ -0,0 +1,26 @@ +package kr.ac.anu.mumu.data.repository + +import kr.ac.anu.mumu.data.datasource.CommunityService +import kr.ac.anu.mumu.domain.model.CommunityPost +import kr.ac.anu.mumu.domain.repository.CommunityRepository +import javax.inject.Inject + +class CommunityRepositoryImpl @Inject constructor( + private val communityService: CommunityService +) : CommunityRepository { + + override suspend fun getPosts(): Result> = runCatching { + val response = communityService.getPosts() + val body = response.body() + if (!response.isSuccessful || body?.success != true) { + error(body?.message ?: "게시글을 불러오지 못했습니다. (${response.code()})") + } + body.data?.content.orEmpty().map { post -> + CommunityPost( + id = post.communityId, + title = post.title, + thumbnailUrl = post.thumbnailUrl + ) + } + } +} diff --git a/app/src/main/java/kr/ac/anu/mumu/di/NetworkModule.kt b/app/src/main/java/kr/ac/anu/mumu/di/NetworkModule.kt index d44ff47..17f8cb4 100644 --- a/app/src/main/java/kr/ac/anu/mumu/di/NetworkModule.kt +++ b/app/src/main/java/kr/ac/anu/mumu/di/NetworkModule.kt @@ -6,6 +6,7 @@ import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import kr.ac.anu.mumu.data.datasource.AnalysisService import kr.ac.anu.mumu.data.datasource.AuthService +import kr.ac.anu.mumu.data.datasource.CommunityService import kr.ac.anu.mumu.data.datasource.HistoryService import kr.ac.anu.mumu.data.datasource.JoinService import kr.ac.anu.mumu.data.datasource.PetService @@ -79,4 +80,10 @@ object NetworkModule { fun provideHistoryService(retrofit: Retrofit): HistoryService { return retrofit.create(HistoryService::class.java) } + + @Provides + @Singleton + fun provideCommunityService(retrofit: Retrofit): CommunityService { + return retrofit.create(CommunityService::class.java) + } } diff --git a/app/src/main/java/kr/ac/anu/mumu/di/RepositoryModule.kt b/app/src/main/java/kr/ac/anu/mumu/di/RepositoryModule.kt index 78060a4..9b84967 100644 --- a/app/src/main/java/kr/ac/anu/mumu/di/RepositoryModule.kt +++ b/app/src/main/java/kr/ac/anu/mumu/di/RepositoryModule.kt @@ -5,10 +5,12 @@ import dagger.Module import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import kr.ac.anu.mumu.data.repository.AnalysisRepositoryImpl +import kr.ac.anu.mumu.data.repository.CommunityRepositoryImpl import kr.ac.anu.mumu.data.repository.HistoryRepositoryImpl import kr.ac.anu.mumu.data.repository.JoinRepositoryImpl import kr.ac.anu.mumu.data.repository.LoginRepositoryImpl import kr.ac.anu.mumu.domain.repository.AnalysisRepository +import kr.ac.anu.mumu.domain.repository.CommunityRepository import kr.ac.anu.mumu.domain.repository.HistoryRepository import kr.ac.anu.mumu.domain.repository.JoinRepository import kr.ac.anu.mumu.domain.repository.LoginRepository @@ -30,6 +32,12 @@ abstract class RepositoryModule { historyRepositoryImpl: HistoryRepositoryImpl ): HistoryRepository + @Binds + @Singleton + abstract fun bindCommunityRepository( + communityRepositoryImpl: CommunityRepositoryImpl + ): CommunityRepository + @Binds @Singleton abstract fun bindLoginRepository( diff --git a/app/src/main/java/kr/ac/anu/mumu/domain/model/CommunityPost.kt b/app/src/main/java/kr/ac/anu/mumu/domain/model/CommunityPost.kt new file mode 100644 index 0000000..08cb008 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/domain/model/CommunityPost.kt @@ -0,0 +1,7 @@ +package kr.ac.anu.mumu.domain.model + +data class CommunityPost( + val id: Long, + val title: String, + val thumbnailUrl: String? +) diff --git a/app/src/main/java/kr/ac/anu/mumu/domain/repository/CommunityRepository.kt b/app/src/main/java/kr/ac/anu/mumu/domain/repository/CommunityRepository.kt new file mode 100644 index 0000000..b5c4745 --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/domain/repository/CommunityRepository.kt @@ -0,0 +1,7 @@ +package kr.ac.anu.mumu.domain.repository + +import kr.ac.anu.mumu.domain.model.CommunityPost + +interface CommunityRepository { + suspend fun getPosts(): Result> +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/PostFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/PostFragment.kt index d124b7f..89733b7 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/main/PostFragment.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/PostFragment.kt @@ -5,24 +5,75 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import androidx.recyclerview.widget.GridLayoutManager +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch import kr.ac.anu.mumu.databinding.FragmentPostBinding +import kr.ac.anu.mumu.presentation.main.adapter.PostAdapter +import kr.ac.anu.mumu.presentation.main.adapter.PostGridSpacingDecoration +@AndroidEntryPoint class PostFragment : Fragment() { private var _binding: FragmentPostBinding? = null private val binding get() = _binding!! + private val viewModel: PostViewModel by viewModels() + private val postAdapter = PostAdapter() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { + ): View { _binding = FragmentPostBinding.inflate(inflater, container, false) return binding.root } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.rvPosts.apply { + adapter = postAdapter + layoutManager = GridLayoutManager(requireContext(), 3) + addItemDecoration(PostGridSpacingDecoration()) + } + binding.btnRetry.setOnClickListener { viewModel.loadPosts() } + + viewLifecycleOwner.lifecycleScope.launch { + viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.uiState.collect(::render) + } + } + } + + private fun render(state: PostUiState) { + binding.progressPosts.visibility = if (state is PostUiState.Loading) View.VISIBLE else View.GONE + binding.layoutError.visibility = if (state is PostUiState.Error) View.VISIBLE else View.GONE + + when (state) { + PostUiState.Loading -> { + binding.rvPosts.visibility = View.GONE + binding.tvEmpty.visibility = View.GONE + } + is PostUiState.Success -> { + postAdapter.submitList(state.posts) + binding.rvPosts.visibility = if (state.posts.isEmpty()) View.GONE else View.VISIBLE + binding.tvEmpty.visibility = if (state.posts.isEmpty()) View.VISIBLE else View.GONE + } + is PostUiState.Error -> { + binding.rvPosts.visibility = View.GONE + binding.tvEmpty.visibility = View.GONE + binding.tvError.text = state.message + } + } + } + override fun onDestroyView() { super.onDestroyView() _binding = null } -} \ No newline at end of file +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/PostViewModel.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/PostViewModel.kt new file mode 100644 index 0000000..379c6fe --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/PostViewModel.kt @@ -0,0 +1,44 @@ +package kr.ac.anu.mumu.presentation.main + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +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 kr.ac.anu.mumu.domain.model.CommunityPost +import kr.ac.anu.mumu.domain.repository.CommunityRepository +import javax.inject.Inject + +sealed interface PostUiState { + data object Loading : PostUiState + data class Success(val posts: List) : PostUiState + data class Error(val message: String) : PostUiState +} + +@HiltViewModel +class PostViewModel @Inject constructor( + private val communityRepository: CommunityRepository +) : ViewModel() { + + private val _uiState = MutableStateFlow(PostUiState.Loading) + val uiState: StateFlow = _uiState.asStateFlow() + + init { + loadPosts() + } + + fun loadPosts() { + viewModelScope.launch { + _uiState.value = PostUiState.Loading + communityRepository.getPosts() + .onSuccess { posts -> _uiState.value = PostUiState.Success(posts) } + .onFailure { error -> + _uiState.value = PostUiState.Error( + error.message ?: "게시글을 불러오지 못했습니다." + ) + } + } + } +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/adapter/PostAdapter.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/adapter/PostAdapter.kt new file mode 100644 index 0000000..e4245aa --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/adapter/PostAdapter.kt @@ -0,0 +1,51 @@ +package kr.ac.anu.mumu.presentation.main.adapter + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import coil3.load +import kr.ac.anu.mumu.R +import kr.ac.anu.mumu.databinding.ItemPostBinding +import kr.ac.anu.mumu.domain.model.CommunityPost + +class PostAdapter : ListAdapter(PostDiffCallback) { + + class PostViewHolder( + private val binding: ItemPostBinding + ) : RecyclerView.ViewHolder(binding.root) { + + fun bind(post: CommunityPost) { + binding.ivPostImage.contentDescription = post.title + if (post.thumbnailUrl.isNullOrBlank()) { + binding.ivPostImage.setImageResource(R.drawable.ic_diary) + } else { + binding.ivPostImage.load(post.thumbnailUrl) + } + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PostViewHolder { + val binding = ItemPostBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + return PostViewHolder(binding) + } + + override fun onBindViewHolder(holder: PostViewHolder, position: Int) { + holder.bind(getItem(position)) + } + + private object PostDiffCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: CommunityPost, newItem: CommunityPost): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSame(oldItem: CommunityPost, newItem: CommunityPost): Boolean { + return oldItem == newItem + } + } +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/adapter/PostGridSpacingDecoration.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/adapter/PostGridSpacingDecoration.kt new file mode 100644 index 0000000..c00203c --- /dev/null +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/adapter/PostGridSpacingDecoration.kt @@ -0,0 +1,36 @@ +package kr.ac.anu.mumu.presentation.main.adapter + +import android.graphics.Rect +import android.view.View +import androidx.recyclerview.widget.RecyclerView + +class PostGridSpacingDecoration : RecyclerView.ItemDecoration() { + + override fun getItemOffsets( + outRect: Rect, + view: View, + parent: RecyclerView, + state: RecyclerView.State + ) { + val position = parent.getChildAdapterPosition(view) + if (position == RecyclerView.NO_POSITION) return + + when (position % SPAN_COUNT) { + 0 -> outRect.set(9.dp(view), 0, 2.dp(view), rowTop(position, view)) + 1 -> outRect.set(6.dp(view), 0, 5.dp(view), rowTop(position, view)) + 2 -> outRect.set(2.dp(view), 0, 9.dp(view), rowTop(position, view)) + } + } + + private fun rowTop(position: Int, view: View): Int { + return if (position < SPAN_COUNT) 0 else 8.dp(view) + } + + private fun Int.dp(view: View): Int { + return (this * view.resources.displayMetrics.density).toInt() + } + + private companion object { + const val SPAN_COUNT = 3 + } +} diff --git a/app/src/main/res/layout/fragment_post.xml b/app/src/main/res/layout/fragment_post.xml index 715ee39..ed1aec2 100644 --- a/app/src/main/res/layout/fragment_post.xml +++ b/app/src/main/res/layout/fragment_post.xml @@ -9,10 +9,72 @@ - \ No newline at end of file + + + + + + + + + + + + diff --git a/app/src/main/res/layout/item_post.xml b/app/src/main/res/layout/item_post.xml index f335351..5ad9450 100644 --- a/app/src/main/res/layout/item_post.xml +++ b/app/src/main/res/layout/item_post.xml @@ -2,17 +2,17 @@ + android:layout_height="wrap_content"> - \ No newline at end of file + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ab4e9b3..effce90 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,6 +14,7 @@ lifecycleViewmodelKtx = "2.10.0" material = "1.13.0" activity = "1.12.1" constraintlayout = "2.2.1" +coil = "3.2.0" navigationFragmentKtx = "2.9.7" retrofit2 = "2.9.0" navigationFragmentKtxVersion = "2.9.8" @@ -38,6 +39,8 @@ kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutine material = { group = "com.google.android.material", name = "material", version.ref = "material" } androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" } androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } +coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" } +coil-network-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil" } retrofit2 = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit2" } navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigationFragmentKtxVersion" } navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigationUiKtx" } From 6a059a5bc224bd0eabc81545d0fd3c9f4c41f0e3 Mon Sep 17 00:00:00 2001 From: bhindor Date: Thu, 27 Aug 2026 09:09:53 +0900 Subject: [PATCH 21/21] =?UTF-8?q?=F0=9F=8E=A8=20::=20ktlint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/kr/ac/anu/mumu/presentation/main/CommFragment.kt | 3 +-- .../java/kr/ac/anu/mumu/presentation/main/DiaryFragment.kt | 3 +-- .../java/kr/ac/anu/mumu/presentation/main/HospitalFragment.kt | 2 +- .../java/kr/ac/anu/mumu/presentation/main/MainViewModel.kt | 3 +-- .../main/java/kr/ac/anu/mumu/presentation/main/MyFragment.kt | 2 +- 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/CommFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/CommFragment.kt index 02ed13b..e89d586 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/main/CommFragment.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/CommFragment.kt @@ -27,5 +27,4 @@ class CommFragment : Fragment() { super.onDestroyView() _binding = null } - -} \ No newline at end of file +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/DiaryFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/DiaryFragment.kt index 9b0bf2a..6d62481 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/main/DiaryFragment.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/DiaryFragment.kt @@ -27,5 +27,4 @@ class DiaryFragment : Fragment() { super.onDestroyView() _binding = null } - -} \ No newline at end of file +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/HospitalFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HospitalFragment.kt index 410521b..966a939 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/main/HospitalFragment.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/HospitalFragment.kt @@ -27,4 +27,4 @@ class HospitalFragment : Fragment() { super.onDestroyView() _binding = null } -} \ No newline at end of file +} diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/MainViewModel.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/MainViewModel.kt index 951029d..d18439d 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/main/MainViewModel.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/MainViewModel.kt @@ -5,5 +5,4 @@ import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @HiltViewModel -class MainViewModel @Inject constructor() : ViewModel() { -} \ No newline at end of file +class MainViewModel @Inject constructor() : ViewModel() diff --git a/app/src/main/java/kr/ac/anu/mumu/presentation/main/MyFragment.kt b/app/src/main/java/kr/ac/anu/mumu/presentation/main/MyFragment.kt index 1d3484d..20ec90d 100644 --- a/app/src/main/java/kr/ac/anu/mumu/presentation/main/MyFragment.kt +++ b/app/src/main/java/kr/ac/anu/mumu/presentation/main/MyFragment.kt @@ -27,4 +27,4 @@ class MyFragment : Fragment() { super.onDestroyView() _binding = null } -} \ No newline at end of file +}