Skip to content

Commit 4e00506

Browse files
committed
simplify snackbar logic, run on ui thread always
Signed-off-by: alperozturk96 <alper_ozturk@proton.me>
1 parent c07191c commit 4e00506

4 files changed

Lines changed: 103 additions & 108 deletions

File tree

app/src/androidTest/java/com/nextcloud/client/ActivitiesActivityIT.kt

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,6 @@ class ActivitiesActivityIT : AbstractIT() {
3434
@ScreenshotTest
3535
fun openDrawer() {
3636
launchActivity<ActivitiesActivity>().use { scenario ->
37-
scenario.onActivity { sut ->
38-
sut.dismissSnackbar()
39-
}
40-
4137
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open())
4238

4339
scenario.onActivity { sut ->
@@ -54,7 +50,6 @@ class ActivitiesActivityIT : AbstractIT() {
5450
fun loading() {
5551
launchActivity<ActivitiesActivity>().use { scenario ->
5652
scenario.onActivity { sut ->
57-
sut.dismissSnackbar()
5853
sut.binding.emptyList.root.visibility = View.GONE
5954
sut.binding.swipeContainingList.visibility = View.GONE
6055
sut.binding.loadingContent.visibility = View.VISIBLE
@@ -76,7 +71,6 @@ class ActivitiesActivityIT : AbstractIT() {
7671
scenario.onActivity { sut ->
7772
sut.showActivities(mutableListOf(), nextcloudClient, -1)
7873
sut.setProgressIndicatorState(false)
79-
sut.dismissSnackbar()
8074
}
8175

8276
val screenShotName = createName(testClassName + "_" + "empty", "")
@@ -170,7 +164,6 @@ class ActivitiesActivityIT : AbstractIT() {
170164
scenario.onActivity { sut ->
171165
sut.showActivities(activities as List<Any>?, nextcloudClient, -1)
172166
sut.setProgressIndicatorState(false)
173-
sut.dismissSnackbar()
174167
}
175168

176169
val screenShotName = createName(testClassName + "_" + "showActivities", "")
@@ -189,7 +182,6 @@ class ActivitiesActivityIT : AbstractIT() {
189182
scenario.onActivity { sut ->
190183
sut.showEmptyContent("Error", "Error! Please try again later!")
191184
sut.setProgressIndicatorState(false)
192-
sut.dismissSnackbar()
193185
}
194186

195187
val screenShotName = createName(testClassName + "_" + "error", "")
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Nextcloud - Android Client
3+
*
4+
* SPDX-FileCopyrightText: 2026 Alper Ozturk <alper.ozturk@nextcloud.com>
5+
* SPDX-License-Identifier: AGPL-3.0-or-later
6+
*/
7+
8+
package com.owncloud.android.utils
9+
10+
import androidx.annotation.StringRes
11+
import androidx.fragment.app.DialogFragment
12+
import androidx.fragment.app.Fragment
13+
import androidx.test.core.app.launchActivity
14+
import androidx.test.espresso.Espresso.onView
15+
import androidx.test.espresso.assertion.ViewAssertions.matches
16+
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
17+
import androidx.test.espresso.matcher.ViewMatchers.isRoot
18+
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
19+
import com.nextcloud.test.TestActivity
20+
import com.owncloud.android.R
21+
import org.junit.Test
22+
23+
class DisplayUtilsFragmentSnackbarTest {
24+
25+
class NormalTestFragment : Fragment()
26+
class DialogTestFragment : DialogFragment()
27+
class BottomSheetTestFragment : BottomSheetDialogFragment()
28+
29+
private fun testFragmentSnackbar(fragment: Fragment, @StringRes msg: Int) {
30+
launchActivity<TestActivity>().use { scenario ->
31+
scenario.onActivity { sut ->
32+
sut.addFragment(fragment)
33+
DisplayUtils.showSnackMessage(fragment, msg)
34+
}
35+
36+
onView(isRoot()).check(matches(isDisplayed()))
37+
}
38+
}
39+
40+
@Test
41+
fun testNormalFragmentSnackbar() {
42+
testFragmentSnackbar(NormalTestFragment(), R.string.app_name)
43+
}
44+
45+
@Test
46+
fun testDialogFragmentSnackbar() {
47+
testFragmentSnackbar(DialogTestFragment(), R.string.app_name)
48+
}
49+
50+
@Test
51+
fun testBottomSheetFragmentSnackbar() {
52+
testFragmentSnackbar(BottomSheetTestFragment(), R.string.app_name)
53+
}
54+
}

app/src/main/java/com/owncloud/android/ui/activities/ActivitiesActivity.java

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import android.view.MenuItem;
1212
import android.view.View;
1313

14-
import com.google.android.material.snackbar.Snackbar;
1514
import com.nextcloud.client.network.ClientFactory;
1615
import com.nextcloud.client.network.ConnectivityService;
1716
import com.nextcloud.common.NextcloudClient;
@@ -54,7 +53,6 @@ public class ActivitiesActivity extends DrawerActivity implements ActivityListIn
5453
private long lastGiven;
5554
private boolean isLoadingActivities;
5655
private ActivitiesContract.ActionListener actionListener;
57-
private Snackbar snackbar;
5856

5957
@Inject ActivitiesRepository activitiesRepository;
6058
@Inject FilesRepository filesRepository;
@@ -191,7 +189,7 @@ public void showActivities(List<Object> activities, NextcloudClient client, long
191189
public void showActivitiesLoadError(String error) {
192190
connectivityService.isNetworkAndServerAvailable(result -> {
193191
if (result) {
194-
snackbar = DisplayUtils.showSnackMessage(this, error);
192+
DisplayUtils.showSnackMessage(this, error);
195193
} else {
196194
showEmptyContent(getString(R.string.server_not_reachable),
197195
getString(R.string.server_not_reachable_content));
@@ -217,12 +215,12 @@ public void showActivityDetailUI(OCFile ocFile) {
217215

218216
@Override
219217
public void showActivityDetailUIIsNull() {
220-
snackbar = DisplayUtils.showSnackMessage(this, R.string.file_not_found);
218+
DisplayUtils.showSnackMessage(this, R.string.file_not_found);
221219
}
222220

223221
@Override
224222
public void showActivityDetailError(String error) {
225-
snackbar = DisplayUtils.showSnackMessage(this, error);
223+
DisplayUtils.showSnackMessage(this, error);
226224
}
227225

228226
@Override
@@ -255,12 +253,4 @@ protected void onStop() {
255253

256254
actionListener.onStop();
257255
}
258-
259-
@VisibleForTesting
260-
public void dismissSnackbar() {
261-
if (snackbar != null && snackbar.isShown()) {
262-
snackbar.dismiss();
263-
snackbar = null;
264-
}
265-
}
266256
}

app/src/main/java/com/owncloud/android/utils/DisplayUtils.java

Lines changed: 46 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
import android.graphics.drawable.Drawable;
3636
import android.net.Uri;
3737
import android.os.AsyncTask;
38+
import android.os.Handler;
39+
import android.os.Looper;
3840
import android.text.Spannable;
3941
import android.text.SpannableStringBuilder;
4042
import android.text.TextUtils;
@@ -124,6 +126,7 @@ public final class DisplayUtils {
124126
public static final String MONTH_YEAR_PATTERN = "MMMM yyyy";
125127
public static final String MONTH_PATTERN = "MMMM";
126128
public static final String YEAR_PATTERN = "yyyy";
129+
private static final Handler mainLooper = new Handler(Looper.getMainLooper());
127130
public static final int SVG_SIZE = 512;
128131

129132
private static Map<String, String> mimeType2HumanReadable;
@@ -574,83 +577,69 @@ public static String getData(InputStream inputStream) {
574577
return text.toString();
575578
}
576579

577-
public static Snackbar showSnackMessage(Fragment fragment, @StringRes int messageResource) {
580+
// region snackbar
581+
public static void showSnackMessage(Fragment fragment, @StringRes int messageResource) {
578582
if (fragment == null) {
579-
return null;
583+
return;
580584
}
581585

582586
final var activity = fragment.getActivity();
583587
if (activity == null) {
584-
return null;
588+
return;
585589
}
586590

587-
return showSnackMessage(activity, messageResource);
591+
showSnackMessage(activity, messageResource);
588592
}
589593

590-
/**
591-
* Show a temporary message in a {@link Snackbar} bound to the content view.
592-
*
593-
* @param activity The {@link Activity} to which's content view the {@link Snackbar} is bound.
594-
* @param messageResource The resource id of the string resource to use. Can be formatted text.
595-
* @return The created {@link Snackbar}
596-
*/
597-
public static Snackbar showSnackMessage(Activity activity, @StringRes int messageResource) {
598-
return showSnackMessage(activity.findViewById(android.R.id.content), messageResource);
594+
public static void showSnackMessage(Activity activity, @StringRes int messageResource) {
595+
showSnackMessage(activity.findViewById(android.R.id.content), messageResource);
599596
}
600597

601-
/**
602-
* Show a temporary message in a {@link Snackbar} bound to the content view.
603-
*
604-
* @param activity The {@link Activity} to which's content view the {@link Snackbar} is bound.
605-
* @param message Message to show.
606-
* @return The created {@link Snackbar}
607-
*/
608-
public static Snackbar showSnackMessage(Activity activity, String message) {
609-
final Snackbar snackbar = Snackbar.make(activity.findViewById(android.R.id.content), message, Snackbar.LENGTH_LONG);
610-
var fab = findFABView(activity);
611-
if (fab != null && fab.getVisibility() == View.VISIBLE) {
612-
snackbar.setAnchorView(fab);
613-
}
614-
snackbar.show();
615-
return snackbar;
598+
public static void showSnackMessage(Activity activity, @StringRes int messageResource, Object... formatArgs) {
599+
showSnackMessage(activity, activity.findViewById(android.R.id.content), messageResource, formatArgs);
616600
}
617601

618-
private static View findFABView(Activity activity) {
619-
return activity.findViewById(R.id.fab_main);
602+
public static void showSnackMessage(Context context, View view, @StringRes int messageResource, Object... formatArgs) {
603+
final Snackbar snackbar = Snackbar.make(view, String.format(context.getString(messageResource, formatArgs)), Snackbar.LENGTH_LONG);
604+
snackbar.show();
620605
}
621606

622-
private static View findFABView(View view) {
623-
return view.findViewById(R.id.fab_main);
607+
public static void showSnackMessage(Activity activity, String message) {
608+
activity.runOnUiThread(() -> {
609+
final Snackbar snackbar = Snackbar.make(activity.findViewById(android.R.id.content), message, Snackbar.LENGTH_LONG);
610+
var fab = findFABView(activity);
611+
if (fab != null && fab.getVisibility() == View.VISIBLE) {
612+
snackbar.setAnchorView(fab);
613+
}
614+
snackbar.show();
615+
});
624616
}
625617

626-
/**
627-
* Show a temporary message in a {@link Snackbar} bound to the given view.
628-
*
629-
* @param view The view the {@link Snackbar} is bound to.
630-
* @param messageResource The resource id of the string resource to use. Can be formatted text.
631-
* @return The created {@link Snackbar}
632-
*/
633-
public static Snackbar showSnackMessage(View view, @StringRes int messageResource) {
618+
public static void showSnackMessage(View view, @StringRes int messageResource) {
634619
final Snackbar snackbar = Snackbar.make(view, messageResource, Snackbar.LENGTH_LONG);
635-
var fab = findFABView(view.getRootView());
636-
if (fab != null && fab.getVisibility() == View.VISIBLE) {
637-
snackbar.setAnchorView(fab);
638-
}
639-
snackbar.show();
640-
return snackbar;
620+
mainLooper.post(() -> {
621+
var fab = findFABView(view.getRootView());
622+
if (fab != null && fab.getVisibility() == View.VISIBLE) {
623+
snackbar.setAnchorView(fab);
624+
}
625+
snackbar.show();
626+
});
641627
}
642628

643-
/**
644-
* Show a temporary message in a {@link Snackbar} bound to the given view.
645-
*
646-
* @param view The view the {@link Snackbar} is bound to.
647-
* @param message The message.
648-
* @return The created {@link Snackbar}
649-
*/
650-
public static Snackbar showSnackMessage(View view, String message) {
651-
final Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_LONG);
652-
snackbar.show();
653-
return snackbar;
629+
public static void showSnackMessage(View view, String message) {
630+
mainLooper.post(() -> {
631+
final Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_LONG);
632+
snackbar.show();
633+
});
634+
}
635+
// endregion
636+
637+
private static View findFABView(Activity activity) {
638+
return activity.findViewById(R.id.fab_main);
639+
}
640+
641+
private static View findFABView(View view) {
642+
return view.findViewById(R.id.fab_main);
654643
}
655644

656645
/**
@@ -664,36 +653,6 @@ public static Snackbar createSnackbar(View view, @StringRes int messageResource,
664653
return Snackbar.make(view, messageResource, length);
665654
}
666655

667-
/**
668-
* Show a temporary message in a {@link Snackbar} bound to the content view.
669-
*
670-
* @param activity The {@link Activity} to which's content view the {@link Snackbar} is bound.
671-
* @param messageResource The resource id of the string resource to use. Can be formatted text.
672-
* @param formatArgs The format arguments that will be used for substitution.
673-
* @return The created {@link Snackbar}
674-
*/
675-
public static Snackbar showSnackMessage(Activity activity, @StringRes int messageResource, Object... formatArgs) {
676-
return showSnackMessage(activity, activity.findViewById(android.R.id.content), messageResource, formatArgs);
677-
}
678-
679-
/**
680-
* Show a temporary message in a {@link Snackbar} bound to the content view.
681-
*
682-
* @param context to load resources.
683-
* @param view The content view the {@link Snackbar} is bound to.
684-
* @param messageResource The resource id of the string resource to use. Can be formatted text.
685-
* @param formatArgs The format arguments that will be used for substitution.
686-
* @return The created {@link Snackbar}
687-
*/
688-
public static Snackbar showSnackMessage(Context context, View view, @StringRes int messageResource, Object... formatArgs) {
689-
final Snackbar snackbar = Snackbar.make(
690-
view,
691-
String.format(context.getString(messageResource, formatArgs)),
692-
Snackbar.LENGTH_LONG);
693-
snackbar
694-
.show();
695-
return snackbar;
696-
}
697656

698657
// Solution inspired by https://stackoverflow.com/questions/34936590/why-isnt-my-vector-drawable-scaling-as-expected
699658
// Copied from https://raw.githubusercontent.com/nextcloud/talk-android/8ec8606bc61878e87e3ac8ad32c8b72d4680013c/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java

0 commit comments

Comments
 (0)