diff --git a/core/navigation/src/main/java/in/koreatech/koin/core/navigation/Navigator.kt b/core/navigation/src/main/java/in/koreatech/koin/core/navigation/Navigator.kt
index fa93473539..87220d59d0 100644
--- a/core/navigation/src/main/java/in/koreatech/koin/core/navigation/Navigator.kt
+++ b/core/navigation/src/main/java/in/koreatech/koin/core/navigation/Navigator.kt
@@ -29,4 +29,8 @@ interface Navigator {
fun navigateToStore(
context: Context
): Intent
+
+ fun navigateToChatRoom(
+ context: Context
+ ): Intent
}
diff --git a/domain/src/main/java/in/koreatech/koin/domain/util/DateFormatUtil.kt b/domain/src/main/java/in/koreatech/koin/domain/util/DateFormatUtil.kt
index ccbf4fb7e2..962fe959b7 100644
--- a/domain/src/main/java/in/koreatech/koin/domain/util/DateFormatUtil.kt
+++ b/domain/src/main/java/in/koreatech/koin/domain/util/DateFormatUtil.kt
@@ -1,6 +1,7 @@
package `in`.koreatech.koin.domain.util
-import java.text.SimpleDateFormat
+import java.time.LocalDate
+import java.time.format.DateTimeFormatter
import java.util.Calendar
import java.util.Date
import java.util.Locale
@@ -19,11 +20,12 @@ object DateFormatUtil {
/**
* yyyy-MM-dd HH:mm:ss -> MM.dd
*/
- fun getSimpleMonthAndDay(dateString: String): String {
- val originalFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
- val targetFormat = SimpleDateFormat("MM.dd", Locale.getDefault())
- val date = originalFormat.parse(dateString)
- return targetFormat.format(date)
+ fun getSimpleMonthAndDay(date: LocalDate): String {
+ return DateTimeFormatter.ofPattern("MM.dd").format(date)
+ }
+
+ fun getFullDate(date: LocalDate): String {
+ return DateTimeFormatter.ofPattern("yyyy-MM-dd").format(date)
}
fun dayOfWeekToIndex(dayOfWeek: String): Int {
diff --git a/feature/lostandfound/.gitignore b/feature/article/.gitignore
similarity index 100%
rename from feature/lostandfound/.gitignore
rename to feature/article/.gitignore
diff --git a/feature/lostandfound/build.gradle.kts b/feature/article/build.gradle.kts
similarity index 64%
rename from feature/lostandfound/build.gradle.kts
rename to feature/article/build.gradle.kts
index 2f6ee7c838..10890292ba 100644
--- a/feature/lostandfound/build.gradle.kts
+++ b/feature/article/build.gradle.kts
@@ -5,7 +5,12 @@ plugins {
}
android {
- namespace = "in.koreatech.koin.feature.lostandfound"
+ namespace = "in.koreatech.koin.feature.article"
+
+ buildFeatures {
+ dataBinding = true
+ viewBinding = true
+ }
}
dependencies {
@@ -14,13 +19,17 @@ dependencies {
implementation(projects.core.onboarding)
implementation(projects.core.designsystem)
implementation(projects.core.analytics)
+ implementation(projects.core.navigation)
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
+ implementation(libs.androidx.navigation.fragment.ktx)
+ implementation(libs.androidx.navigation.ui.ktx)
implementation(libs.material)
implementation(libs.coil.compose)
implementation(libs.coil.gif)
+ implementation(libs.glide)
implementation(libs.timber)
}
diff --git a/feature/lostandfound/consumer-rules.pro b/feature/article/consumer-rules.pro
similarity index 100%
rename from feature/lostandfound/consumer-rules.pro
rename to feature/article/consumer-rules.pro
diff --git a/feature/lostandfound/proguard-rules.pro b/feature/article/proguard-rules.pro
similarity index 100%
rename from feature/lostandfound/proguard-rules.pro
rename to feature/article/proguard-rules.pro
diff --git a/feature/article/src/main/AndroidManifest.xml b/feature/article/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..b2fafaca0e
--- /dev/null
+++ b/feature/article/src/main/AndroidManifest.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/ArticleActivity.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ArticleActivity.kt
similarity index 91%
rename from koin/src/main/java/in/koreatech/koin/ui/article/ArticleActivity.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ArticleActivity.kt
index 8bd2e31ed3..f4e5efa9d8 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/ArticleActivity.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ArticleActivity.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.ui.article
+package `in`.koreatech.koin.feature.article
import android.content.Intent
import android.os.Bundle
@@ -10,7 +10,6 @@ import androidx.core.view.updatePadding
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import dagger.hilt.android.AndroidEntryPoint
-import `in`.koreatech.koin.R
import `in`.koreatech.koin.core.activity.ActivityBase
import `in`.koreatech.koin.core.analytics.AnalyticsConstant
import `in`.koreatech.koin.core.analytics.EventAction
@@ -20,9 +19,11 @@ import `in`.koreatech.koin.core.navigation.utils.EXTRA_BOARD_ID
import `in`.koreatech.koin.core.navigation.utils.EXTRA_ID
import `in`.koreatech.koin.core.util.dataBinding
import `in`.koreatech.koin.core.util.whiteStatusBar
-import `in`.koreatech.koin.databinding.ActivityArticleBinding
-import `in`.koreatech.koin.ui.article.ArticleDetailFragment.Companion.ARTICLE_ID
-import `in`.koreatech.koin.ui.article.ArticleDetailFragment.Companion.NAVIGATED_BOARD_ID
+import `in`.koreatech.koin.feature.article.databinding.ActivityArticleBinding
+import `in`.koreatech.koin.feature.article.enums.ArticleBoardType
+import `in`.koreatech.koin.feature.article.model.ArticleToolbarState
+import `in`.koreatech.koin.feature.article.ui.article.detail.ArticleDetailFragment.Companion.ARTICLE_ID
+import `in`.koreatech.koin.feature.article.ui.article.detail.ArticleDetailFragment.Companion.NAVIGATED_BOARD_ID
import timber.log.Timber
@AndroidEntryPoint
@@ -48,10 +49,9 @@ class ArticleActivity : ActivityBase() {
window.whiteStatusBar()
- val navHostFragment =
- supportFragmentManager.findFragmentById(
- R.id.nav_host_article_fragment
- ) as NavHostFragment
+ val navHostFragment = supportFragmentManager.findFragmentById(
+ R.id.nav_host_article_fragment
+ ) as NavHostFragment
navController = navHostFragment.navController
navController.addOnDestinationChangedListener { _, dest, _ ->
@@ -63,9 +63,11 @@ class ArticleActivity : ActivityBase() {
R.id.articleLostAndFoundWriteLostFragment -> setToolbar(
ArticleToolbarState.ARTICLE_LOSTANDFOUND_LOST_ITEM
)
+
R.id.articleLostAndFoundWriteFoundFragment -> setToolbar(
ArticleToolbarState.ARTICLE_LOSTANDFOUND_FOUND_ITEM
)
+
R.id.articleLostAndFoundDetailFragment -> setToolbar(
ArticleToolbarState.ARTICLE_DETAIL
)
@@ -99,6 +101,7 @@ class ArticleActivity : ActivityBase() {
R.id.articleKeywordFragment
) // See ArticleKeywordFragment, LoginActivity
}
+
"article_detail" -> {
setNavigationGraph()
val articleId = uri.getQueryParameter("article_id")?.toIntOrNull() ?: 0
@@ -112,9 +115,11 @@ class ArticleActivity : ActivityBase() {
)
)
}
+
"article_lost_and_found" -> {
setNavigationGraph(ArticleBoardType.LOSTANDFOUND.id)
}
+
null -> {
val bundle = intent.getBundleExtra(BUNDLE_ARTICLE_EXTRA_KEY)
bundle?.getInt(START_BOARD)?.let {
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/Constant.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/Constant.kt
similarity index 75%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/Constant.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/Constant.kt
index d7007c7093..3e1421d71d 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/Constant.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/Constant.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound
+package `in`.koreatech.koin.feature.article
const val IMAGE_MAX_COUNT = 10
const val DESCRIPTION_MAX_LENGTH = 1000
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/lostandfound/LostAndFoundReportActivity.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/LostAndFoundReportActivity.kt
similarity index 68%
rename from koin/src/main/java/in/koreatech/koin/ui/article/lostandfound/LostAndFoundReportActivity.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/LostAndFoundReportActivity.kt
index 3345bd3eed..0502e7fc99 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/lostandfound/LostAndFoundReportActivity.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/LostAndFoundReportActivity.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.ui.article.lostandfound
+package `in`.koreatech.koin.feature.article
import android.content.Intent
import android.os.Bundle
@@ -7,10 +7,8 @@ import androidx.activity.compose.setContent
import androidx.core.os.bundleOf
import dagger.hilt.android.AndroidEntryPoint
import `in`.koreatech.koin.core.designsystem.util.enableEdgeToEdgeWithDarkStatusBar
-import `in`.koreatech.koin.feature.lostandfound.ui.report.LostAndFoundReport
-import `in`.koreatech.koin.ui.article.ArticleActivity
-import `in`.koreatech.koin.ui.article.ArticleActivity.Companion.BUNDLE_ARTICLE_EXTRA_KEY
-import `in`.koreatech.koin.ui.article.ArticleBoardType
+import `in`.koreatech.koin.feature.article.enums.ArticleBoardType
+import `in`.koreatech.koin.feature.article.ui.lostandfound.report.LostAndFoundReport
@AndroidEntryPoint
class LostAndFoundReportActivity : ComponentActivity() {
@@ -24,9 +22,9 @@ class LostAndFoundReportActivity : ComponentActivity() {
startActivity(
Intent(this, ArticleActivity::class.java).apply {
putExtra(
- BUNDLE_ARTICLE_EXTRA_KEY,
+ ArticleActivity.Companion.BUNDLE_ARTICLE_EXTRA_KEY,
bundleOf(
- ArticleActivity.START_BOARD to ArticleBoardType.LOSTANDFOUND.id
+ ArticleActivity.Companion.START_BOARD to ArticleBoardType.LOSTANDFOUND.id
)
)
}
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/component/Dropdown.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/component/Dropdown.kt
similarity index 93%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/component/Dropdown.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/component/Dropdown.kt
index 43dd032c0e..a05199d985 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/component/Dropdown.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/component/Dropdown.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.component
+package `in`.koreatech.koin.feature.article.component
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
@@ -26,7 +26,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import `in`.koreatech.koin.core.designsystem.noRippleClickable
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.R
+import `in`.koreatech.koin.feature.article.R
/**
* Dropdown Component
@@ -49,8 +49,7 @@ fun Dropdown(
)
Row(
- modifier =
- Modifier
+ modifier = Modifier
.clip(KoinTheme.shapes.medium)
.background(
color = KoinTheme.colors.info200
@@ -81,8 +80,7 @@ fun Dropdown(
* @see [androidx.compose.material3.DropdownMenu]
*/
DropdownMenu(
- modifier =
- Modifier
+ modifier = Modifier
.width(96.dp)
.padding(0.dp),
expanded = isDropdownExpanded,
@@ -92,8 +90,7 @@ fun Dropdown(
shadowElevation = 0.dp
) {
Box(
- modifier =
- Modifier
+ modifier = Modifier
.fillMaxSize()
.clip(KoinTheme.shapes.medium)
.background(
@@ -106,8 +103,7 @@ fun Dropdown(
text = it,
style = KoinTheme.typography.medium14.copy(textAlign = TextAlign.Center),
color = KoinTheme.colors.primary600,
- modifier =
- Modifier
+ modifier = Modifier
.fillMaxWidth()
.noRippleClickable {
onItemSelected(index)
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/component/HotArticle.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/component/HotArticle.kt
similarity index 84%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/component/HotArticle.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/component/HotArticle.kt
index 5be5167253..cb0b93d01c 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/component/HotArticle.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/component/HotArticle.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.component
+package `in`.koreatech.koin.feature.article.component
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -18,9 +18,9 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import `in`.koreatech.koin.core.designsystem.noRippleClickable
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.R
-import `in`.koreatech.koin.feature.lostandfound.enums.ArticleBoardType
-import `in`.koreatech.koin.feature.lostandfound.model.ArticleHeaderState
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.enums.ArticleBoardType
+import `in`.koreatech.koin.feature.article.model.ArticleHeaderState
@Composable
fun HotArticle(
@@ -37,8 +37,7 @@ fun HotArticle(
hotArticleList.forEach { hotArticle ->
HotArticleItem(
- hotArticleData =
- HotArticleData(
+ hotArticleData = HotArticleData(
articleId = hotArticle.id,
articleTitle = hotArticle.title,
board = hotArticle.board
@@ -57,8 +56,7 @@ fun HotArticleItem(
navigateToHotArticle: (HotArticleData) -> Unit
) {
Row(
- modifier =
- modifier
+ modifier = modifier
.fillMaxWidth()
.noRippleClickable { navigateToHotArticle(hotArticleData) }
.padding(vertical = 12.dp, horizontal = 24.dp),
@@ -66,8 +64,7 @@ fun HotArticleItem(
) {
Text(
text = stringResource(hotArticleData.board.koreanName),
- style =
- KoinTheme.typography.bold12.copy(
+ style = KoinTheme.typography.bold12.copy(
fontWeight = FontWeight.SemiBold,
color = KoinTheme.colors.primary600
)
@@ -77,8 +74,7 @@ fun HotArticleItem(
text = hotArticleData.articleTitle,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
- style =
- KoinTheme.typography.bold14.copy(
+ style = KoinTheme.typography.bold14.copy(
fontWeight = FontWeight.SemiBold,
color = Color.Black
)
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/component/ItemTypeChip.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/component/ItemTypeChip.kt
similarity index 90%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/component/ItemTypeChip.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/component/ItemTypeChip.kt
index 95b2a95f14..a6d8ede8db 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/component/ItemTypeChip.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/component/ItemTypeChip.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.component
+package `in`.koreatech.koin.feature.article.component
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
@@ -8,7 +8,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
-import `in`.koreatech.koin.feature.lostandfound.enums.LostItemCategory
+import `in`.koreatech.koin.feature.article.enums.LostItemCategory
@Composable
fun ItemTypeChip(
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/component/KeywordChipGroup.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/component/KeywordChipGroup.kt
similarity index 98%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/component/KeywordChipGroup.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/component/KeywordChipGroup.kt
index be512947e1..f4d70cde8f 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/component/KeywordChipGroup.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/component/KeywordChipGroup.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.component
+package `in`.koreatech.koin.feature.article.component
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@@ -118,8 +118,7 @@ internal fun LostAndFoundTextChipScrollGroup(
.drawWithContent {
drawContent()
drawRect(
- brush =
- Brush.horizontalGradient(
+ brush = Brush.horizontalGradient(
0f to Color.White,
0.1f to Color.Transparent,
0.9f to Color.Transparent,
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/component/LoadingDialog.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/component/LoadingDialog.kt
similarity index 90%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/component/LoadingDialog.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/component/LoadingDialog.kt
index 556b4683de..827b2990f6 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/component/LoadingDialog.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/component/LoadingDialog.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.component
+package `in`.koreatech.koin.feature.article.component
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Row
@@ -16,7 +16,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.R
+import `in`.koreatech.koin.feature.article.R
@Composable
fun LoadingDialog() {
@@ -25,8 +25,7 @@ fun LoadingDialog() {
properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false)
) {
Row(
- modifier =
- Modifier
+ modifier = Modifier
.background(KoinTheme.colors.primary500)
.padding(vertical = 24.dp, horizontal = 24.dp),
verticalAlignment = Alignment.CenterVertically
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/component/LostItemTypeChip.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/component/LostItemTypeChip.kt
similarity index 90%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/component/LostItemTypeChip.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/component/LostItemTypeChip.kt
index dece3e53a4..b33bc87df9 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/component/LostItemTypeChip.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/component/LostItemTypeChip.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.component
+package `in`.koreatech.koin.feature.article.component
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.shape.RoundedCornerShape
@@ -11,7 +11,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import `in`.koreatech.koin.core.designsystem.component.chip.TextChipDefaults
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.enums.LostItemCategory
+import `in`.koreatech.koin.feature.article.enums.LostItemCategory
/**
* 분실물 종류 칩
@@ -48,8 +48,7 @@ fun ReadOnlyTextChip(
showClickRipple = false,
onSelect = {},
contentPadding = contentPadding,
- chipColors =
- TextChipDefaults.chipColors(
+ chipColors = TextChipDefaults.chipColors(
selectedContainerColor = chipColor,
unselectedContainerColor = chipColor,
selectedContentColor = textColor,
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/enums/ArticleBoardType.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/enums/ArticleBoardType.kt
similarity index 74%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/enums/ArticleBoardType.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/enums/ArticleBoardType.kt
index 0db5a7969d..a13cd13231 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/enums/ArticleBoardType.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/enums/ArticleBoardType.kt
@@ -1,11 +1,11 @@
-package `in`.koreatech.koin.feature.lostandfound.enums
+package `in`.koreatech.koin.feature.article.enums
/*
Included from main koin module because we can't access ArticleBoardType from lostandfound module
*/
import androidx.annotation.StringRes
-import `in`.koreatech.koin.feature.lostandfound.R
+import `in`.koreatech.koin.feature.article.R
enum class ArticleBoardType(
val id: Int,
@@ -22,7 +22,24 @@ enum class ArticleBoardType(
RECRUIT(8, R.string.article_recruit, R.string.article_recruit_simple, LinkType.STEMS),
IPP(12, R.string.article_ipp, R.string.article_ipp_simple, LinkType.PORTAL),
STUDENT(13, R.string.article_student, R.string.article_student_simple, LinkType.PORTAL, false),
- KOIN(9, R.string.article_koin, R.string.article_koin, LinkType.NONE, false)
+ KOIN(9, R.string.article_koin, R.string.article_koin, LinkType.NONE, false);
+
+ companion object {
+ fun fromId(id: Int): ArticleBoardType {
+ return when (id) {
+ 4 -> ALL
+ 14 -> LOSTANDFOUND
+ 5 -> NORMAL
+ 6 -> SCHOLARSHIP
+ 7 -> SCHOOL
+ 8 -> RECRUIT
+ 12 -> IPP
+ 13 -> STUDENT
+ 9 -> KOIN
+ else -> ALL
+ }
+ }
+ }
}
/**
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/enums/LostItemCategory.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/enums/LostItemCategory.kt
similarity index 91%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/enums/LostItemCategory.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/enums/LostItemCategory.kt
index 97999a9bea..5c640f6e71 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/enums/LostItemCategory.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/enums/LostItemCategory.kt
@@ -1,7 +1,7 @@
-package `in`.koreatech.koin.feature.lostandfound.enums
+package `in`.koreatech.koin.feature.article.enums
import androidx.annotation.StringRes
-import `in`.koreatech.koin.feature.lostandfound.R
+import `in`.koreatech.koin.feature.article.R
enum class LostItemCategory(
val id: Int,
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/enums/LostOrFoundType.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/enums/LostOrFoundType.kt
similarity index 64%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/enums/LostOrFoundType.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/enums/LostOrFoundType.kt
index f723894911..7d46205c58 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/enums/LostOrFoundType.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/enums/LostOrFoundType.kt
@@ -1,7 +1,7 @@
-package `in`.koreatech.koin.feature.lostandfound.enums
+package `in`.koreatech.koin.feature.article.enums
import androidx.annotation.StringRes
-import `in`.koreatech.koin.feature.lostandfound.R
+import `in`.koreatech.koin.feature.article.R
enum class LostOrFoundType(
@StringRes val stringRes: Int
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/enums/ReportReason.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/enums/ReportReason.kt
similarity index 88%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/enums/ReportReason.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/enums/ReportReason.kt
index 5411fd9bfe..0599df02ac 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/enums/ReportReason.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/enums/ReportReason.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.enums
+package `in`.koreatech.koin.feature.article.enums
enum class ReportReason(val title: String, val description: String) {
OFF_TOPIC("주제에 맞지 않음", "분실물과 관련 없는 글입니다."),
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/model/ArticleHeaderState.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/model/ArticleHeaderState.kt
similarity index 78%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/model/ArticleHeaderState.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/model/ArticleHeaderState.kt
index 944cdf2cec..acdefd5358 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/model/ArticleHeaderState.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/model/ArticleHeaderState.kt
@@ -1,15 +1,13 @@
-package `in`.koreatech.koin.feature.lostandfound.model
+package `in`.koreatech.koin.feature.article.model
import android.os.Parcelable
import `in`.koreatech.koin.domain.model.article.ArticleHeader
-import `in`.koreatech.koin.feature.lostandfound.enums.ArticleBoardType
+import `in`.koreatech.koin.feature.article.enums.ArticleBoardType
import java.time.LocalDate
import kotlinx.parcelize.Parcelize
/**
* For hot articles
- * from main koin module
- * @see `in`.koreatech.koin.feature.main.model.ArticleHeaderState
*/
@Parcelize
data class ArticleHeaderState(
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/ArticleToolbarState.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/model/ArticleToolbarState.kt
similarity index 86%
rename from koin/src/main/java/in/koreatech/koin/ui/article/ArticleToolbarState.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/model/ArticleToolbarState.kt
index 0765edd706..446add0411 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/ArticleToolbarState.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/model/ArticleToolbarState.kt
@@ -1,8 +1,8 @@
-package `in`.koreatech.koin.ui.article
+package `in`.koreatech.koin.feature.article.model
import androidx.annotation.MenuRes
import androidx.annotation.StringRes
-import `in`.koreatech.koin.R
+import `in`.koreatech.koin.feature.article.R
enum class ArticleToolbarState(
@StringRes val title: Int,
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/adapter/ArticleAdapter.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/adapter/ArticleAdapter.kt
similarity index 59%
rename from koin/src/main/java/in/koreatech/koin/ui/article/adapter/ArticleAdapter.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/adapter/ArticleAdapter.kt
index 415e67604a..54de204a53 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/adapter/ArticleAdapter.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/adapter/ArticleAdapter.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.ui.article.adapter
+package `in`.koreatech.koin.feature.article.ui.article.adapter
import android.text.TextUtils
import android.view.LayoutInflater
@@ -6,10 +6,11 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
-import `in`.koreatech.koin.databinding.ItemArticleHeaderBinding
import `in`.koreatech.koin.domain.util.DateFormatUtil
-import `in`.koreatech.koin.domain.util.TimeUtil
-import `in`.koreatech.koin.ui.article.state.ArticleHeaderState
+import `in`.koreatech.koin.feature.article.databinding.ItemArticleHeaderBinding
+import `in`.koreatech.koin.feature.article.model.ArticleHeaderState
+import java.time.ZoneId
+import java.util.Date
class ArticleAdapter(
private val onClick: (ArticleHeaderState) -> Unit
@@ -36,12 +37,11 @@ class ArticleAdapter(
textViewArticleTitle.text = articleHeader.title.trim()
textViewArticleAuthor.text = articleHeader.author
try {
- textViewArticleDate.text =
- TextUtils.concat(
- DateFormatUtil.getSimpleMonthAndDay(articleHeader.registeredAt),
- " ",
- DateFormatUtil.getDayOfWeek(TimeUtil.stringToDateYYYYMMDD(articleHeader.registeredAt))
- )
+ textViewArticleDate.text = TextUtils.concat(
+ DateFormatUtil.getSimpleMonthAndDay(articleHeader.registeredAt),
+ " ",
+ DateFormatUtil.getDayOfWeek(Date.from(articleHeader.registeredAt.atStartOfDay(ZoneId.systemDefault()).toInstant()))
+ )
} catch (e: Exception) {
}
textViewArticleViewCount.text = articleHeader.viewCount.toString()
@@ -52,21 +52,20 @@ class ArticleAdapter(
}
companion object {
- private val diffUtil =
- object : DiffUtil.ItemCallback() {
- override fun areItemsTheSame(
- oldItem: ArticleHeaderState,
- newItem: ArticleHeaderState
- ): Boolean {
- return oldItem.id == newItem.id
- }
+ private val diffUtil = object : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(
+ oldItem: ArticleHeaderState,
+ newItem: ArticleHeaderState
+ ): Boolean {
+ return oldItem.id == newItem.id
+ }
- override fun areContentsTheSame(
- oldItem: ArticleHeaderState,
- newItem: ArticleHeaderState
- ): Boolean {
- return oldItem == newItem
- }
+ override fun areContentsTheSame(
+ oldItem: ArticleHeaderState,
+ newItem: ArticleHeaderState
+ ): Boolean {
+ return oldItem == newItem
}
+ }
}
}
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/adapter/AttachmentAdapter.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/adapter/AttachmentAdapter.kt
similarity index 67%
rename from koin/src/main/java/in/koreatech/koin/ui/article/adapter/AttachmentAdapter.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/adapter/AttachmentAdapter.kt
index dcecc9f871..b80ca2fba8 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/adapter/AttachmentAdapter.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/adapter/AttachmentAdapter.kt
@@ -1,12 +1,12 @@
-package `in`.koreatech.koin.ui.article.adapter
+package `in`.koreatech.koin.feature.article.ui.article.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 `in`.koreatech.koin.databinding.ItemAttachmentBinding
-import `in`.koreatech.koin.ui.article.state.AttachmentState
+import `in`.koreatech.koin.feature.article.databinding.ItemAttachmentBinding
+import `in`.koreatech.koin.feature.article.ui.article.state.AttachmentState
class AttachmentAdapter(
private val onClick: (AttachmentState) -> Unit,
@@ -45,21 +45,20 @@ class AttachmentAdapter(
}
companion object {
- private val diffUtil =
- object : DiffUtil.ItemCallback() {
- override fun areItemsTheSame(
- oldItem: AttachmentState,
- newItem: AttachmentState
- ): Boolean {
- return oldItem.url == newItem.url
- }
+ private val diffUtil = object : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(
+ oldItem: AttachmentState,
+ newItem: AttachmentState
+ ): Boolean {
+ return oldItem.url == newItem.url
+ }
- override fun areContentsTheSame(
- oldItem: AttachmentState,
- newItem: AttachmentState
- ): Boolean {
- return oldItem == newItem
- }
+ override fun areContentsTheSame(
+ oldItem: AttachmentState,
+ newItem: AttachmentState
+ ): Boolean {
+ return oldItem == newItem
}
+ }
}
}
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/adapter/HotArticleAdapter.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/adapter/HotArticleAdapter.kt
similarity index 65%
rename from koin/src/main/java/in/koreatech/koin/ui/article/adapter/HotArticleAdapter.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/adapter/HotArticleAdapter.kt
index e3330a7515..c0372772be 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/adapter/HotArticleAdapter.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/adapter/HotArticleAdapter.kt
@@ -1,12 +1,12 @@
-package `in`.koreatech.koin.ui.article.adapter
+package `in`.koreatech.koin.feature.article.ui.article.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 `in`.koreatech.koin.databinding.ItemHotArticleHeaderBinding
-import `in`.koreatech.koin.ui.article.state.ArticleHeaderState
+import `in`.koreatech.koin.feature.article.databinding.ItemHotArticleHeaderBinding
+import `in`.koreatech.koin.feature.article.model.ArticleHeaderState
class HotArticleAdapter(
private val onClick: (ArticleHeaderState) -> Unit
@@ -40,21 +40,20 @@ class HotArticleAdapter(
}
companion object {
- private val diffUtil =
- object : DiffUtil.ItemCallback() {
- override fun areItemsTheSame(
- oldItem: ArticleHeaderState,
- newItem: ArticleHeaderState
- ): Boolean {
- return oldItem.id == newItem.id
- }
+ private val diffUtil = object : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(
+ oldItem: ArticleHeaderState,
+ newItem: ArticleHeaderState
+ ): Boolean {
+ return oldItem.id == newItem.id
+ }
- override fun areContentsTheSame(
- oldItem: ArticleHeaderState,
- newItem: ArticleHeaderState
- ): Boolean {
- return oldItem == newItem
- }
+ override fun areContentsTheSame(
+ oldItem: ArticleHeaderState,
+ newItem: ArticleHeaderState
+ ): Boolean {
+ return oldItem == newItem
}
+ }
}
}
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/adapter/RecentSearchedHistoryAdapter.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/adapter/RecentSearchedHistoryAdapter.kt
similarity index 74%
rename from koin/src/main/java/in/koreatech/koin/ui/article/adapter/RecentSearchedHistoryAdapter.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/adapter/RecentSearchedHistoryAdapter.kt
index a5318042c5..48854c7f11 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/adapter/RecentSearchedHistoryAdapter.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/adapter/RecentSearchedHistoryAdapter.kt
@@ -1,11 +1,11 @@
-package `in`.koreatech.koin.ui.article.adapter
+package `in`.koreatech.koin.feature.article.ui.article.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 `in`.koreatech.koin.databinding.ItemRecentSearchedHistoryBinding
+import `in`.koreatech.koin.feature.article.databinding.ItemRecentSearchedHistoryBinding
class RecentSearchedHistoryAdapter(
private val onSearchHistoryClicked: (String) -> Unit,
@@ -41,15 +41,14 @@ class RecentSearchedHistoryAdapter(
}
companion object {
- private val diffUtil =
- object : DiffUtil.ItemCallback() {
- override fun areItemsTheSame(oldItem: String, newItem: String): Boolean {
- return oldItem == newItem
- }
+ private val diffUtil = object : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(oldItem: String, newItem: String): Boolean {
+ return oldItem == newItem
+ }
- override fun areContentsTheSame(oldItem: String, newItem: String): Boolean {
- return oldItem == newItem
- }
+ override fun areContentsTheSame(oldItem: String, newItem: String): Boolean {
+ return oldItem == newItem
}
+ }
}
}
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/ArticleDetailFragment.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/detail/ArticleDetailFragment.kt
similarity index 89%
rename from koin/src/main/java/in/koreatech/koin/ui/article/ArticleDetailFragment.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/detail/ArticleDetailFragment.kt
index e0b6ad9f6a..1bb8dc871c 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/ArticleDetailFragment.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/detail/ArticleDetailFragment.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.ui.article
+package `in`.koreatech.koin.feature.article.ui.article.detail
import android.app.DownloadManager
import android.content.Intent
@@ -18,7 +18,6 @@ import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.RecyclerView
import dagger.hilt.android.AndroidEntryPoint
-import `in`.koreatech.koin.R
import `in`.koreatech.koin.core.activity.WebViewActivity
import `in`.koreatech.koin.core.analytics.AnalyticsConstant
import `in`.koreatech.koin.core.analytics.EventAction
@@ -30,15 +29,17 @@ import `in`.koreatech.koin.core.toast.ToastUtil
import `in`.koreatech.koin.core.util.withLoading
import `in`.koreatech.koin.core.webview.loadKoreatechHtml
import `in`.koreatech.koin.core.webview.setOnImageClickListener
-import `in`.koreatech.koin.databinding.FragmentArticleDetailBinding
import `in`.koreatech.koin.domain.util.DateFormatUtil
-import `in`.koreatech.koin.domain.util.TimeUtil
-import `in`.koreatech.koin.ui.article.adapter.AttachmentAdapter
-import `in`.koreatech.koin.ui.article.adapter.HotArticleAdapter
-import `in`.koreatech.koin.ui.article.state.ArticleHeaderState
-import `in`.koreatech.koin.ui.article.state.ArticleState
-import `in`.koreatech.koin.ui.article.state.AttachmentState
-import `in`.koreatech.koin.ui.article.viewmodel.ArticleDetailViewModel
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.databinding.FragmentArticleDetailBinding
+import `in`.koreatech.koin.feature.article.enums.LinkType
+import `in`.koreatech.koin.feature.article.model.ArticleHeaderState
+import `in`.koreatech.koin.feature.article.ui.article.adapter.AttachmentAdapter
+import `in`.koreatech.koin.feature.article.ui.article.adapter.HotArticleAdapter
+import `in`.koreatech.koin.feature.article.ui.article.state.ArticleState
+import `in`.koreatech.koin.feature.article.ui.article.state.AttachmentState
+import java.time.ZoneId
+import java.util.Date
import javax.inject.Inject
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
@@ -64,7 +65,7 @@ class ArticleDetailFragment : Fragment() {
}
private val viewModel: ArticleDetailViewModel by viewModels {
- ArticleDetailViewModel.provideFactory(
+ ArticleDetailViewModel.Companion.provideFactory(
articleDetailViewModelFactory,
requireArguments().getInt(ARTICLE_ID),
requireArguments().getInt(NAVIGATED_BOARD_ID)
@@ -210,12 +211,11 @@ class ArticleDetailFragment : Fragment() {
textViewArticleTitle.text = article.header.title
textViewArticleAuthor.text = article.header.author
try {
- textViewArticleDate.text =
- TextUtils.concat(
- DateFormatUtil.getSimpleMonthAndDay(article.header.registeredAt),
- " ",
- DateFormatUtil.getDayOfWeek(TimeUtil.stringToDateYYYYMMDD(article.header.registeredAt))
- )
+ textViewArticleDate.text = TextUtils.concat(
+ DateFormatUtil.getSimpleMonthAndDay(article.header.registeredAt),
+ " ",
+ DateFormatUtil.getDayOfWeek(Date.from(article.header.registeredAt.atStartOfDay(ZoneId.systemDefault()).toInstant()))
+ )
} catch (_: Exception) {
}
textViewArticleViewCount.text = article.header.viewCount.toString()
@@ -226,11 +226,10 @@ class ArticleDetailFragment : Fragment() {
// binding.htmlView.setHtml(article.content)
binding.webView.apply {
setOnImageClickListener(requireActivity()) {
- val dialog =
- ImageZoomableDialog(requireActivity(), it).apply {
- initialScale = 0.94f
- cancelableOnTouchOutside = false
- }
+ val dialog = ImageZoomableDialog(requireActivity(), it).apply {
+ initialScale = 0.94f
+ cancelableOnTouchOutside = false
+ }
dialog.show()
}
}.loadKoreatechHtml(requireContext(), article.content)
diff --git a/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/detail/ArticleDetailViewModel.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/detail/ArticleDetailViewModel.kt
new file mode 100644
index 0000000000..cf4bd37eb7
--- /dev/null
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/detail/ArticleDetailViewModel.kt
@@ -0,0 +1,99 @@
+package `in`.koreatech.koin.feature.article.ui.article.detail
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.viewModelScope
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import `in`.koreatech.koin.core.viewmodel.BaseViewModel
+import `in`.koreatech.koin.domain.repository.ArticleRepository
+import `in`.koreatech.koin.feature.article.enums.ArticleBoardType
+import `in`.koreatech.koin.feature.article.model.ArticleHeaderState
+import `in`.koreatech.koin.feature.article.model.toArticleHeaderState
+import `in`.koreatech.koin.feature.article.ui.article.state.ArticleState
+import `in`.koreatech.koin.feature.article.ui.article.state.toArticleState
+import java.time.LocalDate
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
+
+class ArticleDetailViewModel @AssistedInject constructor(
+ @Assisted("articleId") articleId: Int,
+ @Assisted("navigatedBoardId") val navigatedBoardId: Int,
+ private val articleRepository: ArticleRepository
+) : BaseViewModel() {
+ val article: StateFlow = articleRepository.fetchArticle(articleId, navigatedBoardId)
+ .onStart {
+ _isLoading.value = true
+ }.map {
+ it.toArticleState()
+ }.onEach {
+ _isLoading.value = false
+ }.stateIn(
+ scope = viewModelScope,
+ started = SharingStarted.WhileSubscribed(5_000),
+ initialValue = ArticleState(
+ header = ArticleHeaderState(
+ id = 0,
+ board = ArticleBoardType.ALL,
+ title = "",
+ author = "",
+ viewCount = 0,
+ registeredAt = LocalDate.now(),
+ updatedAt = ""
+ ),
+ content = "",
+ prevArticleId = null,
+ nextArticleId = null,
+ attachments = listOf(),
+ url = ""
+ )
+ )
+
+ val hotArticles: StateFlow> = articleRepository.fetchHotArticleHeaders()
+ .map {
+ var doesHotContainsThis = false
+ it.filterIndexed { index, hotArticleHeader ->
+ if (articleId == hotArticleHeader.id) {
+ doesHotContainsThis = true
+ }
+ articleId != hotArticleHeader.id && index < (HOT_ARTICLE_COUNT + if (doesHotContainsThis) 1 else 0)
+ }.map { it.toArticleHeaderState() }
+ }.stateIn(
+ scope = viewModelScope,
+ started = SharingStarted.WhileSubscribed(5_000),
+ initialValue = listOf()
+ )
+
+ fun setIsLoading(isLoading: Boolean) {
+ _isLoading.value = isLoading
+ }
+
+ @AssistedFactory
+ interface Factory {
+ fun create(
+ @Assisted("articleId") articleId: Int,
+ @Assisted("navigatedBoardId") navigatedBoardId: Int
+ ): ArticleDetailViewModel
+ }
+
+ companion object {
+ const val HOT_ARTICLE_COUNT = 4
+
+ fun provideFactory(
+ assistedFactory: Factory,
+ article: Int,
+ boardId: Int
+ ): ViewModelProvider.Factory {
+ return object : ViewModelProvider.Factory {
+ override fun create(modelClass: Class): T {
+ return assistedFactory.create(article, boardId) as T
+ }
+ }
+ }
+ }
+}
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/ArticleKeywordFragment.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/keyword/ArticleKeywordFragment.kt
similarity index 92%
rename from koin/src/main/java/in/koreatech/koin/ui/article/ArticleKeywordFragment.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/keyword/ArticleKeywordFragment.kt
index 9ad13d68b2..31a36aa299 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/ArticleKeywordFragment.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/keyword/ArticleKeywordFragment.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.ui.article
+package `in`.koreatech.koin.feature.article.ui.article.keyword
import android.os.Bundle
import android.view.LayoutInflater
@@ -16,7 +16,6 @@ import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.chip.Chip
import dagger.hilt.android.AndroidEntryPoint
-import `in`.koreatech.koin.R
import `in`.koreatech.koin.core.analytics.AnalyticsConstant
import `in`.koreatech.koin.core.analytics.EventAction
import `in`.koreatech.koin.core.analytics.EventLogger
@@ -26,13 +25,9 @@ import `in`.koreatech.koin.core.navigation.Navigator
import `in`.koreatech.koin.core.permission.checkNotificationPermission
import `in`.koreatech.koin.core.toast.ToastUtil
import `in`.koreatech.koin.core.util.SnackbarUtil
-import `in`.koreatech.koin.databinding.FragmentArticleKeywordBinding
import `in`.koreatech.koin.domain.model.notification.SubscribesType
-import `in`.koreatech.koin.ui.article.viewmodel.ArticleKeywordViewModel
-import `in`.koreatech.koin.ui.article.viewmodel.KeywordAddUiState
-import `in`.koreatech.koin.ui.article.viewmodel.KeywordInputUiState
-import `in`.koreatech.koin.ui.notification.viewmodel.NotificationUiState
-import `in`.koreatech.koin.ui.notification.viewmodel.NotificationViewModel
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.databinding.FragmentArticleKeywordBinding
import javax.inject.Inject
import kotlinx.coroutines.launch
@@ -42,7 +37,6 @@ class ArticleKeywordFragment : Fragment() {
private val binding get() = _binding!!
private val viewModel by viewModels()
- private val notificationViewModel by viewModels()
@Inject
lateinit var navigator: Navigator
@@ -60,7 +54,10 @@ class ArticleKeywordFragment : Fragment() {
AnalyticsConstant.Label.LOGIN_PROMPT,
"키워드 알림 팝업"
)
- val intent = navigator.navigateToSignIn(this.requireContext(), redirectUrl = "koin://article/activity?fragment=article_keyword")
+ val intent = navigator.navigateToSignIn(
+ this.requireContext(),
+ redirectUrl = "koin://article/activity?fragment=article_keyword"
+ )
it.dismiss()
startActivity(intent)
},
@@ -78,7 +75,7 @@ class ArticleKeywordFragment : Fragment() {
if (_binding == null) {
_binding = FragmentArticleKeywordBinding.inflate(inflater, container, false)
binding.textViewMaxKeywordCount.text =
- ArticleKeywordViewModel.MAX_KEYWORD_COUNT.toString()
+ ArticleKeywordViewModel.Companion.MAX_KEYWORD_COUNT.toString()
binding.buttonAddKeyword.setOnClickListener {
viewModel.addKeyword(binding.textInputSearch.text.toString())
}
@@ -159,7 +156,7 @@ class ArticleKeywordFragment : Fragment() {
binding.chipGroupSuggestionKeywords.removeAllViews()
suggests.forEach { keyword ->
binding.run {
- if (chipGroupSuggestionKeywords.childCount >= ArticleKeywordViewModel.MAX_SUGGEST_KEYWORD_COUNT) {
+ if (chipGroupSuggestionKeywords.childCount >= ArticleKeywordViewModel.Companion.MAX_SUGGEST_KEYWORD_COUNT) {
return@forEach
}
@@ -325,7 +322,7 @@ class ArticleKeywordFragment : Fragment() {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.user.collect { user ->
if (user.isAnonymous.not()) {
- notificationViewModel.getPermissionInfo()
+ viewModel.getPermissionInfo()
}
}
}
@@ -350,20 +347,20 @@ class ArticleKeywordFragment : Fragment() {
AnalyticsConstant.Label.KEYWORD_NOTIFICATION,
"on"
)
- notificationViewModel.updateSubscription(SubscribesType.ARTICLE_KEYWORD)
+ viewModel.updateSubscription(SubscribesType.ARTICLE_KEYWORD)
} else {
EventLogger.logClickEvent(
EventAction.CAMPUS,
AnalyticsConstant.Label.KEYWORD_NOTIFICATION,
"off"
)
- notificationViewModel.deleteSubscription(SubscribesType.ARTICLE_KEYWORD)
+ viewModel.deleteSubscription(SubscribesType.ARTICLE_KEYWORD)
}
}
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
- notificationViewModel.notificationUiState.collect { uiState ->
+ viewModel.notificationUiState.collect { uiState ->
if (uiState is NotificationUiState.Success) {
uiState.notificationPermissionInfo.subscribes.forEach {
if (it.type == SubscribesType.ARTICLE_KEYWORD) {
diff --git a/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/keyword/ArticleKeywordViewModel.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/keyword/ArticleKeywordViewModel.kt
new file mode 100644
index 0000000000..82b11d0e69
--- /dev/null
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/keyword/ArticleKeywordViewModel.kt
@@ -0,0 +1,213 @@
+package `in`.koreatech.koin.feature.article.ui.article.keyword
+
+import androidx.lifecycle.SavedStateHandle
+import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.lifecycle.HiltViewModel
+import `in`.koreatech.koin.core.viewmodel.BaseViewModel
+import `in`.koreatech.koin.domain.model.notification.NotificationPermissionInfo
+import `in`.koreatech.koin.domain.model.notification.SubscribesDetailType
+import `in`.koreatech.koin.domain.model.notification.SubscribesType
+import `in`.koreatech.koin.domain.model.user.User
+import `in`.koreatech.koin.domain.repository.ArticleRepository
+import `in`.koreatech.koin.domain.usecase.notification.DeleteNotificationSubscriptionDetailUseCase
+import `in`.koreatech.koin.domain.usecase.notification.DeleteNotificationSubscriptionUseCase
+import `in`.koreatech.koin.domain.usecase.notification.GetNotificationPermissionInfoUseCase
+import `in`.koreatech.koin.domain.usecase.notification.UpdateNotificationSubscriptionDetailUseCase
+import `in`.koreatech.koin.domain.usecase.notification.UpdateNotificationSubscriptionUseCase
+import `in`.koreatech.koin.domain.usecase.user.GetUserStatusUseCase
+import `in`.koreatech.koin.domain.util.onFailure
+import `in`.koreatech.koin.domain.util.onSuccess
+import javax.inject.Inject
+import kotlinx.coroutines.channels.BufferOverflow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.update
+
+@HiltViewModel
+class ArticleKeywordViewModel @Inject constructor(
+ private val savedStateHandle: SavedStateHandle,
+ private val articleRepository: ArticleRepository,
+ private val getNotificationPermissionInfoUseCase: GetNotificationPermissionInfoUseCase,
+ private val updateNotificationSubscriptionUseCase: UpdateNotificationSubscriptionUseCase,
+ private val updateNotificationSubscriptionDetailUseCase: UpdateNotificationSubscriptionDetailUseCase,
+ private val deleteNotificationSubscriptionUseCase: DeleteNotificationSubscriptionUseCase,
+ private val deleteNotificationSubscriptionDetailUseCase: DeleteNotificationSubscriptionDetailUseCase,
+ getUserStatusUseCase: GetUserStatusUseCase
+) : BaseViewModel() {
+ private val _notificationUiState =
+ MutableStateFlow(NotificationUiState.Nothing)
+ val notificationUiState = _notificationUiState.asStateFlow()
+
+ val user: StateFlow = getUserStatusUseCase()
+ .stateIn(viewModelScope, SharingStarted.Eagerly, User.Anonymous)
+
+ val keywordInputUiState: StateFlow = savedStateHandle.getStateFlow(KEYWORD_INPUT, "").map {
+ if (it.isEmpty()) KeywordInputUiState.Empty else KeywordInputUiState.Valid(it)
+ }.stateIn(
+ scope = viewModelScope,
+ started = SharingStarted.WhileSubscribed(5_000),
+ initialValue = KeywordInputUiState.Empty
+ )
+
+ val myKeywords: StateFlow> = articleRepository.fetchMyKeyword()
+ .stateIn(
+ scope = viewModelScope,
+ started = SharingStarted.WhileSubscribed(5_000),
+ initialValue = listOf()
+ )
+
+ private val _keywordAddUiState = MutableSharedFlow(
+ extraBufferCapacity = 1,
+ onBufferOverflow = BufferOverflow.DROP_OLDEST
+ )
+ val keywordAddUiState: SharedFlow = _keywordAddUiState
+ .shareIn(
+ scope = viewModelScope,
+ started = SharingStarted.WhileSubscribed(5_000)
+ )
+
+ val suggestedKeywords: StateFlow> = articleRepository.fetchKeywordSuggestions()
+ .stateIn(
+ scope = viewModelScope,
+ started = SharingStarted.WhileSubscribed(5_000),
+ initialValue = listOf()
+ )
+
+ fun addKeyword(keyword: String) {
+ val trimmedKeyword = keyword.trim().ifEmpty {
+ _keywordAddUiState.tryEmit(KeywordAddUiState.RequireInput)
+ return
+ }
+ if (myKeywords.value.size >= MAX_KEYWORD_COUNT) {
+ _keywordAddUiState.tryEmit(KeywordAddUiState.LimitExceeded)
+ return
+ }
+
+ if (trimmedKeyword.length > MAX_KEYWORD_LENGTH || trimmedKeyword.length < MIN_KEYWORD_LENGTH) {
+ _keywordAddUiState.tryEmit(KeywordAddUiState.InvalidLength)
+ return
+ }
+
+ if (myKeywords.value.contains(trimmedKeyword)) {
+ _keywordAddUiState.tryEmit(KeywordAddUiState.AlreadyExist)
+ return
+ }
+
+ if (trimmedKeywordRegex.containsMatchIn(trimmedKeyword)) { // jusang-regex-opt
+ _keywordAddUiState.tryEmit(KeywordAddUiState.BlankNotAllowed)
+ return
+ }
+
+ articleRepository.saveKeyword(trimmedKeyword).onStart {
+ _keywordAddUiState.emit(KeywordAddUiState.Loading)
+ }.onEach {
+ _keywordAddUiState.emit(KeywordAddUiState.Success(trimmedKeyword))
+ }.catch {
+ _keywordAddUiState.emit(KeywordAddUiState.Error)
+ }.launchIn(viewModelScope)
+ }
+
+ fun deleteKeyword(keyword: String) {
+ articleRepository.deleteKeyword(keyword).onEach {
+ _keywordAddUiState.emit(KeywordAddUiState.Success(keyword))
+ }.catch {
+ _keywordAddUiState.emit(KeywordAddUiState.Error)
+ }.launchIn(viewModelScope)
+ }
+
+ fun onKeywordInputChanged(keyword: String) {
+ savedStateHandle[KEYWORD_INPUT] = keyword
+ }
+
+ fun getPermissionInfo() {
+ viewModelScope.launchWithLoading {
+ getNotificationPermissionInfoUseCase().onSuccess { info ->
+ _notificationUiState.update {
+ NotificationUiState.Success(info)
+ }
+ }.onFailure {
+ _notificationUiState.update { NotificationUiState.Failed }
+ }
+ }
+ }
+
+ fun updateSubscription(type: SubscribesType) {
+ viewModelScope.launchWithLoading {
+ updateNotificationSubscriptionUseCase(type)
+ }
+ }
+
+ fun updateSubscriptionDetail(type: SubscribesDetailType) {
+ viewModelScope.launchWithLoading {
+ updateNotificationSubscriptionDetailUseCase(type)
+ }
+ }
+
+ fun deleteSubscription(type: SubscribesType) {
+ viewModelScope.launchWithLoading {
+ deleteNotificationSubscriptionUseCase(type)
+ }
+ }
+
+ fun deleteSubscriptionDetail(type: SubscribesDetailType) {
+ viewModelScope.launchWithLoading {
+ deleteNotificationSubscriptionDetailUseCase(type)
+ }
+ }
+
+ companion object {
+ const val MAX_KEYWORD_COUNT = 10
+ const val MAX_SUGGEST_KEYWORD_COUNT = 5
+ const val MAX_KEYWORD_LENGTH = 20
+ const val MIN_KEYWORD_LENGTH = 2
+ const val KEYWORD_INPUT = "keyword_input"
+ val trimmedKeywordRegex = Regex("""\s+""")
+ }
+}
+
+sealed interface KeywordAddUiState {
+ data object Nothing : KeywordAddUiState
+
+ data object Loading : KeywordAddUiState
+
+ data class Success(val keyword: String) : KeywordAddUiState
+
+ data object AlreadyExist : KeywordAddUiState
+
+ data object LimitExceeded : KeywordAddUiState
+
+ data object BlankNotAllowed : KeywordAddUiState
+
+ data object InvalidLength : KeywordAddUiState
+
+ data object RequireInput : KeywordAddUiState
+
+ data object Error : KeywordAddUiState
+}
+
+sealed interface KeywordInputUiState {
+ data object Empty : KeywordInputUiState
+
+ data class Valid(val keyword: String) : KeywordInputUiState
+}
+
+sealed class NotificationUiState {
+ data class Success(
+ val notificationPermissionInfo: NotificationPermissionInfo
+ ) : NotificationUiState()
+
+ data object Failed : NotificationUiState()
+
+ data object Nothing : NotificationUiState()
+}
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/ArticleListFragment.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/list/ArticleListFragment.kt
similarity index 80%
rename from koin/src/main/java/in/koreatech/koin/ui/article/ArticleListFragment.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/list/ArticleListFragment.kt
index 7484970a77..47c8f82e32 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/ArticleListFragment.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/list/ArticleListFragment.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.ui.article
+package `in`.koreatech.koin.feature.article.ui.article.list
import android.os.Bundle
import android.view.LayoutInflater
@@ -11,16 +11,17 @@ import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.tabs.TabLayout
import dagger.hilt.android.AndroidEntryPoint
-import `in`.koreatech.koin.R
import `in`.koreatech.koin.core.analytics.AnalyticsConstant
import `in`.koreatech.koin.core.analytics.EventAction
import `in`.koreatech.koin.core.analytics.EventLogger
import `in`.koreatech.koin.core.progressdialog.IProgressDialog
import `in`.koreatech.koin.core.util.withLoading
-import `in`.koreatech.koin.databinding.FragmentArticleListBinding
-import `in`.koreatech.koin.ui.article.ArticleActivity.Companion.START_BOARD
-import `in`.koreatech.koin.ui.article.lostandfound.ArticleListLostAndFoundFragment
-import `in`.koreatech.koin.ui.article.viewmodel.ArticleListViewModel
+import `in`.koreatech.koin.feature.article.ArticleActivity.Companion.START_BOARD
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.databinding.FragmentArticleListBinding
+import `in`.koreatech.koin.feature.article.enums.ArticleBoardType
+import `in`.koreatech.koin.feature.article.ui.article.notice.ArticleListNoticeFragment
+import `in`.koreatech.koin.feature.article.ui.lostandfound.fragment.ArticleListLostAndFoundFragment
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
@@ -29,23 +30,22 @@ class ArticleListFragment : Fragment() {
private var _binding: FragmentArticleListBinding? = null
private val binding get() = _binding!!
- private val onTabSelectedListener =
- object : TabLayout.OnTabSelectedListener {
- override fun onTabSelected(tab: TabLayout.Tab?) {
- tab?.let {
- EventLogger.logClickEvent(
- EventAction.CAMPUS,
- AnalyticsConstant.Label.NOTICE_TAB,
- it.text.toString()
- )
- viewModel.setCurrentBoard(ArticleBoardType.entries[it.position])
- }
+ private val onTabSelectedListener = object : TabLayout.OnTabSelectedListener {
+ override fun onTabSelected(tab: TabLayout.Tab?) {
+ tab?.let {
+ EventLogger.logClickEvent(
+ EventAction.CAMPUS,
+ AnalyticsConstant.Label.NOTICE_TAB,
+ it.text.toString()
+ )
+ viewModel.setCurrentBoard(ArticleBoardType.entries[it.position])
}
+ }
- override fun onTabUnselected(tab: TabLayout.Tab?) {}
+ override fun onTabUnselected(tab: TabLayout.Tab?) {}
- override fun onTabReselected(tab: TabLayout.Tab?) {}
- }
+ override fun onTabReselected(tab: TabLayout.Tab?) {}
+ }
private val viewModel by viewModels()
@@ -99,6 +99,7 @@ class ArticleListFragment : Fragment() {
.replace(R.id.frame_layout_article_list, articleListNoticeFragment)
.commit()
}
+
ArticleBoardType.LOSTANDFOUND -> {
childFragmentManager.beginTransaction()
.replace(
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/viewmodel/ArticleListViewModel.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/list/ArticleListViewModel.kt
similarity index 83%
rename from koin/src/main/java/in/koreatech/koin/ui/article/viewmodel/ArticleListViewModel.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/list/ArticleListViewModel.kt
index fef240ab74..b9a71d611d 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/viewmodel/ArticleListViewModel.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/list/ArticleListViewModel.kt
@@ -1,9 +1,9 @@
-package `in`.koreatech.koin.ui.article.viewmodel
+package `in`.koreatech.koin.feature.article.ui.article.list
import androidx.lifecycle.SavedStateHandle
import dagger.hilt.android.lifecycle.HiltViewModel
import `in`.koreatech.koin.core.viewmodel.BaseViewModel
-import `in`.koreatech.koin.ui.article.ArticleBoardType
+import `in`.koreatech.koin.feature.article.enums.ArticleBoardType
import javax.inject.Inject
@HiltViewModel
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/ArticleListNoticeFragment.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/notice/ArticleListNoticeFragment.kt
similarity index 90%
rename from koin/src/main/java/in/koreatech/koin/ui/article/ArticleListNoticeFragment.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/notice/ArticleListNoticeFragment.kt
index 3e99e33a74..c2f5490114 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/ArticleListNoticeFragment.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/notice/ArticleListNoticeFragment.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.ui.article
+package `in`.koreatech.koin.feature.article.ui.article.notice
import android.graphics.Canvas
import android.graphics.Paint
@@ -23,20 +23,22 @@ import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.chip.Chip
import dagger.hilt.android.AndroidEntryPoint
-import `in`.koreatech.koin.R
import `in`.koreatech.koin.core.analytics.AnalyticsConstant
import `in`.koreatech.koin.core.analytics.EventAction
import `in`.koreatech.koin.core.analytics.EventLogger
import `in`.koreatech.koin.core.analytics.EventUtils
+import `in`.koreatech.koin.core.onboarding.ArrowDirection
import `in`.koreatech.koin.core.onboarding.OnboardingManager
+import `in`.koreatech.koin.core.onboarding.OnboardingType
import `in`.koreatech.koin.core.progressdialog.IProgressDialog
import `in`.koreatech.koin.core.util.withLoading
-import `in`.koreatech.koin.databinding.FragmentArticleListNoticeBinding
-import `in`.koreatech.koin.ui.article.ArticleDetailFragment.Companion.ARTICLE_ID
-import `in`.koreatech.koin.ui.article.ArticleDetailFragment.Companion.NAVIGATED_BOARD_ID
-import `in`.koreatech.koin.ui.article.adapter.ArticleAdapter
-import `in`.koreatech.koin.ui.article.state.ArticleHeaderState
-import `in`.koreatech.koin.ui.article.viewmodel.ArticleListNoticeViewModel
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.databinding.FragmentArticleListNoticeBinding
+import `in`.koreatech.koin.feature.article.enums.ArticleBoardType
+import `in`.koreatech.koin.feature.article.model.ArticleHeaderState
+import `in`.koreatech.koin.feature.article.ui.article.adapter.ArticleAdapter
+import `in`.koreatech.koin.feature.article.ui.article.detail.ArticleDetailFragment.Companion.ARTICLE_ID
+import `in`.koreatech.koin.feature.article.ui.article.detail.ArticleDetailFragment.Companion.NAVIGATED_BOARD_ID
import javax.inject.Inject
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
@@ -67,14 +69,13 @@ class ArticleListNoticeFragment : Fragment() {
initArgument()
initArticleRecyclerView()
initPageButtonSelectedListener()
- pageChips =
- arrayListOf(
- binding.chipPage1,
- binding.chipPage2,
- binding.chipPage3,
- binding.chipPage4,
- binding.chipPage5
- )
+ pageChips = arrayListOf(
+ binding.chipPage1,
+ binding.chipPage2,
+ binding.chipPage3,
+ binding.chipPage4,
+ binding.chipPage5
+ )
binding.textViewNextPage.setOnClickListener {
viewModel.setCurrentPage(viewModel.currentPage.value + 1)
}
@@ -132,10 +133,10 @@ class ArticleListNoticeFragment : Fragment() {
private fun initKeywordTooltip() {
with(onboardingManager) {
showOnboardingTooltipIfNeeded(
- type = `in`.koreatech.koin.core.onboarding.OnboardingType.ARTICLE_KEYWORD,
+ type = OnboardingType.ARTICLE_KEYWORD,
view = binding.imageViewToKeywordAddPage,
arrowPosition = 0.135f,
- arrowDirection = `in`.koreatech.koin.core.onboarding.ArrowDirection.TOP
+ arrowDirection = ArrowDirection.TOP
)
}
}
@@ -254,11 +255,10 @@ class ArticleListNoticeFragment : Fragment() {
private fun addKeywordChip(keywords: List) {
keywords.forEach { keyword ->
if (binding.chipGroupMyKeywords.children.any {
- (it as? Chip)?.text ==
- TextUtils.concat(
- "#",
- keyword
- )
+ (it as? Chip)?.text == TextUtils.concat(
+ "#",
+ keyword
+ )
}.not()
) {
binding.chipGroupMyKeywords.addView(
@@ -279,12 +279,11 @@ class ArticleListNoticeFragment : Fragment() {
}
private fun createChip(text: String, isCheckable: Boolean, onChipClicked: () -> Unit): Chip? {
- val chip =
- layoutInflater.inflate(
- R.layout.chip_layout,
- binding.chipGroupMyKeywords,
- false
- ) as? Chip
+ val chip = layoutInflater.inflate(
+ R.layout.chip_layout,
+ binding.chipGroupMyKeywords,
+ false
+ ) as? Chip
return chip?.apply {
id = View.generateViewId()
this.isCheckable = isCheckable
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/viewmodel/ArticleListNoticeViewModel.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/notice/ArticleListNoticeViewModel.kt
similarity index 57%
rename from koin/src/main/java/in/koreatech/koin/ui/article/viewmodel/ArticleListNoticeViewModel.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/notice/ArticleListNoticeViewModel.kt
index f22ddb62f6..b0599a355e 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/viewmodel/ArticleListNoticeViewModel.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/notice/ArticleListNoticeViewModel.kt
@@ -1,13 +1,13 @@
-package `in`.koreatech.koin.ui.article.viewmodel
+package `in`.koreatech.koin.feature.article.ui.article.notice
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import `in`.koreatech.koin.core.viewmodel.BaseViewModel
import `in`.koreatech.koin.domain.repository.ArticleRepository
-import `in`.koreatech.koin.ui.article.ArticleBoardType
-import `in`.koreatech.koin.ui.article.state.ArticlePaginationState
-import `in`.koreatech.koin.ui.article.state.toArticlePaginationState
+import `in`.koreatech.koin.feature.article.enums.ArticleBoardType
+import `in`.koreatech.koin.feature.article.ui.article.state.ArticlePaginationState
+import `in`.koreatech.koin.feature.article.ui.article.state.toArticlePaginationState
import javax.inject.Inject
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -27,46 +27,43 @@ class ArticleListNoticeViewModel @Inject constructor(
val currentPage = savedStateHandle.getStateFlow(CURRENT_PAGE, 1)
val selectedKeyword = savedStateHandle.getStateFlow(SELECTED_KEYWORD, "")
- val pageNumbers =
- savedStateHandle.getStateFlow(
- PAGE_NUMBERS,
- IntArray(PAGE_NUMBER_COUNT)
- ) // 값이 0일 경우 존재하지 않는 페이지
+ val pageNumbers = savedStateHandle.getStateFlow(
+ PAGE_NUMBERS,
+ IntArray(PAGE_NUMBER_COUNT)
+ ) // 값이 0일 경우 존재하지 않는 페이지
- val myKeywords: StateFlow> =
- articleRepository.fetchMyKeyword()
- .stateIn(
- scope = viewModelScope,
- started = SharingStarted.WhileSubscribed(5_000),
- initialValue = listOf()
- )
-
- val articlePagination: StateFlow =
- combine(currentBoard, currentPage, selectedKeyword) { board, page, query ->
- _isLoading.value = true
- if (query.isEmpty()) {
- articleRepository.fetchArticlePagination(board.id, page, ARTICLES_PER_PAGE)
- } else {
- articleRepository.fetchSearchedArticles(
- query,
- board.id,
- page,
- ARTICLES_PER_PAGE
- )
- }
- }.debounce(10).flatMapLatest {
- it.mapLatest { articlePagination ->
- articlePagination.toArticlePaginationState()
- }
- }.onEach {
- _isLoading.value = false
- calculatePageNumber(it.totalPage)
- }.stateIn(
+ val myKeywords: StateFlow> = articleRepository.fetchMyKeyword()
+ .stateIn(
scope = viewModelScope,
- started = SharingStarted.WhileSubscribed(5000),
- initialValue = ArticlePaginationState(emptyList(), 0, 0, 5, 1)
+ started = SharingStarted.WhileSubscribed(5_000),
+ initialValue = listOf()
)
+ val articlePagination: StateFlow = combine(currentBoard, currentPage, selectedKeyword) { board, page, query ->
+ _isLoading.value = true
+ if (query.isEmpty()) {
+ articleRepository.fetchArticlePagination(board.id, page, ARTICLES_PER_PAGE)
+ } else {
+ articleRepository.fetchSearchedArticles(
+ query,
+ board.id,
+ page,
+ ARTICLES_PER_PAGE
+ )
+ }
+ }.debounce(10).flatMapLatest {
+ it.mapLatest { articlePagination ->
+ articlePagination.toArticlePaginationState()
+ }
+ }.onEach {
+ _isLoading.value = false
+ calculatePageNumber(it.totalPage)
+ }.stateIn(
+ scope = viewModelScope,
+ started = SharingStarted.WhileSubscribed(5000),
+ initialValue = ArticlePaginationState(emptyList(), 0, 0, 5, 1)
+ )
+
fun setCurrentBoard(board: ArticleBoardType) {
if (currentBoard.value == board) return
savedStateHandle[BOARD_TYPE] = board
@@ -86,8 +83,7 @@ class ArticleListNoticeViewModel @Inject constructor(
private fun calculatePageNumber(totalPage: Int) {
val newPageNumbers = pageNumbers.value.copyOf()
repeat(PAGE_NUMBER_COUNT) { index ->
- val pageNumber =
- ((currentPage.value - 1) / PAGE_NUMBER_COUNT) * PAGE_NUMBER_COUNT + index + 1
+ val pageNumber = ((currentPage.value - 1) / PAGE_NUMBER_COUNT) * PAGE_NUMBER_COUNT + index + 1
if (pageNumber <= totalPage) {
newPageNumbers[index] = pageNumber
} else {
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/ArticleSearchFragment.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/search/ArticleSearchFragment.kt
similarity index 92%
rename from koin/src/main/java/in/koreatech/koin/ui/article/ArticleSearchFragment.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/search/ArticleSearchFragment.kt
index dcba2891ae..7f32c039e5 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/ArticleSearchFragment.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/search/ArticleSearchFragment.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.ui.article
+package `in`.koreatech.koin.feature.article.ui.article.search
import android.os.Bundle
import android.view.LayoutInflater
@@ -20,21 +20,20 @@ import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.fragment.findNavController
import com.google.android.material.chip.Chip
import dagger.hilt.android.AndroidEntryPoint
-import `in`.koreatech.koin.R
import `in`.koreatech.koin.core.analytics.AnalyticsConstant
import `in`.koreatech.koin.core.analytics.EventAction
import `in`.koreatech.koin.core.analytics.EventLogger
import `in`.koreatech.koin.core.progressdialog.IProgressDialog
import `in`.koreatech.koin.core.util.SnackbarUtil
import `in`.koreatech.koin.core.util.withLoading
-import `in`.koreatech.koin.databinding.FragmentArticleSearchBinding
-import `in`.koreatech.koin.ui.article.ArticleDetailFragment.Companion.ARTICLE_ID
-import `in`.koreatech.koin.ui.article.ArticleDetailFragment.Companion.NAVIGATED_BOARD_ID
-import `in`.koreatech.koin.ui.article.adapter.ArticleAdapter
-import `in`.koreatech.koin.ui.article.adapter.RecentSearchedHistoryAdapter
-import `in`.koreatech.koin.ui.article.state.ArticleHeaderState
-import `in`.koreatech.koin.ui.article.viewmodel.ArticleSearchViewModel
-import `in`.koreatech.koin.ui.article.viewmodel.SearchUiState
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.databinding.FragmentArticleSearchBinding
+import `in`.koreatech.koin.feature.article.enums.ArticleBoardType
+import `in`.koreatech.koin.feature.article.model.ArticleHeaderState
+import `in`.koreatech.koin.feature.article.ui.article.adapter.ArticleAdapter
+import `in`.koreatech.koin.feature.article.ui.article.adapter.RecentSearchedHistoryAdapter
+import `in`.koreatech.koin.feature.article.ui.article.detail.ArticleDetailFragment.Companion.ARTICLE_ID
+import `in`.koreatech.koin.feature.article.ui.article.detail.ArticleDetailFragment.Companion.NAVIGATED_BOARD_ID
import kotlinx.coroutines.launch
@AndroidEntryPoint
@@ -156,7 +155,7 @@ class ArticleSearchFragment : Fragment() {
is SearchUiState.Empty -> {
binding.frameLayoutSearchResult.visibility = View.VISIBLE
- searchResultAdapter.submitList(emptyList())
+ searchResultAdapter.submitList(emptyList())
binding.textViewSearchResultEmpty.visibility = View.VISIBLE
}
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/viewmodel/ArticleSearchViewModel.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/search/ArticleSearchViewModel.kt
similarity index 74%
rename from koin/src/main/java/in/koreatech/koin/ui/article/viewmodel/ArticleSearchViewModel.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/search/ArticleSearchViewModel.kt
index a96848793f..c4d03ddbb9 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/viewmodel/ArticleSearchViewModel.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/search/ArticleSearchViewModel.kt
@@ -1,12 +1,12 @@
-package `in`.koreatech.koin.ui.article.viewmodel
+package `in`.koreatech.koin.feature.article.ui.article.search
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import `in`.koreatech.koin.core.viewmodel.BaseViewModel
import `in`.koreatech.koin.domain.repository.ArticleRepository
-import `in`.koreatech.koin.ui.article.state.ArticlePaginationState
-import `in`.koreatech.koin.ui.article.state.toArticlePaginationState
+import `in`.koreatech.koin.feature.article.ui.article.state.ArticlePaginationState
+import `in`.koreatech.koin.feature.article.ui.article.state.toArticlePaginationState
import javax.inject.Inject
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
@@ -29,36 +29,32 @@ class ArticleSearchViewModel @Inject constructor(
) : BaseViewModel() {
val query = savedStateHandle.getStateFlow(SEARCH_INPUT, "")
- val searchHistory: StateFlow> =
- articleRepository.fetchSearchHistory()
- .map {
- it.take(MAX_SEARCH_HISTORY_COUNT)
- }.stateIn(
- scope = viewModelScope,
- started = SharingStarted.WhileSubscribed(5_000),
- initialValue = emptyList()
- )
-
- private val _searchResultUiState =
- MutableSharedFlow(
- extraBufferCapacity = 1,
- onBufferOverflow = BufferOverflow.DROP_OLDEST
- )
- val searchResultUiState: SharedFlow =
- _searchResultUiState.shareIn(
- scope = viewModelScope,
- started = SharingStarted.WhileSubscribed(5_000)
- )
-
- val mostSearchedKeywords: StateFlow> =
- articleRepository.fetchMostSearchedKeywords(
- MOST_SEARCHED_KEYWORD_COUNT
- ).stateIn(
+ val searchHistory: StateFlow> = articleRepository.fetchSearchHistory()
+ .map {
+ it.take(MAX_SEARCH_HISTORY_COUNT)
+ }.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = emptyList()
)
+ private val _searchResultUiState = MutableSharedFlow(
+ extraBufferCapacity = 1,
+ onBufferOverflow = BufferOverflow.DROP_OLDEST
+ )
+ val searchResultUiState: SharedFlow = _searchResultUiState.shareIn(
+ scope = viewModelScope,
+ started = SharingStarted.WhileSubscribed(5_000)
+ )
+
+ val mostSearchedKeywords: StateFlow> = articleRepository.fetchMostSearchedKeywords(
+ MOST_SEARCHED_KEYWORD_COUNT
+ ).stateIn(
+ scope = viewModelScope,
+ started = SharingStarted.WhileSubscribed(5_000),
+ initialValue = emptyList()
+ )
+
fun onSearchInputChanged(query: String) {
savedStateHandle[SEARCH_INPUT] = query
}
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/state/ArticlePaginationState.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/state/ArticlePaginationState.kt
similarity index 72%
rename from koin/src/main/java/in/koreatech/koin/ui/article/state/ArticlePaginationState.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/state/ArticlePaginationState.kt
index 3ae59bbb97..cef0d27422 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/state/ArticlePaginationState.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/state/ArticlePaginationState.kt
@@ -1,6 +1,8 @@
-package `in`.koreatech.koin.ui.article.state
+package `in`.koreatech.koin.feature.article.ui.article.state
import `in`.koreatech.koin.domain.model.article.ArticlePagination
+import `in`.koreatech.koin.feature.article.model.ArticleHeaderState
+import `in`.koreatech.koin.feature.article.model.toArticleHeaderState
data class ArticlePaginationState(
val articles: List,
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/state/ArticleState.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/state/ArticleState.kt
similarity index 72%
rename from koin/src/main/java/in/koreatech/koin/ui/article/state/ArticleState.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/state/ArticleState.kt
index c575f2a07e..b9ebc06261 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/state/ArticleState.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/state/ArticleState.kt
@@ -1,6 +1,8 @@
-package `in`.koreatech.koin.ui.article.state
+package `in`.koreatech.koin.feature.article.ui.article.state
import `in`.koreatech.koin.domain.model.article.Article
+import `in`.koreatech.koin.feature.article.model.ArticleHeaderState
+import `in`.koreatech.koin.feature.article.model.toArticleHeaderState
data class ArticleState(
val header: ArticleHeaderState,
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/state/AttachmentState.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/state/AttachmentState.kt
similarity index 93%
rename from koin/src/main/java/in/koreatech/koin/ui/article/state/AttachmentState.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/state/AttachmentState.kt
index 759eb74dc7..652234c023 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/state/AttachmentState.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/state/AttachmentState.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.ui.article.state
+package `in`.koreatech.koin.feature.article.ui.article.state
import `in`.koreatech.koin.core.util.RegexPatterns
import `in`.koreatech.koin.domain.model.article.Attachment
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/state/HtmlElement.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/state/HtmlElement.kt
similarity index 93%
rename from koin/src/main/java/in/koreatech/koin/ui/article/state/HtmlElement.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/state/HtmlElement.kt
index 75ca84bed7..cebc8883a3 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/state/HtmlElement.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/article/state/HtmlElement.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.ui.article.state
+package `in`.koreatech.koin.feature.article.ui.article.state
import android.os.Parcelable
import `in`.koreatech.koin.domain.model.article.html.CssAttribute
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/LostAndFoundDetail.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/LostAndFoundDetail.kt
similarity index 86%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/LostAndFoundDetail.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/LostAndFoundDetail.kt
index 436f91b807..59bd128e2c 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/LostAndFoundDetail.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/LostAndFoundDetail.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.detail
+package `in`.koreatech.koin.feature.article.ui.lostandfound.detail
import android.content.Context
import android.content.Intent
@@ -22,15 +22,15 @@ import androidx.hilt.navigation.compose.hiltViewModel
import `in`.koreatech.koin.core.analytics.AnalyticsConstant
import `in`.koreatech.koin.core.analytics.EventLogger
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.R
-import `in`.koreatech.koin.feature.lostandfound.component.HotArticle
-import `in`.koreatech.koin.feature.lostandfound.component.HotArticleData
-import `in`.koreatech.koin.feature.lostandfound.component.LoadingDialog
-import `in`.koreatech.koin.feature.lostandfound.enums.LostOrFoundType
-import `in`.koreatech.koin.feature.lostandfound.ui.detail.component.DetailButtonGroup
-import `in`.koreatech.koin.feature.lostandfound.ui.detail.component.DetailContent
-import `in`.koreatech.koin.feature.lostandfound.ui.detail.component.DetailHeader
-import `in`.koreatech.koin.feature.lostandfound.util.findActivity
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.component.HotArticle
+import `in`.koreatech.koin.feature.article.component.HotArticleData
+import `in`.koreatech.koin.feature.article.component.LoadingDialog
+import `in`.koreatech.koin.feature.article.enums.LostOrFoundType
+import `in`.koreatech.koin.feature.article.ui.lostandfound.detail.component.DetailButtonGroup
+import `in`.koreatech.koin.feature.article.ui.lostandfound.detail.component.DetailContent
+import `in`.koreatech.koin.feature.article.ui.lostandfound.detail.component.DetailHeader
+import `in`.koreatech.koin.feature.article.util.findActivity
import org.orbitmvi.orbit.compose.collectAsState
import org.orbitmvi.orbit.compose.collectSideEffect
@@ -153,10 +153,9 @@ private fun handleSideEffect(
LostAndFoundDetailSideEffect.DeletedArticle -> {
context.findActivity()?.finish()
- val intent =
- Intent(Intent.ACTION_VIEW).apply {
- data = Uri.parse("koin://article/activity?fragment=article_lost_and_found")
- }
+ val intent = Intent(Intent.ACTION_VIEW).apply {
+ data = Uri.parse("koin://article/activity?fragment=article_lost_and_found")
+ }
context.startActivity(intent)
Toast.makeText(
context,
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/LostAndFoundDetailSideEffect.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/LostAndFoundDetailSideEffect.kt
similarity index 85%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/LostAndFoundDetailSideEffect.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/LostAndFoundDetailSideEffect.kt
index f5a96821e0..28d71d96ed 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/LostAndFoundDetailSideEffect.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/LostAndFoundDetailSideEffect.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.detail
+package `in`.koreatech.koin.feature.article.ui.lostandfound.detail
sealed class LostAndFoundDetailSideEffect {
// data class FetchDetail(val id: Int) : LostAndFoundDetailSideEffect()
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/LostAndFoundDetailState.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/LostAndFoundDetailState.kt
similarity index 85%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/LostAndFoundDetailState.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/LostAndFoundDetailState.kt
index 3a7535f1e2..6c45c20bd4 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/LostAndFoundDetailState.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/LostAndFoundDetailState.kt
@@ -1,11 +1,11 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.detail
+package `in`.koreatech.koin.feature.article.ui.lostandfound.detail
import android.net.Uri
import android.os.Parcelable
import `in`.koreatech.koin.domain.model.article.ArticleLostAndFound
-import `in`.koreatech.koin.feature.lostandfound.enums.LostItemCategory
-import `in`.koreatech.koin.feature.lostandfound.enums.LostOrFoundType
-import `in`.koreatech.koin.feature.lostandfound.model.ArticleHeaderState
+import `in`.koreatech.koin.feature.article.enums.LostItemCategory
+import `in`.koreatech.koin.feature.article.enums.LostOrFoundType
+import `in`.koreatech.koin.feature.article.model.ArticleHeaderState
import java.time.LocalDate
import kotlinx.parcelize.Parcelize
diff --git a/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/LostAndFoundDetailViewModel.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/LostAndFoundDetailViewModel.kt
new file mode 100644
index 0000000000..b542995c9e
--- /dev/null
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/LostAndFoundDetailViewModel.kt
@@ -0,0 +1,140 @@
+package `in`.koreatech.koin.feature.article.ui.lostandfound.detail
+
+import android.webkit.URLUtil
+import androidx.lifecycle.SavedStateHandle
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.lifecycle.HiltViewModel
+import `in`.koreatech.koin.domain.model.user.User
+import `in`.koreatech.koin.domain.usecase.article.lostandfound.DeleteArticleLostAndFoundUseCase
+import `in`.koreatech.koin.domain.usecase.article.lostandfound.FetchHotArticlesUseCase
+import `in`.koreatech.koin.domain.usecase.article.lostandfound.FetchLostAndFoundArticleUseCase
+import `in`.koreatech.koin.domain.usecase.user.GetUserStatusUseCase
+import `in`.koreatech.koin.feature.article.model.toArticleHeaderState
+import javax.inject.Inject
+import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
+import org.orbitmvi.orbit.ContainerHost
+import org.orbitmvi.orbit.syntax.simple.intent
+import org.orbitmvi.orbit.syntax.simple.postSideEffect
+import org.orbitmvi.orbit.syntax.simple.reduce
+import org.orbitmvi.orbit.viewmodel.container
+import retrofit2.HttpException
+
+@HiltViewModel
+class LostAndFoundDetailViewModel @Inject constructor(
+ savedStateHandle: SavedStateHandle,
+ private val fetchLostAndFoundArticleUseCase: FetchLostAndFoundArticleUseCase,
+ private val fetchHotArticlesUseCase: FetchHotArticlesUseCase,
+ private val deleteArticleLostAndFoundUseCase: DeleteArticleLostAndFoundUseCase,
+ private val getUserStatusUseCase: GetUserStatusUseCase
+) : ViewModel(), ContainerHost {
+ override val container = container(LostAndFoundDetailState(), savedStateHandle) {
+ val articleId = savedStateHandle.get(ARTICLE_ID)
+ checkNotNull(articleId)
+ fetchLostAndFoundDetail(articleId)
+ }
+
+ init {
+ initUserInfo()
+ fetchHotArticles()
+ }
+
+ private fun initUserInfo() = viewModelScope.launch {
+ getUserStatusUseCase().collectLatest {
+ intent {
+ when (it) {
+ is User.Student -> reduce {
+ state.copy(
+ isLoggedIn = true,
+ currentLoggedInUser = it.nickname ?: ""
+ )
+ }
+ is User.General -> reduce {
+ state.copy(
+ isLoggedIn = true,
+ currentLoggedInUser = it.nickname ?: ""
+ )
+ }
+ is User.Anonymous -> reduce {
+ state.copy(isLoggedIn = false)
+ }
+ }
+ }
+ }
+ }
+
+ fun fetchLostAndFoundDetail(articleId: Int) = viewModelScope.launch {
+ intent {
+ reduce {
+ state.copy(
+ isLoading = true
+ )
+ }
+ fetchLostAndFoundArticleUseCase(articleId).catch {
+ if (it is HttpException && it.code() == 404) {
+ postSideEffect(LostAndFoundDetailSideEffect.DeletedArticle)
+ }
+ }.map {
+ it.toLostAndFoundDetailState()
+ }.collectLatest { article ->
+ reduce {
+ state.copy(
+ lostOrFound = article.lostOrFound,
+ id = article.id,
+ category = article.category,
+ foundPlace = article.foundPlace,
+ foundDate = article.foundDate,
+ content = article.content,
+ author = article.author,
+ images = article.images?.filter { URLUtil.isValidUrl(it.toString()) },
+ registeredAt = article.registeredAt,
+ updatedAt = article.updatedAt,
+ isWriterCouncil = article.isWriterCouncil,
+ isMine = state.currentLoggedInUser == article.author,
+ isAuthorWithdraw = article.author == "탈퇴한 사용자",
+ isLoading = false
+ )
+ }
+ }
+ }
+ }
+
+ fun fetchHotArticles() = viewModelScope.launch {
+ intent {
+ fetchHotArticlesUseCase().collectLatest {
+ reduce {
+ state.copy(
+ hotArticles = it.filterIndexed { index, _ -> index < HOT_ARTICLE_COUNT }
+ .map { it.toArticleHeaderState() }
+ )
+ }
+ }
+ }
+ }
+
+ fun deleteArticle() = viewModelScope.launch {
+ intent {
+ deleteArticleLostAndFoundUseCase(state.id).onSuccess {
+ postSideEffect(LostAndFoundDetailSideEffect.DeleteArticle(state.id))
+ }.onFailure {
+ postSideEffect(LostAndFoundDetailSideEffect.DeleteArticleFailed)
+ }
+ }
+ }
+
+ fun setShowDeleteDialog(show: Boolean) = intent {
+ reduce {
+ state.copy(
+ showDeleteDialog = show
+ )
+ }
+ }
+
+ companion object {
+ const val HOT_ARTICLE_COUNT = 4
+ const val ARTICLE_ID = "article_id"
+ }
+}
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/component/DetailButtonGroup.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/component/DetailButtonGroup.kt
similarity index 98%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/component/DetailButtonGroup.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/component/DetailButtonGroup.kt
index 865593a107..5346d2299f 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/component/DetailButtonGroup.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/component/DetailButtonGroup.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.detail.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.detail.component
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.PaddingValues
@@ -21,7 +21,7 @@ import androidx.compose.ui.unit.dp
import `in`.koreatech.koin.core.analytics.AnalyticsConstant
import `in`.koreatech.koin.core.analytics.EventLogger
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.R
+import `in`.koreatech.koin.feature.article.R
@Composable
fun DetailButtonGroup(
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/component/DetailContent.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/component/DetailContent.kt
similarity index 72%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/component/DetailContent.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/component/DetailContent.kt
index 41612e8c83..059a7f667b 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/component/DetailContent.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/component/DetailContent.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.detail.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.detail.component
import android.net.Uri
import android.os.Build
@@ -37,7 +37,7 @@ import coil.decode.GifDecoder
import coil.decode.ImageDecoderDecoder
import coil.request.ImageRequest
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.R
+import `in`.koreatech.koin.feature.article.R
@Composable
fun DetailContent(
@@ -46,36 +46,32 @@ fun DetailContent(
isWriterAdmin: Boolean,
modifier: Modifier = Modifier
) {
- val imageLoader =
- ImageLoader.Builder(LocalContext.current)
- .components {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- add(ImageDecoderDecoder.Factory())
- } else {
- add(GifDecoder.Factory())
- }
+ val imageLoader = ImageLoader.Builder(LocalContext.current)
+ .components {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ add(ImageDecoderDecoder.Factory())
+ } else {
+ add(GifDecoder.Factory())
}
- .build()
+ }
+ .build()
Column(
- modifier =
- modifier
+ modifier = modifier
.padding(vertical = 24.dp, horizontal = 24.dp)
.fillMaxWidth()
) {
if (imageUris != null) {
- val pagerState =
- rememberPagerState(pageCount = {
- imageUris.size
- })
+ val pagerState = rememberPagerState(pageCount = {
+ imageUris.size
+ })
HorizontalPager(
modifier = Modifier.fillMaxWidth(),
state = pagerState
) { page ->
SubcomposeAsyncImage(
modifier = Modifier.fillMaxWidth().align(Alignment.CenterHorizontally),
- model =
- ImageRequest.Builder(LocalContext.current)
+ model = ImageRequest.Builder(LocalContext.current)
.data(imageUris[page])
.crossfade(true)
.build(),
@@ -96,8 +92,7 @@ fun DetailContent(
Spacer(modifier = Modifier.height(8.dp))
Row(
- modifier =
- Modifier
+ modifier = Modifier
.padding(vertical = 12.dp)
.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally),
@@ -105,16 +100,14 @@ fun DetailContent(
) {
imageUris.indices.forEach { index ->
Image(
- modifier =
- if (index == pagerState.currentPage) {
+ modifier = if (index == pagerState.currentPage) {
Modifier.size(6.dp)
} else {
Modifier.size(
4.dp
)
},
- painter =
- if (index == pagerState.currentPage) {
+ painter = if (index == pagerState.currentPage) {
painterResource(R.drawable.ic_image_page_indicator_filled)
} else {
painterResource(id = R.drawable.ic_image_page_indicator_not_filled)
@@ -137,29 +130,27 @@ fun DetailContent(
Spacer(modifier = Modifier.height(24.dp))
Box(
- modifier =
- Modifier
+ modifier = Modifier
.clip(KoinTheme.shapes.medium)
.fillMaxWidth()
.background(KoinTheme.colors.neutral100)
.padding(vertical = 16.dp, horizontal = 18.dp),
contentAlignment = Alignment.Center
) {
- val infoMessage =
- buildAnnotatedString {
- withStyle(KoinTheme.typography.regular12.toSpanStyle()) {
- append(stringResource(R.string.detail_student_association_info_1))
- }
- withStyle(
- KoinTheme.typography.regular12.copy(fontWeight = FontWeight.Bold)
- .toSpanStyle()
- ) {
- append(stringResource(R.string.detail_student_association_info_2))
- }
- withStyle(KoinTheme.typography.regular12.toSpanStyle()) {
- append(stringResource(R.string.detail_student_association_info_3))
- }
+ val infoMessage = buildAnnotatedString {
+ withStyle(KoinTheme.typography.regular12.toSpanStyle()) {
+ append(stringResource(R.string.detail_student_association_info_1))
+ }
+ withStyle(
+ KoinTheme.typography.regular12.copy(fontWeight = FontWeight.Bold)
+ .toSpanStyle()
+ ) {
+ append(stringResource(R.string.detail_student_association_info_2))
}
+ withStyle(KoinTheme.typography.regular12.toSpanStyle()) {
+ append(stringResource(R.string.detail_student_association_info_3))
+ }
+ }
Text(
text = infoMessage,
textAlign = TextAlign.Center,
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/component/DetailDialog.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/component/DetailDialog.kt
similarity index 96%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/component/DetailDialog.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/component/DetailDialog.kt
index fd26f5526b..743083ac68 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/component/DetailDialog.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/component/DetailDialog.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.detail.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.detail.component
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
@@ -24,7 +24,7 @@ import `in`.koreatech.koin.core.designsystem.component.button.FilledButtonColors
import `in`.koreatech.koin.core.designsystem.component.button.OutlinedBoxButton
import `in`.koreatech.koin.core.designsystem.component.button.OutlinedBoxButtonColors
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.R
+import `in`.koreatech.koin.feature.article.R
/**
* @see in.koreatech.koin.core.designsystem.component.dialog.ChoiceDialog
@@ -52,8 +52,7 @@ fun DetailDialog(
negativeButtonColors: OutlinedBoxButtonColors = OutlinedBoxButtonColors.Neutral
) {
BasicAlertDialog(
- modifier =
- modifier
+ modifier = modifier
.fillMaxWidth()
.wrapContentHeight()
.background(
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/component/DetailHeader.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/component/DetailHeader.kt
similarity index 72%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/component/DetailHeader.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/component/DetailHeader.kt
index 90b1f8d65a..0a17a7664a 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/component/DetailHeader.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/detail/component/DetailHeader.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.detail.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.detail.component
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -12,10 +12,10 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.component.LostItemTypeChip
-import `in`.koreatech.koin.feature.lostandfound.enums.LostItemCategory
-import `in`.koreatech.koin.feature.lostandfound.enums.LostOrFoundType
-import `in`.koreatech.koin.feature.lostandfound.util.getKoreanDayOfWeekShortName
+import `in`.koreatech.koin.feature.article.component.LostItemTypeChip
+import `in`.koreatech.koin.feature.article.enums.LostItemCategory
+import `in`.koreatech.koin.feature.article.enums.LostOrFoundType
+import `in`.koreatech.koin.feature.article.util.getKoreanDayOfWeekShortName
import java.time.LocalDate
import java.time.format.DateTimeFormatter
@@ -30,19 +30,17 @@ fun DetailHeader(
modifier: Modifier = Modifier
) {
val registeredAtFormatType = DateTimeFormatter.ofPattern("MM.dd")
- val convertedRegisteredAt =
- remember(key1 = registeredAt) { "${registeredAt.format(registeredAtFormatType)} ${registeredAt.getKoreanDayOfWeekShortName()}" }
+ val convertedRegisteredAt = remember(key1 = registeredAt) { "${registeredAt.format(registeredAtFormatType)} ${registeredAt.getKoreanDayOfWeekShortName()}" }
val foundDateFormatType = DateTimeFormatter.ofPattern("yy.MM.dd")
- val headerText =
- remember(key1 = foundPlace, key2 = foundDate) {
- "${
- foundPlace.replace(
- "\n",
- " "
- )
- } | ${foundDate.format(foundDateFormatType)}"
- }
+ val headerText = remember(key1 = foundPlace, key2 = foundDate) {
+ "${
+ foundPlace.replace(
+ "\n",
+ " "
+ )
+ } | ${foundDate.format(foundDateFormatType)}"
+ }
Column(
modifier = modifier.padding(vertical = 12.dp, horizontal = 24.dp)
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/lostandfound/ArticleListLostAndFoundFragment.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/fragment/ArticleListLostAndFoundFragment.kt
similarity index 89%
rename from koin/src/main/java/in/koreatech/koin/ui/article/lostandfound/ArticleListLostAndFoundFragment.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/fragment/ArticleListLostAndFoundFragment.kt
index e6897431a8..1cf16b7aba 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/lostandfound/ArticleListLostAndFoundFragment.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/fragment/ArticleListLostAndFoundFragment.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.ui.article.lostandfound
+package `in`.koreatech.koin.feature.article.ui.lostandfound.fragment
import android.os.Bundle
import android.view.LayoutInflater
@@ -10,10 +10,10 @@ import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import dagger.hilt.android.AndroidEntryPoint
-import `in`.koreatech.koin.R
import `in`.koreatech.koin.core.navigation.Navigator
-import `in`.koreatech.koin.feature.lostandfound.ui.lostandfound.LostAndFoundList
-import `in`.koreatech.koin.feature.lostandfound.ui.write.LostAndFoundWriteArticleViewModel.Companion.LOST_OR_FOUND_TYPE
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.ui.lostandfound.list.LostAndFoundList
+import `in`.koreatech.koin.feature.article.ui.lostandfound.write.LostAndFoundWriteArticleViewModel.Companion.LOST_OR_FOUND_TYPE
import javax.inject.Inject
@AndroidEntryPoint
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/lostandfound/ArticleLostAndFoundDetailFragment.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/fragment/ArticleLostAndFoundDetailFragment.kt
similarity index 75%
rename from koin/src/main/java/in/koreatech/koin/ui/article/lostandfound/ArticleLostAndFoundDetailFragment.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/fragment/ArticleLostAndFoundDetailFragment.kt
index 08b0c6bd01..adf43e760f 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/lostandfound/ArticleLostAndFoundDetailFragment.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/fragment/ArticleLostAndFoundDetailFragment.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.ui.article.lostandfound
+package `in`.koreatech.koin.feature.article.ui.lostandfound.fragment
import android.content.Intent
import android.os.Bundle
@@ -10,16 +10,22 @@ import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import dagger.hilt.android.AndroidEntryPoint
-import `in`.koreatech.koin.R
import `in`.koreatech.koin.core.analytics.AnalyticsConstant
import `in`.koreatech.koin.core.analytics.EventAction
import `in`.koreatech.koin.core.analytics.EventLogger
-import `in`.koreatech.koin.feature.chat.ui.room.ChatRoomActivity
-import `in`.koreatech.koin.feature.lostandfound.ui.detail.LostAndFoundDetail
-import `in`.koreatech.koin.ui.article.ArticleDetailFragment.Companion.NAVIGATED_BOARD_ID
+import `in`.koreatech.koin.core.navigation.Navigator
+import `in`.koreatech.koin.feature.article.LostAndFoundReportActivity
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.ui.article.detail.ArticleDetailFragment
+import `in`.koreatech.koin.feature.article.ui.lostandfound.detail.LostAndFoundDetail
+import javax.inject.Inject
@AndroidEntryPoint
class ArticleLostAndFoundDetailFragment : Fragment() {
+
+ @Inject
+ lateinit var navigator: Navigator
+
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -44,16 +50,14 @@ class ArticleLostAndFoundDetailFragment : Fragment() {
R.id.articleLostAndFoundDetailFragment_to_articleDetailFragment,
Bundle().apply {
putInt(ARTICLE_ID, hotArticleData.articleId)
- putInt(NAVIGATED_BOARD_ID, hotArticleData.board.id)
+ putInt(ArticleDetailFragment.Companion.NAVIGATED_BOARD_ID, hotArticleData.board.id)
}
)
},
navigateToChatRoom = { articleId ->
- Intent(requireContext(), ChatRoomActivity::class.java).apply {
- putExtra(ARTICLE_ID, articleId)
- }.also {
- startActivity(it)
- }
+ val intent = navigator.navigateToChatRoom(requireContext())
+ intent.putExtra(ARTICLE_ID, articleId)
+ startActivity(intent)
},
navigateToReport = { articleId ->
Intent(requireContext(), LostAndFoundReportActivity::class.java).apply {
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/lostandfound/ArticleLostAndFoundWriteFoundFragment.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/fragment/ArticleLostAndFoundWriteFoundFragment.kt
similarity index 86%
rename from koin/src/main/java/in/koreatech/koin/ui/article/lostandfound/ArticleLostAndFoundWriteFoundFragment.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/fragment/ArticleLostAndFoundWriteFoundFragment.kt
index 89d15c53cc..5bdeeb225b 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/lostandfound/ArticleLostAndFoundWriteFoundFragment.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/fragment/ArticleLostAndFoundWriteFoundFragment.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.ui.article.lostandfound
+package `in`.koreatech.koin.feature.article.ui.lostandfound.fragment
import android.os.Bundle
import android.view.LayoutInflater
@@ -9,8 +9,8 @@ import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import dagger.hilt.android.AndroidEntryPoint
-import `in`.koreatech.koin.R
-import `in`.koreatech.koin.feature.lostandfound.ui.write.LostAndFoundWriteArticle
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.ui.lostandfound.write.LostAndFoundWriteArticle
@AndroidEntryPoint
class ArticleLostAndFoundWriteFoundFragment : Fragment() {
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/lostandfound/ArticleLostAndFoundWriteLostFragment.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/fragment/ArticleLostAndFoundWriteLostFragment.kt
similarity index 86%
rename from koin/src/main/java/in/koreatech/koin/ui/article/lostandfound/ArticleLostAndFoundWriteLostFragment.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/fragment/ArticleLostAndFoundWriteLostFragment.kt
index 19ce27e497..264a85d545 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/lostandfound/ArticleLostAndFoundWriteLostFragment.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/fragment/ArticleLostAndFoundWriteLostFragment.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.ui.article.lostandfound
+package `in`.koreatech.koin.feature.article.ui.lostandfound.fragment
import android.os.Bundle
import android.view.LayoutInflater
@@ -9,8 +9,8 @@ import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import dagger.hilt.android.AndroidEntryPoint
-import `in`.koreatech.koin.R
-import `in`.koreatech.koin.feature.lostandfound.ui.write.LostAndFoundWriteArticle
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.ui.lostandfound.write.LostAndFoundWriteArticle
@AndroidEntryPoint
class ArticleLostAndFoundWriteLostFragment : Fragment() {
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/LostAndFound.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/LostAndFound.kt
similarity index 94%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/LostAndFound.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/LostAndFound.kt
index a607fa1f9d..b78681974a 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/LostAndFound.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/LostAndFound.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.lostandfound
+package `in`.koreatech.koin.feature.article.ui.lostandfound.list
import android.widget.Toast
import androidx.compose.animation.core.animateDpAsState
@@ -37,16 +37,16 @@ import androidx.lifecycle.compose.LifecycleEventEffect
import `in`.koreatech.koin.core.analytics.AnalyticsConstant
import `in`.koreatech.koin.core.analytics.EventLogger
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.R
-import `in`.koreatech.koin.feature.lostandfound.component.LoadingDialog
-import `in`.koreatech.koin.feature.lostandfound.enums.LostOrFoundType
-import `in`.koreatech.koin.feature.lostandfound.ui.lostandfound.component.LostAndFoundDialog
-import `in`.koreatech.koin.feature.lostandfound.ui.lostandfound.component.LostAndFoundDropdownGroup
-import `in`.koreatech.koin.feature.lostandfound.ui.lostandfound.component.LostAndFoundFAB
-import `in`.koreatech.koin.feature.lostandfound.ui.lostandfound.component.LostAndFoundItem
-import `in`.koreatech.koin.feature.lostandfound.ui.lostandfound.component.LostAndFoundKeywordGroup
-import `in`.koreatech.koin.feature.lostandfound.ui.lostandfound.component.LostAndFoundPagination
-import `in`.koreatech.koin.feature.lostandfound.ui.lostandfound.component.lostAndFoundDialogStyle
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.component.LoadingDialog
+import `in`.koreatech.koin.feature.article.enums.LostOrFoundType
+import `in`.koreatech.koin.feature.article.ui.lostandfound.list.component.LostAndFoundDialog
+import `in`.koreatech.koin.feature.article.ui.lostandfound.list.component.LostAndFoundDropdownGroup
+import `in`.koreatech.koin.feature.article.ui.lostandfound.list.component.LostAndFoundFAB
+import `in`.koreatech.koin.feature.article.ui.lostandfound.list.component.LostAndFoundItem
+import `in`.koreatech.koin.feature.article.ui.lostandfound.list.component.LostAndFoundKeywordGroup
+import `in`.koreatech.koin.feature.article.ui.lostandfound.list.component.LostAndFoundPagination
+import `in`.koreatech.koin.feature.article.ui.lostandfound.list.component.lostAndFoundDialogStyle
import kotlinx.coroutines.launch
import org.orbitmvi.orbit.compose.collectAsState
import org.orbitmvi.orbit.compose.collectSideEffect
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/LostAndFoundItemState.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/LostAndFoundItemState.kt
similarity index 90%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/LostAndFoundItemState.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/LostAndFoundItemState.kt
index ca4fa4f8af..64d540e8c7 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/LostAndFoundItemState.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/LostAndFoundItemState.kt
@@ -1,10 +1,10 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.lostandfound
+package `in`.koreatech.koin.feature.article.ui.lostandfound.list
import android.os.Parcelable
import `in`.koreatech.koin.domain.model.article.ArticleHeader
import `in`.koreatech.koin.domain.model.article.ArticleLostAndFoundHeader
-import `in`.koreatech.koin.feature.lostandfound.enums.LostItemCategory
-import `in`.koreatech.koin.feature.lostandfound.enums.LostOrFoundType
+import `in`.koreatech.koin.feature.article.enums.LostItemCategory
+import `in`.koreatech.koin.feature.article.enums.LostOrFoundType
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import kotlinx.parcelize.Parcelize
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/LostAndFoundSideEffect.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/LostAndFoundSideEffect.kt
similarity index 75%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/LostAndFoundSideEffect.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/LostAndFoundSideEffect.kt
index ae929d33f2..43847cba76 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/LostAndFoundSideEffect.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/LostAndFoundSideEffect.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.lostandfound
+package `in`.koreatech.koin.feature.article.ui.lostandfound.list
sealed class LostAndFoundSideEffect {
data class PageChanged(val page: Int) : LostAndFoundSideEffect()
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/LostAndFoundState.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/LostAndFoundState.kt
similarity index 83%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/LostAndFoundState.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/LostAndFoundState.kt
index a3f95a1906..23f60cd1b6 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/LostAndFoundState.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/LostAndFoundState.kt
@@ -1,7 +1,7 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.lostandfound
+package `in`.koreatech.koin.feature.article.ui.lostandfound.list
import android.os.Parcelable
-import `in`.koreatech.koin.feature.lostandfound.enums.LostOrFoundType
+import `in`.koreatech.koin.feature.article.enums.LostOrFoundType
import kotlinx.parcelize.Parcelize
@Parcelize
diff --git a/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/LostAndFoundViewModel.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/LostAndFoundViewModel.kt
new file mode 100644
index 0000000000..f1449defa6
--- /dev/null
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/LostAndFoundViewModel.kt
@@ -0,0 +1,200 @@
+package `in`.koreatech.koin.feature.article.ui.lostandfound.list
+
+import androidx.lifecycle.SavedStateHandle
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.lifecycle.HiltViewModel
+import `in`.koreatech.koin.domain.model.user.User
+import `in`.koreatech.koin.domain.usecase.article.FetchMyKeywordUseCase
+import `in`.koreatech.koin.domain.usecase.article.lostandfound.FetchLostAndFoundArticlePaginationUseCase
+import `in`.koreatech.koin.domain.usecase.article.lostandfound.FetchSearchedLostAndFoundArticlesUseCase
+import `in`.koreatech.koin.domain.usecase.user.GetUserStatusUseCase
+import `in`.koreatech.koin.feature.article.enums.LostOrFoundType
+import javax.inject.Inject
+import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.launch
+import org.orbitmvi.orbit.ContainerHost
+import org.orbitmvi.orbit.syntax.simple.intent
+import org.orbitmvi.orbit.syntax.simple.postSideEffect
+import org.orbitmvi.orbit.syntax.simple.reduce
+import org.orbitmvi.orbit.viewmodel.container
+import timber.log.Timber
+
+@HiltViewModel
+class LostAndFoundViewModel @Inject constructor(
+ private val fetchLostAndFoundArticlePaginationUseCase: FetchLostAndFoundArticlePaginationUseCase,
+ private val fetchSearchedLostAndFoundArticlesUseCase: FetchSearchedLostAndFoundArticlesUseCase,
+ private val fetchMyKeywordUseCase: FetchMyKeywordUseCase,
+ private val getUserStatusUseCase: GetUserStatusUseCase,
+ savedStateHandle: SavedStateHandle
+) : ViewModel(), ContainerHost {
+ override val container = container(
+ initialState = LostAndFoundState(),
+ savedStateHandle = savedStateHandle
+ )
+
+ init {
+ fetchLostAndFoundList()
+ fetchMyKeyword()
+ getUserType()
+ }
+
+ fun fetchLostAndFoundList() = viewModelScope.launch {
+ intent {
+ reduce {
+ state.copy(
+ isLoading = true
+ )
+ }
+
+ if (state.selectedKeyword.isEmpty()) {
+ fetchLostAndFoundArticlePaginationUseCase(
+ state.currentPage,
+ ARTICLES_PER_PAGE,
+ state.selectedType?.name
+ ).collectLatest {
+ reduce {
+ state.copy(
+ lostAndFoundList = it.articleLostAndFoundHeader.map { it.toLostAndFoundItemState() },
+ currentCount = it.currentCount,
+ totalCount = it.totalCount,
+ currentPage = it.currentPage,
+ totalPage = it.totalPage,
+ isLoading = false
+ )
+ }
+ }
+ } else {
+ fetchSearchedLostAndFoundArticlesUseCase(
+ state.selectedKeyword,
+ state.currentPage,
+ ARTICLES_PER_PAGE
+ ).collectLatest {
+ reduce {
+ state.copy(
+ lostAndFoundList = it.articleLostAndFoundHeader.map { it.toLostAndFoundItemState() },
+ currentCount = it.currentCount,
+ totalCount = it.totalCount,
+ currentPage = it.currentPage,
+ totalPage = it.totalPage
+ )
+ }
+ }
+
+ reduce {
+ state.copy(
+ isLoading = false
+ )
+ }
+ }
+ }
+ }
+
+ fun fetchMyKeyword() = viewModelScope.launch {
+ fetchMyKeywordUseCase().catch {
+ intent {
+ reduce {
+ state.copy(
+ myKeywords = emptyList()
+ )
+ }
+ Timber.d("Failed to fetch my keywords $it")
+ }
+ throw it
+ }.collectLatest {
+ intent {
+ reduce {
+ state.copy(
+ myKeywords = it
+ )
+ }
+ postSideEffect(LostAndFoundSideEffect.KeywordUpdated)
+ }
+ }
+ }
+
+ fun selectKeyword(it: String) {
+ intent {
+ reduce {
+ state.copy(
+ selectedKeyword = it
+ )
+ }
+ }
+ }
+
+ fun getUserType() = viewModelScope.launch {
+ getUserStatusUseCase().collectLatest { user ->
+ intent {
+ when (user) {
+ is User.Student -> reduce {
+ state.copy(
+ isAnonymous = false,
+ userType = user.userType
+ )
+ }
+
+ is User.General -> reduce {
+ state.copy(
+ isAnonymous = false,
+ userType = user.userType
+ )
+ }
+ User.Anonymous -> reduce {
+ state.copy(
+ isAnonymous = true
+ )
+ }
+ }
+ }
+ }
+ }
+
+ fun changePage(page: Int) {
+ intent {
+ reduce {
+ state.copy(
+ currentPage = page
+ )
+ }
+ postSideEffect(LostAndFoundSideEffect.PageChanged(page))
+ }
+ }
+
+ fun setShowLoginRequestDialog(showDialog: Boolean) = intent {
+ reduce {
+ state.copy(
+ showLoginRequestDialog = showDialog
+ )
+ }
+ }
+
+ fun setFabDialogExpanded(isExpanded: Boolean) = intent {
+ reduce {
+ state.copy(
+ isFabDialogExpanded = isExpanded
+ )
+ }
+ }
+
+ fun setDropdownExpanded(isExpanded: Boolean) = intent {
+ reduce {
+ state.copy(
+ isDropdownExpanded = isExpanded
+ )
+ }
+ }
+
+ fun setSelectedType(type: LostOrFoundType?) = intent {
+ reduce {
+ state.copy(
+ selectedType = type
+ )
+ }
+ }
+
+ companion object {
+ private const val ARTICLES_PER_PAGE = 10
+ }
+}
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/component/LostAndFoundDialog.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/component/LostAndFoundDialog.kt
similarity index 98%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/component/LostAndFoundDialog.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/component/LostAndFoundDialog.kt
index 63a62d7bbe..b5512a4c44 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/component/LostAndFoundDialog.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/component/LostAndFoundDialog.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.lostandfound.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.list.component
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
@@ -53,8 +53,7 @@ fun LostAndFoundDialog(
lostAndFoundDialogStyle: LostAndFoundDialogStyle = lostAndFoundDialogStyle()
) {
BasicAlertDialog(
- modifier =
- modifier
+ modifier = modifier
.fillMaxWidth()
.wrapContentHeight()
.background(
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/component/LostAndFoundDropdownGroup.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/component/LostAndFoundDropdownGroup.kt
similarity index 80%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/component/LostAndFoundDropdownGroup.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/component/LostAndFoundDropdownGroup.kt
index bb1348b331..eb949d4484 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/component/LostAndFoundDropdownGroup.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/component/LostAndFoundDropdownGroup.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.lostandfound.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.list.component
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
@@ -8,9 +8,9 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
-import `in`.koreatech.koin.feature.lostandfound.R
-import `in`.koreatech.koin.feature.lostandfound.component.Dropdown
-import `in`.koreatech.koin.feature.lostandfound.enums.LostOrFoundType
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.component.Dropdown
+import `in`.koreatech.koin.feature.article.enums.LostOrFoundType
@Composable
fun LostAndFoundDropdownGroup(
@@ -26,14 +26,12 @@ fun LostAndFoundDropdownGroup(
.padding(horizontal = 24.dp)
) {
Dropdown(
- title =
- when (selectedType) {
+ title = when (selectedType) {
LostOrFoundType.LOST -> stringResource(R.string.dropdown_item_lost)
LostOrFoundType.FOUND -> stringResource(R.string.dropdown_item_found)
else -> stringResource(R.string.dropdown_item_all)
},
- items =
- listOf(
+ items = listOf(
stringResource(R.string.dropdown_item_all),
stringResource(R.string.dropdown_item_found),
stringResource(R.string.dropdown_item_lost)
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/component/LostAndFoundFAB.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/component/LostAndFoundFAB.kt
similarity index 93%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/component/LostAndFoundFAB.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/component/LostAndFoundFAB.kt
index c13d7ed6ea..fb95970e51 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/component/LostAndFoundFAB.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/component/LostAndFoundFAB.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.lostandfound.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.list.component
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
@@ -28,10 +28,9 @@ import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
object LostAndFoundFABDefaults {
val windowInsets: WindowInsets
@Composable
- get() =
- WindowInsets.systemBars.only(
- WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom
- )
+ get() = WindowInsets.systemBars.only(
+ WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom
+ )
}
@Composable
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/component/LostAndFoundItem.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/component/LostAndFoundItem.kt
similarity index 92%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/component/LostAndFoundItem.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/component/LostAndFoundItem.kt
index 6e17463bd4..9b860f55e0 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/component/LostAndFoundItem.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/component/LostAndFoundItem.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.lostandfound.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.list.component
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
@@ -23,11 +23,11 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import `in`.koreatech.koin.core.designsystem.noRippleClickable
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.R
-import `in`.koreatech.koin.feature.lostandfound.component.LostItemTypeChip
-import `in`.koreatech.koin.feature.lostandfound.enums.LostItemCategory
-import `in`.koreatech.koin.feature.lostandfound.enums.LostOrFoundType
-import `in`.koreatech.koin.feature.lostandfound.util.getKoreanDayOfWeekShortName
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.component.LostItemTypeChip
+import `in`.koreatech.koin.feature.article.enums.LostItemCategory
+import `in`.koreatech.koin.feature.article.enums.LostOrFoundType
+import `in`.koreatech.koin.feature.article.util.getKoreanDayOfWeekShortName
import java.time.LocalDate
import java.time.format.DateTimeFormatter
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/component/LostAndFoundKeywordGroup.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/component/LostAndFoundKeywordGroup.kt
similarity index 82%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/component/LostAndFoundKeywordGroup.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/component/LostAndFoundKeywordGroup.kt
index 7e67aadcb3..3e98918ef1 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/component/LostAndFoundKeywordGroup.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/component/LostAndFoundKeywordGroup.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.lostandfound.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.list.component
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
@@ -30,9 +30,9 @@ import `in`.koreatech.koin.core.analytics.AnalyticsConstant
import `in`.koreatech.koin.core.analytics.EventAction
import `in`.koreatech.koin.core.analytics.EventLogger
import `in`.koreatech.koin.core.designsystem.noRippleClickable
-import `in`.koreatech.koin.feature.lostandfound.R
-import `in`.koreatech.koin.feature.lostandfound.component.LostAndFoundTextChip
-import `in`.koreatech.koin.feature.lostandfound.util.horizontalFadingEdge
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.component.LostAndFoundTextChip
+import `in`.koreatech.koin.feature.article.util.horizontalFadingEdge
@Composable
fun LostAndFoundKeywordGroup(
@@ -48,34 +48,29 @@ fun LostAndFoundKeywordGroup(
* TextStyle for keyword chip
* for match design with xml based view
*/
- val textStyle =
- TextStyle(
- fontSize = 14.sp,
- fontStyle = FontStyle.Normal,
- platformStyle =
- PlatformTextStyle(
- includeFontPadding = false
- ),
- lineHeightStyle =
- LineHeightStyle(
- alignment = LineHeightStyle.Alignment.Center,
- trim = LineHeightStyle.Trim.None
- ),
- letterSpacing = 0.2.sp,
- lineHeight = 20.sp
- )
+ val textStyle = TextStyle(
+ fontSize = 14.sp,
+ fontStyle = FontStyle.Normal,
+ platformStyle = PlatformTextStyle(
+ includeFontPadding = false
+ ),
+ lineHeightStyle = LineHeightStyle(
+ alignment = LineHeightStyle.Alignment.Center,
+ trim = LineHeightStyle.Trim.None
+ ),
+ letterSpacing = 0.2.sp,
+ lineHeight = 20.sp
+ )
Row(
- modifier =
- modifier
+ modifier = modifier
.padding(vertical = 16.dp, horizontal = 24.dp)
.horizontalFadingEdge(scrollState, 24.dp, Color.White)
.horizontalScroll(scrollState),
verticalAlignment = Alignment.CenterVertically
) {
Box(
- modifier =
- Modifier
+ modifier = Modifier
.size(32.dp)
.background(
color = Color(0xFFF5F5F5),
@@ -101,8 +96,7 @@ fun LostAndFoundKeywordGroup(
Spacer(modifier = Modifier.width(8.dp))
LostAndFoundTextChip(
- modifier =
- Modifier.defaultMinSize(
+ modifier = Modifier.defaultMinSize(
minWidth = Dp.Unspecified,
minHeight = 32.dp
),
@@ -123,8 +117,7 @@ fun LostAndFoundKeywordGroup(
keyWords.forEachIndexed { index, it ->
LostAndFoundTextChip(
- modifier =
- Modifier.defaultMinSize(
+ modifier = Modifier.defaultMinSize(
minWidth = Dp.Unspecified,
minHeight = 32.dp
),
@@ -140,8 +133,7 @@ fun LostAndFoundKeywordGroup(
if (keyWords.isEmpty()) {
LostAndFoundTextChip(
- modifier =
- Modifier.defaultMinSize(
+ modifier = Modifier.defaultMinSize(
minWidth = Dp.Unspecified,
minHeight = 32.dp
),
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/component/LostAndFoundPagination.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/component/LostAndFoundPagination.kt
similarity index 94%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/component/LostAndFoundPagination.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/component/LostAndFoundPagination.kt
index 08cad7f120..74ddc01bc3 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/component/LostAndFoundPagination.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/list/component/LostAndFoundPagination.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.lostandfound.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.list.component
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
@@ -18,7 +18,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import `in`.koreatech.koin.core.designsystem.noRippleClickable
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.R
+import `in`.koreatech.koin.feature.article.R
@Composable
fun LostAndFoundPagination(
@@ -70,8 +70,7 @@ fun LostAndFoundPaginationButton(
onClick: () -> Unit = {}
) {
Text(
- modifier =
- modifier
+ modifier = modifier
.noRippleClickable {
if (isClickable) {
onClick()
@@ -91,8 +90,7 @@ fun LostAndFoundPaginationPageButton(
onClick: (Int) -> Unit = {}
) {
Box(
- modifier =
- modifier
+ modifier = modifier
.size(32.dp)
.noRippleClickable(onClick = { onClick(page) })
.clip(RoundedCornerShape(6.dp))
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/LostAndFoundReport.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/LostAndFoundReport.kt
similarity index 88%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/LostAndFoundReport.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/LostAndFoundReport.kt
index b572c1f167..177c3487e7 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/LostAndFoundReport.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/LostAndFoundReport.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.report
+package `in`.koreatech.koin.feature.article.ui.lostandfound.report
import android.app.Activity
import android.content.Context
@@ -18,9 +18,9 @@ import `in`.koreatech.koin.core.analytics.AnalyticsConstant
import `in`.koreatech.koin.core.analytics.EventLogger
import `in`.koreatech.koin.core.designsystem.component.topbar.KoinTopAppBar
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.R
-import `in`.koreatech.koin.feature.lostandfound.ui.report.component.LostAndFoundReportContent
-import `in`.koreatech.koin.feature.lostandfound.ui.report.component.lostAndFoundReportReasonList
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.ui.lostandfound.report.component.LostAndFoundReportContent
+import `in`.koreatech.koin.feature.article.ui.lostandfound.report.component.lostAndFoundReportReasonList
import org.orbitmvi.orbit.compose.collectAsState
import org.orbitmvi.orbit.compose.collectSideEffect
import timber.log.Timber
@@ -46,8 +46,7 @@ fun LostAndFoundReport(
KoinTopAppBar(
title = stringResource(R.string.report_title),
onNavigationIconClick = { (context as Activity).finish() },
- colors =
- TopAppBarDefaults.centerAlignedTopAppBarColors().copy(
+ colors = TopAppBarDefaults.centerAlignedTopAppBarColors().copy(
containerColor = KoinTheme.colors.primary500,
navigationIconContentColor = KoinTheme.colors.neutral0,
titleContentColor = KoinTheme.colors.neutral0,
@@ -58,8 +57,7 @@ fun LostAndFoundReport(
containerColor = KoinTheme.colors.neutral0
) { contentPadding ->
LostAndFoundReportContent(
- modifier =
- Modifier
+ modifier = Modifier
.padding(contentPadding)
.consumeWindowInsets(contentPadding),
itemList = lostAndFoundReportReasonList,
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/LostAndFoundReportSideEffect.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/LostAndFoundReportSideEffect.kt
similarity index 74%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/LostAndFoundReportSideEffect.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/LostAndFoundReportSideEffect.kt
index 1cd4ead4a5..c683a053d6 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/LostAndFoundReportSideEffect.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/LostAndFoundReportSideEffect.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.report
+package `in`.koreatech.koin.feature.article.ui.lostandfound.report
sealed class LostAndFoundReportSideEffect {
data object ReportSuccess : LostAndFoundReportSideEffect()
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/LostAndFoundReportState.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/LostAndFoundReportState.kt
similarity index 66%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/LostAndFoundReportState.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/LostAndFoundReportState.kt
index 1854186f8e..0e0093a0b7 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/LostAndFoundReportState.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/LostAndFoundReportState.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.report
+package `in`.koreatech.koin.feature.article.ui.lostandfound.report
data class LostAndFoundReportState(
val selectedReason: IntArray = intArrayOf(),
diff --git a/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/LostAndFoundReportViewModel.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/LostAndFoundReportViewModel.kt
new file mode 100644
index 0000000000..3df2308a0b
--- /dev/null
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/LostAndFoundReportViewModel.kt
@@ -0,0 +1,80 @@
+package `in`.koreatech.koin.feature.article.ui.lostandfound.report
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.lifecycle.HiltViewModel
+import `in`.koreatech.koin.domain.model.article.ArticleLostAndFoundReportItem
+import `in`.koreatech.koin.domain.usecase.article.lostandfound.ReportLostAndFoundArticleUseCase
+import `in`.koreatech.koin.feature.article.enums.ReportReason
+import `in`.koreatech.koin.feature.article.ui.lostandfound.report.component.lostAndFoundReportReasonList
+import javax.inject.Inject
+import kotlinx.coroutines.launch
+import org.orbitmvi.orbit.ContainerHost
+import org.orbitmvi.orbit.syntax.simple.blockingIntent
+import org.orbitmvi.orbit.syntax.simple.intent
+import org.orbitmvi.orbit.syntax.simple.postSideEffect
+import org.orbitmvi.orbit.syntax.simple.reduce
+import org.orbitmvi.orbit.viewmodel.container
+
+@HiltViewModel
+class LostAndFoundReportViewModel @Inject constructor(
+ private val reportLostAndFoundArticleUseCase: ReportLostAndFoundArticleUseCase
+) : ViewModel(), ContainerHost {
+ override val container = container(LostAndFoundReportState())
+
+ private fun addReportReason(reportReason: ReportReason) = intent {
+ reduce {
+ state.copy(selectedReason = state.selectedReason + lostAndFoundReportReasonList.indexOf(reportReason))
+ }
+ }
+
+ private fun removeReportReason(reportReason: ReportReason) = intent {
+ reduce {
+ state.copy(
+ selectedReason = state.selectedReason.filterNot { lostAndFoundReportReasonList[it] == reportReason }.toIntArray()
+ )
+ }
+ }
+
+ fun setReportReason(reportReason: ReportReason) = intent {
+ if (lostAndFoundReportReasonList.indexOf(reportReason) in state.selectedReason) {
+ removeReportReason(reportReason)
+ } else {
+ addReportReason(reportReason)
+ }
+ }
+
+ fun setReportReasonDescription(reportReasonDescription: String) = blockingIntent {
+ reduce {
+ state.copy(reportReasonDescription = reportReasonDescription)
+ }
+ }
+
+ fun reportArticle(articleId: Int) = viewModelScope.launch {
+ val reportReasonList = mutableListOf()
+ intent {
+ state.selectedReason.forEach {
+ if (lostAndFoundReportReasonList[it] == ReportReason.OTHER) {
+ reportReasonList.add(
+ ArticleLostAndFoundReportItem(lostAndFoundReportReasonList[it].title, state.reportReasonDescription)
+ )
+ } else {
+ reportReasonList.add(
+ ArticleLostAndFoundReportItem(
+ lostAndFoundReportReasonList[it].title,
+ lostAndFoundReportReasonList[it].description
+ )
+ )
+ }
+ }
+ reportLostAndFoundArticleUseCase(
+ articleId,
+ reportReasonList
+ ).onSuccess {
+ postSideEffect(LostAndFoundReportSideEffect.ReportSuccess)
+ }.onFailure {
+ postSideEffect(LostAndFoundReportSideEffect.ReportFailure(it.message ?: ""))
+ }
+ }
+ }
+}
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/component/LostAndFoundReportContent.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/component/LostAndFoundReportContent.kt
similarity index 90%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/component/LostAndFoundReportContent.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/component/LostAndFoundReportContent.kt
index abc2647138..6eb04caaa9 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/component/LostAndFoundReportContent.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/component/LostAndFoundReportContent.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.report.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.report.component
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
@@ -17,8 +17,8 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import `in`.koreatech.koin.core.designsystem.component.button.FilledButton
import `in`.koreatech.koin.core.designsystem.component.tab.KoinSurface
-import `in`.koreatech.koin.feature.lostandfound.R
-import `in`.koreatech.koin.feature.lostandfound.enums.ReportReason
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.enums.ReportReason
@Composable
fun LostAndFoundReportContent(
@@ -33,8 +33,7 @@ fun LostAndFoundReportContent(
val scrollState = rememberScrollState()
Column(
- modifier =
- modifier
+ modifier = modifier
.fillMaxSize()
.imePadding()
.verticalScroll(scrollState)
@@ -54,8 +53,7 @@ fun LostAndFoundReportContent(
FilledButton(
text = stringResource(id = R.string.report_submit),
onClick = onReport,
- modifier =
- Modifier
+ modifier = Modifier
.padding(vertical = 20.dp, horizontal = 24.dp)
.fillMaxWidth()
)
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/component/LostAndFoundReportHeader.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/component/LostAndFoundReportHeader.kt
similarity index 90%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/component/LostAndFoundReportHeader.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/component/LostAndFoundReportHeader.kt
index ac46743abe..cf41e66740 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/component/LostAndFoundReportHeader.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/component/LostAndFoundReportHeader.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.report.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.report.component
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
@@ -12,7 +12,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.R
+import `in`.koreatech.koin.feature.article.R
@Composable
fun LostAndFoundReportHeader(modifier: Modifier = Modifier) {
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/component/LostAndFoundReportReasons.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/component/LostAndFoundReportReasons.kt
similarity index 93%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/component/LostAndFoundReportReasons.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/component/LostAndFoundReportReasons.kt
index 0dcc8116c7..240e88a231 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/component/LostAndFoundReportReasons.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/report/component/LostAndFoundReportReasons.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.report.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.report.component
import androidx.compose.foundation.Image
import androidx.compose.foundation.border
@@ -28,9 +28,9 @@ import androidx.compose.ui.unit.dp
import `in`.koreatech.koin.core.designsystem.component.tab.KoinSurface
import `in`.koreatech.koin.core.designsystem.noRippleClickable
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.R
-import `in`.koreatech.koin.feature.lostandfound.REPORT_OTHER_REASON_MAX_LENGTH
-import `in`.koreatech.koin.feature.lostandfound.enums.ReportReason
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.REPORT_OTHER_REASON_MAX_LENGTH
+import `in`.koreatech.koin.feature.article.enums.ReportReason
@Composable
fun LostAndFoundReportReasons(
@@ -56,8 +56,7 @@ fun LostAndFoundReportReasons(
)
} else {
LostAndFoundReportReasonItem(
- modifier =
- Modifier.noRippleClickable {
+ modifier = Modifier.noRippleClickable {
onSelectedItemChange(index)
},
reportReason = reportReason,
@@ -113,8 +112,7 @@ fun LostAndFoundReportReasonOtherItem(
isSelected: Boolean = false
) {
Column(
- modifier =
- modifier
+ modifier = modifier
.padding(vertical = 14.dp)
.noRippleClickable {
onFocused()
@@ -125,8 +123,7 @@ fun LostAndFoundReportReasonOtherItem(
) {
Image(
modifier = Modifier.padding(horizontal = 8.dp),
- painter =
- painterResource(
+ painter = painterResource(
id = if (isSelected) R.drawable.ic_report_item_selected else R.drawable.ic_report_item_unselected
),
contentDescription = null
@@ -184,8 +181,7 @@ fun ReportTextField(
}
BasicTextField(
- modifier =
- modifier
+ modifier = modifier
.fillMaxWidth()
.border(1.dp, color = KoinTheme.colors.neutral300, shape = KoinTheme.shapes.extraSmall)
.padding(vertical = 12.dp, horizontal = 16.dp),
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/LostAndFoundWriteArticle.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/LostAndFoundWriteArticle.kt
similarity index 90%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/LostAndFoundWriteArticle.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/LostAndFoundWriteArticle.kt
index 8c7dafbb3b..082900e9ea 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/LostAndFoundWriteArticle.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/LostAndFoundWriteArticle.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.write
+package `in`.koreatech.koin.feature.article.ui.lostandfound.write
import android.content.Context
import android.net.Uri
@@ -36,18 +36,18 @@ import androidx.hilt.navigation.compose.hiltViewModel
import `in`.koreatech.koin.core.analytics.AnalyticsConstant
import `in`.koreatech.koin.core.analytics.EventLogger
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.MAX_ITEM_COUNT
-import `in`.koreatech.koin.feature.lostandfound.R
-import `in`.koreatech.koin.feature.lostandfound.enums.LostItemCategory
-import `in`.koreatech.koin.feature.lostandfound.enums.LostItemCategory.Companion.getCategoryKoreanWord
-import `in`.koreatech.koin.feature.lostandfound.enums.LostOrFoundType
-import `in`.koreatech.koin.feature.lostandfound.ui.write.component.WriteArticleAddItemButton
-import `in`.koreatech.koin.feature.lostandfound.ui.write.component.WriteArticleDoneButton
-import `in`.koreatech.koin.feature.lostandfound.ui.write.component.WriteArticleHeader
-import `in`.koreatech.koin.feature.lostandfound.ui.write.component.WriteArticleItemChip
-import `in`.koreatech.koin.feature.lostandfound.ui.write.component.WriteArticleItemDetail
-import `in`.koreatech.koin.feature.lostandfound.ui.write.component.WriteArticleItemType
-import `in`.koreatech.koin.feature.lostandfound.ui.write.component.WriteArticleUploadImage
+import `in`.koreatech.koin.feature.article.MAX_ITEM_COUNT
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.enums.LostItemCategory
+import `in`.koreatech.koin.feature.article.enums.LostItemCategory.Companion.getCategoryKoreanWord
+import `in`.koreatech.koin.feature.article.enums.LostOrFoundType
+import `in`.koreatech.koin.feature.article.ui.lostandfound.write.component.WriteArticleAddItemButton
+import `in`.koreatech.koin.feature.article.ui.lostandfound.write.component.WriteArticleDoneButton
+import `in`.koreatech.koin.feature.article.ui.lostandfound.write.component.WriteArticleHeader
+import `in`.koreatech.koin.feature.article.ui.lostandfound.write.component.WriteArticleItemChip
+import `in`.koreatech.koin.feature.article.ui.lostandfound.write.component.WriteArticleItemDetail
+import `in`.koreatech.koin.feature.article.ui.lostandfound.write.component.WriteArticleItemType
+import `in`.koreatech.koin.feature.article.ui.lostandfound.write.component.WriteArticleUploadImage
import java.time.LocalDate
import org.orbitmvi.orbit.compose.collectAsState
import org.orbitmvi.orbit.compose.collectSideEffect
@@ -203,14 +203,13 @@ fun WriteFoundItemArticleImpl(
onShowDatePickerChange: (showDatePicker: Boolean) -> Unit = {},
onDateChange: (date: LocalDate?) -> Unit = {}
) {
- val pickMultipleMedia =
- rememberLauncherForActivityResult(ActivityResultContracts.PickMultipleVisualMedia(10)) { uris ->
- if (uris.isNotEmpty()) {
- uris.forEach {
- onAddImageClick(it)
- }
+ val pickMultipleMedia = rememberLauncherForActivityResult(ActivityResultContracts.PickMultipleVisualMedia(10)) { uris ->
+ if (uris.isNotEmpty()) {
+ uris.forEach {
+ onAddImageClick(it)
}
}
+ }
val imageList = articleData.images
@@ -292,9 +291,8 @@ fun handleSideEffect(
if (fileNameIndex != -1 && fileSizeIndex != -1) {
val fileName = cursor.getString(fileNameIndex)
val fileSize = cursor.getLong(fileSizeIndex)
- val fileType =
- context.contentResolver.getType(imageContextUri)
- ?: "image/${fileName.split(".").last()}"
+ val fileType = context.contentResolver.getType(imageContextUri)
+ ?: "image/${fileName.split(".").last()}"
viewModel.getPreSignedUrl(
fileSize,
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/LostAndFoundWriteArticleItemState.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/LostAndFoundWriteArticleItemState.kt
similarity index 77%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/LostAndFoundWriteArticleItemState.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/LostAndFoundWriteArticleItemState.kt
index ca40bf1d55..11ba55ef6e 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/LostAndFoundWriteArticleItemState.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/LostAndFoundWriteArticleItemState.kt
@@ -1,10 +1,10 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.write
+package `in`.koreatech.koin.feature.article.ui.lostandfound.write
import android.os.Parcelable
import `in`.koreatech.koin.domain.model.article.ArticleLostAndFoundUpload
-import `in`.koreatech.koin.feature.lostandfound.enums.LostItemCategory
-import `in`.koreatech.koin.feature.lostandfound.enums.LostItemCategory.Companion.getCategoryKoreanWord
-import `in`.koreatech.koin.feature.lostandfound.enums.LostOrFoundType
+import `in`.koreatech.koin.feature.article.enums.LostItemCategory
+import `in`.koreatech.koin.feature.article.enums.LostItemCategory.Companion.getCategoryKoreanWord
+import `in`.koreatech.koin.feature.article.enums.LostOrFoundType
import java.time.LocalDate
import kotlinx.parcelize.Parcelize
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/LostAndFoundWriteArticleSideEffect.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/LostAndFoundWriteArticleSideEffect.kt
similarity index 95%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/LostAndFoundWriteArticleSideEffect.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/LostAndFoundWriteArticleSideEffect.kt
index 40539d1fd2..ee55fd5c6d 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/LostAndFoundWriteArticleSideEffect.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/LostAndFoundWriteArticleSideEffect.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.write
+package `in`.koreatech.koin.feature.article.ui.lostandfound.write
import android.net.Uri
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/LostAndFoundWriteArticleState.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/LostAndFoundWriteArticleState.kt
similarity index 70%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/LostAndFoundWriteArticleState.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/LostAndFoundWriteArticleState.kt
index 0c5acdeeba..3a9e5d9223 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/LostAndFoundWriteArticleState.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/LostAndFoundWriteArticleState.kt
@@ -1,7 +1,7 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.write
+package `in`.koreatech.koin.feature.article.ui.lostandfound.write
import android.os.Parcelable
-import `in`.koreatech.koin.feature.lostandfound.enums.LostOrFoundType
+import `in`.koreatech.koin.feature.article.enums.LostOrFoundType
import kotlinx.parcelize.Parcelize
@Parcelize
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/LostAndFoundWriteArticleViewModel.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/LostAndFoundWriteArticleViewModel.kt
similarity index 71%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/LostAndFoundWriteArticleViewModel.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/LostAndFoundWriteArticleViewModel.kt
index 95264e58c7..37c6a17722 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/LostAndFoundWriteArticleViewModel.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/LostAndFoundWriteArticleViewModel.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.write
+package `in`.koreatech.koin.feature.article.ui.lostandfound.write
import android.net.Uri
import androidx.lifecycle.SavedStateHandle
@@ -8,9 +8,9 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import `in`.koreatech.koin.domain.usecase.article.lostandfound.UploadLostAndFoundArticleUseCase
import `in`.koreatech.koin.domain.usecase.business.UploadFileUseCase
import `in`.koreatech.koin.domain.usecase.presignedurl.GetLostAndFoundPreSignedUrlUseCase
-import `in`.koreatech.koin.feature.lostandfound.IMAGE_MAX_COUNT
-import `in`.koreatech.koin.feature.lostandfound.enums.LostItemCategory
-import `in`.koreatech.koin.feature.lostandfound.enums.LostOrFoundType
+import `in`.koreatech.koin.feature.article.IMAGE_MAX_COUNT
+import `in`.koreatech.koin.feature.article.enums.LostItemCategory
+import `in`.koreatech.koin.feature.article.enums.LostOrFoundType
import java.time.LocalDate
import javax.inject.Inject
import kotlinx.coroutines.launch
@@ -28,46 +28,41 @@ class LostAndFoundWriteArticleViewModel @Inject constructor(
private val uploadFilesUseCase: UploadFileUseCase
) : ViewModel(),
ContainerHost {
- override val container =
- container(
- LostAndFoundWriteArticleState(),
- savedStateHandle
- ) {
- val rawLostOrFoundType = savedStateHandle.get(LOST_OR_FOUND_TYPE)
- val lostOrFoundType =
- LostOrFoundType.entries.find {
- it.name == rawLostOrFoundType
- } ?: LostOrFoundType.FOUND
- setLostOrFoundType(lostOrFoundType)
- addItem(
- LostAndFoundWriteArticleItemState(
- lostOrFoundType = lostOrFoundType
- )
+ override val container = container(
+ LostAndFoundWriteArticleState(),
+ savedStateHandle
+ ) {
+ val rawLostOrFoundType = savedStateHandle.get(LOST_OR_FOUND_TYPE)
+ val lostOrFoundType = LostOrFoundType.entries.find {
+ it.name == rawLostOrFoundType
+ } ?: LostOrFoundType.FOUND
+ setLostOrFoundType(lostOrFoundType)
+ addItem(
+ LostAndFoundWriteArticleItemState(
+ lostOrFoundType = lostOrFoundType
)
- }
+ )
+ }
- private fun setLostOrFoundType(lostOrFoundType: LostOrFoundType) =
- intent {
- reduce {
- state.copy(lostOrFoundType = lostOrFoundType)
- }
+ private fun setLostOrFoundType(lostOrFoundType: LostOrFoundType) = intent {
+ reduce {
+ state.copy(lostOrFoundType = lostOrFoundType)
}
+ }
- fun addItem(item: LostAndFoundWriteArticleItemState) =
- intent {
- // postSideEffect(LostAndFoundWriteArticleSideEffect.AddItem(item))
- reduce {
- state.copy(itemList = state.itemList + item)
- }
+ fun addItem(item: LostAndFoundWriteArticleItemState) = intent {
+ // postSideEffect(LostAndFoundWriteArticleSideEffect.AddItem(item))
+ reduce {
+ state.copy(itemList = state.itemList + item)
}
+ }
- fun removeItem(index: Int) =
- intent {
- // postSideEffect(LostAndFoundWriteArticleSideEffect.RemoveItem(index))
- reduce {
- state.copy(itemList = state.itemList.filterIndexed { i, _ -> i != index })
- }
+ fun removeItem(index: Int) = intent {
+ // postSideEffect(LostAndFoundWriteArticleSideEffect.RemoveItem(index))
+ reduce {
+ state.copy(itemList = state.itemList.filterIndexed { i, _ -> i != index })
}
+ }
fun updateItemType(
index: Int,
@@ -77,8 +72,7 @@ class LostAndFoundWriteArticleViewModel @Inject constructor(
// postSideEffect(LostAndFoundWriteArticleSideEffect.UpdateItemType(index, category))
reduce {
state.copy(
- itemList =
- state.itemList.mapIndexed { i, item ->
+ itemList = state.itemList.mapIndexed { i, item ->
if (i == index) {
return@mapIndexed item.copy(
category = category,
@@ -111,12 +105,10 @@ class LostAndFoundWriteArticleViewModel @Inject constructor(
intent {
reduce {
state.copy(
- itemList =
- state.itemList.mapIndexed { i, item ->
+ itemList = state.itemList.mapIndexed { i, item ->
if (i == itemIndex) {
return@mapIndexed item.copy(
- images =
- item.images.mapIndexed { j, currentValue ->
+ images = item.images.mapIndexed { j, currentValue ->
if (j == imageIndex) {
return@mapIndexed fileUrl // Replace placeholder to real image url
} else {
@@ -179,8 +171,7 @@ class LostAndFoundWriteArticleViewModel @Inject constructor(
reduce {
state.copy(
- itemList =
- state.itemList.mapIndexed { i, item ->
+ itemList = state.itemList.mapIndexed { i, item ->
if (i == itemIndex) {
return@mapIndexed item.copy(images = item.images + "") // Add empty string as placeholder
} else {
@@ -206,8 +197,7 @@ class LostAndFoundWriteArticleViewModel @Inject constructor(
) = intent {
reduce {
state.copy(
- itemList =
- state.itemList.mapIndexed { i, item ->
+ itemList = state.itemList.mapIndexed { i, item ->
if (i == itemIndex) {
return@mapIndexed item.copy(images = item.images.filterIndexed { j, _ -> j != imageIndex })
} else {
@@ -225,8 +215,7 @@ class LostAndFoundWriteArticleViewModel @Inject constructor(
// postSideEffect(LostAndFoundWriteArticleSideEffect.UpdateDescription(itemIndex, content))
reduce {
state.copy(
- itemList =
- state.itemList.mapIndexed { i, item ->
+ itemList = state.itemList.mapIndexed { i, item ->
if (i == itemIndex) {
return@mapIndexed item.copy(content = content)
} else {
@@ -244,8 +233,7 @@ class LostAndFoundWriteArticleViewModel @Inject constructor(
// postSideEffect(LostAndFoundWriteArticleSideEffect.UpdateLocation(itemIndex, foundPlace))
reduce {
state.copy(
- itemList =
- state.itemList.mapIndexed { i, item ->
+ itemList = state.itemList.mapIndexed { i, item ->
if (i == itemIndex) {
return@mapIndexed item.copy(
foundPlace = foundPlace,
@@ -266,8 +254,7 @@ class LostAndFoundWriteArticleViewModel @Inject constructor(
// postSideEffect(LostAndFoundWriteArticleSideEffect.UpdateDate(itemIndex, date))
reduce {
state.copy(
- itemList =
- state.itemList.mapIndexed { i, item ->
+ itemList = state.itemList.mapIndexed { i, item ->
if (i == itemIndex) {
return@mapIndexed item.copy(foundDate = date, dateRequired = date == null)
} else {
@@ -278,25 +265,23 @@ class LostAndFoundWriteArticleViewModel @Inject constructor(
}
}
- fun checkAllFieldValid() =
- intent {
- postSideEffect(LostAndFoundWriteArticleSideEffect.CheckAllFieldValid(state.itemList))
- }
+ fun checkAllFieldValid() = intent {
+ postSideEffect(LostAndFoundWriteArticleSideEffect.CheckAllFieldValid(state.itemList))
+ }
- fun writeArticle() =
- viewModelScope.launch {
- intent {
- uploadLostAndFoundArticleUseCase(
- state.itemList.map {
- it.toArticleLostAndFoundUpload()
- }
- ).onSuccess {
- postSideEffect(LostAndFoundWriteArticleSideEffect.LostAndFoundWriteArticle(it.id))
- }.onFailure {
- postSideEffect(LostAndFoundWriteArticleSideEffect.LostAndFoundWriteArticleFailed)
+ fun writeArticle() = viewModelScope.launch {
+ intent {
+ uploadLostAndFoundArticleUseCase(
+ state.itemList.map {
+ it.toArticleLostAndFoundUpload()
}
+ ).onSuccess {
+ postSideEffect(LostAndFoundWriteArticleSideEffect.LostAndFoundWriteArticle(it.id))
+ }.onFailure {
+ postSideEffect(LostAndFoundWriteArticleSideEffect.LostAndFoundWriteArticleFailed)
}
}
+ }
companion object {
const val LOST_OR_FOUND_TYPE = "lost_or_found_type"
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleAddItemButtom.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleAddItemButtom.kt
similarity index 92%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleAddItemButtom.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleAddItemButtom.kt
index 701a1ee7e7..78c7b0c6d0 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleAddItemButtom.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleAddItemButtom.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.write.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.write.component
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
@@ -21,7 +21,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.R
+import `in`.koreatech.koin.feature.article.R
@Composable
fun WriteArticleAddItemButton(
@@ -32,8 +32,7 @@ fun WriteArticleAddItemButton(
Button(
modifier = Modifier.align(Alignment.CenterEnd),
onClick = onItemAdd,
- colors =
- ButtonDefaults.buttonColors(
+ colors = ButtonDefaults.buttonColors(
containerColor = KoinTheme.colors.info200
),
shape = RoundedCornerShape(8.dp),
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleDoneButton.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleDoneButton.kt
similarity index 89%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleDoneButton.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleDoneButton.kt
index 5434d21ea9..df6a7df13e 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleDoneButton.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleDoneButton.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.write.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.write.component
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -22,15 +22,14 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.R
+import `in`.koreatech.koin.feature.article.R
object WriteArticleDoneButtonDefaults {
val windowInsets: WindowInsets
@Composable
- get() =
- WindowInsets.systemBars.only(
- WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom
- )
+ get() = WindowInsets.systemBars.only(
+ WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom
+ )
}
@Composable
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleHeader.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleHeader.kt
similarity index 83%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleHeader.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleHeader.kt
index 845c70e011..e4c0ea4f77 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleHeader.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleHeader.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.write.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.write.component
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
@@ -13,8 +13,8 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.R
-import `in`.koreatech.koin.feature.lostandfound.enums.LostOrFoundType
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.enums.LostOrFoundType
@Composable
fun WriteArticleHeader(
@@ -25,8 +25,7 @@ fun WriteArticleHeader(
Row {
Text(
style = KoinTheme.typography.regular18,
- text =
- when (type) {
+ text = when (type) {
LostOrFoundType.LOST -> stringResource(R.string.header_lost_title)
LostOrFoundType.FOUND -> stringResource(R.string.header_found_title)
}
@@ -34,8 +33,7 @@ fun WriteArticleHeader(
Spacer(modifier = Modifier.size(8.dp))
Image(
modifier = Modifier.size(24.dp),
- painter =
- when (type) {
+ painter = when (type) {
LostOrFoundType.LOST -> painterResource(R.drawable.ic_lost)
LostOrFoundType.FOUND -> painterResource(R.drawable.ic_found)
},
@@ -45,8 +43,7 @@ fun WriteArticleHeader(
Text(
color = KoinTheme.colors.neutral500,
style = KoinTheme.typography.regular12,
- text =
- when (type) {
+ text = when (type) {
LostOrFoundType.LOST -> stringResource(R.string.header_lost_description)
LostOrFoundType.FOUND -> stringResource(R.string.header_found_description)
}
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleItemChip.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleItemChip.kt
similarity index 89%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleItemChip.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleItemChip.kt
index 86c33f9e2c..aa2875debd 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleItemChip.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleItemChip.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.write.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.write.component
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
@@ -18,8 +18,8 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.R
-import `in`.koreatech.koin.feature.lostandfound.enums.LostOrFoundType
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.enums.LostOrFoundType
@Composable
fun WriteArticleItemChip(
@@ -34,8 +34,7 @@ fun WriteArticleItemChip(
verticalAlignment = Alignment.CenterVertically
) {
Box(
- modifier =
- Modifier
+ modifier = Modifier
.background(
color = KoinTheme.colors.info200,
shape = RoundedCornerShape(12.dp)
@@ -58,8 +57,7 @@ fun WriteArticleItemChip(
}
if (shouldShowDelete) {
Image(
- modifier =
- Modifier
+ modifier = Modifier
.width(36.dp)
.height(28.dp)
.padding(vertical = 4.dp, horizontal = 8.dp)
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleItemDetail.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleItemDetail.kt
similarity index 87%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleItemDetail.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleItemDetail.kt
index 63596ce04d..8ac1b14243 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleItemDetail.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleItemDetail.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.write.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.write.component
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.Image
@@ -40,9 +40,9 @@ import `in`.koreatech.koin.core.designsystem.component.picker.rememberPickerStat
import `in`.koreatech.koin.core.designsystem.component.text.LeadingIconText
import `in`.koreatech.koin.core.designsystem.noRippleClickable
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.DESCRIPTION_MAX_LENGTH
-import `in`.koreatech.koin.feature.lostandfound.R
-import `in`.koreatech.koin.feature.lostandfound.enums.LostOrFoundType
+import `in`.koreatech.koin.feature.article.DESCRIPTION_MAX_LENGTH
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.enums.LostOrFoundType
import java.time.LocalDate
@Composable
@@ -82,8 +82,7 @@ fun WriteArticleItemDetail(
}
Column(
- modifier =
- modifier
+ modifier = modifier
.fillMaxWidth()
) {
Row(
@@ -93,8 +92,7 @@ fun WriteArticleItemDetail(
) {
Text(
style = KoinTheme.typography.medium14,
- text =
- when (type) {
+ text = when (type) {
LostOrFoundType.LOST -> stringResource(id = R.string.lost_date)
LostOrFoundType.FOUND -> stringResource(id = R.string.found_date)
}
@@ -103,8 +101,7 @@ fun WriteArticleItemDetail(
if (dateRequired) {
LeadingIconText(
textStyle = KoinTheme.typography.medium12.copy(color = Color(0xFFF7941E)),
- text =
- when (type) {
+ text = when (type) {
LostOrFoundType.LOST -> stringResource(id = R.string.lost_date_required)
LostOrFoundType.FOUND -> stringResource(id = R.string.found_date_required)
},
@@ -119,8 +116,7 @@ fun WriteArticleItemDetail(
var dateComposablePosition by remember { mutableStateOf(Offset.Zero) }
Box(
- modifier =
- Modifier
+ modifier = Modifier
.clip(RoundedCornerShape(8.dp))
.background(KoinTheme.colors.neutral100)
.padding(vertical = 8.dp, horizontal = 16.dp)
@@ -143,8 +139,7 @@ fun WriteArticleItemDetail(
modifier = Modifier.weight(1f),
color = KoinTheme.colors.neutral500,
style = KoinTheme.typography.regular12,
- text =
- when (type) {
+ text = when (type) {
LostOrFoundType.LOST -> stringResource(id = R.string.lost_date_hint)
LostOrFoundType.FOUND -> stringResource(id = R.string.found_date_hint)
}
@@ -165,13 +160,11 @@ fun WriteArticleItemDetail(
)
Image(
- modifier =
- Modifier
+ modifier = Modifier
.size(24.dp)
.rotate(rotateDegree),
painter = painterResource(id = R.drawable.ic_dropdown_arrow),
- contentDescription =
- when (type) {
+ contentDescription = when (type) {
LostOrFoundType.LOST -> stringResource(id = R.string.lost_date_hint)
LostOrFoundType.FOUND -> stringResource(id = R.string.found_date_hint)
}
@@ -218,43 +211,38 @@ fun WriteArticleItemDetail(
if (monthPickerState.selectedItem == now.monthValue.toString()) {
dayList = (1..now.dayOfMonth).map { it.toString() }
} else {
- val lastDayOfMonth =
- getLastDayOfMonth(
- now.year,
- Integer.parseInt(monthPickerState.selectedItem)
- )
+ val lastDayOfMonth = getLastDayOfMonth(
+ now.year,
+ Integer.parseInt(monthPickerState.selectedItem)
+ )
dayList = (1..lastDayOfMonth).map { it.toString() }
}
} else {
monthList = (1..12).map { it.toString() }
- val lastDayOfMonth =
- getLastDayOfMonth(
- Integer.parseInt(yearPickerState.selectedItem),
- Integer.parseInt(monthPickerState.selectedItem)
- )
+ val lastDayOfMonth = getLastDayOfMonth(
+ Integer.parseInt(yearPickerState.selectedItem),
+ Integer.parseInt(monthPickerState.selectedItem)
+ )
dayList = (1..lastDayOfMonth).map { it.toString() }
}
}
Popup(
- offset =
- IntOffset(
+ offset = IntOffset(
dateComposablePosition.x.toInt(),
dateComposablePosition.y.toInt()
)
) {
Box(
- modifier =
- Modifier
+ modifier = Modifier
.fillMaxWidth()
.padding(vertical = 12.dp, horizontal = 24.dp)
.clip(RoundedCornerShape(8.dp))
.background(KoinTheme.colors.neutral100)
) {
Row(
- modifier =
- Modifier
+ modifier = Modifier
.padding(vertical = 12.dp, horizontal = 32.dp)
.fillMaxWidth()
) {
@@ -266,12 +254,10 @@ fun WriteArticleItemDetail(
contentPadding = PaddingValues(vertical = 3.dp, horizontal = 12.dp),
startIndex = yearPickerState.selectedItemIndex,
infiniteScroll = false,
- selectedTextStyle =
- KoinTheme.typography.medium16.copy(
+ selectedTextStyle = KoinTheme.typography.medium16.copy(
textAlign = TextAlign.Center
),
- unselectedTextStyle =
- KoinTheme.typography.medium16.copy(
+ unselectedTextStyle = KoinTheme.typography.medium16.copy(
textAlign = TextAlign.Center
)
)
@@ -283,12 +269,10 @@ fun WriteArticleItemDetail(
contentPadding = PaddingValues(vertical = 3.dp, horizontal = 12.dp),
startIndex = monthPickerState.selectedItemIndex,
infiniteScroll = false,
- selectedTextStyle =
- KoinTheme.typography.medium16.copy(
+ selectedTextStyle = KoinTheme.typography.medium16.copy(
textAlign = TextAlign.Center
),
- unselectedTextStyle =
- KoinTheme.typography.medium16.copy(
+ unselectedTextStyle = KoinTheme.typography.medium16.copy(
textAlign = TextAlign.Center
)
)
@@ -300,12 +284,10 @@ fun WriteArticleItemDetail(
contentPadding = PaddingValues(vertical = 3.dp, horizontal = 12.dp),
startIndex = dayPickerState.selectedItemIndex,
infiniteScroll = false,
- selectedTextStyle =
- KoinTheme.typography.medium16.copy(
+ selectedTextStyle = KoinTheme.typography.medium16.copy(
textAlign = TextAlign.Center
),
- unselectedTextStyle =
- KoinTheme.typography.medium16.copy(
+ unselectedTextStyle = KoinTheme.typography.medium16.copy(
textAlign = TextAlign.Center
)
)
@@ -324,8 +306,7 @@ fun WriteArticleItemDetail(
) {
Text(
style = KoinTheme.typography.medium14,
- text =
- when (type) {
+ text = when (type) {
LostOrFoundType.LOST -> stringResource(id = R.string.lost_location)
LostOrFoundType.FOUND -> stringResource(id = R.string.found_location)
}
@@ -334,8 +315,7 @@ fun WriteArticleItemDetail(
if (locationRequired) {
LeadingIconText(
textStyle = KoinTheme.typography.medium12.copy(color = Color(0xFFF7941E)),
- text =
- when (type) {
+ text = when (type) {
LostOrFoundType.LOST -> stringResource(id = R.string.lost_location_required)
LostOrFoundType.FOUND -> stringResource(id = R.string.found_location_required)
},
@@ -351,13 +331,11 @@ fun WriteArticleItemDetail(
value = location,
onValueChange = onLocationChange,
singleLine = true,
- hint =
- when (type) {
+ hint = when (type) {
LostOrFoundType.LOST -> stringResource(id = R.string.lost_location_hint)
LostOrFoundType.FOUND -> stringResource(id = R.string.found_location_hint)
},
- modifier =
- Modifier
+ modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp))
.background(KoinTheme.colors.neutral100),
@@ -394,8 +372,7 @@ fun WriteArticleItemDetail(
}
},
hint = stringResource(id = R.string.more_description_hint),
- modifier =
- Modifier
+ modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp))
.background(KoinTheme.colors.neutral100),
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleItemType.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleItemType.kt
similarity index 89%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleItemType.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleItemType.kt
index 74d77d7c28..087032bfd3 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleItemType.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleItemType.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.write.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.write.component
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -17,9 +17,9 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import `in`.koreatech.koin.core.designsystem.component.text.LeadingIconText
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
-import `in`.koreatech.koin.feature.lostandfound.R
-import `in`.koreatech.koin.feature.lostandfound.component.ItemTypeChip
-import `in`.koreatech.koin.feature.lostandfound.enums.LostItemCategory
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.component.ItemTypeChip
+import `in`.koreatech.koin.feature.article.enums.LostItemCategory
@Composable
fun WriteArticleItemType(
@@ -29,8 +29,7 @@ fun WriteArticleItemType(
onItemSelected: (Int) -> Unit = {}
) {
Column(
- modifier =
- modifier
+ modifier = modifier
.fillMaxWidth()
.padding(bottom = 24.dp)
) {
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleTextField.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleTextField.kt
similarity index 92%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleTextField.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleTextField.kt
index 550c78cdc1..e1686a96bd 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleTextField.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleTextField.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.write.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.write.component
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
@@ -31,8 +31,7 @@ fun WriteArticleTextField(
}
BasicTextField(
- modifier =
- Modifier
+ modifier = Modifier
.padding(textPaddingValues)
.fillMaxWidth(),
value = value,
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleUploadImage.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleUploadImage.kt
similarity index 90%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleUploadImage.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleUploadImage.kt
index fe485c6c88..60608c129f 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/write/component/WriteArticleUploadImage.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/ui/lostandfound/write/component/WriteArticleUploadImage.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.write.component
+package `in`.koreatech.koin.feature.article.ui.lostandfound.write.component
import android.net.Uri
import androidx.compose.foundation.Image
@@ -45,9 +45,9 @@ import coil.request.ImageRequest
import `in`.koreatech.koin.core.designsystem.noRippleClickable
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
import `in`.koreatech.koin.core.util.pxToDp
-import `in`.koreatech.koin.feature.lostandfound.IMAGE_MAX_COUNT
-import `in`.koreatech.koin.feature.lostandfound.R
-import `in`.koreatech.koin.feature.lostandfound.enums.LostOrFoundType
+import `in`.koreatech.koin.feature.article.IMAGE_MAX_COUNT
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.enums.LostOrFoundType
@Composable
fun WriteArticleUploadImage(
@@ -59,8 +59,7 @@ fun WriteArticleUploadImage(
onRemoveImage: (index: Int) -> Unit = {}
) {
Column(
- modifier =
- modifier
+ modifier = modifier
.fillMaxWidth()
.padding(bottom = 24.dp)
) {
@@ -72,8 +71,7 @@ fun WriteArticleUploadImage(
Text(
modifier = Modifier.weight(1f),
style = KoinTheme.typography.regular12,
- text =
- when (type) {
+ text = when (type) {
LostOrFoundType.LOST -> stringResource(id = R.string.upload_image_of_lost_item)
LostOrFoundType.FOUND -> stringResource(id = R.string.upload_image_of_found_item)
},
@@ -89,8 +87,7 @@ fun WriteArticleUploadImage(
if (uploadedImageCount > 0) {
LazyRow(
- modifier =
- Modifier
+ modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp))
.background(KoinTheme.colors.neutral100)
@@ -113,8 +110,7 @@ fun WriteArticleUploadImage(
Button(
onClick = onUploadImage,
- colors =
- ButtonDefaults.buttonColors(
+ colors = ButtonDefaults.buttonColors(
containerColor = KoinTheme.colors.info200
),
modifier = Modifier.fillMaxWidth(),
@@ -157,8 +153,7 @@ fun WriteArticleUploadImageThumbnail(
}
} else {
SubcomposeAsyncImage(
- model =
- ImageRequest.Builder(LocalContext.current)
+ model = ImageRequest.Builder(LocalContext.current)
.data(imageUrl)
.crossfade(true)
.build(),
@@ -172,8 +167,7 @@ fun WriteArticleUploadImageThumbnail(
},
contentScale = ContentScale.Fit,
contentDescription = null,
- modifier =
- modifier.onGloballyPositioned {
+ modifier = modifier.onGloballyPositioned {
removeButtonPosition = it.positionInParent() +
Offset(
it.size.width.toFloat(),
@@ -185,8 +179,7 @@ fun WriteArticleUploadImageThumbnail(
Image(
painter = painterResource(id = R.drawable.ic_delete_image),
contentDescription = null,
- modifier =
- Modifier
+ modifier = Modifier
.offset(
x = removeButtonPosition.x.pxToDp - 8.dp,
y = removeButtonPosition.y.pxToDp - 8.dp
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/util/ContextExtensions.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/util/ContextExtensions.kt
similarity index 85%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/util/ContextExtensions.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/util/ContextExtensions.kt
index 1cf609ce85..1302bae463 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/util/ContextExtensions.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/util/ContextExtensions.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.util
+package `in`.koreatech.koin.feature.article.util
import android.content.Context
import android.content.ContextWrapper
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/HtmlView.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/util/HtmlView.kt
similarity index 80%
rename from koin/src/main/java/in/koreatech/koin/ui/article/HtmlView.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/util/HtmlView.kt
index 96af2650f3..a9a8f79414 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/HtmlView.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/util/HtmlView.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.ui.article
+package `in`.koreatech.koin.feature.article.util
import android.annotation.SuppressLint
import android.content.Context
@@ -14,14 +14,13 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
-import `in`.koreatech.koin.R
+import com.bumptech.glide.request.target.Target
import `in`.koreatech.koin.core.dialog.ImageZoomableDialog
import `in`.koreatech.koin.domain.model.article.html.CssAttribute
import `in`.koreatech.koin.domain.model.article.html.HtmlAttribute
import `in`.koreatech.koin.domain.model.article.html.HtmlTag
-import `in`.koreatech.koin.ui.article.HtmlView.OnPostDrawListener
-import `in`.koreatech.koin.ui.article.HtmlView.OnPreDrawListener
-import `in`.koreatech.koin.ui.article.state.HtmlElement
+import `in`.koreatech.koin.feature.article.R
+import `in`.koreatech.koin.feature.article.ui.article.state.HtmlElement
class HtmlView @JvmOverloads constructor(
context: Context,
@@ -60,18 +59,15 @@ class HtmlView @JvmOverloads constructor(
if (lastAddedView is TextView && // 직전 View가 TextView이고
lastAddedView.textAlignment == self.styles[CssAttribute.TEXT_ALIGN].parseTextAlignment()
) { // Text-align이 같으면 TextView 재사용
- val frontLineBreak =
- when (self.tag) {
- HtmlTag.P, HtmlTag.DIV, HtmlTag.BR, HtmlTag.LI, HtmlTag.OL, HtmlTag.UL -> if (self.children.isEmpty()) "" else "\n"
- else -> ""
- }
+ val frontLineBreak = when (self.tag) {
+ HtmlTag.P, HtmlTag.DIV, HtmlTag.BR, HtmlTag.LI, HtmlTag.OL, HtmlTag.UL -> if (self.children.isEmpty()) "" else "\n"
+ else -> ""
+ }
val listMarker = createListMarker(self.tag, html.tag, i)
- val originalText =
- SpannableStringBuilder((lastAddedView as TextView).text)
- val newTextBuilder =
- SpannableStringBuilder(frontLineBreak + listMarker + self.content)
+ val originalText = SpannableStringBuilder((lastAddedView as TextView).text)
+ val newTextBuilder = SpannableStringBuilder(frontLineBreak + listMarker + self.content)
val newSpanned = newTextBuilder.getStyledText(
0,
newTextBuilder.length,
@@ -87,8 +83,7 @@ class HtmlView @JvmOverloads constructor(
val listMarker = createListMarker(self.tag, html.tag, i)
- val newTextBuilder =
- SpannableStringBuilder(listMarker + self.content)
+ val newTextBuilder = SpannableStringBuilder(listMarker + self.content)
text = newTextBuilder.getStyledText(0, newTextBuilder.length, self.styles)
this.textAlignment = self.styles[CssAttribute.TEXT_ALIGN].parseTextAlignment()
@@ -99,11 +94,10 @@ class HtmlView @JvmOverloads constructor(
addHtmlView(self)
}
HtmlTag.HR -> {
- val hr =
- View(context).apply {
- // layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, 1)
- // setBackgroundColor(Color.BLACK)
- }
+ val hr = View(context).apply {
+ // layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, 1)
+ // setBackgroundColor(Color.BLACK)
+ }
addView(hr)
lastAddedView = hr
}
@@ -129,10 +123,9 @@ class HtmlView @JvmOverloads constructor(
}
private fun drawImage(self: HtmlElement): ImageView {
- val imageView =
- ImageView(context).apply {
- layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
- }
+ val imageView = ImageView(context).apply {
+ layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
+ }
addView(imageView)
Glide.with(context).load(self.attributes[HtmlAttribute.SRC]).error(
Glide.with(
@@ -145,7 +138,7 @@ class HtmlView @JvmOverloads constructor(
override fun onLoadFailed(
e: GlideException?,
model: Any?,
- target: com.bumptech.glide.request.target.Target,
+ target: Target,
isFirstResource: Boolean
): Boolean {
return false
@@ -154,7 +147,7 @@ class HtmlView @JvmOverloads constructor(
override fun onResourceReady(
resource: Drawable,
model: Any,
- target: com.bumptech.glide.request.target.Target,
+ target: Target,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/util/KoreanDateUtil.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/util/KoreanDateUtil.kt
similarity index 91%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/util/KoreanDateUtil.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/util/KoreanDateUtil.kt
index 53366109ff..b96de5a114 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/util/KoreanDateUtil.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/util/KoreanDateUtil.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.util
+package `in`.koreatech.koin.feature.article.util
import java.time.DayOfWeek
import java.time.LocalDate
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/util/ModifierUtil.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/util/ModifierUtil.kt
similarity index 83%
rename from feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/util/ModifierUtil.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/util/ModifierUtil.kt
index ab35737da6..8dba604419 100644
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/util/ModifierUtil.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/util/ModifierUtil.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.feature.lostandfound.util
+package `in`.koreatech.koin.feature.article.util
import androidx.compose.foundation.ScrollState
import androidx.compose.ui.Modifier
@@ -29,28 +29,23 @@ fun Modifier.horizontalFadingEdge(
drawContent()
drawRect(
- brush =
- Brush.horizontalGradient(
- colors =
- listOf(
+ brush = Brush.horizontalGradient(
+ colors = listOf(
color,
Color.Transparent
),
startX = 0f,
endX = startFadingEdgeStrength
),
- size =
- Size(
+ size = Size(
startFadingEdgeStrength,
this.size.height
)
)
drawRect(
- brush =
- Brush.horizontalGradient(
- colors =
- listOf(
+ brush = Brush.horizontalGradient(
+ colors = listOf(
Color.Transparent,
color
),
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/ParsingExtensions.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/util/ParsingExtensions.kt
similarity index 95%
rename from koin/src/main/java/in/koreatech/koin/ui/article/ParsingExtensions.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/util/ParsingExtensions.kt
index f47d88d3d9..8363fc77da 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/ParsingExtensions.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/util/ParsingExtensions.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.ui.article
+package `in`.koreatech.koin.feature.article.util
import android.graphics.Color
import `in`.koreatech.koin.core.util.RegexPatterns
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/TextExtensions.kt b/feature/article/src/main/java/in/koreatech/koin/feature/article/util/TextExtensions.kt
similarity index 98%
rename from koin/src/main/java/in/koreatech/koin/ui/article/TextExtensions.kt
rename to feature/article/src/main/java/in/koreatech/koin/feature/article/util/TextExtensions.kt
index f1a92ad310..ffbb08b562 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/article/TextExtensions.kt
+++ b/feature/article/src/main/java/in/koreatech/koin/feature/article/util/TextExtensions.kt
@@ -1,4 +1,4 @@
-package `in`.koreatech.koin.ui.article
+package `in`.koreatech.koin.feature.article.util
import android.graphics.Color
import android.graphics.Typeface
diff --git a/feature/article/src/main/res/anim/fade.xml b/feature/article/src/main/res/anim/fade.xml
new file mode 100644
index 0000000000..5436d31fc0
--- /dev/null
+++ b/feature/article/src/main/res/anim/fade.xml
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/feature/article/src/main/res/anim/fade_out.xml b/feature/article/src/main/res/anim/fade_out.xml
new file mode 100644
index 0000000000..ce741c752f
--- /dev/null
+++ b/feature/article/src/main/res/anim/fade_out.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/koin/src/main/res/anim/slide_in_from_left_in.xml b/feature/article/src/main/res/anim/slide_in_from_left_in.xml
similarity index 100%
rename from koin/src/main/res/anim/slide_in_from_left_in.xml
rename to feature/article/src/main/res/anim/slide_in_from_left_in.xml
diff --git a/koin/src/main/res/anim/slide_in_from_right_fade_in.xml b/feature/article/src/main/res/anim/slide_in_from_right_fade_in.xml
similarity index 100%
rename from koin/src/main/res/anim/slide_in_from_right_fade_in.xml
rename to feature/article/src/main/res/anim/slide_in_from_right_fade_in.xml
diff --git a/feature/lostandfound/src/main/res/drawable/background_chip_icon.xml b/feature/article/src/main/res/drawable/background_chip_icon.xml
similarity index 100%
rename from feature/lostandfound/src/main/res/drawable/background_chip_icon.xml
rename to feature/article/src/main/res/drawable/background_chip_icon.xml
diff --git a/koin/src/main/res/drawable/ic_add_round.xml b/feature/article/src/main/res/drawable/ic_add_round.xml
similarity index 100%
rename from koin/src/main/res/drawable/ic_add_round.xml
rename to feature/article/src/main/res/drawable/ic_add_round.xml
diff --git a/feature/lostandfound/src/main/res/drawable/ic_article_delete.xml b/feature/article/src/main/res/drawable/ic_article_delete.xml
similarity index 100%
rename from feature/lostandfound/src/main/res/drawable/ic_article_delete.xml
rename to feature/article/src/main/res/drawable/ic_article_delete.xml
diff --git a/feature/lostandfound/src/main/res/drawable/ic_article_report.xml b/feature/article/src/main/res/drawable/ic_article_report.xml
similarity index 100%
rename from feature/lostandfound/src/main/res/drawable/ic_article_report.xml
rename to feature/article/src/main/res/drawable/ic_article_report.xml
diff --git a/feature/lostandfound/src/main/res/drawable/ic_article_reported.xml b/feature/article/src/main/res/drawable/ic_article_reported.xml
similarity index 100%
rename from feature/lostandfound/src/main/res/drawable/ic_article_reported.xml
rename to feature/article/src/main/res/drawable/ic_article_reported.xml
diff --git a/feature/lostandfound/src/main/res/drawable/ic_chat.xml b/feature/article/src/main/res/drawable/ic_chat.xml
similarity index 100%
rename from feature/lostandfound/src/main/res/drawable/ic_chat.xml
rename to feature/article/src/main/res/drawable/ic_chat.xml
diff --git a/feature/lostandfound/src/main/res/drawable/ic_delete_image.xml b/feature/article/src/main/res/drawable/ic_delete_image.xml
similarity index 100%
rename from feature/lostandfound/src/main/res/drawable/ic_delete_image.xml
rename to feature/article/src/main/res/drawable/ic_delete_image.xml
diff --git a/feature/lostandfound/src/main/res/drawable/ic_dropdown_arrow.xml b/feature/article/src/main/res/drawable/ic_dropdown_arrow.xml
similarity index 100%
rename from feature/lostandfound/src/main/res/drawable/ic_dropdown_arrow.xml
rename to feature/article/src/main/res/drawable/ic_dropdown_arrow.xml
diff --git a/feature/lostandfound/src/main/res/drawable/ic_fab_write.xml b/feature/article/src/main/res/drawable/ic_fab_write.xml
similarity index 100%
rename from feature/lostandfound/src/main/res/drawable/ic_fab_write.xml
rename to feature/article/src/main/res/drawable/ic_fab_write.xml
diff --git a/feature/lostandfound/src/main/res/drawable/ic_found.xml b/feature/article/src/main/res/drawable/ic_found.xml
similarity index 100%
rename from feature/lostandfound/src/main/res/drawable/ic_found.xml
rename to feature/article/src/main/res/drawable/ic_found.xml
diff --git a/feature/lostandfound/src/main/res/drawable/ic_go_to_keyword.xml b/feature/article/src/main/res/drawable/ic_go_to_keyword.xml
similarity index 100%
rename from feature/lostandfound/src/main/res/drawable/ic_go_to_keyword.xml
rename to feature/article/src/main/res/drawable/ic_go_to_keyword.xml
diff --git a/feature/lostandfound/src/main/res/drawable/ic_image_page_indicator_filled.xml b/feature/article/src/main/res/drawable/ic_image_page_indicator_filled.xml
similarity index 100%
rename from feature/lostandfound/src/main/res/drawable/ic_image_page_indicator_filled.xml
rename to feature/article/src/main/res/drawable/ic_image_page_indicator_filled.xml
diff --git a/feature/lostandfound/src/main/res/drawable/ic_image_page_indicator_not_filled.xml b/feature/article/src/main/res/drawable/ic_image_page_indicator_not_filled.xml
similarity index 100%
rename from feature/lostandfound/src/main/res/drawable/ic_image_page_indicator_not_filled.xml
rename to feature/article/src/main/res/drawable/ic_image_page_indicator_not_filled.xml
diff --git a/feature/lostandfound/src/main/res/drawable/ic_item_add.xml b/feature/article/src/main/res/drawable/ic_item_add.xml
similarity index 100%
rename from feature/lostandfound/src/main/res/drawable/ic_item_add.xml
rename to feature/article/src/main/res/drawable/ic_item_add.xml
diff --git a/feature/lostandfound/src/main/res/drawable/ic_item_delete.xml b/feature/article/src/main/res/drawable/ic_item_delete.xml
similarity index 100%
rename from feature/lostandfound/src/main/res/drawable/ic_item_delete.xml
rename to feature/article/src/main/res/drawable/ic_item_delete.xml
diff --git a/feature/lostandfound/src/main/res/drawable/ic_lost.xml b/feature/article/src/main/res/drawable/ic_lost.xml
similarity index 100%
rename from feature/lostandfound/src/main/res/drawable/ic_lost.xml
rename to feature/article/src/main/res/drawable/ic_lost.xml
diff --git a/feature/lostandfound/src/main/res/drawable/ic_report_item_selected.xml b/feature/article/src/main/res/drawable/ic_report_item_selected.xml
similarity index 100%
rename from feature/lostandfound/src/main/res/drawable/ic_report_item_selected.xml
rename to feature/article/src/main/res/drawable/ic_report_item_selected.xml
diff --git a/feature/lostandfound/src/main/res/drawable/ic_report_item_unselected.xml b/feature/article/src/main/res/drawable/ic_report_item_unselected.xml
similarity index 100%
rename from feature/lostandfound/src/main/res/drawable/ic_report_item_unselected.xml
rename to feature/article/src/main/res/drawable/ic_report_item_unselected.xml
diff --git a/feature/lostandfound/src/main/res/drawable/ic_required.xml b/feature/article/src/main/res/drawable/ic_required.xml
similarity index 100%
rename from feature/lostandfound/src/main/res/drawable/ic_required.xml
rename to feature/article/src/main/res/drawable/ic_required.xml
diff --git a/feature/lostandfound/src/main/res/drawable/ic_upload_image.xml b/feature/article/src/main/res/drawable/ic_upload_image.xml
similarity index 100%
rename from feature/lostandfound/src/main/res/drawable/ic_upload_image.xml
rename to feature/article/src/main/res/drawable/ic_upload_image.xml
diff --git a/koin/src/main/res/drawable/ic_view.xml b/feature/article/src/main/res/drawable/ic_view.xml
similarity index 100%
rename from koin/src/main/res/drawable/ic_view.xml
rename to feature/article/src/main/res/drawable/ic_view.xml
diff --git a/koin/src/main/res/drawable/tab_layout_underline.xml b/feature/article/src/main/res/drawable/tab_layout_underline.xml
similarity index 100%
rename from koin/src/main/res/drawable/tab_layout_underline.xml
rename to feature/article/src/main/res/drawable/tab_layout_underline.xml
diff --git a/koin/src/main/res/layout/activity_article.xml b/feature/article/src/main/res/layout/activity_article.xml
similarity index 94%
rename from koin/src/main/res/layout/activity_article.xml
rename to feature/article/src/main/res/layout/activity_article.xml
index 72baddf752..240d6557ca 100644
--- a/koin/src/main/res/layout/activity_article.xml
+++ b/feature/article/src/main/res/layout/activity_article.xml
@@ -7,7 +7,7 @@
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context=".ui.article.ArticleActivity">
+ tools:context=".feature.article.ui.article.ArticleActivity">
-
게시글을 작성 하려면\n로그인이 필요해요.
로그인 후 분실물 주인을 찾아주세요!
- 게시글이 존재하지 않습니다.
-
글쓰기
주인을 찾아요
잃어버렸어요
@@ -122,4 +120,53 @@
분실물 쪽지 보내기
습득물 쪽지 보내기
신고하기
+
+ 첨부파일
+ 검색
+ 다운로드가 완료되었습니다.
+ 원본 글 바로가기
+ 아우누리 바로가기
+ 학생종합경력개발 바로가기
+ 다운로드 중
+ 파일을 다운로드합니다.
+ 키워드 알림을 받으려면\n로그인이 필요해요.
+ 로그인 후 간편하게 공지사항 키워드\n알림을 받아보세요!
+ 게시판
+ 공지사항
+ 공지글 검색
+ 키워드 관리
+ 분실물 신고
+ 습득물 신고
+ 신고하기
+ 이전
+ 다음
+ •
+ 목록
+ 다음 글
+ 이전 글
+ 인기있는 게시글
+ 모두보기
+ 내 키워드
+ 키워드는 최대 10개까지 추가 가능합니다.
+ 추가
+ 추천 키워드
+ 키워드 알림
+ 키워드가 포함된 게시물의 알림을 받을 수 있습니다.
+ 키워드 알림받기
+ 알림받을 키워드를 입력해 주세요.
+ 키워드를 입력해주세요.
+ 키워드는 최대 10개까지 추가 가능합니다.
+ 이미 추가되어 있는 키워드입니다.
+ 키워드 길이는 2글자 이상, 20글자 이하입니다.
+ 키워드에 공백은 포함할 수 없습니다.
+ 새 키워드 추가
+ 게시글이 존재하지 않습니다.
+ 많이 검색된 키워드
+ 최근 검색기록
+ 전체 삭제
+ 검색어를 입력해주세요.
+ 일치하는 공지글이 없습니다.\n다른 키워드로 다시 시도해주세요.
+
+ 알 수 없는 오류가 발생했습니다.
+ 설정에서 알림 권한을 허용해주세요
diff --git a/feature/lostandfound/src/main/AndroidManifest.xml b/feature/lostandfound/src/main/AndroidManifest.xml
deleted file mode 100644
index a5918e68ab..0000000000
--- a/feature/lostandfound/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/LostAndFoundDetailViewModel.kt b/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/LostAndFoundDetailViewModel.kt
deleted file mode 100644
index 1f7bbe49e8..0000000000
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/detail/LostAndFoundDetailViewModel.kt
+++ /dev/null
@@ -1,147 +0,0 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.detail
-
-import android.webkit.URLUtil
-import androidx.lifecycle.SavedStateHandle
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
-import dagger.hilt.android.lifecycle.HiltViewModel
-import `in`.koreatech.koin.domain.model.user.User
-import `in`.koreatech.koin.domain.usecase.article.lostandfound.DeleteArticleLostAndFoundUseCase
-import `in`.koreatech.koin.domain.usecase.article.lostandfound.FetchHotArticlesUseCase
-import `in`.koreatech.koin.domain.usecase.article.lostandfound.FetchLostAndFoundArticleUseCase
-import `in`.koreatech.koin.domain.usecase.user.GetUserStatusUseCase
-import `in`.koreatech.koin.feature.lostandfound.model.toArticleHeaderState
-import javax.inject.Inject
-import kotlinx.coroutines.flow.catch
-import kotlinx.coroutines.flow.collectLatest
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.launch
-import org.orbitmvi.orbit.ContainerHost
-import org.orbitmvi.orbit.syntax.simple.intent
-import org.orbitmvi.orbit.syntax.simple.postSideEffect
-import org.orbitmvi.orbit.syntax.simple.reduce
-import org.orbitmvi.orbit.viewmodel.container
-import retrofit2.HttpException
-
-@HiltViewModel
-class LostAndFoundDetailViewModel @Inject constructor(
- savedStateHandle: SavedStateHandle,
- private val fetchLostAndFoundArticleUseCase: FetchLostAndFoundArticleUseCase,
- private val fetchHotArticlesUseCase: FetchHotArticlesUseCase,
- private val deleteArticleLostAndFoundUseCase: DeleteArticleLostAndFoundUseCase,
- private val getUserStatusUseCase: GetUserStatusUseCase
-) : ViewModel(), ContainerHost {
- override val container =
- container(LostAndFoundDetailState(), savedStateHandle) {
- val articleId = savedStateHandle.get(ARTICLE_ID)
- checkNotNull(articleId)
- fetchLostAndFoundDetail(articleId)
- }
-
- init {
- initUserInfo()
- fetchHotArticles()
- }
-
- private fun initUserInfo() =
- viewModelScope.launch {
- getUserStatusUseCase().collectLatest {
- intent {
- when (it) {
- is User.Student -> reduce {
- state.copy(
- isLoggedIn = true,
- currentLoggedInUser = it.nickname ?: ""
- )
- }
- is User.General -> reduce {
- state.copy(
- isLoggedIn = true,
- currentLoggedInUser = it.nickname ?: ""
- )
- }
- is User.Anonymous -> reduce {
- state.copy(isLoggedIn = false)
- }
- }
- }
- }
- }
-
- fun fetchLostAndFoundDetail(articleId: Int) =
- viewModelScope.launch {
- intent {
- reduce {
- state.copy(
- isLoading = true
- )
- }
- fetchLostAndFoundArticleUseCase(articleId).catch {
- if (it is HttpException && it.code() == 404) {
- postSideEffect(LostAndFoundDetailSideEffect.DeletedArticle)
- }
- }.map {
- it.toLostAndFoundDetailState()
- }.collectLatest { article ->
- reduce {
- state.copy(
- lostOrFound = article.lostOrFound,
- id = article.id,
- category = article.category,
- foundPlace = article.foundPlace,
- foundDate = article.foundDate,
- content = article.content,
- author = article.author,
- images = article.images?.filter { URLUtil.isValidUrl(it.toString()) },
- registeredAt = article.registeredAt,
- updatedAt = article.updatedAt,
- isWriterCouncil = article.isWriterCouncil,
- isMine = state.currentLoggedInUser == article.author,
- isAuthorWithdraw = article.author == "탈퇴한 사용자",
- isLoading = false
- )
- }
- }
- }
- }
-
- fun fetchHotArticles() =
- viewModelScope.launch {
- intent {
- fetchHotArticlesUseCase().collectLatest {
- reduce {
- state.copy(
- hotArticles =
- it.filterIndexed { index, _ -> index < HOT_ARTICLE_COUNT }
- .map { it.toArticleHeaderState() }
- )
- }
- }
- }
- }
-
- fun deleteArticle() =
- viewModelScope.launch {
- intent {
- deleteArticleLostAndFoundUseCase(state.id).onSuccess {
- postSideEffect(LostAndFoundDetailSideEffect.DeleteArticle(state.id))
- }.onFailure {
- postSideEffect(LostAndFoundDetailSideEffect.DeleteArticleFailed)
- }
- }
- }
-
- fun setShowDeleteDialog(show: Boolean) =
- intent {
- reduce {
- state.copy(
- showDeleteDialog = show
- )
- }
- }
-
- companion object {
- const val HOT_ARTICLE_COUNT = 4
- const val ARTICLE_ID = "article_id"
- }
-}
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/LostAndFoundViewModel.kt b/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/LostAndFoundViewModel.kt
deleted file mode 100644
index 0ba5ad84d5..0000000000
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/lostandfound/LostAndFoundViewModel.kt
+++ /dev/null
@@ -1,208 +0,0 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.lostandfound
-
-import androidx.lifecycle.SavedStateHandle
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
-import dagger.hilt.android.lifecycle.HiltViewModel
-import `in`.koreatech.koin.domain.model.user.User
-import `in`.koreatech.koin.domain.usecase.article.FetchMyKeywordUseCase
-import `in`.koreatech.koin.domain.usecase.article.lostandfound.FetchLostAndFoundArticlePaginationUseCase
-import `in`.koreatech.koin.domain.usecase.article.lostandfound.FetchSearchedLostAndFoundArticlesUseCase
-import `in`.koreatech.koin.domain.usecase.user.GetUserStatusUseCase
-import `in`.koreatech.koin.feature.lostandfound.enums.LostOrFoundType
-import javax.inject.Inject
-import kotlinx.coroutines.flow.catch
-import kotlinx.coroutines.flow.collectLatest
-import kotlinx.coroutines.launch
-import org.orbitmvi.orbit.ContainerHost
-import org.orbitmvi.orbit.syntax.simple.intent
-import org.orbitmvi.orbit.syntax.simple.postSideEffect
-import org.orbitmvi.orbit.syntax.simple.reduce
-import org.orbitmvi.orbit.viewmodel.container
-import timber.log.Timber
-
-@HiltViewModel
-class LostAndFoundViewModel @Inject constructor(
- private val fetchLostAndFoundArticlePaginationUseCase: FetchLostAndFoundArticlePaginationUseCase,
- private val fetchSearchedLostAndFoundArticlesUseCase: FetchSearchedLostAndFoundArticlesUseCase,
- private val fetchMyKeywordUseCase: FetchMyKeywordUseCase,
- private val getUserStatusUseCase: GetUserStatusUseCase,
- savedStateHandle: SavedStateHandle
-) : ViewModel(), ContainerHost {
- override val container =
- container(
- initialState = LostAndFoundState(),
- savedStateHandle = savedStateHandle
- )
-
- init {
- fetchLostAndFoundList()
- fetchMyKeyword()
- getUserType()
- }
-
- fun fetchLostAndFoundList() =
- viewModelScope.launch {
- intent {
- reduce {
- state.copy(
- isLoading = true
- )
- }
-
- if (state.selectedKeyword.isEmpty()) {
- fetchLostAndFoundArticlePaginationUseCase(
- state.currentPage,
- ARTICLES_PER_PAGE,
- state.selectedType?.name
- ).collectLatest {
- reduce {
- state.copy(
- lostAndFoundList = it.articleLostAndFoundHeader.map { it.toLostAndFoundItemState() },
- currentCount = it.currentCount,
- totalCount = it.totalCount,
- currentPage = it.currentPage,
- totalPage = it.totalPage,
- isLoading = false
- )
- }
- }
- } else {
- fetchSearchedLostAndFoundArticlesUseCase(
- state.selectedKeyword,
- state.currentPage,
- ARTICLES_PER_PAGE
- ).collectLatest {
- reduce {
- state.copy(
- lostAndFoundList = it.articleLostAndFoundHeader.map { it.toLostAndFoundItemState() },
- currentCount = it.currentCount,
- totalCount = it.totalCount,
- currentPage = it.currentPage,
- totalPage = it.totalPage
- )
- }
- }
-
- reduce {
- state.copy(
- isLoading = false
- )
- }
- }
- }
- }
-
- fun fetchMyKeyword() =
- viewModelScope.launch {
- fetchMyKeywordUseCase().catch {
- intent {
- reduce {
- state.copy(
- myKeywords = emptyList()
- )
- }
- Timber.d("Failed to fetch my keywords $it")
- }
- throw it
- }.collectLatest {
- intent {
- reduce {
- state.copy(
- myKeywords = it
- )
- }
- postSideEffect(LostAndFoundSideEffect.KeywordUpdated)
- }
- }
- }
-
- fun selectKeyword(it: String) {
- intent {
- reduce {
- state.copy(
- selectedKeyword = it
- )
- }
- }
- }
-
- fun getUserType() =
- viewModelScope.launch {
- getUserStatusUseCase().collectLatest { user ->
- intent {
- when (user) {
- is User.Student -> reduce {
- state.copy(
- isAnonymous = false,
- userType = user.userType
- )
- }
-
- is User.General -> reduce {
- state.copy(
- isAnonymous = false,
- userType = user.userType
- )
- }
- User.Anonymous -> reduce {
- state.copy(
- isAnonymous = true
- )
- }
- }
- }
- }
- }
-
- fun changePage(page: Int) {
- intent {
- reduce {
- state.copy(
- currentPage = page
- )
- }
- postSideEffect(LostAndFoundSideEffect.PageChanged(page))
- }
- }
-
- fun setShowLoginRequestDialog(showDialog: Boolean) =
- intent {
- reduce {
- state.copy(
- showLoginRequestDialog = showDialog
- )
- }
- }
-
- fun setFabDialogExpanded(isExpanded: Boolean) =
- intent {
- reduce {
- state.copy(
- isFabDialogExpanded = isExpanded
- )
- }
- }
-
- fun setDropdownExpanded(isExpanded: Boolean) =
- intent {
- reduce {
- state.copy(
- isDropdownExpanded = isExpanded
- )
- }
- }
-
- fun setSelectedType(type: LostOrFoundType?) =
- intent {
- reduce {
- state.copy(
- selectedType = type
- )
- }
- }
-
- companion object {
- private const val ARTICLES_PER_PAGE = 10
- }
-}
diff --git a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/LostAndFoundReportViewModel.kt b/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/LostAndFoundReportViewModel.kt
deleted file mode 100644
index 16b9a7157e..0000000000
--- a/feature/lostandfound/src/main/java/in/koreatech/koin/feature/lostandfound/ui/report/LostAndFoundReportViewModel.kt
+++ /dev/null
@@ -1,86 +0,0 @@
-package `in`.koreatech.koin.feature.lostandfound.ui.report
-
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
-import dagger.hilt.android.lifecycle.HiltViewModel
-import `in`.koreatech.koin.domain.model.article.ArticleLostAndFoundReportItem
-import `in`.koreatech.koin.domain.usecase.article.lostandfound.ReportLostAndFoundArticleUseCase
-import `in`.koreatech.koin.feature.lostandfound.enums.ReportReason
-import `in`.koreatech.koin.feature.lostandfound.ui.report.component.lostAndFoundReportReasonList
-import javax.inject.Inject
-import kotlinx.coroutines.launch
-import org.orbitmvi.orbit.ContainerHost
-import org.orbitmvi.orbit.syntax.simple.blockingIntent
-import org.orbitmvi.orbit.syntax.simple.intent
-import org.orbitmvi.orbit.syntax.simple.postSideEffect
-import org.orbitmvi.orbit.syntax.simple.reduce
-import org.orbitmvi.orbit.viewmodel.container
-
-@HiltViewModel
-class LostAndFoundReportViewModel @Inject constructor(
- private val reportLostAndFoundArticleUseCase: ReportLostAndFoundArticleUseCase
-) : ViewModel(), ContainerHost {
- override val container =
- container(LostAndFoundReportState())
-
- private fun addReportReason(reportReason: ReportReason) =
- intent {
- reduce {
- state.copy(selectedReason = state.selectedReason + lostAndFoundReportReasonList.indexOf(reportReason))
- }
- }
-
- private fun removeReportReason(reportReason: ReportReason) =
- intent {
- reduce {
- state.copy(
- selectedReason = state.selectedReason.filterNot { lostAndFoundReportReasonList[it] == reportReason }.toIntArray()
- )
- }
- }
-
- fun setReportReason(reportReason: ReportReason) =
- intent {
- if (lostAndFoundReportReasonList.indexOf(reportReason) in state.selectedReason) {
- removeReportReason(reportReason)
- } else {
- addReportReason(reportReason)
- }
- }
-
- fun setReportReasonDescription(reportReasonDescription: String) =
- blockingIntent {
- reduce {
- state.copy(reportReasonDescription = reportReasonDescription)
- }
- }
-
- fun reportArticle(articleId: Int) =
- viewModelScope.launch {
- val reportReasonList = mutableListOf()
- intent {
- state.selectedReason.forEach {
- if (lostAndFoundReportReasonList[it] == ReportReason.OTHER) {
- reportReasonList.add(
- ArticleLostAndFoundReportItem(lostAndFoundReportReasonList[it].title, state.reportReasonDescription)
- )
- } else {
- reportReasonList.add(
- ArticleLostAndFoundReportItem(
- lostAndFoundReportReasonList[it].title,
- lostAndFoundReportReasonList[it].description
- )
- )
- }
- }
- reportLostAndFoundArticleUseCase(
- articleId,
- reportReasonList
- ).onSuccess {
- postSideEffect(LostAndFoundReportSideEffect.ReportSuccess)
- }.onFailure {
- postSideEffect(LostAndFoundReportSideEffect.ReportFailure(it.message ?: ""))
- }
- }
- }
-}
diff --git a/koin/build.gradle.kts b/koin/build.gradle.kts
index 3b28be707b..08890dc746 100644
--- a/koin/build.gradle.kts
+++ b/koin/build.gradle.kts
@@ -106,7 +106,7 @@ dependencies {
implementation(projects.core.onboarding)
implementation(projects.feature.timetable)
implementation(projects.feature.bus)
- implementation(projects.feature.lostandfound)
+ implementation(projects.feature.article)
implementation(projects.feature.chat)
implementation(projects.feature.banner)
implementation(projects.feature.store)
diff --git a/koin/src/main/AndroidManifest.xml b/koin/src/main/AndroidManifest.xml
index aa81965b74..fcbb5f4b07 100644
--- a/koin/src/main/AndroidManifest.xml
+++ b/koin/src/main/AndroidManifest.xml
@@ -86,28 +86,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
ALL
- 14 -> LOSTANDFOUND
- 5 -> NORMAL
- 6 -> SCHOLARSHIP
- 7 -> SCHOOL
- 8 -> RECRUIT
- 12 -> IPP
- 13 -> STUDENT
- 9 -> KOIN
- else -> ALL
- }
- }
- }
-}
-
-/**
- * Koreatech 페이지로 이동할 때 사용
- * @property NONE 링크 없음
- * @property ARTICLE 원본 게시글로 이동 (로그인 필요없는 게시판)
- * @property PORTAL 아우누리로 이동 (로그인 필요한 게시판)
- * @property STEMS 학생종합경력개발로 이동 (로그인 필요한 게시판)
- */
-enum class LinkType {
- NONE,
- ARTICLE,
- PORTAL,
- STEMS
-}
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/state/ArticleHeaderState.kt b/koin/src/main/java/in/koreatech/koin/ui/article/state/ArticleHeaderState.kt
deleted file mode 100644
index dc7338073c..0000000000
--- a/koin/src/main/java/in/koreatech/koin/ui/article/state/ArticleHeaderState.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-package `in`.koreatech.koin.ui.article.state
-
-import android.os.Parcelable
-import `in`.koreatech.koin.domain.model.article.ArticleHeader
-import `in`.koreatech.koin.ui.article.ArticleBoardType
-import kotlinx.parcelize.Parcelize
-
-@Parcelize
-data class ArticleHeaderState(
- val id: Int,
- val board: ArticleBoardType,
- val title: String,
- val author: String,
- val viewCount: Int,
- val registeredAt: String,
- val updatedAt: String
-) : Parcelable
-
-fun ArticleHeader.toArticleHeaderState() = ArticleHeaderState(
- id = id,
- board = ArticleBoardType.entries.firstOrNull { it.id == boardId } ?: ArticleBoardType.ALL,
- title = title,
- author = author,
- viewCount = viewCount,
- registeredAt = registeredAt,
- updatedAt = updatedAt
-)
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/viewmodel/ArticleDetailViewModel.kt b/koin/src/main/java/in/koreatech/koin/ui/article/viewmodel/ArticleDetailViewModel.kt
deleted file mode 100644
index 10f34bd044..0000000000
--- a/koin/src/main/java/in/koreatech/koin/ui/article/viewmodel/ArticleDetailViewModel.kt
+++ /dev/null
@@ -1,102 +0,0 @@
-package `in`.koreatech.koin.ui.article.viewmodel
-
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-import androidx.lifecycle.viewModelScope
-import dagger.assisted.Assisted
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
-import `in`.koreatech.koin.core.viewmodel.BaseViewModel
-import `in`.koreatech.koin.domain.repository.ArticleRepository
-import `in`.koreatech.koin.ui.article.ArticleBoardType
-import `in`.koreatech.koin.ui.article.state.ArticleHeaderState
-import `in`.koreatech.koin.ui.article.state.ArticleState
-import `in`.koreatech.koin.ui.article.state.toArticleHeaderState
-import `in`.koreatech.koin.ui.article.state.toArticleState
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.flow.onStart
-import kotlinx.coroutines.flow.stateIn
-
-class ArticleDetailViewModel @AssistedInject constructor(
- @Assisted("articleId") articleId: Int,
- @Assisted("navigatedBoardId") val navigatedBoardId: Int,
- private val articleRepository: ArticleRepository
-) : BaseViewModel() {
- val article: StateFlow =
- articleRepository.fetchArticle(articleId, navigatedBoardId)
- .onStart {
- _isLoading.value = true
- }.map {
- it.toArticleState()
- }.onEach {
- _isLoading.value = false
- }.stateIn(
- scope = viewModelScope,
- started = SharingStarted.WhileSubscribed(5_000),
- initialValue =
- ArticleState(
- header =
- ArticleHeaderState(
- id = 0,
- board = ArticleBoardType.ALL,
- title = "",
- author = "",
- viewCount = 0,
- registeredAt = "",
- updatedAt = ""
- ),
- content = "",
- prevArticleId = null,
- nextArticleId = null,
- attachments = listOf(),
- url = ""
- )
- )
-
- val hotArticles: StateFlow> =
- articleRepository.fetchHotArticleHeaders()
- .map {
- var doesHotContainsThis = false
- it.filterIndexed { index, hotArticleHeader ->
- if (articleId == hotArticleHeader.id) {
- doesHotContainsThis = true
- }
- articleId != hotArticleHeader.id && index < (HOT_ARTICLE_COUNT + if (doesHotContainsThis) 1 else 0)
- }.map { it.toArticleHeaderState() }
- }.stateIn(
- scope = viewModelScope,
- started = SharingStarted.WhileSubscribed(5_000),
- initialValue = listOf()
- )
-
- fun setIsLoading(isLoading: Boolean) {
- _isLoading.value = isLoading
- }
-
- @AssistedFactory
- interface Factory {
- fun create(
- @Assisted("articleId") articleId: Int,
- @Assisted("navigatedBoardId") navigatedBoardId: Int
- ): ArticleDetailViewModel
- }
-
- companion object {
- const val HOT_ARTICLE_COUNT = 4
-
- fun provideFactory(
- assistedFactory: Factory,
- article: Int,
- boardId: Int
- ): ViewModelProvider.Factory {
- return object : ViewModelProvider.Factory {
- override fun create(modelClass: Class): T {
- return assistedFactory.create(article, boardId) as T
- }
- }
- }
- }
-}
diff --git a/koin/src/main/java/in/koreatech/koin/ui/article/viewmodel/ArticleKeywordViewModel.kt b/koin/src/main/java/in/koreatech/koin/ui/article/viewmodel/ArticleKeywordViewModel.kt
deleted file mode 100644
index 91b7493a17..0000000000
--- a/koin/src/main/java/in/koreatech/koin/ui/article/viewmodel/ArticleKeywordViewModel.kt
+++ /dev/null
@@ -1,152 +0,0 @@
-package `in`.koreatech.koin.ui.article.viewmodel
-
-import androidx.lifecycle.SavedStateHandle
-import androidx.lifecycle.viewModelScope
-import dagger.hilt.android.lifecycle.HiltViewModel
-import `in`.koreatech.koin.core.viewmodel.BaseViewModel
-import `in`.koreatech.koin.domain.model.user.User
-import `in`.koreatech.koin.domain.repository.ArticleRepository
-import `in`.koreatech.koin.domain.usecase.user.GetUserStatusUseCase
-import javax.inject.Inject
-import kotlinx.coroutines.channels.BufferOverflow
-import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.SharedFlow
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.catch
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.flow.onStart
-import kotlinx.coroutines.flow.shareIn
-import kotlinx.coroutines.flow.stateIn
-
-@HiltViewModel
-class ArticleKeywordViewModel @Inject constructor(
- private val savedStateHandle: SavedStateHandle,
- private val articleRepository: ArticleRepository,
- getUserStatusUseCase: GetUserStatusUseCase
-) : BaseViewModel() {
- val user: StateFlow =
- getUserStatusUseCase()
- .stateIn(viewModelScope, SharingStarted.Eagerly, User.Anonymous)
-
- val keywordInputUiState: StateFlow =
- savedStateHandle.getStateFlow(KEYWORD_INPUT, "").map {
- if (it.isEmpty()) KeywordInputUiState.Empty else KeywordInputUiState.Valid(it)
- }.stateIn(
- scope = viewModelScope,
- started = SharingStarted.WhileSubscribed(5_000),
- initialValue = KeywordInputUiState.Empty
- )
-
- val myKeywords: StateFlow> =
- articleRepository.fetchMyKeyword()
- .stateIn(
- scope = viewModelScope,
- started = SharingStarted.WhileSubscribed(5_000),
- initialValue = listOf()
- )
-
- private val _keywordAddUiState =
- MutableSharedFlow(
- extraBufferCapacity = 1,
- onBufferOverflow = BufferOverflow.DROP_OLDEST
- )
- val keywordAddUiState: SharedFlow =
- _keywordAddUiState
- .shareIn(
- scope = viewModelScope,
- started = SharingStarted.WhileSubscribed(5_000)
- )
-
- val suggestedKeywords: StateFlow> =
- articleRepository.fetchKeywordSuggestions()
- .stateIn(
- scope = viewModelScope,
- started = SharingStarted.WhileSubscribed(5_000),
- initialValue = listOf()
- )
-
- fun addKeyword(keyword: String) {
- val trimmedKeyword =
- keyword.trim().ifEmpty {
- _keywordAddUiState.tryEmit(KeywordAddUiState.RequireInput)
- return
- }
- if (myKeywords.value.size >= MAX_KEYWORD_COUNT) {
- _keywordAddUiState.tryEmit(KeywordAddUiState.LimitExceeded)
- return
- }
-
- if (trimmedKeyword.length > MAX_KEYWORD_LENGTH || trimmedKeyword.length < MIN_KEYWORD_LENGTH) {
- _keywordAddUiState.tryEmit(KeywordAddUiState.InvalidLength)
- return
- }
-
- if (myKeywords.value.contains(trimmedKeyword)) {
- _keywordAddUiState.tryEmit(KeywordAddUiState.AlreadyExist)
- return
- }
-
- if (trimmedKeywordRegex.containsMatchIn(trimmedKeyword)) { // jusang-regex-opt
- _keywordAddUiState.tryEmit(KeywordAddUiState.BlankNotAllowed)
- return
- }
-
- articleRepository.saveKeyword(trimmedKeyword).onStart {
- _keywordAddUiState.emit(KeywordAddUiState.Loading)
- }.onEach {
- _keywordAddUiState.emit(KeywordAddUiState.Success(trimmedKeyword))
- }.catch {
- _keywordAddUiState.emit(KeywordAddUiState.Error)
- }.launchIn(viewModelScope)
- }
-
- fun deleteKeyword(keyword: String) {
- articleRepository.deleteKeyword(keyword).onEach {
- _keywordAddUiState.emit(KeywordAddUiState.Success(keyword))
- }.catch {
- _keywordAddUiState.emit(KeywordAddUiState.Error)
- }.launchIn(viewModelScope)
- }
-
- fun onKeywordInputChanged(keyword: String) {
- savedStateHandle[KEYWORD_INPUT] = keyword
- }
-
- companion object {
- const val MAX_KEYWORD_COUNT = 10
- const val MAX_SUGGEST_KEYWORD_COUNT = 5
- const val MAX_KEYWORD_LENGTH = 20
- const val MIN_KEYWORD_LENGTH = 2
- const val KEYWORD_INPUT = "keyword_input"
- val trimmedKeywordRegex = Regex("""\s+""")
- }
-}
-
-sealed interface KeywordAddUiState {
- data object Nothing : KeywordAddUiState
-
- data object Loading : KeywordAddUiState
-
- data class Success(val keyword: String) : KeywordAddUiState
-
- data object AlreadyExist : KeywordAddUiState
-
- data object LimitExceeded : KeywordAddUiState
-
- data object BlankNotAllowed : KeywordAddUiState
-
- data object InvalidLength : KeywordAddUiState
-
- data object RequireInput : KeywordAddUiState
-
- data object Error : KeywordAddUiState
-}
-
-sealed interface KeywordInputUiState {
- data object Empty : KeywordInputUiState
-
- data class Valid(val keyword: String) : KeywordInputUiState
-}
diff --git a/koin/src/main/java/in/koreatech/koin/ui/main/activity/MainActivity.kt b/koin/src/main/java/in/koreatech/koin/ui/main/activity/MainActivity.kt
index 7ea0330473..3a9671bf1c 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/main/activity/MainActivity.kt
+++ b/koin/src/main/java/in/koreatech/koin/ui/main/activity/MainActivity.kt
@@ -54,12 +54,12 @@ import `in`.koreatech.koin.core.util.blueStatusBar
import `in`.koreatech.koin.core.util.dataBinding
import `in`.koreatech.koin.databinding.ActivityMainBinding
import `in`.koreatech.koin.domain.model.article.ArticleNotiType
+import `in`.koreatech.koin.feature.article.ArticleActivity
import `in`.koreatech.koin.feature.banner.ui.BannerActivity
import `in`.koreatech.koin.feature.club.ui.MainClubWidgetA
import `in`.koreatech.koin.feature.club.ui.MainClubWidgetB
import `in`.koreatech.koin.feature.store.MainStoreWidget
import `in`.koreatech.koin.navigation.SchemeType
-import `in`.koreatech.koin.ui.article.ArticleActivity
import `in`.koreatech.koin.ui.main.adapter.StoreCategoriesRecyclerAdapter
import `in`.koreatech.koin.ui.main.compose.HotArticlePager
import `in`.koreatech.koin.ui.main.viewmodel.MainActivityViewModel
diff --git a/koin/src/main/java/in/koreatech/koin/ui/navigation/KoinNavigationDrawerActivity.kt b/koin/src/main/java/in/koreatech/koin/ui/navigation/KoinNavigationDrawerActivity.kt
index 7b63468bcc..8a676a2ab6 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/navigation/KoinNavigationDrawerActivity.kt
+++ b/koin/src/main/java/in/koreatech/koin/ui/navigation/KoinNavigationDrawerActivity.kt
@@ -41,13 +41,13 @@ import `in`.koreatech.koin.core.util.blueStatusBar
import `in`.koreatech.koin.core.util.whiteStatusBar
import `in`.koreatech.koin.data.constant.URLConstant
import `in`.koreatech.koin.domain.model.user.User
+import `in`.koreatech.koin.feature.article.ArticleActivity
import `in`.koreatech.koin.feature.chat.ui.list.ChatListActivity
import `in`.koreatech.koin.feature.club.ui.ClubActivity
import `in`.koreatech.koin.feature.dining.ui.DiningActivity
import `in`.koreatech.koin.feature.store.StoreActivity
import `in`.koreatech.koin.feature.user.ui.signin.SignInActivity
import `in`.koreatech.koin.feature.user.ui.signup.SignUpActivity
-import `in`.koreatech.koin.ui.article.ArticleActivity
import `in`.koreatech.koin.ui.land.LandActivity
import `in`.koreatech.koin.ui.main.activity.MainActivity
import `in`.koreatech.koin.ui.navigation.state.MenuState
diff --git a/koin/src/main/java/in/koreatech/koin/ui/splash/SplashActivity.kt b/koin/src/main/java/in/koreatech/koin/ui/splash/SplashActivity.kt
index ad9e6fd63e..55c002dbfc 100644
--- a/koin/src/main/java/in/koreatech/koin/ui/splash/SplashActivity.kt
+++ b/koin/src/main/java/in/koreatech/koin/ui/splash/SplashActivity.kt
@@ -35,7 +35,7 @@ import `in`.koreatech.koin.core.navigation.utils.EXTRA_TYPE
import `in`.koreatech.koin.core.onboarding.OnboardingManager
import `in`.koreatech.koin.core.toast.ToastUtil
import `in`.koreatech.koin.domain.state.version.VersionUpdatePriority
-import `in`.koreatech.koin.ui.article.ArticleActivity
+import `in`.koreatech.koin.feature.article.ArticleActivity
import `in`.koreatech.koin.ui.forceupdate.ForceUpdateActivity
import `in`.koreatech.koin.ui.main.activity.MainActivity
import `in`.koreatech.koin.ui.splash.state.TokenState
diff --git a/koin/src/main/res/values/strings.xml b/koin/src/main/res/values/strings.xml
index 39548b086a..e3fc633639 100644
--- a/koin/src/main/res/values/strings.xml
+++ b/koin/src/main/res/values/strings.xml
@@ -232,7 +232,6 @@
%d/%d
메뉴 더보기
메뉴 접기
- 검색
일반
@@ -521,77 +520,12 @@
알림 설정 바로가기
- 게시판
- 공지사항
- 공지글 검색
- 키워드 관리
- 분실물 신고
- 습득물 신고
- 더보기
- 자유게시판
- 취업게시판
- 익명게시판
- 전체공지
- 분실물
- 일반공지
- 일반
- 학사공지
- 학사
- 장학공지
- 장학
- 취업공지
- 취업
- 코인
- 질문게시판
- 홍보게시판
- 현장실습
- 현장실습
- 학생생활
- 학생
- 신고하기
- 이전
- 다음
- •
- 목록
- 다음 글
- 이전 글
- 원본 글 바로가기
- 아우누리 바로가기
- 학생종합경력개발 바로가기
- 인기있는 게시글
- 모두보기
- 내 키워드
- 키워드는 최대 10개까지 추가 가능합니다.
- 추가
- 추천 키워드
- 키워드 알림
- 키워드가 포함된 게시물의 알림을 받을 수 있습니다.
- 키워드 알림받기
- 알림받을 키워드를 입력해 주세요.
- 키워드를 입력해주세요.
- 키워드는 최대 10개까지 추가 가능합니다.
- 이미 추가되어 있는 키워드입니다.
- 키워드 길이는 2글자 이상, 20글자 이하입니다.
- 키워드에 공백은 포함할 수 없습니다.
- 새 키워드 추가
- 게시글이 존재하지 않습니다.
- 많이 검색된 키워드
- 최근 검색기록
- 전체 삭제
- 키워드 알림을 받으려면\n로그인이 필요해요.
- 로그인 후 간편하게 공지사항 키워드\n알림을 받아보세요!
- 검색어를 입력해주세요.
- 일치하는 공지글이 없습니다.\n다른 키워드로 다시 시도해주세요.
지금 인기있는 공지
자취방 양도글, 가장 먼저 확인하고 싶을 때?
공지가 업로드 되면 바로 알려주는\n키워드 알림 설정하러가기
분실물은 여기 다 모아뒀어요
바로가기 >>
첨부파일
- 다운로드 중
- 파일을 다운로드합니다.
- 다운로드가 완료되었습니다.
-
리뷰 (%1$s)
diff --git a/settings.gradle b/settings.gradle
index 4c55aa0100..d520fcaed4 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -30,7 +30,7 @@ include ':feature:timetable'
include ':core:designsystem'
include ':feature:bus'
include ':core:analytics'
-include ':feature:lostandfound'
+include ':feature:article'
include ':feature:chat'
include ':feature:banner'
include ':feature:store'