From ae8e398e8714ee556a0aca5cd02e6299f9acf502 Mon Sep 17 00:00:00 2001
From: Sehwan Yun <39579912+l5x5l@users.noreply.github.com>
Date: Tue, 8 Oct 2024 19:12:45 +0900
Subject: [PATCH] =?UTF-8?q?[Feature]=20#76=20=EC=95=94=EC=8B=9C=EC=A0=81?=
=?UTF-8?q?=20=EC=9D=B8=ED=85=90=ED=8A=B8=EB=A5=BC=20=ED=86=B5=ED=95=9C=20?=
=?UTF-8?q?=EB=A7=81=ED=81=AC=20=EC=A0=80=EC=9E=A5=20=EA=B8=B0=EB=8A=A5=20?=
=?UTF-8?q?=EA=B5=AC=ED=98=84=20(#77)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* [FEATURE] 공유하기 암시적 인텐트 수신 기능 구현
* [FIX] 설정 화면에서 로그아웃 후 로그인 화면에서 뒤로가기 클릭시 로그인 화면이 종료되지 않는 문제 수정
* [CHORE] ktlint 적용
---
app/src/main/AndroidManifest.xml | 10 +++-
.../main/java/pokitmons/pokit/MainActivity.kt | 40 ++++++++++---
.../java/pokitmons/pokit/MainViewModel.kt | 56 +++++++++++++++++++
.../pokit/navigation/RootDestination.kt | 2 +
.../pokitmons/pokit/navigation/RootNavHost.kt | 2 +-
.../java/pokitmons/pokit/home/HomeScreen.kt | 3 +
.../pokit/home/model/HomeSideEffect.kt | 1 +
.../home/model/PendingSharedLinkManager.kt | 19 +++++++
.../pokit/home/pokit/PokitViewModel.kt | 10 ++++
9 files changed, 132 insertions(+), 11 deletions(-)
create mode 100644 app/src/main/java/pokitmons/pokit/MainViewModel.kt
create mode 100644 feature/home/src/main/java/pokitmons/pokit/home/model/PendingSharedLinkManager.kt
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index fcab7b1f..e928a13c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -18,14 +18,20 @@
android:screenOrientation="portrait"
android:name=".MainActivity"
android:exported="true"
- android:label="@string/app_name"
android:windowSoftInputMode="adjustResize"
- android:theme="@style/Theme.Pokit">
+ android:theme="@style/Theme.Pokit"
+ android:launchMode="singleInstance"
+ tools:ignore="DiscouragedApi,LockedOrientationActivity">
+
+
+
+
+
diff --git a/app/src/main/java/pokitmons/pokit/MainActivity.kt b/app/src/main/java/pokitmons/pokit/MainActivity.kt
index 3c78fe92..7fd8ede5 100644
--- a/app/src/main/java/pokitmons/pokit/MainActivity.kt
+++ b/app/src/main/java/pokitmons/pokit/MainActivity.kt
@@ -2,10 +2,12 @@ package pokitmons.pokit
import android.content.ClipData
import android.content.ClipboardManager
+import android.content.Intent
import android.os.Build
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
+import androidx.activity.viewModels
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
@@ -24,14 +26,18 @@ import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.delay
+import pokitmons.pokit.core.feature.flow.collectAsEffect
import pokitmons.pokit.core.ui.theme.PokitTheme
-import pokitmons.pokit.home.model.ClipboardLinkManager
+import pokitmons.pokit.navigation.AddLink
import pokitmons.pokit.navigation.RootNavHost
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
+ private val viewModel: MainViewModel by viewModels()
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ handleSharedLinkIntent(intent)
setContent {
var showSplash by remember { mutableStateOf(true) }
@@ -44,6 +50,12 @@ class MainActivity : ComponentActivity() {
val navBackStackEntry by navHostController.currentBackStackEntryAsState()
val currentDestination by remember(navBackStackEntry) { derivedStateOf { navBackStackEntry?.destination } }
+ viewModel.navigationEvent.collectAsEffect { navigationEvent ->
+ if (navigationEvent is NavigationEvent.AddLink) {
+ navHostController.navigate("${AddLink.route}?${AddLink.linkUrl}=${navigationEvent.url}")
+ }
+ }
+
PokitTheme {
if (showSplash) {
SplashScreen()
@@ -53,25 +65,26 @@ class MainActivity : ComponentActivity() {
LaunchedEffect(currentDestination) {
currentDestination?.route?.let { route ->
- // 믹스패널/파베 애널리틱스 화면 이동 로깅용
+ viewModel.setCurrentRoute(route)
}
}
}
}
}
+ override fun onNewIntent(intent: Intent) {
+ super.onNewIntent(intent)
+ handleSharedLinkIntent(intent)
+ }
+
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if (hasFocus) {
val clipboardManager = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
clipboardManager.primaryClip?.let { clipData ->
- if (clipData.itemCount == 0) return@let
- val clipboardTextData = clipData.getItemAt(0).text.toString()
-
- if (!ClipboardLinkManager.checkUrlIsValid(clipboardTextData)) return@let
-
- ClipboardLinkManager.setClipboardLink(clipboardTextData)
+ val setClipDataSuccess = viewModel.setClipData(clipData)
+ if (!setClipDataSuccess) return@let
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
clipboardManager.clearPrimaryClip()
} else {
@@ -81,6 +94,17 @@ class MainActivity : ComponentActivity() {
}
}
}
+
+ private fun handleSharedLinkIntent(intent: Intent) {
+ val action = intent.action ?: return
+
+ val isSharedLinkData = (action == Intent.ACTION_SEND && intent.type == "text/plain")
+ if (isSharedLinkData) {
+ intent.getStringExtra(Intent.EXTRA_TEXT)?.let { url ->
+ viewModel.setSharedLinkUrl(url)
+ }
+ }
+ }
}
@Composable
diff --git a/app/src/main/java/pokitmons/pokit/MainViewModel.kt b/app/src/main/java/pokitmons/pokit/MainViewModel.kt
new file mode 100644
index 00000000..75711b8f
--- /dev/null
+++ b/app/src/main/java/pokitmons/pokit/MainViewModel.kt
@@ -0,0 +1,56 @@
+package pokitmons.pokit
+
+import android.content.ClipData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+import pokitmons.pokit.core.feature.flow.EventFlow
+import pokitmons.pokit.core.feature.flow.MutableEventFlow
+import pokitmons.pokit.core.feature.flow.asEventFlow
+import pokitmons.pokit.home.model.ClipboardLinkManager
+import pokitmons.pokit.home.model.PendingSharedLinkManager
+import pokitmons.pokit.navigation.Login
+import pokitmons.pokit.navigation.ROUTE_WITHOUT_LOGIN
+import javax.inject.Inject
+
+@HiltViewModel
+class MainViewModel @Inject constructor() : ViewModel() {
+ private val _currentRoute: MutableStateFlow = MutableStateFlow(Login.route)
+ val currentRoute: StateFlow = _currentRoute.asStateFlow()
+
+ private val _navigationEvent: MutableEventFlow = MutableEventFlow()
+ val navigationEvent: EventFlow = _navigationEvent.asEventFlow()
+
+ fun setCurrentRoute(route: String) {
+ _currentRoute.update { route }
+ }
+
+ fun setClipData(clipData: ClipData): Boolean {
+ if (clipData.itemCount == 0) return false
+ val clipboardTextData = clipData.getItemAt(0).text.toString()
+
+ if (!ClipboardLinkManager.checkUrlIsValid(clipboardTextData)) return false
+
+ ClipboardLinkManager.setClipboardLink(clipboardTextData)
+ return true
+ }
+
+ fun setSharedLinkUrl(url: String) {
+ if (currentRoute.value in ROUTE_WITHOUT_LOGIN) {
+ PendingSharedLinkManager.setSharedLink(url)
+ } else {
+ viewModelScope.launch {
+ _navigationEvent.emit(NavigationEvent.AddLink(url))
+ }
+ }
+ }
+}
+
+sealed class NavigationEvent {
+ data class AddLink(val url: String) : NavigationEvent()
+}
diff --git a/app/src/main/java/pokitmons/pokit/navigation/RootDestination.kt b/app/src/main/java/pokitmons/pokit/navigation/RootDestination.kt
index f2b1a432..d2214709 100644
--- a/app/src/main/java/pokitmons/pokit/navigation/RootDestination.kt
+++ b/app/src/main/java/pokitmons/pokit/navigation/RootDestination.kt
@@ -3,6 +3,8 @@ package pokitmons.pokit.navigation
import androidx.navigation.NavType
import androidx.navigation.navArgument
+val ROUTE_WITHOUT_LOGIN = listOf(Login.route, TermOfService.route, InputNickname.route, SelectKeyword.route, SignUpSuccess.route)
+
object Login {
val route: String = "login"
}
diff --git a/app/src/main/java/pokitmons/pokit/navigation/RootNavHost.kt b/app/src/main/java/pokitmons/pokit/navigation/RootNavHost.kt
index 3ea5bfed..439d88df 100644
--- a/app/src/main/java/pokitmons/pokit/navigation/RootNavHost.kt
+++ b/app/src/main/java/pokitmons/pokit/navigation/RootNavHost.kt
@@ -154,7 +154,7 @@ fun RootNavHost(
onNavigateToEditNickname = { navHostController.navigate(EditNickname.route) },
onNavigateToLogin = {
navHostController.navigate(Login.route) {
- popUpTo(navHostController.graph.startDestinationId) {
+ popUpTo(navHostController.graph.id) {
inclusive = true
}
}
diff --git a/feature/home/src/main/java/pokitmons/pokit/home/HomeScreen.kt b/feature/home/src/main/java/pokitmons/pokit/home/HomeScreen.kt
index bfa97b10..a48fea1a 100644
--- a/feature/home/src/main/java/pokitmons/pokit/home/HomeScreen.kt
+++ b/feature/home/src/main/java/pokitmons/pokit/home/HomeScreen.kt
@@ -70,6 +70,9 @@ fun HomeScreen(
HomeSideEffect.NavigateToAddPokit -> {
onNavigateAddPokit()
}
+ is HomeSideEffect.NavigateToAddLink -> {
+ onNavigateAddLink(homeSideEffect.url)
+ }
}
}
diff --git a/feature/home/src/main/java/pokitmons/pokit/home/model/HomeSideEffect.kt b/feature/home/src/main/java/pokitmons/pokit/home/model/HomeSideEffect.kt
index 3b0f6344..d44c77e6 100644
--- a/feature/home/src/main/java/pokitmons/pokit/home/model/HomeSideEffect.kt
+++ b/feature/home/src/main/java/pokitmons/pokit/home/model/HomeSideEffect.kt
@@ -2,4 +2,5 @@ package pokitmons.pokit.home.model
sealed class HomeSideEffect {
data object NavigateToAddPokit : HomeSideEffect()
+ data class NavigateToAddLink(val url: String) : HomeSideEffect()
}
diff --git a/feature/home/src/main/java/pokitmons/pokit/home/model/PendingSharedLinkManager.kt b/feature/home/src/main/java/pokitmons/pokit/home/model/PendingSharedLinkManager.kt
new file mode 100644
index 00000000..068c488c
--- /dev/null
+++ b/feature/home/src/main/java/pokitmons/pokit/home/model/PendingSharedLinkManager.kt
@@ -0,0 +1,19 @@
+package pokitmons.pokit.home.model
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import pokitmons.pokit.core.feature.flow.EventFlow
+import pokitmons.pokit.core.feature.flow.MutableEventFlow
+import pokitmons.pokit.core.feature.flow.asEventFlow
+
+object PendingSharedLinkManager {
+ private val _sharedLinkUrl: MutableEventFlow = MutableEventFlow()
+ val sharedLinkUrl: EventFlow = _sharedLinkUrl.asEventFlow()
+
+ fun setSharedLink(linkUrl: String) {
+ CoroutineScope(Dispatchers.IO).launch {
+ _sharedLinkUrl.emit(linkUrl)
+ }
+ }
+}
diff --git a/feature/home/src/main/java/pokitmons/pokit/home/pokit/PokitViewModel.kt b/feature/home/src/main/java/pokitmons/pokit/home/pokit/PokitViewModel.kt
index 4da93d56..10de1192 100644
--- a/feature/home/src/main/java/pokitmons/pokit/home/pokit/PokitViewModel.kt
+++ b/feature/home/src/main/java/pokitmons/pokit/home/pokit/PokitViewModel.kt
@@ -34,6 +34,7 @@ import pokitmons.pokit.home.model.ClipboardLinkManager
import pokitmons.pokit.home.model.HomeSideEffect
import pokitmons.pokit.home.model.HomeToastMessage
import pokitmons.pokit.home.model.LinkAddToastMessage
+import pokitmons.pokit.home.model.PendingSharedLinkManager
import javax.inject.Inject
import kotlin.math.max
import com.strayalpaca.pokitdetail.model.Link as DetailLink
@@ -107,6 +108,14 @@ class PokitViewModel @Inject constructor(
}
}
+ private fun initPendingSharedLinkUrlDetector() {
+ viewModelScope.launch {
+ PendingSharedLinkManager.sharedLinkUrl.collectLatest { linkUrl ->
+ _sideEffect.emit(HomeSideEffect.NavigateToAddLink(linkUrl))
+ }
+ }
+ }
+
private fun initPokitUpdateEventDetector() {
viewModelScope.launch {
PokitUpdateEvent.updatedPokit.collectLatest { updatedPokit ->
@@ -239,6 +248,7 @@ class PokitViewModel @Inject constructor(
initPokitAddEventDetector()
initLinkRemoveEventDetector()
initClipboardLinkUrlDetector()
+ initPendingSharedLinkUrlDetector()
loadUnCategoryLinks()
loadPokits()