diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/data/repository/DefaultHomeRepository.java b/app/src/main/java/com/d4rk/androidtutorials/java/data/repository/DefaultHomeRepository.java new file mode 100644 index 00000000..11160ff7 --- /dev/null +++ b/app/src/main/java/com/d4rk/androidtutorials/java/data/repository/DefaultHomeRepository.java @@ -0,0 +1,42 @@ +package com.d4rk.androidtutorials.java.data.repository; + +import android.content.Intent; + +import com.d4rk.androidtutorials.java.data.source.HomeLocalDataSource; +import com.d4rk.androidtutorials.java.data.source.HomeRemoteDataSource; +import com.d4rk.androidtutorials.java.data.source.HomeRemoteDataSource.PromotedAppsCallback; + +/** + * Default implementation of {@link HomeRepository} combining local and remote sources. + */ +public class DefaultHomeRepository implements HomeRepository { + + private final HomeRemoteDataSource remoteDataSource; + private final HomeLocalDataSource localDataSource; + + public DefaultHomeRepository(HomeRemoteDataSource remoteDataSource, + HomeLocalDataSource localDataSource) { + this.remoteDataSource = remoteDataSource; + this.localDataSource = localDataSource; + } + + @Override + public Intent getPlayStoreIntent() { + return localDataSource.getPlayStoreIntent(); + } + + @Override + public Intent getAppPlayStoreIntent(String packageName) { + return localDataSource.getAppPlayStoreIntent(packageName); + } + + @Override + public String getDailyTip() { + return localDataSource.getDailyTip(); + } + + @Override + public void fetchPromotedApps(PromotedAppsCallback callback) { + remoteDataSource.fetchPromotedApps(callback); + } +} diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/data/repository/DefaultQuizRepository.java b/app/src/main/java/com/d4rk/androidtutorials/java/data/repository/DefaultQuizRepository.java new file mode 100644 index 00000000..d602426e --- /dev/null +++ b/app/src/main/java/com/d4rk/androidtutorials/java/data/repository/DefaultQuizRepository.java @@ -0,0 +1,23 @@ +package com.d4rk.androidtutorials.java.data.repository; + +import com.d4rk.androidtutorials.java.data.model.QuizQuestion; +import com.d4rk.androidtutorials.java.data.source.QuizLocalDataSource; + +import java.util.List; + +/** + * Default implementation of {@link QuizRepository} using a local data source. + */ +public class DefaultQuizRepository implements QuizRepository { + + private final QuizLocalDataSource localDataSource; + + public DefaultQuizRepository(QuizLocalDataSource localDataSource) { + this.localDataSource = localDataSource; + } + + @Override + public List loadQuestions() { + return localDataSource.loadQuestions(); + } +} diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/data/repository/HomeRepository.java b/app/src/main/java/com/d4rk/androidtutorials/java/data/repository/HomeRepository.java new file mode 100644 index 00000000..77815888 --- /dev/null +++ b/app/src/main/java/com/d4rk/androidtutorials/java/data/repository/HomeRepository.java @@ -0,0 +1,20 @@ +package com.d4rk.androidtutorials.java.data.repository; + +import android.content.Intent; + +import com.d4rk.androidtutorials.java.data.model.PromotedApp; +import com.d4rk.androidtutorials.java.data.source.HomeRemoteDataSource.PromotedAppsCallback; + +/** + * Abstraction over home data operations. + */ +public interface HomeRepository { + + Intent getPlayStoreIntent(); + + Intent getAppPlayStoreIntent(String packageName); + + String getDailyTip(); + + void fetchPromotedApps(PromotedAppsCallback callback); +} diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/data/repository/QuizRepository.java b/app/src/main/java/com/d4rk/androidtutorials/java/data/repository/QuizRepository.java new file mode 100644 index 00000000..fc884e65 --- /dev/null +++ b/app/src/main/java/com/d4rk/androidtutorials/java/data/repository/QuizRepository.java @@ -0,0 +1,12 @@ +package com.d4rk.androidtutorials.java.data.repository; + +import com.d4rk.androidtutorials.java.data.model.QuizQuestion; + +import java.util.List; + +/** + * Abstraction over quiz data operations. + */ +public interface QuizRepository { + List loadQuestions(); +} diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/data/source/DefaultHomeLocalDataSource.java b/app/src/main/java/com/d4rk/androidtutorials/java/data/source/DefaultHomeLocalDataSource.java new file mode 100644 index 00000000..906749dc --- /dev/null +++ b/app/src/main/java/com/d4rk/androidtutorials/java/data/source/DefaultHomeLocalDataSource.java @@ -0,0 +1,48 @@ +package com.d4rk.androidtutorials.java.data.source; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; + +import com.d4rk.androidtutorials.java.R; + +/** + * Default implementation that reads from Android resources. + */ +public class DefaultHomeLocalDataSource implements HomeLocalDataSource { + + private final Context context; + + public DefaultHomeLocalDataSource(Context context) { + this.context = context.getApplicationContext(); + } + + @Override + public Intent getPlayStoreIntent() { + String playStoreUrl = "https://play.google.com/store/apps/details?id=com.d4rk.androidtutorials"; + return buildPlayStoreIntent(playStoreUrl); + } + + @Override + public Intent getAppPlayStoreIntent(String packageName) { + String url = "https://play.google.com/store/apps/details?id=" + packageName; + return buildPlayStoreIntent(url); + } + + @Override + public String getDailyTip() { + String[] tips = context.getResources().getStringArray(R.array.daily_tips); + long daysSinceEpoch = System.currentTimeMillis() / (24L * 60 * 60 * 1000); + int index = (int) (daysSinceEpoch % tips.length); + return tips[index]; + } + + private Intent buildPlayStoreIntent(String url) { + Intent playStoreIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + playStoreIntent.setPackage("com.android.vending"); + if (playStoreIntent.resolveActivity(context.getPackageManager()) != null) { + return playStoreIntent; + } + return new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + } +} diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/data/source/DefaultHomeRemoteDataSource.java b/app/src/main/java/com/d4rk/androidtutorials/java/data/source/DefaultHomeRemoteDataSource.java new file mode 100644 index 00000000..2aa155d9 --- /dev/null +++ b/app/src/main/java/com/d4rk/androidtutorials/java/data/source/DefaultHomeRemoteDataSource.java @@ -0,0 +1,60 @@ +package com.d4rk.androidtutorials.java.data.source; + +import com.android.volley.Request; +import com.android.volley.RequestQueue; +import com.android.volley.toolbox.JsonObjectRequest; +import com.d4rk.androidtutorials.java.data.model.PromotedApp; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Volley based implementation of {@link HomeRemoteDataSource}. + */ +public class DefaultHomeRemoteDataSource implements HomeRemoteDataSource { + + private final RequestQueue requestQueue; + private final String apiUrl; + + public DefaultHomeRemoteDataSource(RequestQueue requestQueue, String apiUrl) { + this.requestQueue = requestQueue; + this.apiUrl = apiUrl; + } + + @Override + public void fetchPromotedApps(PromotedAppsCallback callback) { + JsonObjectRequest request = new JsonObjectRequest( + Request.Method.GET, + apiUrl, + null, + response -> { + List result = new ArrayList<>(); + try { + JSONArray apps = response.getJSONObject("data").getJSONArray("apps"); + for (int i = 0; i < apps.length(); i++) { + JSONObject obj = apps.getJSONObject(i); + String pkg = obj.getString("packageName"); + if (pkg.contains("com.d4rk.androidtutorials")) { + continue; + } + result.add(new PromotedApp( + obj.getString("name"), + pkg, + obj.getString("iconLogo") + )); + } + } catch (JSONException e) { + result = Collections.emptyList(); + } + callback.onResult(result); + }, + error -> callback.onResult(Collections.emptyList()) + ); + requestQueue.add(request); + } +} diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/quiz/repository/QuizRepository.java b/app/src/main/java/com/d4rk/androidtutorials/java/data/source/DefaultQuizLocalDataSource.java similarity index 72% rename from app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/quiz/repository/QuizRepository.java rename to app/src/main/java/com/d4rk/androidtutorials/java/data/source/DefaultQuizLocalDataSource.java index 81a119be..eaa25537 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/quiz/repository/QuizRepository.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/data/source/DefaultQuizLocalDataSource.java @@ -1,6 +1,6 @@ -package com.d4rk.androidtutorials.java.ui.screens.quiz.repository; +package com.d4rk.androidtutorials.java.data.source; -import android.content.Context; +import android.content.res.AssetManager; import com.d4rk.androidtutorials.java.data.model.QuizQuestion; @@ -16,25 +16,21 @@ import java.util.List; /** - * Repository responsible for loading quiz question data from JSON assets. + * Reads quiz questions from the assets folder. */ -public class QuizRepository { +public class DefaultQuizLocalDataSource implements QuizLocalDataSource { - private final Context context; + private final AssetManager assetManager; - public QuizRepository(Context context) { - this.context = context.getApplicationContext(); + public DefaultQuizLocalDataSource(AssetManager assetManager) { + this.assetManager = assetManager; } - /** - * Loads the quiz questions from the assets folder. - */ + @Override public List loadQuestions() { - try { - InputStream is = context.getAssets().open("quiz_questions.json"); + try (InputStream is = assetManager.open("quiz_questions.json")) { byte[] buffer = new byte[is.available()]; int read = is.read(buffer); - is.close(); String json = new String(buffer, 0, read, StandardCharsets.UTF_8); JSONArray array = new JSONArray(json); List result = new ArrayList<>(); diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/data/source/HomeLocalDataSource.java b/app/src/main/java/com/d4rk/androidtutorials/java/data/source/HomeLocalDataSource.java new file mode 100644 index 00000000..002b7ff9 --- /dev/null +++ b/app/src/main/java/com/d4rk/androidtutorials/java/data/source/HomeLocalDataSource.java @@ -0,0 +1,15 @@ +package com.d4rk.androidtutorials.java.data.source; + +import android.content.Intent; + +/** + * Local data access for the home feature. + */ +public interface HomeLocalDataSource { + + Intent getPlayStoreIntent(); + + Intent getAppPlayStoreIntent(String packageName); + + String getDailyTip(); +} diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/data/source/HomeRemoteDataSource.java b/app/src/main/java/com/d4rk/androidtutorials/java/data/source/HomeRemoteDataSource.java new file mode 100644 index 00000000..78e8fe86 --- /dev/null +++ b/app/src/main/java/com/d4rk/androidtutorials/java/data/source/HomeRemoteDataSource.java @@ -0,0 +1,17 @@ +package com.d4rk.androidtutorials.java.data.source; + +import com.d4rk.androidtutorials.java.data.model.PromotedApp; + +import java.util.List; + +/** + * Contract for fetching home screen data from remote sources. + */ +public interface HomeRemoteDataSource { + + interface PromotedAppsCallback { + void onResult(List apps); + } + + void fetchPromotedApps(PromotedAppsCallback callback); +} diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/data/source/QuizLocalDataSource.java b/app/src/main/java/com/d4rk/androidtutorials/java/data/source/QuizLocalDataSource.java new file mode 100644 index 00000000..7b5297bb --- /dev/null +++ b/app/src/main/java/com/d4rk/androidtutorials/java/data/source/QuizLocalDataSource.java @@ -0,0 +1,12 @@ +package com.d4rk.androidtutorials.java.data.source; + +import com.d4rk.androidtutorials.java.data.model.QuizQuestion; + +import java.util.List; + +/** + * Contract for reading quiz data from local storage. + */ +public interface QuizLocalDataSource { + List loadQuestions(); +} diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/domain/home/GetDailyTipUseCase.java b/app/src/main/java/com/d4rk/androidtutorials/java/domain/home/GetDailyTipUseCase.java index b77e8f4a..2887344e 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/domain/home/GetDailyTipUseCase.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/domain/home/GetDailyTipUseCase.java @@ -1,6 +1,6 @@ package com.d4rk.androidtutorials.java.domain.home; -import com.d4rk.androidtutorials.java.ui.screens.home.repository.HomeRepository; +import com.d4rk.androidtutorials.java.data.repository.HomeRepository; /** Use case that provides the daily tip text. */ public class GetDailyTipUseCase { diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/domain/home/GetPromotedAppsUseCase.java b/app/src/main/java/com/d4rk/androidtutorials/java/domain/home/GetPromotedAppsUseCase.java index b48e781e..a9ac99ba 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/domain/home/GetPromotedAppsUseCase.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/domain/home/GetPromotedAppsUseCase.java @@ -1,7 +1,7 @@ package com.d4rk.androidtutorials.java.domain.home; import com.d4rk.androidtutorials.java.data.model.PromotedApp; -import com.d4rk.androidtutorials.java.ui.screens.home.repository.HomeRepository; +import com.d4rk.androidtutorials.java.data.repository.HomeRepository; import java.util.List; diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/domain/quiz/LoadQuizQuestionsUseCase.java b/app/src/main/java/com/d4rk/androidtutorials/java/domain/quiz/LoadQuizQuestionsUseCase.java index fb92aa01..d6ebe5aa 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/domain/quiz/LoadQuizQuestionsUseCase.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/domain/quiz/LoadQuizQuestionsUseCase.java @@ -1,7 +1,7 @@ package com.d4rk.androidtutorials.java.domain.quiz; import com.d4rk.androidtutorials.java.data.model.QuizQuestion; -import com.d4rk.androidtutorials.java.ui.screens.quiz.repository.QuizRepository; +import com.d4rk.androidtutorials.java.data.repository.QuizRepository; import java.util.List; /** Loads quiz questions from assets. */ 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 99fa2f52..9585fd9d 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 @@ -8,9 +8,15 @@ 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.ui.screens.home.repository.HomeRepository; +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; @@ -31,7 +37,12 @@ public class HomeViewModel extends AndroidViewModel { public HomeViewModel(@NonNull Application application) { super(application); - homeRepository = new HomeRepository(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); diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/home/repository/HomeRepository.java b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/home/repository/HomeRepository.java deleted file mode 100644 index 1c486528..00000000 --- a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/home/repository/HomeRepository.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.d4rk.androidtutorials.java.ui.screens.home.repository; - -import android.content.Context; -import android.content.Intent; -import android.net.Uri; - -import com.android.volley.Request; -import com.android.volley.RequestQueue; -import com.android.volley.toolbox.JsonObjectRequest; -import com.android.volley.toolbox.Volley; -import com.d4rk.androidtutorials.java.R; -import com.d4rk.androidtutorials.java.data.model.PromotedApp; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -/** - * Repository for Home screen data/logic. - * Here you can manage fetching or storing any data needed on the HomeFragment. - */ -public class HomeRepository { - - private final Context context; - private final RequestQueue requestQueue; - private static final String PROMOTED_APPS_URL = - "https://raw.githubusercontent.com/D4rK7355608/com.d4rk.apis/refs/heads/main/App%20Toolkit/release/en/home/api_android_apps.json"; - - public HomeRepository(Context context) { - this.context = context.getApplicationContext(); - this.requestQueue = Volley.newRequestQueue(this.context); - } - - /** - * Returns an Intent that opens the Google Play Store page for your app. - * You can change the package name or URL as needed. - */ - public Intent getPlayStoreIntent() { - String playStoreUrl = "https://play.google.com/store/apps/details?id=com.d4rk.androidtutorials"; - return buildPlayStoreIntent(playStoreUrl); - } - - /** - * Returns an Intent that opens the Google Play Store page for the provided package. - */ - public Intent getAppPlayStoreIntent(String packageName) { - String url = "https://play.google.com/store/apps/details?id=" + packageName; - return buildPlayStoreIntent(url); - } - - /** - * Builds an intent that opens a Play Store url if the Google Play app is - * installed, otherwise falls back to a generic ACTION_VIEW intent. - */ - private Intent buildPlayStoreIntent(String url) { - Intent playStoreIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - playStoreIntent.setPackage("com.android.vending"); - if (playStoreIntent.resolveActivity(context.getPackageManager()) != null) { - return playStoreIntent; - } - return new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - } - - /** - * Returns a daily tip based on the current date. - */ - public String getDailyTip() { - String[] tips = context.getResources().getStringArray(R.array.daily_tips); - long daysSinceEpoch = System.currentTimeMillis() / (24L * 60 * 60 * 1000); - int index = (int) (daysSinceEpoch % tips.length); - return tips[index]; - } - - /** Callback used for delivering promoted apps. */ - public interface PromotedAppsCallback { - void onResult(List apps); - } - - /** - * Fetches the promoted apps list from the remote JSON API. - */ - public void fetchPromotedApps(PromotedAppsCallback callback) { - JsonObjectRequest request = new JsonObjectRequest( - Request.Method.GET, - PROMOTED_APPS_URL, - null, - response -> { - List result = new ArrayList<>(); - try { - JSONArray apps = response.getJSONObject("data").getJSONArray("apps"); - for (int i = 0; i < apps.length(); i++) { - JSONObject obj = apps.getJSONObject(i); - String pkg = obj.getString("packageName"); - if (pkg.contains("com.d4rk.androidtutorials")) { - continue; - } - result.add(new PromotedApp( - obj.getString("name"), - pkg, - obj.getString("iconLogo") - )); - } - } catch (JSONException e) { - result = Collections.emptyList(); - } - callback.onResult(result); - }, - error -> callback.onResult(Collections.emptyList()) - ); - requestQueue.add(request); - } -} \ No newline at end of file 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 c24bebf6..146f25d4 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 @@ -8,7 +8,10 @@ import androidx.lifecycle.MutableLiveData; import com.d4rk.androidtutorials.java.data.model.QuizQuestion; -import com.d4rk.androidtutorials.java.ui.screens.quiz.repository.QuizRepository; +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; @@ -25,7 +28,8 @@ public class QuizViewModel extends AndroidViewModel { public QuizViewModel(@NonNull Application application) { super(application); - QuizRepository repository = new QuizRepository(application); + QuizLocalDataSource local = new DefaultQuizLocalDataSource(application.getAssets()); + QuizRepository repository = new DefaultQuizRepository(local); loadQuizQuestionsUseCase = new LoadQuizQuestionsUseCase(repository); questions = loadQuizQuestionsUseCase.invoke(); }