Skip to content

Commit 902fbc9

Browse files
Merge pull request #68 from MihaiCristianCondrea/codex/create-use-cases-for-play-store-urls-and-tips
refactor: add use cases and decouple home viewmodel
2 parents bac8f9f + 850459d commit 902fbc9

File tree

6 files changed

+90
-34
lines changed

6 files changed

+90
-34
lines changed

app/src/main/java/com/d4rk/androidtutorials/java/di/AppModule.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import com.d4rk.androidtutorials.java.domain.help.RequestReviewFlowUseCase;
2626
import com.d4rk.androidtutorials.java.domain.home.GetDailyTipUseCase;
2727
import com.d4rk.androidtutorials.java.domain.home.GetPromotedAppsUseCase;
28+
import com.d4rk.androidtutorials.java.domain.home.GetPlayStoreUrlUseCase;
29+
import com.d4rk.androidtutorials.java.domain.home.GetAppPlayStoreUrlUseCase;
2830
import com.d4rk.androidtutorials.java.domain.main.ApplyLanguageSettingsUseCase;
2931
import com.d4rk.androidtutorials.java.domain.main.ApplyThemeSettingsUseCase;
3032
import com.d4rk.androidtutorials.java.domain.main.BuildShortcutIntentUseCase;
@@ -107,6 +109,16 @@ public GetPromotedAppsUseCase provideGetPromotedAppsUseCase(HomeRepository repos
107109
return new GetPromotedAppsUseCase(repository);
108110
}
109111

112+
@Provides
113+
public GetPlayStoreUrlUseCase provideGetPlayStoreUrlUseCase(HomeRepository repository) {
114+
return new GetPlayStoreUrlUseCase(repository);
115+
}
116+
117+
@Provides
118+
public GetAppPlayStoreUrlUseCase provideGetAppPlayStoreUrlUseCase(HomeRepository repository) {
119+
return new GetAppPlayStoreUrlUseCase(repository);
120+
}
121+
110122
@Provides
111123
@Singleton
112124
public AboutRepository provideAboutRepository(Application application) {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.d4rk.androidtutorials.java.domain.home;
2+
3+
import com.d4rk.androidtutorials.java.data.repository.HomeRepository;
4+
5+
/** Use case that builds a Play Store URL for a given package name. */
6+
public class GetAppPlayStoreUrlUseCase {
7+
private final HomeRepository repository;
8+
9+
public GetAppPlayStoreUrlUseCase(HomeRepository repository) {
10+
this.repository = repository;
11+
}
12+
13+
/** Returns the Play Store URL for the specified package name. */
14+
public String invoke(String packageName) {
15+
return repository.getAppPlayStoreUrl(packageName);
16+
}
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.d4rk.androidtutorials.java.domain.home;
2+
3+
import com.d4rk.androidtutorials.java.data.repository.HomeRepository;
4+
5+
/** Use case that provides the Play Store URL for this app. */
6+
public class GetPlayStoreUrlUseCase {
7+
private final HomeRepository repository;
8+
9+
public GetPlayStoreUrlUseCase(HomeRepository repository) {
10+
this.repository = repository;
11+
}
12+
13+
/** Returns the Play Store URL for the application. */
14+
public String invoke() {
15+
return repository.getPlayStoreUrl();
16+
}
17+
}

app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/home/HomeFragment.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
3535
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
3636
super.onViewCreated(view, savedInstanceState);
3737
homeViewModel = new ViewModelProvider(this).get(HomeViewModel.class);
38+
homeViewModel.setAnnouncements(
39+
getString(com.d4rk.androidtutorials.java.R.string.announcement_title),
40+
getString(com.d4rk.androidtutorials.java.R.string.announcement_subtitle)
41+
);
3842
LayoutInflater inflater = LayoutInflater.from(requireContext());
3943
homeViewModel.getUiState().observe(getViewLifecycleOwner(), state -> {
4044
binding.announcementTitle.setText(state.announcementTitle());

app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/home/HomeViewModel.java

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
package com.d4rk.androidtutorials.java.ui.screens.home;
22

3-
import android.app.Application;
43
import android.content.Intent;
54
import android.net.Uri;
65

76
import androidx.lifecycle.LiveData;
87
import androidx.lifecycle.MutableLiveData;
98
import androidx.lifecycle.ViewModel;
109

11-
import com.d4rk.androidtutorials.java.R;
1210
import com.d4rk.androidtutorials.java.data.model.PromotedApp;
13-
import com.d4rk.androidtutorials.java.data.repository.HomeRepository;
1411
import com.d4rk.androidtutorials.java.domain.home.GetDailyTipUseCase;
1512
import com.d4rk.androidtutorials.java.domain.home.GetPromotedAppsUseCase;
13+
import com.d4rk.androidtutorials.java.domain.home.GetPlayStoreUrlUseCase;
14+
import com.d4rk.androidtutorials.java.domain.home.GetAppPlayStoreUrlUseCase;
1615

1716
import dagger.hilt.android.lifecycle.HiltViewModel;
1817
import javax.inject.Inject;
@@ -24,26 +23,26 @@
2423
@HiltViewModel
2524
public class HomeViewModel extends ViewModel {
2625

27-
private final Application application;
28-
private final HomeRepository homeRepository;
2926
private final GetDailyTipUseCase getDailyTipUseCase;
3027
private final GetPromotedAppsUseCase getPromotedAppsUseCase;
28+
private final GetPlayStoreUrlUseCase getPlayStoreUrlUseCase;
29+
private final GetAppPlayStoreUrlUseCase getAppPlayStoreUrlUseCase;
3130

3231
private final MutableLiveData<HomeUiState> uiState = new MutableLiveData<>();
3332

3433
@Inject
35-
public HomeViewModel(Application application,
36-
HomeRepository homeRepository,
37-
GetDailyTipUseCase getDailyTipUseCase,
38-
GetPromotedAppsUseCase getPromotedAppsUseCase) {
39-
this.application = application;
40-
this.homeRepository = homeRepository;
34+
public HomeViewModel(GetDailyTipUseCase getDailyTipUseCase,
35+
GetPromotedAppsUseCase getPromotedAppsUseCase,
36+
GetPlayStoreUrlUseCase getPlayStoreUrlUseCase,
37+
GetAppPlayStoreUrlUseCase getAppPlayStoreUrlUseCase) {
4138
this.getDailyTipUseCase = getDailyTipUseCase;
4239
this.getPromotedAppsUseCase = getPromotedAppsUseCase;
40+
this.getPlayStoreUrlUseCase = getPlayStoreUrlUseCase;
41+
this.getAppPlayStoreUrlUseCase = getAppPlayStoreUrlUseCase;
4342

4443
HomeUiState initialState = new HomeUiState(
45-
application.getString(R.string.announcement_title),
46-
application.getString(R.string.announcement_subtitle),
44+
"",
45+
"",
4746
getDailyTipUseCase.invoke(),
4847
new ArrayList<>()
4948
);
@@ -75,6 +74,16 @@ public HomeViewModel(Application application,
7574
});
7675
}
7776

77+
public void setAnnouncements(String title, String subtitle) {
78+
HomeUiState current = uiState.getValue();
79+
if (current == null) {
80+
current = new HomeUiState(title, subtitle, getDailyTipUseCase.invoke(), new ArrayList<>());
81+
} else {
82+
current = new HomeUiState(title, subtitle, current.dailyTip(), current.promotedApps());
83+
}
84+
uiState.setValue(current);
85+
}
86+
7887
/**
7988
* Exposes the UI state for the Home screen.
8089
*/
@@ -87,22 +96,17 @@ public LiveData<HomeUiState> getUiState() {
8796
* The HomeFragment can startActivity(...) on it.
8897
*/
8998
public Intent getOpenPlayStoreIntent() {
90-
return buildPlayStoreIntent(homeRepository.getPlayStoreUrl());
99+
return buildPlayStoreIntent(getPlayStoreUrlUseCase.invoke());
91100
}
92101

93102
/**
94103
* Builds an intent to open the Google Play listing for the provided package.
95104
*/
96105
public Intent getPromotedAppIntent(String packageName) {
97-
return buildPlayStoreIntent(homeRepository.getAppPlayStoreUrl(packageName));
106+
return buildPlayStoreIntent(getAppPlayStoreUrlUseCase.invoke(packageName));
98107
}
99108

100109
private Intent buildPlayStoreIntent(String url) {
101-
Intent playStoreIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
102-
playStoreIntent.setPackage("com.android.vending");
103-
if (playStoreIntent.resolveActivity(application.getPackageManager()) != null) {
104-
return playStoreIntent;
105-
}
106110
return new Intent(Intent.ACTION_VIEW, Uri.parse(url));
107111
}
108112
}

app/src/test/java/com/d4rk/androidtutorials/java/ui/screens/home/HomeViewModelTest.java

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
package com.d4rk.androidtutorials.java.ui.screens.home;
22

3-
import android.app.Application;
4-
53
import androidx.arch.core.executor.testing.InstantTaskExecutorRule;
64

7-
import com.d4rk.androidtutorials.java.R;
85
import com.d4rk.androidtutorials.java.data.model.PromotedApp;
96
import com.d4rk.androidtutorials.java.data.repository.HomeRepository;
107
import com.d4rk.androidtutorials.java.domain.home.GetDailyTipUseCase;
118
import com.d4rk.androidtutorials.java.domain.home.GetPromotedAppsUseCase;
9+
import com.d4rk.androidtutorials.java.domain.home.GetPlayStoreUrlUseCase;
10+
import com.d4rk.androidtutorials.java.domain.home.GetAppPlayStoreUrlUseCase;
1211

1312
import org.junit.Rule;
1413
import org.junit.Test;
@@ -17,7 +16,6 @@
1716

1817
import static org.junit.Assert.*;
1918

20-
import org.mockito.Mockito;
2119

2220
public class HomeViewModelTest {
2321

@@ -44,11 +42,13 @@ static class FakeHomeRepository implements HomeRepository {
4442
public void uiStateUpdatesWithData() {
4543
List<PromotedApp> promoted = List.of(new PromotedApp("App", "pkg", "icon"));
4644
FakeHomeRepository repo = new FakeHomeRepository("tip", promoted);
47-
Application app = Mockito.mock(Application.class);
48-
Mockito.when(app.getString(R.string.announcement_title)).thenReturn("Title");
49-
Mockito.when(app.getString(R.string.announcement_subtitle)).thenReturn("Subtitle");
50-
HomeViewModel viewModel = new HomeViewModel(app, repo,
51-
new GetDailyTipUseCase(repo), new GetPromotedAppsUseCase(repo));
45+
HomeViewModel viewModel = new HomeViewModel(
46+
new GetDailyTipUseCase(repo),
47+
new GetPromotedAppsUseCase(repo),
48+
new GetPlayStoreUrlUseCase(repo),
49+
new GetAppPlayStoreUrlUseCase(repo)
50+
);
51+
viewModel.setAnnouncements("Title", "Subtitle");
5252

5353
HomeUiState state = viewModel.getUiState().getValue();
5454
assertNotNull(state);
@@ -61,11 +61,13 @@ public void uiStateUpdatesWithData() {
6161
@Test
6262
public void uiStateHandlesEmptyPromotedApps() {
6363
FakeHomeRepository repo = new FakeHomeRepository("tip", List.of());
64-
Application app = Mockito.mock(Application.class);
65-
Mockito.when(app.getString(R.string.announcement_title)).thenReturn("Title");
66-
Mockito.when(app.getString(R.string.announcement_subtitle)).thenReturn("Subtitle");
67-
HomeViewModel viewModel = new HomeViewModel(app, repo,
68-
new GetDailyTipUseCase(repo), new GetPromotedAppsUseCase(repo));
64+
HomeViewModel viewModel = new HomeViewModel(
65+
new GetDailyTipUseCase(repo),
66+
new GetPromotedAppsUseCase(repo),
67+
new GetPlayStoreUrlUseCase(repo),
68+
new GetAppPlayStoreUrlUseCase(repo)
69+
);
70+
viewModel.setAnnouncements("Title", "Subtitle");
6971

7072
HomeUiState state = viewModel.getUiState().getValue();
7173
assertNotNull(state);

0 commit comments

Comments
 (0)