diff --git a/app/src/main/java/com/hmh/hamyeonham/SampleActivity.kt b/app/src/main/java/com/hmh/hamyeonham/SampleActivity.kt index 7747ed58e..34c4731a4 100644 --- a/app/src/main/java/com/hmh/hamyeonham/SampleActivity.kt +++ b/app/src/main/java/com/hmh/hamyeonham/SampleActivity.kt @@ -22,6 +22,7 @@ class SampleActivity : AppCompatActivity() { initSplashAnimation(splashScreen) setContentView(binding.root) startActivity(Intent(this, OnBoardingActivity::class.java)) + finish() } private fun initSplashAnimation(splashScreen: SplashScreen) { diff --git a/app/src/main/java/com/hmh/hamyeonham/di/NavigatorModule.kt b/app/src/main/java/com/hmh/hamyeonham/di/NavigatorModule.kt new file mode 100644 index 000000000..02f1a12aa --- /dev/null +++ b/app/src/main/java/com/hmh/hamyeonham/di/NavigatorModule.kt @@ -0,0 +1,17 @@ +package com.hmh.hamyeonham.di + +import com.hmh.hamyeonham.common.navigation.NavigationProvider +import com.hmh.hamyeonham.navigation.DefaultNavigationProvider +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +interface NavigatorModule { + @Binds + @Singleton + fun bindNavigator(navigator: DefaultNavigationProvider): NavigationProvider +} diff --git a/app/src/main/java/com/hmh/hamyeonham/navigation/DefaultNavigationProvider.kt b/app/src/main/java/com/hmh/hamyeonham/navigation/DefaultNavigationProvider.kt new file mode 100644 index 000000000..7f067392d --- /dev/null +++ b/app/src/main/java/com/hmh/hamyeonham/navigation/DefaultNavigationProvider.kt @@ -0,0 +1,31 @@ +package com.hmh.hamyeonham.navigation + +import android.content.Context +import android.content.Intent +import com.hmh.hamyeonham.common.navigation.NavigationProvider +import com.hmh.hamyeonham.feature.login.LoginActivity +import com.hmh.hamyeonham.feature.login.UserInfoActivity +import com.hmh.hamyeonham.feature.onboarding.OnBoardingActivity +import com.hmh.hamyeonham.statistics.StaticsActivity +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject + +class DefaultNavigationProvider @Inject constructor( + @ApplicationContext private val context: Context +) : NavigationProvider { + override fun toOnboarding(): Intent { + return Intent(context, OnBoardingActivity::class.java) + } + + override fun toLogin(): Intent { + return Intent(context, LoginActivity::class.java) + } + + override fun toUserInfo(): Intent { + return Intent(context, UserInfoActivity::class.java) + } + + override fun toStatics(): Intent { + return Intent(context, StaticsActivity::class.java) + } +} diff --git a/core/common/src/main/java/com/hmh/hamyeonham/common/navigation/NavigationProvider.kt b/core/common/src/main/java/com/hmh/hamyeonham/common/navigation/NavigationProvider.kt index 753fba19e..606c00c43 100644 --- a/core/common/src/main/java/com/hmh/hamyeonham/common/navigation/NavigationProvider.kt +++ b/core/common/src/main/java/com/hmh/hamyeonham/common/navigation/NavigationProvider.kt @@ -4,8 +4,7 @@ import android.content.Intent interface NavigationProvider { fun toOnboarding(): Intent - fun toLicense(): Intent - fun toHome(): Intent - fun toAlbumList(albumId: Long): Intent - fun toSignUp(): Intent + fun toLogin(): Intent + fun toUserInfo(): Intent + fun toStatics(): Intent } diff --git a/core/common/src/main/java/com/hmh/hamyeonham/common/time/TimeExt.kt b/core/common/src/main/java/com/hmh/hamyeonham/common/time/TimeExt.kt index 8d400fc48..da2a509bb 100644 --- a/core/common/src/main/java/com/hmh/hamyeonham/common/time/TimeExt.kt +++ b/core/common/src/main/java/com/hmh/hamyeonham/common/time/TimeExt.kt @@ -50,13 +50,12 @@ fun getCurrentDayStartEndEpochMillis(): Pair { return Pair(startOfDay, endOfDay) } -fun convertMillisecondsToMinute(ms: Long) = TimeUnit.MILLISECONDS.toMinutes(ms) - fun convertTimeToString(time: Long): String { - val hour = convertMillisecondsToMinute(time) / 60 - val min = convertMillisecondsToMinute(time) % 60 - var result = "" - if (hour > 0) result = result.plus("$hour" + "시간") - if (min >= 0) result = result.plus("$min" + "분") - return result + val hours = TimeUnit.MILLISECONDS.toHours(time) + val minutes = TimeUnit.MILLISECONDS.toMinutes(time) % 60 + + return buildString { + if (hours > 0) append("$hours 시간") + if (minutes > 0 || hours == 0L) append(" $minutes 분") + }.trim() } diff --git a/data/usagestats/src/main/java/com/hmh/hamyeonham/usagestats/datasource/UsageGoalsDataSource.kt b/data/usagestats/src/main/java/com/hmh/hamyeonham/usagestats/datasource/UsageGoalsDataSource.kt index a12659816..546e835b5 100644 --- a/data/usagestats/src/main/java/com/hmh/hamyeonham/usagestats/datasource/UsageGoalsDataSource.kt +++ b/data/usagestats/src/main/java/com/hmh/hamyeonham/usagestats/datasource/UsageGoalsDataSource.kt @@ -1,24 +1,16 @@ package com.hmh.hamyeonham.usagestats.datasource import com.hmh.hamyeonham.usagestats.model.UsageGoalModel -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import javax.inject.Singleton +import javax.inject.Inject -@Module -@InstallIn(SingletonComponent::class) -class UsageGoalsDataSource { - @Provides - @Singleton +class UsageGoalsDataSource @Inject constructor() { fun getUsageGoals(): List { return listOf( - UsageGoalModel("total", 201519990), - UsageGoalModel("com.kakao.talk", 15686 * 2), - UsageGoalModel("com.google.android.gms", 7134), - UsageGoalModel("com.google.android.youtube", 71349), - UsageGoalModel("com.android.chrome", 39445), + UsageGoalModel("total", 9459489), + UsageGoalModel("com.kakao.talk", 10737116), + UsageGoalModel("com.google.android.gms", 10607821), + UsageGoalModel("com.google.android.youtube", 7409658), + UsageGoalModel("com.android.chrome", 9346527), ) } } diff --git a/data/usagestats/src/main/java/com/hmh/hamyeonham/usagestats/repository/DefaultUsageGoalsRepository.kt b/data/usagestats/src/main/java/com/hmh/hamyeonham/usagestats/repository/DefaultUsageGoalsRepository.kt index 7a24f4049..dd82b4fbf 100644 --- a/data/usagestats/src/main/java/com/hmh/hamyeonham/usagestats/repository/DefaultUsageGoalsRepository.kt +++ b/data/usagestats/src/main/java/com/hmh/hamyeonham/usagestats/repository/DefaultUsageGoalsRepository.kt @@ -1,19 +1,20 @@ package com.hmh.hamyeonham.usagestats.repository +import com.hmh.hamyeonham.usagestats.datasource.UsageGoalsDataSource import com.hmh.hamyeonham.usagestats.model.UsageGoal -import com.hmh.hamyeonham.usagestats.model.UsageGoalModel import javax.inject.Inject class DefaultUsageGoalsRepository @Inject constructor( - private val usageGoalList: List, + private val usageGoalsDataSource: UsageGoalsDataSource ) : UsageGoalsRepository { override fun getUsageGoals(): List { - return usageGoalList.map { + return usageGoalsDataSource.getUsageGoals().map { UsageGoal(it.packageName, it.goalTime) } } override fun getUsageGoalTime(packageName: String): Long { - return usageGoalList.firstOrNull { it.packageName == packageName }?.goalTime ?: 0 + return usageGoalsDataSource.getUsageGoals() + .firstOrNull { it.packageName == packageName }?.goalTime ?: 0 } } diff --git a/domain/usagestats/src/main/java/com/hmh/hamyeonham/usagestats/model/UsageStatAndGoal.kt b/domain/usagestats/src/main/java/com/hmh/hamyeonham/usagestats/model/UsageStatAndGoal.kt index 6d140a876..0fb344601 100644 --- a/domain/usagestats/src/main/java/com/hmh/hamyeonham/usagestats/model/UsageStatAndGoal.kt +++ b/domain/usagestats/src/main/java/com/hmh/hamyeonham/usagestats/model/UsageStatAndGoal.kt @@ -7,17 +7,9 @@ data class UsageStatAndGoal( ) { private val challengeSuccess: Boolean = (goalTime - totalTimeInForeground) >= 0 val timeLeft: Long by lazy { - if (challengeSuccess) { - goalTime - totalTimeInForeground - } else { - 0L - } + if (challengeSuccess) goalTime - totalTimeInForeground else 0L } val usedPercentage: Int by lazy { - if (challengeSuccess) { - (totalTimeInForeground * 100 / goalTime).toInt() - } else { - 100 - } + if (challengeSuccess) (totalTimeInForeground * 100 / goalTime).toInt() else 100 } } diff --git a/domain/usagestats/src/main/java/com/hmh/hamyeonham/usagestats/usecase/StaticsUseCase.kt b/domain/usagestats/src/main/java/com/hmh/hamyeonham/usagestats/usecase/GetUsageStatsListUseCase.kt similarity index 58% rename from domain/usagestats/src/main/java/com/hmh/hamyeonham/usagestats/usecase/StaticsUseCase.kt rename to domain/usagestats/src/main/java/com/hmh/hamyeonham/usagestats/usecase/GetUsageStatsListUseCase.kt index 526699bb8..1675f8b91 100644 --- a/domain/usagestats/src/main/java/com/hmh/hamyeonham/usagestats/usecase/StaticsUseCase.kt +++ b/domain/usagestats/src/main/java/com/hmh/hamyeonham/usagestats/usecase/GetUsageStatsListUseCase.kt @@ -1,46 +1,61 @@ -package com.hmh.hamyeonham.usagestats.usecase - -import com.hmh.hamyeonham.usagestats.model.UsageStatAndGoal -import com.hmh.hamyeonham.usagestats.repository.UsageGoalsRepository -import com.hmh.hamyeonham.usagestats.repository.UsageStatsRepository -import javax.inject.Inject - -class StaticsUseCase @Inject constructor( - private val usageStatsRepository: UsageStatsRepository, - private val usageGoalsRepository: UsageGoalsRepository, -) { - fun getUsageStatsAndGoals( - startTime: Long, - endTime: Long, - ): List { - val totalUsage = getTotalUsage(startTime, endTime) - val usageForSelectedApps = getUsageStatsAndGoalsForSelectedApps(startTime, endTime) - val totalUsageStatAndGoal = - UsageStatAndGoal("total", totalUsage, usageGoalsRepository.getUsageGoalTime("total")) - return listOf(totalUsageStatAndGoal) + usageForSelectedApps - } - - private fun getUsageStatsAndGoalsForSelectedApps( - startTime: Long, - endTime: Long, - ): List { - val appList = getSelectedAppList() - return usageStatsRepository.getUsageTimeForPackages(startTime, endTime, appList).map { - UsageStatAndGoal( - it.packageName, - it.totalTimeInForeground, - usageGoalsRepository.getUsageGoalTime(it.packageName), - ) - } - } - - private fun getTotalUsage( - startTime: Long, - endTime: Long, - ): Long = usageStatsRepository.getUsageStats(startTime, endTime).sumOf { - it.totalTimeInForeground - } - - private fun getSelectedAppList(): List = - usageGoalsRepository.getUsageGoals().map { it.packageName } -} +package com.hmh.hamyeonham.usagestats.usecase + +import com.hmh.hamyeonham.usagestats.model.UsageStatAndGoal +import com.hmh.hamyeonham.usagestats.repository.UsageGoalsRepository +import com.hmh.hamyeonham.usagestats.repository.UsageStatsRepository +import javax.inject.Inject + +class GetUsageStatsListUseCase @Inject constructor( + private val usageStatsRepository: UsageStatsRepository, + private val usageGoalsRepository: UsageGoalsRepository, +) { + + companion object { + private const val TOTAL = "total" + } + + fun getUsageStatsAndGoals( + startTime: Long, + endTime: Long, + ): List { + val totalUsage = getTotalUsage(startTime, endTime) + val usageForSelectedApps = getUsageStatsAndGoalsForSelectedApps(startTime, endTime) + val totalUsageStatAndGoal = + UsageStatAndGoal(TOTAL, totalUsage, usageGoalsRepository.getUsageGoalTime(TOTAL)) + return listOf(totalUsageStatAndGoal) + usageForSelectedApps + } + + private fun getUsageStatsAndGoalsForSelectedApps( + startTime: Long, + endTime: Long, + ): List { + val appList = getSelectedPackageList() + return usageStatsRepository.getUsageTimeForPackages(startTime, endTime, appList) + .map { + createUsageStatAndGoal( + it.packageName, + it.totalTimeInForeground, + it.packageName + ) + } + } + + private fun getTotalUsage( + startTime: Long, + endTime: Long, + ): Long = usageStatsRepository.getUsageStats(startTime, endTime).sumOf { + it.totalTimeInForeground + } + + private fun getSelectedPackageList(): List = + usageGoalsRepository.getUsageGoals().map { it.packageName }.distinct() + + private fun createUsageStatAndGoal( + packageName: String, + totalTimeInForeground: Long, + goalKey: String + ): UsageStatAndGoal { + val goalTime = usageGoalsRepository.getUsageGoalTime(goalKey) + return UsageStatAndGoal(packageName, totalTimeInForeground, goalTime) + } +} diff --git a/feature/login/build.gradle.kts b/feature/login/build.gradle.kts index c4b4405ab..c30b53317 100644 --- a/feature/login/build.gradle.kts +++ b/feature/login/build.gradle.kts @@ -8,11 +8,16 @@ android { } dependencies { + + // Common implementation(projects.core.common) // kakao implementation(libs.kakao.login) - implementation(libs.dot.indicator) + // coil implementation(libs.coil.core) + + // dot indicator + implementation(libs.dot.indicator) } diff --git a/feature/login/src/main/java/com/hmh/hamyeonham/feature/login/LoginActivity.kt b/feature/login/src/main/java/com/hmh/hamyeonham/feature/login/LoginActivity.kt index c5fddea46..4f0595d0e 100644 --- a/feature/login/src/main/java/com/hmh/hamyeonham/feature/login/LoginActivity.kt +++ b/feature/login/src/main/java/com/hmh/hamyeonham/feature/login/LoginActivity.kt @@ -1,23 +1,30 @@ package com.hmh.hamyeonham.feature.login -import android.content.Intent import android.os.Bundle +import android.util.Log import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import com.hmh.hamyeonham.common.context.toast +import com.hmh.hamyeonham.common.navigation.NavigationProvider import com.hmh.hamyeonham.feature.login.data.DummyImage import com.hmh.hamyeonham.feature.login.databinding.ActivityLoginBinding import com.kakao.sdk.auth.model.OAuthToken import com.kakao.sdk.common.model.ClientError import com.kakao.sdk.common.model.ClientErrorCause import com.kakao.sdk.user.UserApiClient +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject +@AndroidEntryPoint class LoginActivity : AppCompatActivity() { private lateinit var binding: ActivityLoginBinding private val loginViewModel: LoginViewModel by viewModels() private lateinit var loginViewPagerAdapter: LoginViewPagerAdapter + @Inject + lateinit var navigationProvider: NavigationProvider + // 삭제 예정 private val dummyImageList = listOf( DummyImage( @@ -86,7 +93,7 @@ class LoginActivity : AppCompatActivity() { } private fun moveToUserInfoActivity() { - startActivity(Intent(this, UserInfoActivity::class.java)) + startActivity(navigationProvider.toStatics()) finish() } } diff --git a/feature/onboarding/build.gradle.kts b/feature/onboarding/build.gradle.kts index 3d6ed42a3..13498eeb6 100644 --- a/feature/onboarding/build.gradle.kts +++ b/feature/onboarding/build.gradle.kts @@ -9,5 +9,4 @@ android { dependencies { implementation(projects.core.common) - implementation(projects.feature.login) } diff --git a/feature/onboarding/src/main/AndroidManifest.xml b/feature/onboarding/src/main/AndroidManifest.xml index a2fcd80d7..1d23c4a79 100644 --- a/feature/onboarding/src/main/AndroidManifest.xml +++ b/feature/onboarding/src/main/AndroidManifest.xml @@ -5,6 +5,7 @@ + @@ -25,5 +26,9 @@ android:name="android.accessibilityservice" android:resource="@xml/accessibility_service_config" /> + + diff --git a/feature/onboarding/src/main/java/com/hmh/hamyeonham/feature/onboarding/LockActivity.kt b/feature/onboarding/src/main/java/com/hmh/hamyeonham/feature/onboarding/LockActivity.kt new file mode 100644 index 000000000..2b56f0b1c --- /dev/null +++ b/feature/onboarding/src/main/java/com/hmh/hamyeonham/feature/onboarding/LockActivity.kt @@ -0,0 +1,20 @@ +package com.hmh.hamyeonham.feature.onboarding + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import com.hmh.hamyeonham.common.context.toast +import com.hmh.hamyeonham.common.view.viewBinding +import com.hmh.hamyeonham.feature.onboarding.databinding.ActivityLockBinding + +class LockActivity : AppCompatActivity() { + private val binding by viewBinding(ActivityLockBinding::inflate) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(binding.root) + + binding.btnLock.setOnClickListener { + toast("유튜브 잠금 설정 완료") + } + } +} diff --git a/feature/onboarding/src/main/java/com/hmh/hamyeonham/feature/onboarding/OnBoardingAccessibilityService.kt b/feature/onboarding/src/main/java/com/hmh/hamyeonham/feature/onboarding/OnBoardingAccessibilityService.kt index 5cc0cc69a..42d8bf158 100644 --- a/feature/onboarding/src/main/java/com/hmh/hamyeonham/feature/onboarding/OnBoardingAccessibilityService.kt +++ b/feature/onboarding/src/main/java/com/hmh/hamyeonham/feature/onboarding/OnBoardingAccessibilityService.kt @@ -1,6 +1,7 @@ package com.hmh.hamyeonham.feature.onboarding import android.accessibilityservice.AccessibilityService +import android.content.Intent import android.util.Log import android.view.accessibility.AccessibilityEvent @@ -8,10 +9,13 @@ class OnBoardingAccessibilityService : AccessibilityService() { override fun onAccessibilityEvent(event: AccessibilityEvent) { if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { val packageName = event.packageName ?: return - Log.d("AccessibilityService", "현재 실행 중인 앱 패키지: $packageName") + Log.d("OnBoardingAccessibilityService", "onAccessibilityEvent: $packageName") + if (packageName != "com.google.android.youtube") return + val intent = Intent(this, LockActivity::class.java) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + startActivity(intent) } } - override fun onInterrupt() { - } + override fun onInterrupt() {} } diff --git a/feature/onboarding/src/main/java/com/hmh/hamyeonham/feature/onboarding/OnBoardingActivity.kt b/feature/onboarding/src/main/java/com/hmh/hamyeonham/feature/onboarding/OnBoardingActivity.kt index a948e6d28..25a254602 100644 --- a/feature/onboarding/src/main/java/com/hmh/hamyeonham/feature/onboarding/OnBoardingActivity.kt +++ b/feature/onboarding/src/main/java/com/hmh/hamyeonham/feature/onboarding/OnBoardingActivity.kt @@ -10,13 +10,19 @@ import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity import com.hmh.hamyeonham.common.context.toast -import com.hmh.hamyeonham.feature.login.LoginActivity +import com.hmh.hamyeonham.common.navigation.NavigationProvider import com.hmh.hamyeonham.feature.onboarding.databinding.ActivityOnBoardingBinding +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject +@AndroidEntryPoint class OnBoardingActivity : AppCompatActivity() { private lateinit var binding: ActivityOnBoardingBinding + @Inject + lateinit var navigationProvider: NavigationProvider + private val accessibilitySettingsLauncher: ActivityResultLauncher = registerForActivityResult( ActivityResultContracts.StartActivityForResult(), @@ -52,10 +58,11 @@ class OnBoardingActivity : AppCompatActivity() { binding.btnLogin.setOnClickListener { if (isAccessibilityServiceEnabled() && hasUsageStatsPermission() && hasOverlayPermission()) { toast("모든 권한이 허용되었습니다.") + startActivity(navigationProvider.toLogin()) + finish() } else { toast("모든 권한을 허용해주세요.") } - startActivity(Intent(this, LoginActivity::class.java)) } } diff --git a/feature/onboarding/src/main/res/layout/activity_lock.xml b/feature/onboarding/src/main/res/layout/activity_lock.xml new file mode 100644 index 000000000..7077206f6 --- /dev/null +++ b/feature/onboarding/src/main/res/layout/activity_lock.xml @@ -0,0 +1,17 @@ + + + +