Skip to content

Commit

Permalink
[AN] feat: 놀이터 온보딩 UI 구현 (#775)
Browse files Browse the repository at this point in the history
Co-authored-by: JunJangE <[email protected]>
  • Loading branch information
gaeun5744 and junjange authored Jan 2, 2025
1 parent a37d5bf commit 3c7d1ca
Show file tree
Hide file tree
Showing 24 changed files with 388 additions and 2 deletions.
2 changes: 2 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@
android:exported="false"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize" />
<activity android:name=".presentation.ui.playground.onboarding.OnboardingActivity"
android:exported="false"/>

<activity
android:name=".presentation.ui.recentpet.RecentPetActivity"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.happy.friendogly.data.source.KakaoLoginDataSource
import com.happy.friendogly.data.source.MemberDataSource
import com.happy.friendogly.data.source.MessagingDataSource
import com.happy.friendogly.data.source.MyClubDataSource
import com.happy.friendogly.data.source.OnboardingDataSource
import com.happy.friendogly.data.source.PetDataSource
import com.happy.friendogly.data.source.PlaygroundDataSource
import com.happy.friendogly.data.source.RecentPetsDataSource
Expand All @@ -20,6 +21,7 @@ import com.happy.friendogly.firebase.source.MessagingDataSourceImpl
import com.happy.friendogly.kakao.source.KakaoLoginDataSourceImpl
import com.happy.friendogly.local.source.AddressDataSourceImpl
import com.happy.friendogly.local.source.AlarmSettingDataSourceImpl
import com.happy.friendogly.local.source.OnboardingDataSourceImpl
import com.happy.friendogly.local.source.RecentPetsDataSourceImpl
import com.happy.friendogly.local.source.TokenDataSourceImpl
import com.happy.friendogly.remote.source.AlamTokenDataSourceImpl
Expand Down Expand Up @@ -104,4 +106,8 @@ abstract class DataSourceModule {
@Binds
@Singleton
abstract fun bindsRecentPetsDataSource(dataSourceImpl: RecentPetsDataSourceImpl): RecentPetsDataSource

@Binds
@Singleton
abstract fun bindOnboardingDataSource(dataSourceImpl: OnboardingDataSourceImpl): OnboardingDataSource
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.Context
import com.happy.friendogly.local.di.AddressModule
import com.happy.friendogly.local.di.AlarmTokenModule
import com.happy.friendogly.local.di.ChatAlarmModule
import com.happy.friendogly.local.di.OnboardingModule
import com.happy.friendogly.local.di.PlaygroundAlarmModule
import com.happy.friendogly.local.di.TokenManager
import dagger.Module
Expand Down Expand Up @@ -45,4 +46,10 @@ object DataStoreModule {
fun providesPlaygroundAlarmModule(
@ApplicationContext appContext: Context,
): PlaygroundAlarmModule = PlaygroundAlarmModule(appContext)

@Provides
@Singleton
fun providesOnboardingModule(
@ApplicationContext appContext: Context,
): OnboardingModule = OnboardingModule(appContext)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.happy.friendogly.data.repository.KakaoLoginRepositoryImpl
import com.happy.friendogly.data.repository.MemberRepositoryImpl
import com.happy.friendogly.data.repository.MessagingRepositoryImpl
import com.happy.friendogly.data.repository.MyClubRepositoryImpl
import com.happy.friendogly.data.repository.OnboardingRepositoryImpl
import com.happy.friendogly.data.repository.PetRepositoryImpl
import com.happy.friendogly.data.repository.PlaygroundRepositoryImpl
import com.happy.friendogly.data.repository.RecentPetsRepositoryImpl
Expand All @@ -28,6 +29,7 @@ import com.happy.friendogly.domain.repository.KakaoLoginRepository
import com.happy.friendogly.domain.repository.MemberRepository
import com.happy.friendogly.domain.repository.MessagingRepository
import com.happy.friendogly.domain.repository.MyClubRepository
import com.happy.friendogly.domain.repository.OnboardingRepository
import com.happy.friendogly.domain.repository.PetRepository
import com.happy.friendogly.domain.repository.PlaygroundRepository
import com.happy.friendogly.domain.repository.RecentPetsRepository
Expand Down Expand Up @@ -110,4 +112,8 @@ abstract class RepositoryModule {
@Binds
@Singleton
abstract fun bindsRecentPetsRepository(repositoryImpl: RecentPetsRepositoryImpl): RecentPetsRepository

@Binds
@Singleton
abstract fun bindOnboardingRepository(repositoryImpl: OnboardingRepositoryImpl): OnboardingRepository
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.happy.friendogly.data.repository

import com.happy.friendogly.data.source.OnboardingDataSource
import com.happy.friendogly.domain.repository.OnboardingRepository
import javax.inject.Inject

class OnboardingRepositoryImpl
@Inject
constructor(
private val source: OnboardingDataSource,
) : OnboardingRepository {
override suspend fun isShown(): Result<Boolean> = source.isShown()

override suspend fun setShown(isShown: Boolean): Result<Unit> = source.setShown(isShown)

override suspend fun deleteIsShown(): Result<Unit> = source.deleteShown()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.happy.friendogly.data.source

interface OnboardingDataSource {
suspend fun isShown(): Result<Boolean>

suspend fun setShown(isShown: Boolean): Result<Unit>

suspend fun deleteShown(): Result<Unit>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.happy.friendogly.domain.repository

interface OnboardingRepository {
suspend fun isShown(): Result<Boolean>

suspend fun setShown(isShown: Boolean): Result<Unit>

suspend fun deleteIsShown(): Result<Unit>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.happy.friendogly.domain.usecase

import com.happy.friendogly.domain.repository.OnboardingRepository
import javax.inject.Inject

class DeleteOnboardingShownUseCase
@Inject
constructor(
private val repository: OnboardingRepository,
) {
suspend operator fun invoke(): Result<Unit> = repository.deleteIsShown()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.happy.friendogly.domain.usecase

import com.happy.friendogly.domain.repository.OnboardingRepository
import javax.inject.Inject

class GetOnboardingShownUseCase
@Inject
constructor(
private val repository: OnboardingRepository,
) {
suspend operator fun invoke(): Result<Boolean> = repository.isShown()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.happy.friendogly.domain.usecase

import com.happy.friendogly.domain.repository.OnboardingRepository
import javax.inject.Inject

class SetOnboardingShownUseCase
@Inject
constructor(
private val repository: OnboardingRepository,
) {
suspend operator fun invoke(isShown: Boolean): Result<Unit> = repository.setShown(isShown)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.happy.friendogly.local.di

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.emptyPreferences
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
import java.io.IOException

class OnboardingModule(val context: Context) {
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = DATA_STORE_NAME)

private val key = booleanPreferencesKey(IS_ONBOARDING)

var isShown: Flow<Boolean> =
context.dataStore.data.catch { exception ->
if (exception is IOException) {
emit(emptyPreferences())
} else {
throw exception
}
}.map { preferences ->
preferences[key] ?: false
}

suspend fun setShown(value: Boolean) {
context.dataStore.edit { preferences ->
preferences[key] = value
}
}

suspend fun deleteIsShown() {
context.dataStore.edit { prefs ->
prefs.remove(key)
}
}

companion object {
private const val IS_ONBOARDING = "IS_ONBOARDING_SHOWN"
private const val DATA_STORE_NAME = "onboardingDataStore"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.happy.friendogly.local.source

import com.happy.friendogly.data.source.OnboardingDataSource
import com.happy.friendogly.local.di.OnboardingModule
import kotlinx.coroutines.flow.first
import javax.inject.Inject

class OnboardingDataSourceImpl
@Inject
constructor(
private val onboardingModule: OnboardingModule,
) : OnboardingDataSource {
override suspend fun isShown(): Result<Boolean> =
runCatching {
onboardingModule.isShown.first()
}

override suspend fun setShown(isShown: Boolean): Result<Unit> =
runCatching {
onboardingModule.setShown(isShown)
}

override suspend fun deleteShown(): Result<Unit> =
runCatching {
onboardingModule.deleteIsShown()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ import android.content.Context
import android.content.Intent
import androidx.activity.result.ActivityResultLauncher
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.happy.friendogly.R
import com.happy.friendogly.databinding.ActivityMainBinding
import com.happy.friendogly.domain.usecase.GetOnboardingShownUseCase
import com.happy.friendogly.domain.usecase.SetOnboardingShownUseCase
import com.happy.friendogly.firebase.analytics.AnalyticsHelper
import com.happy.friendogly.presentation.base.BaseActivity
import com.happy.friendogly.presentation.ui.chatlist.ChatListFragment
Expand All @@ -19,6 +22,7 @@ import com.happy.friendogly.presentation.ui.permission.MultiPermission
import com.happy.friendogly.presentation.ui.petdetail.PetDetailActivity
import com.happy.friendogly.presentation.ui.petdetail.PetsDetail
import com.happy.friendogly.presentation.ui.playground.PlaygroundFragment
import com.happy.friendogly.presentation.ui.playground.onboarding.OnboardingActivity
import com.happy.friendogly.presentation.ui.profilesetting.ProfileSettingActivity
import com.happy.friendogly.presentation.ui.profilesetting.model.Profile
import com.happy.friendogly.presentation.ui.recentpet.RecentPetActivity
Expand All @@ -31,6 +35,7 @@ import com.happy.friendogly.presentation.utils.logMyClubClick
import com.happy.friendogly.presentation.utils.logMyPageFragmentSwitched
import com.happy.friendogly.presentation.utils.logPlaygroundFragmentSwitched
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import javax.inject.Inject

@AndroidEntryPoint
Expand All @@ -40,6 +45,12 @@ class MainActivity :
@Inject
lateinit var analyticsHelper: AnalyticsHelper

@Inject
lateinit var setOnboardingShownUseCase: SetOnboardingShownUseCase

@Inject
lateinit var getOnboardingShownUseCase: GetOnboardingShownUseCase

private lateinit var permission: MultiPermission

override fun initCreateView() {
Expand Down Expand Up @@ -83,17 +94,20 @@ class MainActivity :
ClubListFragment.TAG,
)

R.id.playgroundFragment ->
R.id.playgroundFragment -> {
showOnboarding()
switchFragment(
PlaygroundFragment::class.java,
PlaygroundFragment.TAG,
)
}

R.id.chatListFragment ->
R.id.chatListFragment -> {
switchFragment(
ChatListFragment::class.java,
ChatListFragment.TAG,
)
}

R.id.myPageFragment ->
switchFragment(
Expand All @@ -106,6 +120,15 @@ class MainActivity :
}
}

private fun showOnboarding() {
lifecycleScope.launch {
if (!getOnboardingShownUseCase().getOrDefault(false)) {
startActivity(Intent(this@MainActivity, OnboardingActivity::class.java))
setOnboardingShownUseCase(true)
}
}
}

private fun switchFragment(
fragmentClass: Class<out Fragment>,
tag: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.happy.friendogly.presentation.ui.playground.onboarding

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.tabs.TabLayoutMediator
import com.happy.friendogly.databinding.ActivityOnboardingBinding

class OnboardingActivity : AppCompatActivity() {
lateinit var binding: ActivityOnboardingBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityOnboardingBinding.inflate(layoutInflater)
setContentView(binding.root)
initOnboardingPager()
}

private fun initOnboardingPager() {
binding.vpDescExplain.adapter = OnboardingAdapter(this)
TabLayoutMediator(binding.tlDescIndicator, binding.vpDescExplain) { tab, position ->
}.attach()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.happy.friendogly.presentation.ui.playground.onboarding

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter

class OnboardingAdapter(
fragmentActivity: FragmentActivity,
) : FragmentStateAdapter(fragmentActivity) {
override fun getItemCount(): Int = 3

override fun createFragment(position: Int): Fragment {
return OnboardingFragment().apply {
arguments = OnboardingFragment.getBundle(position)
}
}
}
Loading

0 comments on commit 3c7d1ca

Please sign in to comment.