Skip to content

Commit d7b6a47

Browse files
Polish onboarding UI and consent handling
1 parent 31c0d53 commit d7b6a47

File tree

9 files changed

+145
-30
lines changed

9 files changed

+145
-30
lines changed

app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/onboarding/DoneFragment.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@
99
import androidx.annotation.Nullable;
1010
import androidx.fragment.app.Fragment;
1111

12+
import androidx.lifecycle.ViewModelProvider;
13+
1214
import com.d4rk.androidtutorials.java.databinding.FragmentOnboardingDoneBinding;
1315

1416
public class DoneFragment extends Fragment {
1517

1618
private FragmentOnboardingDoneBinding binding;
19+
private OnboardingViewModel viewModel;
1720

1821
@Nullable
1922
@Override
@@ -23,6 +26,18 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
2326
return binding.getRoot();
2427
}
2528

29+
@Override
30+
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
31+
super.onViewCreated(view, savedInstanceState);
32+
viewModel = new ViewModelProvider(requireActivity()).get(OnboardingViewModel.class);
33+
binding.buttonGetStarted.setOnClickListener(v -> {
34+
viewModel.markOnboardingComplete();
35+
if (getActivity() instanceof OnboardingActivity) {
36+
((OnboardingActivity) getActivity()).finishOnboarding();
37+
}
38+
});
39+
}
40+
2641
@Override
2742
public void onDestroyView() {
2843
super.onDestroyView();

app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/onboarding/OnboardingActivity.java

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

33
import android.content.Intent;
4+
import android.content.SharedPreferences;
45
import android.os.Bundle;
56
import android.view.View;
67
import android.widget.ImageView;
8+
import android.widget.LinearLayout;
79

810
import androidx.annotation.NonNull;
11+
import androidx.preference.PreferenceManager;
912
import androidx.appcompat.app.AppCompatActivity;
1013
import androidx.fragment.app.Fragment;
1114
import androidx.lifecycle.ViewModelProvider;
@@ -14,6 +17,8 @@
1417
import com.d4rk.androidtutorials.java.R;
1518
import com.d4rk.androidtutorials.java.databinding.ActivityOnboardingBinding;
1619
import com.d4rk.androidtutorials.java.ui.screens.main.MainActivity;
20+
import com.d4rk.androidtutorials.java.ui.screens.startup.dialogs.ConsentDialogFragment;
21+
import com.d4rk.androidtutorials.java.utils.ConsentUtils;
1722
import com.google.android.material.tabs.TabLayout;
1823
import com.google.android.material.tabs.TabLayoutMediator;
1924

@@ -38,6 +43,14 @@ protected void onCreate(Bundle savedInstanceState) {
3843
adapter = new OnboardingPagerAdapter(this);
3944
binding.viewPager.setAdapter(adapter);
4045

46+
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
47+
String keyAnalytics = getString(R.string.key_consent_analytics);
48+
if (!prefs.contains(keyAnalytics)) {
49+
ConsentDialogFragment dialog = new ConsentDialogFragment();
50+
dialog.setConsentListener((a,b,c,d) -> ConsentUtils.updateFirebaseConsent(this, a,b,c,d));
51+
dialog.show(getSupportFragmentManager(), "consent");
52+
}
53+
4154
binding.viewPager.registerOnPageChangeCallback(new androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback() {
4255
@Override
4356
public void onPageSelected(int position) {
@@ -59,6 +72,11 @@ public void onPageSelected(int position) {
5972
new TabLayoutMediator(binding.tabIndicator, binding.viewPager, (tab, position) -> {
6073
ImageView dot = new ImageView(this);
6174
dot.setImageResource(R.drawable.onboarding_dot_unselected);
75+
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
76+
LinearLayout.LayoutParams.WRAP_CONTENT,
77+
LinearLayout.LayoutParams.WRAP_CONTENT);
78+
params.setMargins(8,0,8,0);
79+
dot.setLayoutParams(params);
6280
tab.setCustomView(dot);
6381
}).attach();
6482

@@ -95,6 +113,11 @@ public void onTabReselected(TabLayout.Tab tab) {
95113
}
96114
});
97115

116+
binding.buttonSkip.setOnClickListener(v -> {
117+
viewModel.markOnboardingComplete();
118+
finishOnboarding();
119+
});
120+
98121
binding.buttonNext.setOnClickListener(v -> {
99122
int current = binding.viewPager.getCurrentItem();
100123
Fragment fragment = getSupportFragmentManager().findFragmentByTag("f" + current);
@@ -123,11 +146,15 @@ void finishOnboarding() {
123146
}
124147

125148
private void updateButtons(int position) {
126-
binding.buttonBack.setVisibility(position == 0 ? View.INVISIBLE : View.VISIBLE);
127149
if (position == adapter.getItemCount() - 1) {
128-
binding.buttonNext.setText(R.string.finish);
150+
binding.bottomBar.setVisibility(View.GONE);
151+
binding.buttonSkip.setVisibility(View.GONE);
129152
} else {
153+
binding.bottomBar.setVisibility(View.VISIBLE);
154+
binding.buttonSkip.setVisibility(View.VISIBLE);
155+
binding.buttonBack.setVisibility(position == 0 ? View.INVISIBLE : View.VISIBLE);
130156
binding.buttonNext.setText(R.string.next);
157+
binding.buttonNext.setIconResource(R.drawable.ic_arrow_forward);
131158
}
132159
}
133160

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:width="24dp"
4+
android:height="24dp"
5+
android:viewportWidth="24"
6+
android:viewportHeight="24">
7+
<path
8+
android:fillColor="@android:color/black"
9+
android:pathData="M19,11H7.83l5.59-5.59L12,4l-8,8 8,8 1.41-1.41L7.83,13H19v-2z" />
10+
</vector>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:width="24dp"
4+
android:height="24dp"
5+
android:viewportWidth="24"
6+
android:viewportHeight="24">
7+
<path
8+
android:fillColor="@android:color/black"
9+
android:pathData="M18.3,5.71L12,12l6.3,6.29-1.41,1.42L12,13.41l-6.29,6.3-1.42-1.42L10.59,12 4.29,5.71 5.71,4.29 12,10.59l6.29-6.3z" />
10+
</vector>

app/src/main/res/layout/activity_onboarding.xml

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@
55
android:layout_height="match_parent"
66
android:fitsSystemWindows="true">
77

8+
<com.google.android.material.button.MaterialButton
9+
android:id="@+id/buttonSkip"
10+
style="?attr/materialButtonOutlinedStyle"
11+
android:layout_width="wrap_content"
12+
android:layout_height="wrap_content"
13+
android:text="@string/skip"
14+
app:icon="@drawable/ic_close"
15+
app:iconGravity="textStart"
16+
app:layout_constraintTop_toTopOf="parent"
17+
app:layout_constraintEnd_toEndOf="parent"
18+
android:layout_margin="16dp"/>
19+
820
<androidx.viewpager2.widget.ViewPager2
921
android:id="@+id/viewPager"
1022
android:layout_width="0dp"
@@ -30,23 +42,29 @@
3042
style="?attr/materialButtonOutlinedStyle"
3143
android:layout_width="wrap_content"
3244
android:layout_height="wrap_content"
33-
android:text="@string/back" />
45+
android:text="@string/back"
46+
app:icon="@drawable/ic_arrow_back"
47+
app:iconGravity="textStart" />
3448

3549
<com.google.android.material.tabs.TabLayout
3650
android:id="@+id/tabIndicator"
3751
android:layout_width="0dp"
38-
android:layout_height="wrap_content"
52+
android:layout_height="16dp"
3953
android:layout_weight="1"
4054
android:background="@android:color/transparent"
55+
android:minHeight="0dp"
4156
app:tabIndicatorFullWidth="false"
4257
app:tabIndicatorGravity="center"
58+
app:tabIndicatorHeight="0dp"
4359
app:tabRippleColor="@android:color/transparent" />
4460

4561
<com.google.android.material.button.MaterialButton
4662
android:id="@+id/buttonNext"
4763
android:layout_width="wrap_content"
4864
android:layout_height="wrap_content"
49-
android:text="@string/next" />
65+
android:text="@string/next"
66+
app:icon="@drawable/ic_arrow_forward"
67+
app:iconGravity="textStart" />
5068

5169
</LinearLayout>
5270

app/src/main/res/layout/fragment_onboarding_data.xml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
33
xmlns:app="http://schemas.android.com/apk/res-auto"
44
android:layout_width="match_parent"
5-
android:layout_height="match_parent"
6-
android:background="?attr/colorSurfaceContainer">
5+
android:layout_height="match_parent">
76

87
<LinearLayout
98
android:layout_width="match_parent"
Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,76 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
2+
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
33
xmlns:app="http://schemas.android.com/apk/res-auto"
4+
xmlns:tools="http://schemas.android.com/tools"
45
android:layout_width="match_parent"
5-
android:layout_height="match_parent">
6+
android:layout_height="match_parent"
7+
android:padding="24dp">
68

79
<LinearLayout
8-
android:layout_width="match_parent"
10+
android:id="@+id/content"
11+
android:layout_width="0dp"
912
android:layout_height="wrap_content"
13+
android:gravity="center_horizontal"
1014
android:orientation="vertical"
11-
android:padding="24dp">
15+
app:layout_constraintTop_toTopOf="parent"
16+
app:layout_constraintBottom_toBottomOf="parent"
17+
app:layout_constraintStart_toStartOf="parent"
18+
app:layout_constraintEnd_toEndOf="parent">
1219

1320
<com.google.android.material.card.MaterialCardView
21+
style="@style/Widget.Material3.CardView.Outlined"
1422
android:layout_width="match_parent"
1523
android:layout_height="wrap_content"
16-
android:padding="24dp"
17-
app:cardElevation="0dp">
24+
app:cardCornerRadius="24dp"
25+
app:cardElevation="0dp"
26+
app:strokeWidth="1dp">
1827

1928
<LinearLayout
2029
android:layout_width="match_parent"
2130
android:layout_height="wrap_content"
2231
android:gravity="center"
23-
android:orientation="vertical">
32+
android:orientation="vertical"
33+
android:padding="32dp">
2434

2535
<ImageView
26-
android:layout_width="64dp"
27-
android:layout_height="64dp"
28-
android:layout_marginBottom="16dp"
29-
android:src="@drawable/ic_check_circle" />
36+
android:id="@+id/success_icon"
37+
android:layout_width="80dp"
38+
android:layout_height="80dp"
39+
android:src="@drawable/ic_check_circle"
40+
android:contentDescription="@string/success_icon"
41+
app:tint="?attr/colorPrimary" />
3042

3143
<com.google.android.material.textview.MaterialTextView
32-
style="@style/TextAppearance.Material3.TitleLarge"
44+
android:id="@+id/title_text"
45+
style="@style/TextAppearance.Material3.HeadlineSmall"
3346
android:layout_width="wrap_content"
3447
android:layout_height="wrap_content"
35-
android:layout_marginBottom="8dp"
36-
android:text="@string/onboarding_done_title" />
48+
android:layout_marginTop="24dp"
49+
android:text="@string/onboarding_done_title"
50+
android:textAlignment="center" />
3751

3852
<com.google.android.material.textview.MaterialTextView
39-
style="@style/TextAppearance.Material3.BodyMedium"
53+
android:id="@+id/subtitle_text"
54+
style="@style/TextAppearance.Material3.BodyLarge"
4055
android:layout_width="wrap_content"
4156
android:layout_height="wrap_content"
42-
android:gravity="center"
43-
android:text="@string/onboarding_done_subtitle" />
57+
android:layout_marginTop="12dp"
58+
android:text="@string/onboarding_done_subtitle"
59+
android:textAlignment="center"
60+
android:textColor="?attr/colorOnSurfaceVariant" />
4461

4562
</LinearLayout>
4663
</com.google.android.material.card.MaterialCardView>
64+
65+
<com.google.android.material.button.MaterialButton
66+
android:id="@+id/button_get_started"
67+
android:layout_width="wrap_content"
68+
android:layout_height="wrap_content"
69+
android:layout_marginTop="24dp"
70+
android:text="@string/get_started_button"
71+
app:icon="@drawable/ic_arrow_forward"
72+
app:iconGravity="textStart" />
73+
4774
</LinearLayout>
48-
</ScrollView>
75+
76+
</androidx.constraintlayout.widget.ConstraintLayout>

app/src/main/res/layout/item_onboarding_option.xml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<androidx.constraintlayout.widget.ConstraintLayout
1212
android:layout_width="match_parent"
1313
android:layout_height="wrap_content"
14-
android:padding="20dp">
14+
android:padding="16dp">
1515

1616
<androidx.appcompat.widget.AppCompatImageView
1717
android:id="@+id/icon"
@@ -29,8 +29,11 @@
2929
android:layout_width="0dp"
3030
android:layout_height="wrap_content"
3131
android:layout_marginStart="16dp"
32+
android:layout_marginEnd="16dp"
3233
android:text="@{title}"
3334
android:textAppearance="?attr/textAppearanceTitleMedium"
35+
android:breakStrategy="balanced"
36+
android:hyphenationFrequency="none"
3437
app:layout_constraintStart_toEndOf="@id/icon"
3538
app:layout_constraintTop_toTopOf="parent"
3639
app:layout_constraintEnd_toStartOf="@id/radio_button"
@@ -43,15 +46,18 @@
4346
android:text="@{description}"
4447
android:textAppearance="?attr/textAppearanceBodyMedium"
4548
android:textColor="?attr/colorOnSurfaceVariant"
49+
android:breakStrategy="balanced"
50+
android:hyphenationFrequency="none"
4651
app:layout_constraintStart_toStartOf="@id/title_text"
4752
app:layout_constraintTop_toBottomOf="@id/title_text"
48-
app:layout_constraintEnd_toEndOf="@id/title_text"
53+
app:layout_constraintEnd_toStartOf="@id/radio_button"
4954
tools:text="Bright and energetic."/>
5055

5156
<com.google.android.material.radiobutton.MaterialRadioButton
5257
android:id="@+id/radio_button"
5358
android:layout_width="wrap_content"
5459
android:layout_height="wrap_content"
60+
android:layout_marginEnd="4dp"
5561
app:layout_constraintEnd_toEndOf="parent"
5662
app:layout_constraintTop_toTopOf="parent"
5763
app:layout_constraintBottom_toBottomOf="parent"/>

app/src/main/res/values/strings.xml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@
254254
<string name="dark_mode">Dark mode</string>
255255
<string name="auto_battery_mode">Auto battery dark mode</string>
256256
<string name="default_tab">Default tab</string>
257-
<string name="default_tab_description">Select the tab that opens at launch</string>
257+
<string name="default_tab_description">Choose which tab appears when the app opens</string>
258258
<string name="home_description">Top stories and recent updates</string>
259259
<string name="android_studio_description">Android Studio tools, tips, and the full tutorial catalog</string>
260260
<string name="about_description">App details, version, and credits</string>
@@ -362,8 +362,10 @@
362362
<string name="privacy_policy_link">Read our Privacy Policy</string>
363363
<string name="privacy_icon">Privacy Icon</string>
364364
<string name="arrow_icon">Arrow Icon</string>
365-
<string name="onboarding_done_title">You\'re All Set</string>
366-
<string name="onboarding_done_subtitle">Thanks for setting up your preferences. Enjoy the app.</string>
365+
<string name="onboarding_done_title">You\'re All Set!</string>
366+
<string name="onboarding_done_subtitle">Your setup is complete. You are now ready to explore all the features.</string>
367+
<string name="get_started_button">Get Started</string>
368+
<string name="success_icon">Success Icon</string>
367369
<string name="summary_preference_permissions_access_notification_policy">Allows the app to access and modify the device\'s notification policy, controlling how and when notifications are displayed to the user and providing custom notification management features.</string>
368370
<string name="summary_preference_permissions_foreground_service">Allows the app to create and use services that run in the foreground, giving them priority over other background processes and improving performance and reliability.</string>
369371
<string name="summary_preference_settings_language">Set application language.</string>

0 commit comments

Comments
 (0)