Display errors with snackbars instead of toasts

This commit is contained in:
Shinokuni 2019-07-25 16:59:20 +02:00
parent 8a8e4394ce
commit 8c8d6d65c2
20 changed files with 121 additions and 61 deletions

View File

@ -3,7 +3,6 @@ package com.readrops.app.activities;
import android.content.Intent;
import android.os.Bundle;
import android.view.MenuItem;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
@ -13,6 +12,7 @@ import com.afollestad.materialdialogs.MaterialDialog;
import com.readrops.app.R;
import com.readrops.app.database.entities.Account;
import com.readrops.app.databinding.ActivityAccountSettingsBinding;
import com.readrops.app.utils.Utils;
import com.readrops.app.viewmodels.AccountViewModel;
import io.reactivex.android.schedulers.AndroidSchedulers;
@ -72,7 +72,7 @@ public class AccountSettingsActivity extends AppCompatActivity {
@Override
public void onError(Throwable e) {
Toast.makeText(AccountSettingsActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
Utils.showSnackbar(binding.accountSettingsRoot, e.getMessage());
}
})))
.show();

View File

@ -4,7 +4,6 @@ import android.content.Intent;
import android.os.Bundle;
import android.os.Parcelable;
import android.widget.LinearLayout;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
@ -15,6 +14,7 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import com.readrops.app.R;
import com.readrops.app.database.entities.Account;
import com.readrops.app.databinding.ActivityAccountTypeListBinding;
import com.readrops.app.utils.Utils;
import com.readrops.app.viewmodels.AccountViewModel;
import com.readrops.app.views.AccountTypeListAdapter;
@ -102,7 +102,7 @@ public class AccountTypeListActivity extends AppCompatActivity {
@Override
public void onError(Throwable e) {
Toast.makeText(AccountTypeListActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
Utils.showSnackbar(binding.accountTypeListRoot, e.getMessage());
}
});
}

View File

@ -14,6 +14,7 @@ import com.readrops.app.R;
import com.readrops.app.database.entities.Account;
import com.readrops.app.databinding.ActivityAddAccountBinding;
import com.readrops.app.utils.SharedPreferencesManager;
import com.readrops.app.utils.Utils;
import com.readrops.app.viewmodels.AccountViewModel;
import io.reactivex.CompletableObserver;
@ -92,7 +93,8 @@ public class AddAccountActivity extends AppCompatActivity {
public void onError(Throwable e) {
binding.addAccountLoading.setVisibility(View.GONE);
binding.addAccountValidate.setEnabled(true);
Toast.makeText(AddAccountActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
Utils.showSnackbar(binding.addAccountRoot, e.getMessage());
}
});
} else {
@ -142,7 +144,8 @@ public class AddAccountActivity extends AppCompatActivity {
public void onError(Throwable e) {
binding.addAccountLoading.setVisibility(View.GONE);
binding.addAccountValidate.setEnabled(true);
Toast.makeText(AddAccountActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
Utils.showSnackbar(binding.addAccountRoot, e.getMessage());
}
});
}

View File

@ -12,10 +12,10 @@ import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.widget.NestedScrollView;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
@ -50,6 +50,8 @@ public class AddFeedActivity extends AppCompatActivity implements View.OnClickLi
private RecyclerView parseResultsRecyclerView;
private TextView resultsTextView;
private NestedScrollView rootLayout;
private ProgressBar feedInsertionProgressBar;
private RecyclerView insertionResultsRecyclerView;
@ -78,6 +80,8 @@ public class AddFeedActivity extends AppCompatActivity implements View.OnClickLi
insertionResultsRecyclerView = findViewById(R.id.add_feed_inserted_results_recyclerview);
accountSpinner = findViewById(R.id.add_feed_account_spinner);
rootLayout = findViewById(R.id.add_feed_root);
load.setOnClickListener(this);
validate.setOnClickListener(this);
validate.setEnabled(false);
@ -232,7 +236,7 @@ public class AddFeedActivity extends AppCompatActivity implements View.OnClickLi
@Override
public void onError(Throwable e) {
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
Utils.showSnackbar(rootLayout, e.getMessage());
progressBar.setVisibility(View.GONE);
}
});
@ -276,7 +280,7 @@ public class AddFeedActivity extends AppCompatActivity implements View.OnClickLi
@Override
public void onError(Throwable e) {
Toast.makeText(AddFeedActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
Utils.showSnackbar(rootLayout, e.getMessage());
}
});
}

View File

@ -12,12 +12,12 @@ import android.view.View;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.lifecycle.ViewModelProviders;
import androidx.paging.PagedList;
@ -43,6 +43,7 @@ import com.readrops.app.database.pojo.ItemWithFeed;
import com.readrops.app.utils.DrawerManager;
import com.readrops.app.utils.GlideApp;
import com.readrops.app.utils.SharedPreferencesManager;
import com.readrops.app.utils.Utils;
import com.readrops.app.viewmodels.MainViewModel;
import com.readrops.app.views.MainItemListAdapter;
@ -71,6 +72,7 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
private RecyclerView recyclerView;
private MainItemListAdapter adapter;
private SwipeRefreshLayout refreshLayout;
private ConstraintLayout rootLayout;
private Toolbar toolbar;
private Drawer drawer;
@ -105,6 +107,7 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
emptyListLayout = findViewById(R.id.empty_list_layout);
refreshLayout = findViewById(R.id.swipe_refresh_layout);
refreshLayout.setOnRefreshListener(this);
rootLayout = findViewById(R.id.main_root);
syncProgressLayout = findViewById(R.id.sync_progress_layout);
syncProgress = findViewById(R.id.sync_progress_text_view);
@ -230,7 +233,7 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
@Override
public void onError(Throwable e) {
Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
Utils.showSnackbar(rootLayout, e.getMessage());
}
});
}
@ -262,8 +265,7 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
!itemWithFeed.getItem().isReadChanged())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnError(throwable -> Toast.makeText(getApplicationContext(),
"Error when updating in db", Toast.LENGTH_LONG).show())
.doOnError(throwable -> Utils.showSnackbar(rootLayout, throwable.getMessage()))
.subscribe();
itemWithFeed.getItem().setRead(true);
@ -379,6 +381,7 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
!itemWithFeed.getItem().isReadChanged())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnError(throwable -> Utils.showSnackbar(rootLayout, throwable.getMessage()))
.subscribe();
itemWithFeed.getItem().setRead(!itemWithFeed.getItem().isRead());
@ -388,6 +391,7 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
viewModel.setItemReadItLater((int) adapter.getItemId(viewHolder.getAdapterPosition()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnError(throwable -> Utils.showSnackbar(rootLayout, throwable.getMessage()))
.subscribe();
if (viewModel.getFilterType() == MainViewModel.FilterType.READ_IT_LATER_FILTER)
@ -426,6 +430,7 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
viewModel.setAllItemsReadState(read)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnError(throwable -> Utils.showSnackbar(rootLayout, throwable.getMessage()))
.subscribe();
allItemsSelected = false;
@ -433,8 +438,7 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
viewModel.setItemsReadState(adapter.getSelectedItems(), read)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnError(throwable -> Toast.makeText(getApplicationContext(),
"Error when updating in db", Toast.LENGTH_LONG).show())
.doOnError(throwable -> Utils.showSnackbar(rootLayout, throwable.getMessage()))
.subscribe();
}
@ -461,7 +465,7 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
@Override
public void onError(Throwable e) {
Toast.makeText(getApplicationContext(), "error on getting feeds number", Toast.LENGTH_LONG).show();
Utils.showSnackbar(rootLayout, e.getMessage());
}
});
}
@ -550,7 +554,8 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
e.printStackTrace();
refreshLayout.setRefreshing(false);
syncProgressLayout.setVisibility(View.GONE);
Toast.makeText(getApplication(), e.getMessage(), Toast.LENGTH_LONG).show();
Utils.showSnackbar(rootLayout, e.getMessage());
}
@Override
@ -617,7 +622,7 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
int index = viewModel.getSortType() == ListSortType.OLDEST_TO_NEWEST ? 1 : 0;
new MaterialDialog.Builder(this)
.title(getString(R.string.filter))
.title(R.string.filter)
.items(R.array.filter_items)
.itemsCallbackSingleChoice(index, (dialog, itemView, which, text) -> {
String[] items = getResources().getStringArray(R.array.filter_items);

View File

@ -4,7 +4,6 @@ import android.graphics.Color;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
@ -22,10 +21,12 @@ import com.readrops.app.database.entities.Folder;
import com.readrops.app.databinding.ActivityManageFeedsFoldersBinding;
import com.readrops.app.fragments.FeedsFragment;
import com.readrops.app.fragments.FoldersFragment;
import com.readrops.app.utils.Utils;
import com.readrops.app.viewmodels.ManageFeedsFoldersViewModel;
import com.readrops.readropslibrary.utils.ConflictException;
import com.readrops.readropslibrary.utils.UnknownFormatException;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.observers.DisposableCompletableObserver;
import io.reactivex.schedulers.Schedulers;
public class ManageFeedsFoldersActivity extends AppCompatActivity {
@ -113,17 +114,18 @@ public class ManageFeedsFoldersActivity extends AppCompatActivity {
viewModel.addFolder(folder)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableCompletableObserver() {
@Override
public void onComplete() {
Toast.makeText(getApplicationContext(), "folder inserted", Toast.LENGTH_LONG).show();
}
.doOnError(throwable -> {
String message;
if (throwable instanceof ConflictException)
message = getString(R.string.folder_already_exists);
else if (throwable instanceof UnknownFormatException)
message = getString(R.string.folder_bad_format);
else
message = getString(R.string.error_occured);
@Override
public void onError(Throwable e) {
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
});
Utils.showSnackbar(binding.manageFeedsFoldersRoot, message);
})
.subscribe();
})
.show();
}

View File

@ -2,7 +2,6 @@ package com.readrops.app.activities;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProviders;
@ -45,7 +44,7 @@ public class SplashActivity extends AppCompatActivity {
@Override
public void onError(Throwable e) {
Toast.makeText(SplashActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
}
});
}

View File

@ -2,13 +2,13 @@ package com.readrops.app.fragments;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.os.Vibrator;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -28,6 +28,7 @@ import com.readrops.app.database.entities.Feed;
import com.readrops.app.database.pojo.FeedWithFolder;
import com.readrops.app.databinding.FragmentFeedsBinding;
import com.readrops.app.utils.SharedPreferencesManager;
import com.readrops.app.utils.Utils;
import com.readrops.app.viewmodels.ManageFeedsFoldersViewModel;
import com.readrops.app.views.EditFeedDialog;
import com.readrops.app.views.FeedsAdapter;
@ -151,13 +152,21 @@ public class FeedsFragment extends Fragment {
.subscribe(new DisposableCompletableObserver() {
@Override
public void onComplete() {
Toast.makeText(getContext(), "feed deleted", Toast.LENGTH_LONG).show();
Utils.showSnackbar(binding.feedsRoot,
getString(R.string.feed_deleted, feed.getName()));
}
@Override
public void onError(Throwable e) {
adapter.notifyItemChanged(position);
Toast.makeText(getContext(), "error on feed deletion", Toast.LENGTH_LONG).show();
String message;
if (e instanceof Resources.NotFoundException)
message = getString(R.string.feed_doesnt_exist, feed.getName());
else
message = getString(R.string.error_occured);
Utils.showSnackbar(binding.feedsRoot, message);
}
}))
.onNegative(((dialog, which) -> adapter.notifyItemChanged(position)))

View File

@ -1,11 +1,11 @@
package com.readrops.app.fragments;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -23,11 +23,13 @@ import com.readrops.app.database.entities.Account;
import com.readrops.app.database.entities.Folder;
import com.readrops.app.databinding.FragmentFoldersBinding;
import com.readrops.app.utils.SharedPreferencesManager;
import com.readrops.app.utils.Utils;
import com.readrops.app.viewmodels.ManageFeedsFoldersViewModel;
import com.readrops.app.views.FoldersAdapter;
import com.readrops.readropslibrary.utils.ConflictException;
import com.readrops.readropslibrary.utils.UnknownFormatException;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.observers.DisposableCompletableObserver;
import io.reactivex.schedulers.Schedulers;
public class FoldersFragment extends Fragment {
@ -108,17 +110,20 @@ public class FoldersFragment extends Fragment {
viewModel.updateFolder(folder)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableCompletableObserver() {
@Override
public void onComplete() {
.doOnError(throwable -> {
String message;
if (throwable instanceof ConflictException)
message = getString(R.string.folder_already_exists);
else if (throwable instanceof UnknownFormatException)
message = getString(R.string.folder_bad_format);
else if (throwable instanceof Resources.NotFoundException)
message = getString(R.string.folder_doesnt_exist);
else
message = getString(R.string.error_occured);
}
@Override
public void onError(Throwable e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
}
});
Utils.showSnackbar(binding.foldersRoot, message);
})
.subscribe();
})
.show();
}
@ -131,17 +136,16 @@ public class FoldersFragment extends Fragment {
.onPositive((dialog, which) -> viewModel.deleteFolder(folder)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableCompletableObserver() {
@Override
public void onComplete() {
.doOnError(throwable -> {
String message;
if (throwable instanceof Resources.NotFoundException)
message = getString(R.string.folder_doesnt_exist);
else
message = throwable.getMessage();
}
@Override
public void onError(Throwable e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
}
}))
Utils.showSnackbar(binding.foldersRoot, message);
})
.subscribe())
.onNegative((dialog, which) -> adapter.notifyItemChanged(position))
.show();
}

View File

@ -10,10 +10,13 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.util.DisplayMetrics;
import android.view.View;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import com.google.android.material.snackbar.Snackbar;
import java.io.InputStream;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
@ -90,4 +93,16 @@ public final class Utils {
return drawable;
}
public static void showSnackBarWithAction(View root, String message, String action, View.OnClickListener listener) {
Snackbar snackbar = Snackbar.make(root, message, Snackbar.LENGTH_LONG);
snackbar.setAction(action, listener);
snackbar.show();
}
public static void showSnackbar(View root, String message) {
Snackbar snackbar = Snackbar.make(root, message, Snackbar.LENGTH_LONG);
snackbar.show();
}
}

View File

@ -5,6 +5,7 @@
tools:context=".activities.AccountSettingsActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/account_settings_root"
android:layout_width="match_parent"
android:layout_height="match_parent">

View File

@ -5,6 +5,7 @@
tools:context=".activities.AccountTypeListActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/account_type_list_root"
android:layout_width="match_parent"
android:layout_height="match_parent">

View File

@ -5,6 +5,7 @@
tools:context=".activities.AddAccountActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/add_account_root"
android:layout_width="match_parent"
android:layout_height="match_parent">

View File

@ -2,6 +2,7 @@
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/add_feed_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.AddFeedActivity">

View File

@ -2,6 +2,7 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.MainActivity">
@ -19,7 +20,6 @@
android:background="?attr/colorPrimary"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
<RelativeLayout
android:id="@+id/sync_progress_layout"
android:layout_width="match_parent"
@ -71,8 +71,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
tools:listitem="@layout/image_item"
tools:itemCount="3"
tools:listitem="@layout/image_item"
tools:visibility="visible" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
@ -113,9 +113,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:onClick="openAddFeedActivity"
android:src="@drawable/ic_add_white"
android:layout_margin="16dp"/>
android:src="@drawable/ic_add_white" />
</FrameLayout>

View File

@ -5,6 +5,7 @@
tools:context=".activities.ManageFeedsFoldersActivity">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/manage_feeds_folders_root"
android:layout_width="match_parent"
android:layout_height="match_parent">

View File

@ -4,6 +4,7 @@
tools:context=".fragments.FeedsFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/feeds_root"
android:layout_width="match_parent"
android:layout_height="match_parent">

View File

@ -4,6 +4,7 @@
tools:context=".fragments.FoldersFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/folders_root"
android:layout_width="match_parent"
android:layout_height="match_parent">

View File

@ -68,5 +68,11 @@
<string name="delete_folder">Supprimer le dossier ?</string>
<string name="delete_account">Supprimer le compte</string>
<string name="delete_account_question">Supprimer le compte ?</string>
<string name="feed_deleted">Le flux %1$s a été supprimé</string>
<string name="feed_doesnt_exist">Le flux %1$s n\'existe pas sur le serveur</string>
<string name="error_occured">Une erreur s\'est produite</string>
<string name="folder_already_exists">Le dossier existe déjà</string>
<string name="folder_bad_format">Mauvais format pour le nouveau dossier</string>
<string name="folder_doesnt_exist">Le dossier n\'existe pas sur le serveur</string>
</resources>

View File

@ -73,4 +73,10 @@
<string name="delete_folder">Delete folder ?</string>
<string name="delete_account">Delete account</string>
<string name="delete_account_question">Delete account ?</string>
<string name="feed_deleted">The feed %1$s has been deleted</string>
<string name="feed_doesnt_exist">The feed %1$s doesn\'t exist on the server</string>
<string name="error_occured">An error occured</string>
<string name="folder_already_exists">The folder already exists</string>
<string name="folder_bad_format">Bad format for the new folder</string>
<string name="folder_doesnt_exist">The folder doesn\'t exist on the server</string>
</resources>