From ea9fe2b81d030e51c41a320ffe55897f13a7a813 Mon Sep 17 00:00:00 2001 From: Mihai-Cristian Condrea Date: Sun, 31 Aug 2025 11:08:44 +0300 Subject: [PATCH] feat: integrate hilt for viewmodels --- app/build.gradle | 3 + .../java/ads/managers/AppOpenAd.java | 3 + .../androidtutorials/java/di/AppModule.java | 268 ++++++++++++++++++ .../java/ui/screens/about/AboutViewModel.java | 21 +- .../java/ui/screens/help/HelpViewModel.java | 22 +- .../java/ui/screens/home/HomeViewModel.java | 37 ++- .../java/ui/screens/main/MainViewModel.java | 61 ++-- .../java/ui/screens/quiz/QuizViewModel.java | 23 +- .../screens/settings/SettingsViewModel.java | 25 +- .../ui/screens/startup/StartupViewModel.java | 22 +- .../ui/screens/support/SupportViewModel.java | 29 +- build.gradle | 1 + gradle/libs.versions.toml | 3 + 13 files changed, 403 insertions(+), 115 deletions(-) create mode 100644 app/src/main/java/com/d4rk/androidtutorials/java/di/AppModule.java diff --git a/app/build.gradle b/app/build.gradle index 96f9b6e9..5c9935ba 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,6 +3,7 @@ plugins { id 'com.google.gms.google-services' id 'com.google.firebase.crashlytics' id 'com.mikepenz.aboutlibraries.plugin' + id 'com.google.dagger.hilt.android' } android { @@ -93,4 +94,6 @@ dependencies { implementation libs.library implementation libs.materialratingbar.library implementation libs.codeview + implementation libs.hilt.android + annotationProcessor libs.hilt.compiler } \ No newline at end of file diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/ads/managers/AppOpenAd.java b/app/src/main/java/com/d4rk/androidtutorials/java/ads/managers/AppOpenAd.java index 35ccca56..d3c72e2a 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/ads/managers/AppOpenAd.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/ads/managers/AppOpenAd.java @@ -20,9 +20,12 @@ import com.google.android.gms.ads.MobileAds; import com.google.android.gms.ads.appopen.AppOpenAd.AppOpenAdLoadCallback; +import dagger.hilt.android.HiltAndroidApp; + import java.util.Date; @SuppressWarnings("ALL") +@HiltAndroidApp public class AppOpenAd extends Application implements ActivityLifecycleCallbacks, LifecycleObserver { private AppOpenAdManager appOpenAdManager; private Activity currentActivity; diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/di/AppModule.java b/app/src/main/java/com/d4rk/androidtutorials/java/di/AppModule.java new file mode 100644 index 00000000..afcca2e4 --- /dev/null +++ b/app/src/main/java/com/d4rk/androidtutorials/java/di/AppModule.java @@ -0,0 +1,268 @@ +package com.d4rk.androidtutorials.java.di; + +import android.app.Application; +import android.content.res.AssetManager; + +import com.android.volley.RequestQueue; +import com.android.volley.toolbox.Volley; +import com.d4rk.androidtutorials.java.data.repository.DefaultHomeRepository; +import com.d4rk.androidtutorials.java.data.repository.DefaultQuizRepository; +import com.d4rk.androidtutorials.java.data.repository.HomeRepository; +import com.d4rk.androidtutorials.java.data.repository.QuizRepository; +import com.d4rk.androidtutorials.java.data.source.DefaultHomeLocalDataSource; +import com.d4rk.androidtutorials.java.data.source.DefaultHomeRemoteDataSource; +import com.d4rk.androidtutorials.java.data.source.DefaultQuizLocalDataSource; +import com.d4rk.androidtutorials.java.data.source.HomeLocalDataSource; +import com.d4rk.androidtutorials.java.data.source.HomeRemoteDataSource; +import com.d4rk.androidtutorials.java.data.source.QuizLocalDataSource; +import com.d4rk.androidtutorials.java.domain.about.GetCurrentYearUseCase; +import com.d4rk.androidtutorials.java.domain.about.GetVersionStringUseCase; +import com.d4rk.androidtutorials.java.domain.help.LaunchReviewFlowUseCase; +import com.d4rk.androidtutorials.java.domain.help.RequestReviewFlowUseCase; +import com.d4rk.androidtutorials.java.domain.home.GetDailyTipUseCase; +import com.d4rk.androidtutorials.java.domain.home.GetPromotedAppsUseCase; +import com.d4rk.androidtutorials.java.domain.main.ApplyLanguageSettingsUseCase; +import com.d4rk.androidtutorials.java.domain.main.ApplyThemeSettingsUseCase; +import com.d4rk.androidtutorials.java.domain.main.BuildShortcutIntentUseCase; +import com.d4rk.androidtutorials.java.domain.main.GetAppUpdateManagerUseCase; +import com.d4rk.androidtutorials.java.domain.main.GetBottomNavLabelVisibilityUseCase; +import com.d4rk.androidtutorials.java.domain.main.GetDefaultTabPreferenceUseCase; +import com.d4rk.androidtutorials.java.domain.main.IsAppInstalledUseCase; +import com.d4rk.androidtutorials.java.domain.main.MarkStartupScreenShownUseCase; +import com.d4rk.androidtutorials.java.domain.main.ShouldShowStartupScreenUseCase; +import com.d4rk.androidtutorials.java.domain.quiz.LoadQuizQuestionsUseCase; +import com.d4rk.androidtutorials.java.domain.settings.ApplyConsentUseCase; +import com.d4rk.androidtutorials.java.domain.settings.GetSharedPreferencesUseCase; +import com.d4rk.androidtutorials.java.domain.settings.OnPreferenceChangedUseCase; +import com.d4rk.androidtutorials.java.domain.startup.LoadConsentFormUseCase; +import com.d4rk.androidtutorials.java.domain.startup.RequestConsentInfoUseCase; +import com.d4rk.androidtutorials.java.domain.support.InitBillingClientUseCase; +import com.d4rk.androidtutorials.java.domain.support.InitMobileAdsUseCase; +import com.d4rk.androidtutorials.java.domain.support.InitiatePurchaseUseCase; +import com.d4rk.androidtutorials.java.domain.support.QueryProductDetailsUseCase; +import com.d4rk.androidtutorials.java.ui.screens.about.repository.AboutRepository; +import com.d4rk.androidtutorials.java.ui.screens.help.repository.HelpRepository; +import com.d4rk.androidtutorials.java.ui.screens.main.repository.MainRepository; +import com.d4rk.androidtutorials.java.ui.screens.settings.repository.SettingsRepository; +import com.d4rk.androidtutorials.java.ui.screens.startup.repository.StartupRepository; +import com.d4rk.androidtutorials.java.ui.screens.support.repository.SupportRepository; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import dagger.Module; +import dagger.Provides; +import dagger.hilt.InstallIn; +import dagger.hilt.components.SingletonComponent; +import javax.inject.Singleton; + +@Module +@InstallIn(SingletonComponent.class) +public class AppModule { + + @Provides + @Singleton + public ExecutorService provideExecutorService() { + return Executors.newSingleThreadExecutor(); + } + + @Provides + @Singleton + public RequestQueue provideRequestQueue(Application application) { + return Volley.newRequestQueue(application); + } + + @Provides + @Singleton + public HomeRemoteDataSource provideHomeRemoteDataSource(RequestQueue queue) { + return new DefaultHomeRemoteDataSource(queue, + "https://raw.githubusercontent.com/D4rK7355608/com.d4rk.apis/refs/heads/main/App%20Toolkit/release/en/home/api_android_apps.json"); + } + + @Provides + @Singleton + public HomeLocalDataSource provideHomeLocalDataSource(Application application) { + return new DefaultHomeLocalDataSource(application); + } + + @Provides + @Singleton + public HomeRepository provideHomeRepository(HomeRemoteDataSource remote, + HomeLocalDataSource local) { + return new DefaultHomeRepository(remote, local); + } + + @Provides + public GetDailyTipUseCase provideGetDailyTipUseCase(HomeRepository repository) { + return new GetDailyTipUseCase(repository); + } + + @Provides + public GetPromotedAppsUseCase provideGetPromotedAppsUseCase(HomeRepository repository) { + return new GetPromotedAppsUseCase(repository); + } + + @Provides + @Singleton + public AboutRepository provideAboutRepository(Application application) { + return new AboutRepository(application); + } + + @Provides + public GetVersionStringUseCase provideGetVersionStringUseCase(AboutRepository repository) { + return new GetVersionStringUseCase(repository); + } + + @Provides + public GetCurrentYearUseCase provideGetCurrentYearUseCase(AboutRepository repository) { + return new GetCurrentYearUseCase(repository); + } + + @Provides + @Singleton + public MainRepository provideMainRepository(Application application) { + return new MainRepository(application); + } + + @Provides + public ApplyThemeSettingsUseCase provideApplyThemeSettingsUseCase(MainRepository repository) { + return new ApplyThemeSettingsUseCase(repository); + } + + @Provides + public GetBottomNavLabelVisibilityUseCase provideGetBottomNavLabelVisibilityUseCase(MainRepository repository) { + return new GetBottomNavLabelVisibilityUseCase(repository); + } + + @Provides + public GetDefaultTabPreferenceUseCase provideGetDefaultTabPreferenceUseCase(MainRepository repository) { + return new GetDefaultTabPreferenceUseCase(repository); + } + + @Provides + public ApplyLanguageSettingsUseCase provideApplyLanguageSettingsUseCase(MainRepository repository) { + return new ApplyLanguageSettingsUseCase(repository); + } + + @Provides + public ShouldShowStartupScreenUseCase provideShouldShowStartupScreenUseCase(MainRepository repository) { + return new ShouldShowStartupScreenUseCase(repository); + } + + @Provides + public MarkStartupScreenShownUseCase provideMarkStartupScreenShownUseCase(MainRepository repository) { + return new MarkStartupScreenShownUseCase(repository); + } + + @Provides + public IsAppInstalledUseCase provideIsAppInstalledUseCase(MainRepository repository) { + return new IsAppInstalledUseCase(repository); + } + + @Provides + public BuildShortcutIntentUseCase provideBuildShortcutIntentUseCase(MainRepository repository) { + return new BuildShortcutIntentUseCase(repository); + } + + @Provides + public GetAppUpdateManagerUseCase provideGetAppUpdateManagerUseCase(MainRepository repository) { + return new GetAppUpdateManagerUseCase(repository); + } + + @Provides + @Singleton + public SettingsRepository provideSettingsRepository(Application application) { + return new SettingsRepository(application); + } + + @Provides + public OnPreferenceChangedUseCase provideOnPreferenceChangedUseCase(SettingsRepository repository) { + return new OnPreferenceChangedUseCase(repository); + } + + @Provides + public GetSharedPreferencesUseCase provideGetSharedPreferencesUseCase(SettingsRepository repository) { + return new GetSharedPreferencesUseCase(repository); + } + + @Provides + public ApplyConsentUseCase provideApplyConsentUseCase(SettingsRepository repository) { + return new ApplyConsentUseCase(repository); + } + + @Provides + @Singleton + public QuizLocalDataSource provideQuizLocalDataSource(Application application) { + AssetManager manager = application.getAssets(); + return new DefaultQuizLocalDataSource(manager); + } + + @Provides + @Singleton + public QuizRepository provideQuizRepository(QuizLocalDataSource local) { + return new DefaultQuizRepository(local); + } + + @Provides + public LoadQuizQuestionsUseCase provideLoadQuizQuestionsUseCase(QuizRepository repository) { + return new LoadQuizQuestionsUseCase(repository); + } + + @Provides + @Singleton + public StartupRepository provideStartupRepository(Application application) { + return new StartupRepository(application); + } + + @Provides + public RequestConsentInfoUseCase provideRequestConsentInfoUseCase(StartupRepository repository) { + return new RequestConsentInfoUseCase(repository); + } + + @Provides + public LoadConsentFormUseCase provideLoadConsentFormUseCase(StartupRepository repository) { + return new LoadConsentFormUseCase(repository); + } + + @Provides + @Singleton + public SupportRepository provideSupportRepository(Application application) { + return new SupportRepository(application); + } + + @Provides + public InitBillingClientUseCase provideInitBillingClientUseCase(SupportRepository repository) { + return new InitBillingClientUseCase(repository); + } + + @Provides + public QueryProductDetailsUseCase provideQueryProductDetailsUseCase(SupportRepository repository) { + return new QueryProductDetailsUseCase(repository); + } + + @Provides + public InitiatePurchaseUseCase provideInitiatePurchaseUseCase(SupportRepository repository) { + return new InitiatePurchaseUseCase(repository); + } + + @Provides + public InitMobileAdsUseCase provideInitMobileAdsUseCase(SupportRepository repository) { + return new InitMobileAdsUseCase(repository); + } + + @Provides + @Singleton + public HelpRepository provideHelpRepository(Application application) { + return new HelpRepository(application); + } + + @Provides + public RequestReviewFlowUseCase provideRequestReviewFlowUseCase(HelpRepository repository) { + return new RequestReviewFlowUseCase(repository); + } + + @Provides + public LaunchReviewFlowUseCase provideLaunchReviewFlowUseCase(HelpRepository repository) { + return new LaunchReviewFlowUseCase(repository); + } +} diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/about/AboutViewModel.java b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/about/AboutViewModel.java index 89c7ce53..28762b66 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/about/AboutViewModel.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/about/AboutViewModel.java @@ -1,11 +1,10 @@ package com.d4rk.androidtutorials.java.ui.screens.about; -import android.app.Application; +import androidx.lifecycle.ViewModel; -import androidx.annotation.NonNull; -import androidx.lifecycle.AndroidViewModel; +import dagger.hilt.android.lifecycle.HiltViewModel; +import javax.inject.Inject; -import com.d4rk.androidtutorials.java.ui.screens.about.repository.AboutRepository; import com.d4rk.androidtutorials.java.domain.about.GetVersionStringUseCase; import com.d4rk.androidtutorials.java.domain.about.GetCurrentYearUseCase; @@ -13,17 +12,17 @@ /** * ViewModel for the About screen. Delegates data/logic to AboutRepository. */ -public class AboutViewModel extends AndroidViewModel { +@HiltViewModel +public class AboutViewModel extends ViewModel { - private final AboutRepository repository; private final GetVersionStringUseCase getVersionStringUseCase; private final GetCurrentYearUseCase getCurrentYearUseCase; - public AboutViewModel(@NonNull Application application) { - super(application); - repository = new AboutRepository(application); - getVersionStringUseCase = new GetVersionStringUseCase(repository); - getCurrentYearUseCase = new GetCurrentYearUseCase(repository); + @Inject + public AboutViewModel(GetVersionStringUseCase getVersionStringUseCase, + GetCurrentYearUseCase getCurrentYearUseCase) { + this.getVersionStringUseCase = getVersionStringUseCase; + this.getCurrentYearUseCase = getCurrentYearUseCase; } /** diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/help/HelpViewModel.java b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/help/HelpViewModel.java index c5b87950..100b4970 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/help/HelpViewModel.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/help/HelpViewModel.java @@ -2,30 +2,32 @@ import android.app.Activity; -import android.app.Application; -import androidx.annotation.NonNull; -import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.ViewModel; -import com.d4rk.androidtutorials.java.ui.screens.help.repository.HelpRepository; import com.d4rk.androidtutorials.java.domain.help.RequestReviewFlowUseCase; import com.d4rk.androidtutorials.java.domain.help.LaunchReviewFlowUseCase; import com.google.android.play.core.review.ReviewInfo; +import com.d4rk.androidtutorials.java.ui.screens.help.repository.HelpRepository; + +import dagger.hilt.android.lifecycle.HiltViewModel; +import javax.inject.Inject; /** * ViewModel for the Help screen. Delegates to HelpRepository for * requesting or launching in-app reviews. */ -public class HelpViewModel extends AndroidViewModel { +@HiltViewModel +public class HelpViewModel extends ViewModel { private final RequestReviewFlowUseCase requestReviewFlowUseCase; private final LaunchReviewFlowUseCase launchReviewFlowUseCase; - public HelpViewModel(@NonNull Application application) { - super(application); - HelpRepository repository = new HelpRepository(application); - requestReviewFlowUseCase = new RequestReviewFlowUseCase(repository); - launchReviewFlowUseCase = new LaunchReviewFlowUseCase(repository); + @Inject + public HelpViewModel(RequestReviewFlowUseCase requestReviewFlowUseCase, + LaunchReviewFlowUseCase launchReviewFlowUseCase) { + this.requestReviewFlowUseCase = requestReviewFlowUseCase; + this.launchReviewFlowUseCase = launchReviewFlowUseCase; } /** diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/home/HomeViewModel.java b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/home/HomeViewModel.java index cea7e877..c19960a7 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/home/HomeViewModel.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/home/HomeViewModel.java @@ -4,29 +4,27 @@ import android.content.Intent; import android.net.Uri; -import androidx.annotation.NonNull; -import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.ViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; -import com.android.volley.toolbox.Volley; import com.d4rk.androidtutorials.java.R; import com.d4rk.androidtutorials.java.data.model.PromotedApp; -import com.d4rk.androidtutorials.java.data.repository.DefaultHomeRepository; import com.d4rk.androidtutorials.java.data.repository.HomeRepository; -import com.d4rk.androidtutorials.java.data.source.DefaultHomeLocalDataSource; -import com.d4rk.androidtutorials.java.data.source.DefaultHomeRemoteDataSource; -import com.d4rk.androidtutorials.java.data.source.HomeLocalDataSource; -import com.d4rk.androidtutorials.java.data.source.HomeRemoteDataSource; import com.d4rk.androidtutorials.java.domain.home.GetDailyTipUseCase; import com.d4rk.androidtutorials.java.domain.home.GetPromotedAppsUseCase; +import dagger.hilt.android.lifecycle.HiltViewModel; +import javax.inject.Inject; + import java.util.ArrayList; import java.util.List; -public class HomeViewModel extends AndroidViewModel { +@HiltViewModel +public class HomeViewModel extends ViewModel { + private final Application application; private final HomeRepository homeRepository; private final GetDailyTipUseCase getDailyTipUseCase; private final GetPromotedAppsUseCase getPromotedAppsUseCase; @@ -36,16 +34,15 @@ public class HomeViewModel extends AndroidViewModel { private final MutableLiveData dailyTip = new MutableLiveData<>(); private final MutableLiveData> promotedApps = new MutableLiveData<>(new ArrayList<>()); - public HomeViewModel(@NonNull Application application) { - super(application); - HomeRemoteDataSource remote = new DefaultHomeRemoteDataSource( - Volley.newRequestQueue(application), - "https://raw.githubusercontent.com/D4rK7355608/com.d4rk.apis/refs/heads/main/App%20Toolkit/release/en/home/api_android_apps.json" - ); - HomeLocalDataSource local = new DefaultHomeLocalDataSource(application); - homeRepository = new DefaultHomeRepository(remote, local); - getDailyTipUseCase = new GetDailyTipUseCase(homeRepository); - getPromotedAppsUseCase = new GetPromotedAppsUseCase(homeRepository); + @Inject + public HomeViewModel(Application application, + HomeRepository homeRepository, + GetDailyTipUseCase getDailyTipUseCase, + GetPromotedAppsUseCase getPromotedAppsUseCase) { + this.application = application; + this.homeRepository = homeRepository; + this.getDailyTipUseCase = getDailyTipUseCase; + this.getPromotedAppsUseCase = getPromotedAppsUseCase; announcementTitle.setValue(application.getString(R.string.announcement_title)); announcementSubtitle.setValue(application.getString(R.string.announcement_subtitle)); @@ -111,7 +108,7 @@ public Intent getPromotedAppIntent(String packageName) { private Intent buildPlayStoreIntent(String url) { Intent playStoreIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); playStoreIntent.setPackage("com.android.vending"); - if (playStoreIntent.resolveActivity(getApplication().getPackageManager()) != null) { + if (playStoreIntent.resolveActivity(application.getPackageManager()) != null) { return playStoreIntent; } return new Intent(Intent.ACTION_VIEW, Uri.parse(url)); diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/main/MainViewModel.java b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/main/MainViewModel.java index bb9c5a88..56cdb63e 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/main/MainViewModel.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/main/MainViewModel.java @@ -4,13 +4,11 @@ import android.content.Intent; import android.content.pm.PackageManager; -import androidx.annotation.NonNull; -import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.ViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import com.d4rk.androidtutorials.java.R; -import com.d4rk.androidtutorials.java.ui.screens.main.repository.MainRepository; import com.d4rk.androidtutorials.java.domain.main.ApplyThemeSettingsUseCase; import com.d4rk.androidtutorials.java.domain.main.GetBottomNavLabelVisibilityUseCase; import com.d4rk.androidtutorials.java.domain.main.GetDefaultTabPreferenceUseCase; @@ -23,13 +21,17 @@ import com.google.android.material.navigation.NavigationBarView; import com.google.android.play.core.appupdate.AppUpdateManager; +import dagger.hilt.android.lifecycle.HiltViewModel; +import javax.inject.Inject; + /** * ViewModel for MainActivity. It interacts with MainRepository to retrieve or * update data, and exposes it to the UI. */ -public class MainViewModel extends AndroidViewModel { +@HiltViewModel +public class MainViewModel extends ViewModel { - private final MainRepository mainRepository; + private final Application application; private final ApplyThemeSettingsUseCase applyThemeSettingsUseCase; private final GetBottomNavLabelVisibilityUseCase getBottomNavLabelVisibilityUseCase; private final GetDefaultTabPreferenceUseCase getDefaultTabPreferenceUseCase; @@ -43,18 +45,27 @@ public class MainViewModel extends AndroidViewModel { private final MutableLiveData defaultNavDestination = new MutableLiveData<>(); private final MutableLiveData themeChanged = new MutableLiveData<>(); - public MainViewModel(@NonNull Application application) { - super(application); - mainRepository = new MainRepository(application); - applyThemeSettingsUseCase = new ApplyThemeSettingsUseCase(mainRepository); - getBottomNavLabelVisibilityUseCase = new GetBottomNavLabelVisibilityUseCase(mainRepository); - getDefaultTabPreferenceUseCase = new GetDefaultTabPreferenceUseCase(mainRepository); - applyLanguageSettingsUseCase = new ApplyLanguageSettingsUseCase(mainRepository); - shouldShowStartupScreenUseCase = new ShouldShowStartupScreenUseCase(mainRepository); - markStartupScreenShownUseCase = new MarkStartupScreenShownUseCase(mainRepository); - isAppInstalledUseCase = new IsAppInstalledUseCase(mainRepository); - buildShortcutIntentUseCase = new BuildShortcutIntentUseCase(mainRepository); - getAppUpdateManagerUseCase = new GetAppUpdateManagerUseCase(mainRepository); + @Inject + public MainViewModel(Application application, + ApplyThemeSettingsUseCase applyThemeSettingsUseCase, + GetBottomNavLabelVisibilityUseCase getBottomNavLabelVisibilityUseCase, + GetDefaultTabPreferenceUseCase getDefaultTabPreferenceUseCase, + ApplyLanguageSettingsUseCase applyLanguageSettingsUseCase, + ShouldShowStartupScreenUseCase shouldShowStartupScreenUseCase, + MarkStartupScreenShownUseCase markStartupScreenShownUseCase, + IsAppInstalledUseCase isAppInstalledUseCase, + BuildShortcutIntentUseCase buildShortcutIntentUseCase, + GetAppUpdateManagerUseCase getAppUpdateManagerUseCase) { + this.application = application; + this.applyThemeSettingsUseCase = applyThemeSettingsUseCase; + this.getBottomNavLabelVisibilityUseCase = getBottomNavLabelVisibilityUseCase; + this.getDefaultTabPreferenceUseCase = getDefaultTabPreferenceUseCase; + this.applyLanguageSettingsUseCase = applyLanguageSettingsUseCase; + this.shouldShowStartupScreenUseCase = shouldShowStartupScreenUseCase; + this.markStartupScreenShownUseCase = markStartupScreenShownUseCase; + this.isAppInstalledUseCase = isAppInstalledUseCase; + this.buildShortcutIntentUseCase = buildShortcutIntentUseCase; + this.getAppUpdateManagerUseCase = getAppUpdateManagerUseCase; } private static int getVisibilityMode(String labelVisibilityStr, String[] bottomNavBarLabelsValues) { @@ -75,22 +86,22 @@ private static int getVisibilityMode(String labelVisibilityStr, String[] bottomN */ public void applySettings() { boolean changedTheme = applyThemeSettingsUseCase.invoke( - getApplication().getResources().getStringArray(R.array.preference_theme_values) + application.getResources().getStringArray(R.array.preference_theme_values) ); themeChanged.setValue(changedTheme); - String labelKey = getApplication().getString(R.string.key_bottom_navigation_bar_labels); - String labelDefaultValue = getApplication().getString(R.string.default_value_bottom_navigation_bar_labels); + String labelKey = application.getString(R.string.key_bottom_navigation_bar_labels); + String labelDefaultValue = application.getString(R.string.default_value_bottom_navigation_bar_labels); String[] bottomNavBarLabelsValues = - getApplication().getResources().getStringArray(R.array.preference_bottom_navigation_bar_labels_values); + application.getResources().getStringArray(R.array.preference_bottom_navigation_bar_labels_values); String labelVisibilityStr = getBottomNavLabelVisibilityUseCase.invoke(labelKey, labelDefaultValue); int visibilityMode = getVisibilityMode(labelVisibilityStr, bottomNavBarLabelsValues); bottomNavLabelVisibility.setValue(visibilityMode); - String defaultTabKey = getApplication().getString(R.string.key_default_tab); - String defaultTabValue = getApplication().getString(R.string.default_value_tab); - String[] defaultTabValues = getApplication().getResources().getStringArray(R.array.preference_default_tab_values); + String defaultTabKey = application.getString(R.string.key_default_tab); + String defaultTabValue = application.getString(R.string.default_value_tab); + String[] defaultTabValues = application.getResources().getStringArray(R.array.preference_default_tab_values); String startFragmentIdValue = getDefaultTabPreferenceUseCase.invoke(defaultTabKey, defaultTabValue); int startFragmentId; @@ -125,7 +136,7 @@ public void markStartupScreenShown() { * Check if the “Android Tutorials” app is installed or not. */ public boolean isAndroidTutorialsInstalled() { - PackageManager pm = getApplication().getPackageManager(); + PackageManager pm = application.getPackageManager(); return isAppInstalledUseCase.invoke(pm, "com.d4rk.androidtutorials.java"); } diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/quiz/QuizViewModel.java b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/quiz/QuizViewModel.java index 146f25d4..e1d32107 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/quiz/QuizViewModel.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/quiz/QuizViewModel.java @@ -1,36 +1,31 @@ package com.d4rk.androidtutorials.java.ui.screens.quiz; -import android.app.Application; - -import androidx.annotation.NonNull; -import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.ViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import com.d4rk.androidtutorials.java.data.model.QuizQuestion; -import com.d4rk.androidtutorials.java.data.repository.DefaultQuizRepository; -import com.d4rk.androidtutorials.java.data.repository.QuizRepository; -import com.d4rk.androidtutorials.java.data.source.DefaultQuizLocalDataSource; -import com.d4rk.androidtutorials.java.data.source.QuizLocalDataSource; import com.d4rk.androidtutorials.java.domain.quiz.LoadQuizQuestionsUseCase; import java.util.List; +import dagger.hilt.android.lifecycle.HiltViewModel; +import javax.inject.Inject; + /** * ViewModel managing quiz state and scoring. */ -public class QuizViewModel extends AndroidViewModel { +@HiltViewModel +public class QuizViewModel extends ViewModel { private final List questions; private final MutableLiveData currentIndex = new MutableLiveData<>(0); private final MutableLiveData score = new MutableLiveData<>(0); private final LoadQuizQuestionsUseCase loadQuizQuestionsUseCase; - public QuizViewModel(@NonNull Application application) { - super(application); - QuizLocalDataSource local = new DefaultQuizLocalDataSource(application.getAssets()); - QuizRepository repository = new DefaultQuizRepository(local); - loadQuizQuestionsUseCase = new LoadQuizQuestionsUseCase(repository); + @Inject + public QuizViewModel(LoadQuizQuestionsUseCase loadQuizQuestionsUseCase) { + this.loadQuizQuestionsUseCase = loadQuizQuestionsUseCase; questions = loadQuizQuestionsUseCase.invoke(); } diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/settings/SettingsViewModel.java b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/settings/SettingsViewModel.java index e7f1dcbe..42ca6f44 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/settings/SettingsViewModel.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/settings/SettingsViewModel.java @@ -1,34 +1,35 @@ package com.d4rk.androidtutorials.java.ui.screens.settings; -import android.app.Application; import android.content.SharedPreferences; -import androidx.annotation.NonNull; -import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.ViewModel; -import com.d4rk.androidtutorials.java.ui.screens.settings.repository.SettingsRepository; import com.d4rk.androidtutorials.java.domain.settings.OnPreferenceChangedUseCase; import com.d4rk.androidtutorials.java.domain.settings.GetSharedPreferencesUseCase; import com.d4rk.androidtutorials.java.domain.settings.ApplyConsentUseCase; +import dagger.hilt.android.lifecycle.HiltViewModel; +import javax.inject.Inject; + /** * ViewModel for the Settings screen. Delegates to SettingsRepository for * reading/writing preferences, applying theme, etc. */ -public class SettingsViewModel extends AndroidViewModel { +@HiltViewModel +public class SettingsViewModel extends ViewModel { - private final SettingsRepository settingsRepository; private final OnPreferenceChangedUseCase onPreferenceChangedUseCase; private final GetSharedPreferencesUseCase getSharedPreferencesUseCase; private final ApplyConsentUseCase applyConsentUseCase; - public SettingsViewModel(@NonNull Application application) { - super(application); - settingsRepository = new SettingsRepository(application); - onPreferenceChangedUseCase = new OnPreferenceChangedUseCase(settingsRepository); - getSharedPreferencesUseCase = new GetSharedPreferencesUseCase(settingsRepository); - applyConsentUseCase = new ApplyConsentUseCase(settingsRepository); + @Inject + public SettingsViewModel(OnPreferenceChangedUseCase onPreferenceChangedUseCase, + GetSharedPreferencesUseCase getSharedPreferencesUseCase, + ApplyConsentUseCase applyConsentUseCase) { + this.onPreferenceChangedUseCase = onPreferenceChangedUseCase; + this.getSharedPreferencesUseCase = getSharedPreferencesUseCase; + this.applyConsentUseCase = applyConsentUseCase; } /** diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/startup/StartupViewModel.java b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/startup/StartupViewModel.java index 4d2a5250..21b703c2 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/startup/StartupViewModel.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/startup/StartupViewModel.java @@ -2,30 +2,32 @@ import android.app.Activity; -import android.app.Application; -import androidx.annotation.NonNull; -import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.ViewModel; -import com.d4rk.androidtutorials.java.ui.screens.startup.repository.StartupRepository; import com.d4rk.androidtutorials.java.domain.startup.RequestConsentInfoUseCase; import com.d4rk.androidtutorials.java.domain.startup.LoadConsentFormUseCase; import com.google.android.ump.ConsentRequestParameters; +import com.d4rk.androidtutorials.java.ui.screens.startup.repository.StartupRepository; + +import dagger.hilt.android.lifecycle.HiltViewModel; +import javax.inject.Inject; /** * ViewModel for the startup screen. * Handles consent logic by delegating to StartupRepository. */ -public class StartupViewModel extends AndroidViewModel { +@HiltViewModel +public class StartupViewModel extends ViewModel { private final RequestConsentInfoUseCase requestConsentInfoUseCase; private final LoadConsentFormUseCase loadConsentFormUseCase; - public StartupViewModel(@NonNull Application application) { - super(application); - StartupRepository repository = new StartupRepository(application); - requestConsentInfoUseCase = new RequestConsentInfoUseCase(repository); - loadConsentFormUseCase = new LoadConsentFormUseCase(repository); + @Inject + public StartupViewModel(RequestConsentInfoUseCase requestConsentInfoUseCase, + LoadConsentFormUseCase loadConsentFormUseCase) { + this.requestConsentInfoUseCase = requestConsentInfoUseCase; + this.loadConsentFormUseCase = loadConsentFormUseCase; } /** diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/SupportViewModel.java b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/SupportViewModel.java index aacb00a6..f00188b1 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/SupportViewModel.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/SupportViewModel.java @@ -1,35 +1,38 @@ package com.d4rk.androidtutorials.java.ui.screens.support; import android.app.Activity; -import android.app.Application; -import androidx.annotation.NonNull; -import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.ViewModel; import com.d4rk.androidtutorials.java.databinding.ActivitySupportBinding; -import com.d4rk.androidtutorials.java.ui.screens.support.repository.SupportRepository; import com.d4rk.androidtutorials.java.domain.support.InitBillingClientUseCase; import com.d4rk.androidtutorials.java.domain.support.QueryProductDetailsUseCase; import com.d4rk.androidtutorials.java.domain.support.InitiatePurchaseUseCase; import com.d4rk.androidtutorials.java.domain.support.InitMobileAdsUseCase; +import com.d4rk.androidtutorials.java.ui.screens.support.repository.SupportRepository; + +import dagger.hilt.android.lifecycle.HiltViewModel; +import javax.inject.Inject; import java.util.List; -public class SupportViewModel extends AndroidViewModel { +@HiltViewModel +public class SupportViewModel extends ViewModel { - private final SupportRepository repository; private final InitBillingClientUseCase initBillingClientUseCase; private final QueryProductDetailsUseCase queryProductDetailsUseCase; private final InitiatePurchaseUseCase initiatePurchaseUseCase; private final InitMobileAdsUseCase initMobileAdsUseCase; - public SupportViewModel(@NonNull Application application) { - super(application); - repository = new SupportRepository(application); - initBillingClientUseCase = new InitBillingClientUseCase(repository); - queryProductDetailsUseCase = new QueryProductDetailsUseCase(repository); - initiatePurchaseUseCase = new InitiatePurchaseUseCase(repository); - initMobileAdsUseCase = new InitMobileAdsUseCase(repository); + @Inject + public SupportViewModel(InitBillingClientUseCase initBillingClientUseCase, + QueryProductDetailsUseCase queryProductDetailsUseCase, + InitiatePurchaseUseCase initiatePurchaseUseCase, + InitMobileAdsUseCase initMobileAdsUseCase) { + this.initBillingClientUseCase = initBillingClientUseCase; + this.queryProductDetailsUseCase = queryProductDetailsUseCase; + this.initiatePurchaseUseCase = initiatePurchaseUseCase; + this.initMobileAdsUseCase = initMobileAdsUseCase; } public void initBillingClient(Runnable onConnected) { diff --git a/build.gradle b/build.gradle index 28ecc966..de209ddd 100644 --- a/build.gradle +++ b/build.gradle @@ -4,4 +4,5 @@ plugins { id 'com.google.firebase.crashlytics' version '3.0.6' apply false //noinspection NewerVersionAvailable id 'com.mikepenz.aboutlibraries.plugin' version '11.3.0' apply true + id 'com.google.dagger.hilt.android' version '2.51.1' apply false } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 00e1e775..ca93c9eb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,6 +24,7 @@ material = "1.12.0" multidex = "2.0.1" playServicesAds = "24.5.0" codeview = "1.3.9" +hilt = "2.51.1" [libraries] aboutlibraries = { module = "com.mikepenz:aboutlibraries", version.ref = "aboutlibraries" } @@ -56,3 +57,5 @@ play-services-ads = { module = "com.google.android.gms:play-services-ads", versi review = { module = "com.google.android.play:review", version.ref = "review" } volley = { module = "com.android.volley:volley", version.ref = "volley" } codeview = { module = "io.github.amrdeveloper:codeview", version.ref = "codeview" } +hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" } +hilt-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hilt" }