Skip to content

Commit 022f1d2

Browse files
Merge pull request #265 from MihaiCristianCondrea/codex/fix-scroll-behavior-and-spacing-in-faq
Refine help screen edge-to-edge layout
2 parents 65d477f + 3e10c79 commit 022f1d2

File tree

10 files changed

+361
-238
lines changed

10 files changed

+361
-238
lines changed

.github/workflows/android.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@ jobs:
2424
run: chmod +x gradlew
2525

2626
- name: Build & run all tests
27-
run: ./gradlew build --stacktrace --info
27+
run: ./gradlew build

app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/help/HelpActivity.java

Lines changed: 103 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,49 +4,69 @@
44
import android.content.Intent;
55
import android.net.Uri;
66
import android.os.Bundle;
7+
import android.view.LayoutInflater;
78
import android.view.Menu;
89
import android.view.MenuItem;
10+
import android.view.View;
11+
import android.view.ViewGroup;
12+
import android.widget.FrameLayout;
913

14+
import androidx.annotation.Nullable;
1015
import androidx.annotation.NonNull;
16+
import androidx.annotation.StringRes;
1117
import androidx.appcompat.app.AlertDialog;
18+
import androidx.appcompat.widget.LinearLayoutCompat;
19+
import androidx.core.view.ViewCompat;
1220
import androidx.lifecycle.ViewModelProvider;
1321
import androidx.preference.Preference;
1422
import androidx.preference.PreferenceFragmentCompat;
23+
import androidx.recyclerview.widget.RecyclerView;
1524

1625
import com.d4rk.androidtutorials.java.BuildConfig;
1726
import com.d4rk.androidtutorials.java.R;
1827
import com.d4rk.androidtutorials.java.ads.AdUtils;
1928
import com.d4rk.androidtutorials.java.databinding.ActivityHelpBinding;
2029
import com.d4rk.androidtutorials.java.databinding.DialogVersionInfoBinding;
30+
import com.d4rk.androidtutorials.java.databinding.ItemHelpFaqBinding;
2131
import com.d4rk.androidtutorials.java.ui.components.navigation.BaseActivity;
2232
import com.d4rk.androidtutorials.java.ui.screens.help.repository.HelpRepository;
23-
import com.d4rk.androidtutorials.java.utils.EdgeToEdgeDelegate;
2433
import com.d4rk.androidtutorials.java.utils.OpenSourceLicensesUtils;
2534
import com.google.android.material.snackbar.Snackbar;
2635
import com.google.android.play.core.review.ReviewInfo;
2736

2837
import dagger.hilt.android.AndroidEntryPoint;
2938
import me.zhanghai.android.fastscroll.FastScrollerBuilder;
3039

40+
import java.util.Arrays;
41+
import java.util.List;
42+
3143
@AndroidEntryPoint
3244
public class HelpActivity extends BaseActivity {
3345

3446
private HelpViewModel helpViewModel;
47+
private static final List<FaqItem> FAQ_ITEMS = Arrays.asList(
48+
new FaqItem(R.string.question_1, R.string.summary_preference_faq_1),
49+
new FaqItem(R.string.question_2, R.string.summary_preference_faq_2),
50+
new FaqItem(R.string.question_3, R.string.summary_preference_faq_3),
51+
new FaqItem(R.string.question_4, R.string.summary_preference_faq_4),
52+
new FaqItem(R.string.question_5, R.string.summary_preference_faq_5),
53+
new FaqItem(R.string.question_6, R.string.summary_preference_faq_6),
54+
new FaqItem(R.string.question_7, R.string.summary_preference_faq_7),
55+
new FaqItem(R.string.question_8, R.string.summary_preference_faq_8),
56+
new FaqItem(R.string.question_9, R.string.summary_preference_faq_9)
57+
);
3558

3659
@Override
3760
protected void onCreate(Bundle savedInstanceState) {
3861
super.onCreate(savedInstanceState);
3962
ActivityHelpBinding binding = ActivityHelpBinding.inflate(getLayoutInflater());
4063
setContentView(binding.getRoot());
41-
EdgeToEdgeDelegate.apply(this, binding.getRoot());
4264
AdUtils.loadBanner(binding.faqNativeAd);
4365
helpViewModel = new ViewModelProvider(this).get(HelpViewModel.class);
44-
new FastScrollerBuilder(binding.scrollContainer)
66+
new FastScrollerBuilder(binding.scrollView)
4567
.useMd2Style()
4668
.build();
47-
getSupportFragmentManager().beginTransaction()
48-
.replace(R.id.frame_layout_faq, new FaqFragment())
49-
.commit();
69+
bindFaqItems(binding);
5070

5171
getSupportFragmentManager().beginTransaction()
5272
.replace(R.id.frame_layout_feedback, new FeedbackFragment())
@@ -121,13 +141,6 @@ private void openLink(String url) {
121141
startActivity(browserIntent);
122142
}
123143

124-
public static class FaqFragment extends PreferenceFragmentCompat {
125-
@Override
126-
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
127-
setPreferencesFromResource(R.xml.preferences_faq, rootKey);
128-
}
129-
}
130-
131144
public static class FeedbackFragment extends PreferenceFragmentCompat {
132145

133146
@Override
@@ -157,6 +170,29 @@ public void onFailure(Exception e) {
157170
}
158171
}
159172

173+
@Override
174+
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
175+
super.onViewCreated(view, savedInstanceState);
176+
RecyclerView listView = getListView();
177+
listView.setNestedScrollingEnabled(false);
178+
listView.setOverScrollMode(View.OVER_SCROLL_NEVER);
179+
listView.setClipToPadding(false);
180+
181+
ViewGroup.LayoutParams layoutParams = listView.getLayoutParams();
182+
FrameLayout.LayoutParams frameLayoutParams;
183+
if (layoutParams instanceof FrameLayout.LayoutParams) {
184+
frameLayoutParams = (FrameLayout.LayoutParams) layoutParams;
185+
} else {
186+
frameLayoutParams = new FrameLayout.LayoutParams(
187+
ViewGroup.LayoutParams.MATCH_PARENT,
188+
ViewGroup.LayoutParams.WRAP_CONTENT
189+
);
190+
}
191+
frameLayoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
192+
frameLayoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
193+
listView.setLayoutParams(frameLayoutParams);
194+
}
195+
160196
private void launchGooglePlayReviews() {
161197
Uri uri = Uri.parse("https://play.google.com/store/apps/details?id=" + requireActivity().getPackageName() + "&showAllReviews=true");
162198
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
@@ -171,4 +207,58 @@ private void launchGooglePlayReviews() {
171207
}
172208
}
173209
}
210+
211+
private void bindFaqItems(ActivityHelpBinding binding) {
212+
LinearLayoutCompat faqList = binding.faqList;
213+
faqList.removeAllViews();
214+
LayoutInflater inflater = LayoutInflater.from(this);
215+
216+
for (int i = 0; i < FAQ_ITEMS.size(); i++) {
217+
FaqItem item = FAQ_ITEMS.get(i);
218+
ItemHelpFaqBinding itemBinding = ItemHelpFaqBinding.inflate(inflater, faqList, false);
219+
itemBinding.question.setText(item.questionResId);
220+
itemBinding.answer.setText(item.answerResId);
221+
itemBinding.answer.setVisibility(View.GONE);
222+
itemBinding.toggleIcon.setRotation(0f);
223+
CharSequence questionText = itemBinding.question.getText();
224+
itemBinding.getRoot().setContentDescription(questionText);
225+
itemBinding.questionContainer.setContentDescription(questionText);
226+
ViewCompat.setStateDescription(itemBinding.getRoot(), getString(R.string.faq_state_collapsed));
227+
ViewCompat.setStateDescription(itemBinding.questionContainer, getString(R.string.faq_state_collapsed));
228+
229+
View.OnClickListener toggleListener = v -> toggleFaqItem(itemBinding);
230+
itemBinding.getRoot().setOnClickListener(toggleListener);
231+
itemBinding.questionContainer.setOnClickListener(toggleListener);
232+
itemBinding.toggleIcon.setOnClickListener(toggleListener);
233+
itemBinding.divider.setVisibility(i == FAQ_ITEMS.size() - 1 ? View.GONE : View.VISIBLE);
234+
faqList.addView(itemBinding.getRoot());
235+
}
236+
}
237+
238+
private void toggleFaqItem(ItemHelpFaqBinding binding) {
239+
boolean expand = binding.answer.getVisibility() != View.VISIBLE;
240+
binding.answer.setVisibility(expand ? View.VISIBLE : View.GONE);
241+
float rotation = expand ? 180f : 0f;
242+
binding.toggleIcon.animate().cancel();
243+
binding.toggleIcon.animate()
244+
.rotation(rotation)
245+
.setDuration(200L)
246+
.start();
247+
int stateRes = expand ? R.string.faq_state_expanded : R.string.faq_state_collapsed;
248+
CharSequence stateDescription = getString(stateRes);
249+
ViewCompat.setStateDescription(binding.getRoot(), stateDescription);
250+
ViewCompat.setStateDescription(binding.questionContainer, stateDescription);
251+
}
252+
253+
private static final class FaqItem {
254+
@StringRes
255+
private final int questionResId;
256+
@StringRes
257+
private final int answerResId;
258+
259+
private FaqItem(@StringRes int questionResId, @StringRes int answerResId) {
260+
this.questionResId = questionResId;
261+
this.answerResId = answerResId;
262+
}
263+
}
174264
}
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/white"
9+
android:pathData="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z" />
10+
</vector>
Lines changed: 49 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,66 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<me.zhanghai.android.fastscroll.FastScrollScrollView
2+
<androidx.constraintlayout.widget.ConstraintLayout
33
xmlns:android="http://schemas.android.com/apk/res/android"
44
xmlns:app="http://schemas.android.com/apk/res-auto"
5-
android:id="@+id/scroll_container"
5+
android:id="@+id/container"
66
android:layout_width="match_parent"
77
android:layout_height="match_parent">
88

9-
<LinearLayout
10-
android:id="@+id/container"
9+
<me.zhanghai.android.fastscroll.FastScrollScrollView
10+
android:id="@+id/scroll_view"
1111
android:layout_width="match_parent"
12-
android:layout_height="wrap_content"
13-
android:orientation="vertical">
12+
android:layout_height="0dp"
13+
android:clipToPadding="false"
14+
app:layout_constraintBottom_toBottomOf="parent"
15+
app:layout_constraintTop_toTopOf="parent">
1416

15-
<com.google.android.material.textview.MaterialTextView
16-
android:id="@+id/text_view_faq"
17-
android:layout_width="wrap_content"
18-
android:layout_height="wrap_content"
19-
android:layout_marginBottom="16dp"
20-
android:text="@string/faq"
21-
android:textAppearance="@style/TextAppearance.Material3.TitleMedium" />
22-
23-
<com.google.android.material.card.MaterialCardView
24-
android:id="@+id/card_view_faq"
25-
style="@style/Widget.Material3.CardView.Filled"
17+
<androidx.appcompat.widget.LinearLayoutCompat
18+
android:id="@+id/content_container"
2619
android:layout_width="match_parent"
2720
android:layout_height="wrap_content"
28-
app:shapeAppearance="@style/ShapeAppearanceOverlay.CardViewTopRoundedFilled">
21+
android:orientation="vertical"
22+
android:paddingStart="24dp"
23+
android:paddingTop="16dp"
24+
android:paddingEnd="24dp"
25+
android:paddingBottom="32dp">
26+
27+
<com.google.android.material.textview.MaterialTextView
28+
android:id="@+id/text_view_faq"
29+
android:layout_width="wrap_content"
30+
android:layout_height="wrap_content"
31+
android:layout_marginBottom="16dp"
32+
android:text="@string/faq"
33+
android:textAppearance="@style/TextAppearance.Material3.TitleMedium" />
2934

30-
<LinearLayout
35+
<com.google.android.material.card.MaterialCardView
36+
android:id="@+id/card_view_faq"
37+
style="@style/Widget.Material3.CardView.Filled"
3138
android:layout_width="match_parent"
3239
android:layout_height="wrap_content"
33-
android:orientation="vertical"
34-
android:padding="12dp">
35-
<FrameLayout
36-
android:id="@+id/frame_layout_faq"
40+
android:layout_marginBottom="2dp"
41+
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.CardViewTopRoundedFilled">
42+
43+
<androidx.appcompat.widget.LinearLayoutCompat
44+
android:id="@+id/faq_list"
3745
android:layout_width="match_parent"
38-
android:layout_height="wrap_content" />
39-
</LinearLayout>
40-
</com.google.android.material.card.MaterialCardView>
46+
android:layout_height="wrap_content"
47+
android:orientation="vertical" />
48+
</com.google.android.material.card.MaterialCardView>
4149

42-
<com.d4rk.androidtutorials.java.ads.views.NativeAdBannerView
43-
android:id="@+id/faq_native_ad"
44-
android:layout_width="match_parent"
45-
android:layout_height="wrap_content"
46-
android:layout_marginTop="2dp"
47-
app:nativeAdLayout="@layout/ad_help" />
50+
<com.d4rk.androidtutorials.java.ads.views.NativeAdBannerView
51+
android:id="@+id/faq_native_ad"
52+
android:layout_width="match_parent"
53+
android:layout_height="wrap_content"
54+
android:layout_marginBottom="24dp"
55+
app:nativeAdLayout="@layout/ad_help" />
4856

49-
<FrameLayout
50-
android:id="@+id/frame_layout_feedback"
51-
android:layout_width="match_parent"
52-
android:layout_height="wrap_content" />
57+
<FrameLayout
58+
android:id="@+id/frame_layout_feedback"
59+
android:layout_width="match_parent"
60+
android:layout_height="wrap_content" />
61+
62+
</androidx.appcompat.widget.LinearLayoutCompat>
63+
64+
</me.zhanghai.android.fastscroll.FastScrollScrollView>
5365

54-
</LinearLayout>
55-
</me.zhanghai.android.fastscroll.FastScrollScrollView>
66+
</androidx.constraintlayout.widget.ConstraintLayout>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
style="@style/Widget.Material3.CardView.Filled"
99
android:layout_width="match_parent"
1010
android:layout_height="wrap_content"
11-
app:shapeAppearance="@style/ShapeAppearanceOverlay.CardViewBottomRoundedFilled">
11+
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.CardViewBottomRoundedFilled">
1212

1313
<androidx.appcompat.widget.LinearLayoutCompat
1414
android:layout_width="match_parent"

0 commit comments

Comments
 (0)