Adds removing a monster from the dashboard via long press.
This commit is contained in:
@@ -21,8 +21,6 @@ import androidx.navigation.fragment.NavHostFragment;
|
|||||||
import androidx.navigation.ui.AppBarConfiguration;
|
import androidx.navigation.ui.AppBarConfiguration;
|
||||||
import androidx.navigation.ui.NavigationUI;
|
import androidx.navigation.ui.NavigationUI;
|
||||||
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.majinnaibu.monstercards.helpers.MonsterImportHelper;
|
import com.majinnaibu.monstercards.helpers.MonsterImportHelper;
|
||||||
@@ -31,6 +29,7 @@ import com.majinnaibu.monstercards.importers.BinderImporter;
|
|||||||
import com.majinnaibu.monstercards.importers.DnDBeyondImporter;
|
import com.majinnaibu.monstercards.importers.DnDBeyondImporter;
|
||||||
import com.majinnaibu.monstercards.init.AppCenterInitializer;
|
import com.majinnaibu.monstercards.init.AppCenterInitializer;
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
import com.majinnaibu.monstercards.utils.Logger;
|
||||||
|
import com.majinnaibu.monstercards.utils.ToastHelper;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -141,24 +140,24 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
public void importMonsterFromInputAndNavigate(@NonNull String input) {
|
public void importMonsterFromInputAndNavigate(@NonNull String input) {
|
||||||
BinderImporter binderImporter = new BinderImporter();
|
BinderImporter binderImporter = new BinderImporter();
|
||||||
if (binderImporter.canImport(input)) {
|
if (binderImporter.canImport(input)) {
|
||||||
Toast.makeText(this, R.string.toast_importing_url, Toast.LENGTH_SHORT).show();
|
ToastHelper.showShort(this, R.string.toast_importing_url);
|
||||||
Single.fromCallable(() -> binderImporter.parse(input))
|
Single.fromCallable(() -> binderImporter.parse(input))
|
||||||
.flatMapCompletable(binder -> ((MonsterCardsApplication) getApplication()).getMonsterRepository().importBinder(binder))
|
.flatMapCompletable(binder -> ((MonsterCardsApplication) getApplication()).getMonsterRepository().importBinder(binder))
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(() -> {
|
.subscribe(() -> {
|
||||||
Toast.makeText(this, R.string.snackbar_import_binder_success, Toast.LENGTH_LONG).show();
|
ToastHelper.showLong(this, R.string.snackbar_import_binder_success);
|
||||||
NavHostFragment navHostFragment = Objects.requireNonNull((NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment));
|
NavHostFragment navHostFragment = Objects.requireNonNull((NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment));
|
||||||
NavController navController = navHostFragment.getNavController();
|
NavController navController = navHostFragment.getNavController();
|
||||||
navController.navigate(R.id.navigation_library);
|
navController.navigate(R.id.navigation_library);
|
||||||
}, throwable -> {
|
}, throwable -> {
|
||||||
Logger.logError("Failed to import binder from input", throwable);
|
Logger.logError("Failed to import binder from input", throwable);
|
||||||
Toast.makeText(this, R.string.failed_to_import_url, Toast.LENGTH_LONG).show();
|
ToastHelper.showLong(this, R.string.failed_to_import_url);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Toast.makeText(this, R.string.toast_importing_url, Toast.LENGTH_SHORT).show();
|
ToastHelper.showShort(this, R.string.toast_importing_url);
|
||||||
Single.fromCallable(() -> MonsterImportHelper.fromJSON(input))
|
Single.fromCallable(() -> MonsterImportHelper.fromJSON(input))
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
@@ -170,7 +169,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
navController.navigate(navAction);
|
navController.navigate(navAction);
|
||||||
}, throwable -> {
|
}, throwable -> {
|
||||||
Logger.logError("Failed to import monster from input", throwable);
|
Logger.logError("Failed to import monster from input", throwable);
|
||||||
Toast.makeText(this, R.string.failed_to_import_url, Toast.LENGTH_LONG).show();
|
ToastHelper.showLong(this, R.string.failed_to_import_url);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ package com.majinnaibu.monstercards.data;
|
|||||||
import androidx.room.Dao;
|
import androidx.room.Dao;
|
||||||
import androidx.room.Insert;
|
import androidx.room.Insert;
|
||||||
import androidx.room.Query;
|
import androidx.room.Query;
|
||||||
|
import androidx.room.Transaction;
|
||||||
import androidx.room.Update;
|
import androidx.room.Update;
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.models.DashboardMonster;
|
import com.majinnaibu.monstercards.models.DashboardMonster;
|
||||||
|
import com.majinnaibu.monstercards.models.DashboardMonsterWithMonster;
|
||||||
import com.majinnaibu.monstercards.models.Monster;
|
import com.majinnaibu.monstercards.models.Monster;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -19,6 +21,10 @@ public interface DashboardDAO {
|
|||||||
@Query("SELECT monsters.* FROM monsters INNER JOIN dashboard_monsters ON monsters.id = dashboard_monsters.monster_id ORDER BY dashboard_monsters.ordinal ASC, dashboard_monsters.id ASC")
|
@Query("SELECT monsters.* FROM monsters INNER JOIN dashboard_monsters ON monsters.id = dashboard_monsters.monster_id ORDER BY dashboard_monsters.ordinal ASC, dashboard_monsters.id ASC")
|
||||||
Flowable<List<Monster>> getDashboardMonsters();
|
Flowable<List<Monster>> getDashboardMonsters();
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
@Query("SELECT * FROM dashboard_monsters ORDER BY ordinal ASC, id ASC")
|
||||||
|
Flowable<List<DashboardMonsterWithMonster>> getDashboardMonstersWithMonster();
|
||||||
|
|
||||||
@Query("SELECT * FROM dashboard_monsters ORDER BY ordinal ASC, id ASC")
|
@Query("SELECT * FROM dashboard_monsters ORDER BY ordinal ASC, id ASC")
|
||||||
Flowable<List<DashboardMonster>> getDashboardMonsterEntries();
|
Flowable<List<DashboardMonster>> getDashboardMonsterEntries();
|
||||||
|
|
||||||
@@ -28,9 +34,12 @@ public interface DashboardDAO {
|
|||||||
@Query("DELETE FROM dashboard_monsters WHERE id = :id")
|
@Query("DELETE FROM dashboard_monsters WHERE id = :id")
|
||||||
Completable removeDashboardMonsterById(long id);
|
Completable removeDashboardMonsterById(long id);
|
||||||
|
|
||||||
@Query("DELETE FROM dashboard_monsters WHERE monster_id = :monsterId")
|
@Query("DELETE FROM dashboard_monsters WHERE id = (SELECT id FROM dashboard_monsters WHERE monster_id = :monsterId LIMIT 1)")
|
||||||
Completable removeMonsterFromDashboard(String monsterId);
|
Completable removeMonsterFromDashboard(String monsterId);
|
||||||
|
|
||||||
|
@Query("DELETE FROM dashboard_monsters WHERE monster_id = :monsterId")
|
||||||
|
Completable removeAllMonstersFromDashboard(String monsterId);
|
||||||
|
|
||||||
@Query("DELETE FROM dashboard_monsters")
|
@Query("DELETE FROM dashboard_monsters")
|
||||||
Completable clearDashboard();
|
Completable clearDashboard();
|
||||||
|
|
||||||
|
|||||||
@@ -208,6 +208,13 @@ public class MonsterRepository {
|
|||||||
.observeOn(AndroidSchedulers.mainThread());
|
.observeOn(AndroidSchedulers.mainThread());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Flowable<List<com.majinnaibu.monstercards.models.DashboardMonsterWithMonster>> getDashboardMonstersWithMonster() {
|
||||||
|
return m_db.dashboardDAO()
|
||||||
|
.getDashboardMonstersWithMonster()
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread());
|
||||||
|
}
|
||||||
|
|
||||||
public Flowable<List<DashboardMonster>> getDashboardMonsterEntries() {
|
public Flowable<List<DashboardMonster>> getDashboardMonsterEntries() {
|
||||||
return m_db.dashboardDAO()
|
return m_db.dashboardDAO()
|
||||||
.getDashboardMonsterEntries()
|
.getDashboardMonsterEntries()
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.majinnaibu.monstercards.models;
|
||||||
|
|
||||||
|
import androidx.room.Embedded;
|
||||||
|
import androidx.room.Relation;
|
||||||
|
|
||||||
|
public class DashboardMonsterWithMonster {
|
||||||
|
@Embedded
|
||||||
|
public DashboardMonster dashboardEntry;
|
||||||
|
|
||||||
|
@Relation(
|
||||||
|
parentColumn = "monster_id",
|
||||||
|
entityColumn = "id"
|
||||||
|
)
|
||||||
|
public Monster monster;
|
||||||
|
|
||||||
|
public DashboardMonsterWithMonster() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public DashboardMonsterWithMonster(DashboardMonster dashboardEntry, Monster monster) {
|
||||||
|
this.dashboardEntry = dashboardEntry;
|
||||||
|
this.monster = monster;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,15 +21,18 @@ import androidx.recyclerview.widget.GridLayoutManager;
|
|||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
|
||||||
import com.majinnaibu.monstercards.R;
|
import com.majinnaibu.monstercards.R;
|
||||||
import com.majinnaibu.monstercards.data.MonsterRepository;
|
import com.majinnaibu.monstercards.data.MonsterRepository;
|
||||||
import com.majinnaibu.monstercards.models.Collection;
|
import com.majinnaibu.monstercards.models.Collection;
|
||||||
|
import com.majinnaibu.monstercards.models.DashboardMonster;
|
||||||
|
import com.majinnaibu.monstercards.models.DashboardMonsterWithMonster;
|
||||||
import com.majinnaibu.monstercards.models.Monster;
|
import com.majinnaibu.monstercards.models.Monster;
|
||||||
import com.majinnaibu.monstercards.ui.dashboard.DashboardRecyclerViewAdapter;
|
import com.majinnaibu.monstercards.ui.dashboard.DashboardRecyclerViewAdapter;
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
import com.majinnaibu.monstercards.utils.Logger;
|
||||||
|
import com.majinnaibu.monstercards.utils.SnackbarHelper;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@@ -80,7 +83,15 @@ public class CollectionDetailFragment extends MCFragment {
|
|||||||
|
|
||||||
mViewModel.getMonsters().observe(getViewLifecycleOwner(), monsters -> {
|
mViewModel.getMonsters().observe(getViewLifecycleOwner(), monsters -> {
|
||||||
if (mAdapter != null) {
|
if (mAdapter != null) {
|
||||||
mAdapter.submitList(monsters);
|
List<DashboardMonsterWithMonster> items = new ArrayList<>();
|
||||||
|
if (monsters != null) {
|
||||||
|
for (int i = 0; i < monsters.size(); i++) {
|
||||||
|
DashboardMonster dm = new DashboardMonster(monsters.get(i).id, i);
|
||||||
|
dm.id = i + 1;
|
||||||
|
items.add(new DashboardMonsterWithMonster(dm, monsters.get(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mAdapter.submitList(items);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -113,9 +124,9 @@ public class CollectionDetailFragment extends MCFragment {
|
|||||||
GridLayoutManager layoutManager = new GridLayoutManager(context, columnCount);
|
GridLayoutManager layoutManager = new GridLayoutManager(context, columnCount);
|
||||||
recyclerView.setLayoutManager(layoutManager);
|
recyclerView.setLayoutManager(layoutManager);
|
||||||
|
|
||||||
mAdapter = new DashboardRecyclerViewAdapter(monster -> {
|
mAdapter = new DashboardRecyclerViewAdapter(item -> {
|
||||||
if (monster != null) {
|
if (item != null && item.monster != null) {
|
||||||
navigateToMonsterDetail(monster.id);
|
navigateToMonsterDetail(item.monster.id);
|
||||||
} else {
|
} else {
|
||||||
Logger.logError("Can't navigate to MonsterDetailFragment with a null monster");
|
Logger.logError("Can't navigate to MonsterDetailFragment with a null monster");
|
||||||
}
|
}
|
||||||
@@ -133,7 +144,7 @@ public class CollectionDetailFragment extends MCFragment {
|
|||||||
if (monsters.isEmpty()) {
|
if (monsters.isEmpty()) {
|
||||||
View view = getView();
|
View view = getView();
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
Snackbar.make(view, getString(R.string.snackbar_failed_to_create_monster), Snackbar.LENGTH_LONG).show();
|
SnackbarHelper.showLong(view, getString(R.string.snackbar_failed_to_create_monster));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -162,11 +173,7 @@ public class CollectionDetailFragment extends MCFragment {
|
|||||||
if (view != null) {
|
if (view != null) {
|
||||||
Collection collection = mViewModel.getCollection().getValue();
|
Collection collection = mViewModel.getCollection().getValue();
|
||||||
String collectionName = collection != null ? collection.name : "";
|
String collectionName = collection != null ? collection.name : "";
|
||||||
Snackbar.make(
|
SnackbarHelper.showLong(view, getString(R.string.snackbar_monster_added_to_collection, monster.name, collectionName));
|
||||||
view,
|
|
||||||
getString(R.string.snackbar_monster_added_to_collection, monster.name, collectionName),
|
|
||||||
Snackbar.LENGTH_LONG)
|
|
||||||
.show();
|
|
||||||
}
|
}
|
||||||
}, Logger::logError));
|
}, Logger::logError));
|
||||||
}
|
}
|
||||||
@@ -219,7 +226,7 @@ public class CollectionDetailFragment extends MCFragment {
|
|||||||
if (view != null) {
|
if (view != null) {
|
||||||
Collection collection = mViewModel.getCollection().getValue();
|
Collection collection = mViewModel.getCollection().getValue();
|
||||||
String collectionName = collection != null ? collection.name : "";
|
String collectionName = collection != null ? collection.name : "";
|
||||||
Snackbar.make(view, getString(R.string.snackbar_collection_added_to_dashboard, collectionName), Snackbar.LENGTH_LONG).show();
|
SnackbarHelper.showLong(view, getString(R.string.snackbar_collection_added_to_dashboard, collectionName));
|
||||||
}
|
}
|
||||||
}, Logger::logError));
|
}, Logger::logError));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,13 +20,13 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
|||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
|
||||||
import com.majinnaibu.monstercards.R;
|
import com.majinnaibu.monstercards.R;
|
||||||
import com.majinnaibu.monstercards.data.MonsterRepository;
|
import com.majinnaibu.monstercards.data.MonsterRepository;
|
||||||
import com.majinnaibu.monstercards.models.Collection;
|
import com.majinnaibu.monstercards.models.Collection;
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
||||||
import com.majinnaibu.monstercards.ui.shared.SwipeToDeleteCallback;
|
import com.majinnaibu.monstercards.ui.shared.SwipeToDeleteCallback;
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
import com.majinnaibu.monstercards.utils.Logger;
|
||||||
|
import com.majinnaibu.monstercards.utils.SnackbarHelper;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@@ -150,10 +150,7 @@ public class CollectionsFragment extends MCFragment {
|
|||||||
public void onComplete() {
|
public void onComplete() {
|
||||||
View view = getView();
|
View view = getView();
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
Snackbar.make(
|
SnackbarHelper.makeLong(view, getString(R.string.snackbar_collection_created, collection.name))
|
||||||
view,
|
|
||||||
getString(R.string.snackbar_collection_created, collection.name),
|
|
||||||
Snackbar.LENGTH_LONG)
|
|
||||||
.setAction("View", v -> navigateToCollectionDetail(collection.id))
|
.setAction("View", v -> navigateToCollectionDetail(collection.id))
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
@@ -164,7 +161,7 @@ public class CollectionsFragment extends MCFragment {
|
|||||||
Logger.logError("Error creating collection", e);
|
Logger.logError("Error creating collection", e);
|
||||||
View view = getView();
|
View view = getView();
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
Snackbar.make(view, getString(R.string.snackbar_failed_to_create_collection), Snackbar.LENGTH_LONG).show();
|
SnackbarHelper.showLong(view, getString(R.string.snackbar_failed_to_create_collection));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,13 +21,13 @@ import androidx.recyclerview.widget.ItemTouchHelper;
|
|||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
|
||||||
import com.majinnaibu.monstercards.R;
|
import com.majinnaibu.monstercards.R;
|
||||||
import com.majinnaibu.monstercards.data.MonsterRepository;
|
import com.majinnaibu.monstercards.data.MonsterRepository;
|
||||||
import com.majinnaibu.monstercards.models.Collection;
|
import com.majinnaibu.monstercards.models.Collection;
|
||||||
import com.majinnaibu.monstercards.models.Monster;
|
import com.majinnaibu.monstercards.models.Monster;
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
import com.majinnaibu.monstercards.utils.Logger;
|
||||||
|
import com.majinnaibu.monstercards.utils.SnackbarHelper;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -69,7 +69,7 @@ public class DashboardFragment extends MCFragment {
|
|||||||
|
|
||||||
private void loadDashboardMonsters() {
|
private void loadDashboardMonsters() {
|
||||||
MonsterRepository repository = getMonsterRepository();
|
MonsterRepository repository = getMonsterRepository();
|
||||||
mDisposables.add(repository.getDashboardMonsters()
|
mDisposables.add(repository.getDashboardMonstersWithMonster()
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(monsters -> mViewModel.setMonsters(monsters), Logger::logError));
|
.subscribe(monsters -> mViewModel.setMonsters(monsters), Logger::logError));
|
||||||
@@ -82,14 +82,21 @@ public class DashboardFragment extends MCFragment {
|
|||||||
GridLayoutManager layoutManager = new GridLayoutManager(context, columnCount);
|
GridLayoutManager layoutManager = new GridLayoutManager(context, columnCount);
|
||||||
recyclerView.setLayoutManager(layoutManager);
|
recyclerView.setLayoutManager(layoutManager);
|
||||||
|
|
||||||
LiveData<List<Monster>> monsterData = mViewModel.getMonsters();
|
LiveData<List<com.majinnaibu.monstercards.models.DashboardMonsterWithMonster>> monsterData = mViewModel.getMonsters();
|
||||||
mAdapter = new DashboardRecyclerViewAdapter(monster -> {
|
mAdapter = new DashboardRecyclerViewAdapter(
|
||||||
if (monster != null) {
|
item -> {
|
||||||
navigateToMonsterDetail(monster);
|
if (item != null && item.monster != null) {
|
||||||
|
navigateToMonsterDetail(item.monster);
|
||||||
} else {
|
} else {
|
||||||
Logger.logError("Can't navigate to MonsterDetailFragment with a null monster");
|
Logger.logError("Can't navigate to MonsterDetailFragment with a null monster");
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
item -> {
|
||||||
|
if (item != null) {
|
||||||
|
showCardOptionsMenu(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
if (monsterData != null) {
|
if (monsterData != null) {
|
||||||
monsterData.observe(getViewLifecycleOwner(), monsters -> {
|
monsterData.observe(getViewLifecycleOwner(), monsters -> {
|
||||||
mAdapter.submitList(monsters);
|
mAdapter.submitList(monsters);
|
||||||
@@ -113,9 +120,9 @@ public class DashboardFragment extends MCFragment {
|
|||||||
int fromPos = viewHolder.getAdapterPosition();
|
int fromPos = viewHolder.getAdapterPosition();
|
||||||
int toPos = target.getAdapterPosition();
|
int toPos = target.getAdapterPosition();
|
||||||
if (fromPos != RecyclerView.NO_POSITION && toPos != RecyclerView.NO_POSITION) {
|
if (fromPos != RecyclerView.NO_POSITION && toPos != RecyclerView.NO_POSITION) {
|
||||||
List<Monster> currentList = new ArrayList<>(mAdapter.getCurrentList());
|
List<com.majinnaibu.monstercards.models.DashboardMonsterWithMonster> currentList = new ArrayList<>(mAdapter.getCurrentList());
|
||||||
if (fromPos < currentList.size() && toPos < currentList.size()) {
|
if (fromPos < currentList.size() && toPos < currentList.size()) {
|
||||||
Monster moved = currentList.remove(fromPos);
|
com.majinnaibu.monstercards.models.DashboardMonsterWithMonster moved = currentList.remove(fromPos);
|
||||||
currentList.add(toPos, moved);
|
currentList.add(toPos, moved);
|
||||||
mAdapter.submitList(currentList);
|
mAdapter.submitList(currentList);
|
||||||
}
|
}
|
||||||
@@ -127,10 +134,10 @@ public class DashboardFragment extends MCFragment {
|
|||||||
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
|
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
|
||||||
int position = viewHolder.getAdapterPosition();
|
int position = viewHolder.getAdapterPosition();
|
||||||
if (position != RecyclerView.NO_POSITION) {
|
if (position != RecyclerView.NO_POSITION) {
|
||||||
List<Monster> currentList = mAdapter.getCurrentList();
|
List<com.majinnaibu.monstercards.models.DashboardMonsterWithMonster> currentList = mAdapter.getCurrentList();
|
||||||
if (position < currentList.size()) {
|
if (position < currentList.size()) {
|
||||||
Monster monster = currentList.get(position);
|
com.majinnaibu.monstercards.models.DashboardMonsterWithMonster item = currentList.get(position);
|
||||||
removeMonsterFromDashboard(monster);
|
removeDashboardMonsterEntry(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,6 +149,7 @@ public class DashboardFragment extends MCFragment {
|
|||||||
String[] options = new String[]{
|
String[] options = new String[]{
|
||||||
getString(R.string.action_add_single_monster),
|
getString(R.string.action_add_single_monster),
|
||||||
getString(R.string.action_add_collection_option),
|
getString(R.string.action_add_collection_option),
|
||||||
|
getString(R.string.action_remove_single_monster),
|
||||||
getString(R.string.action_clear_dashboard)
|
getString(R.string.action_clear_dashboard)
|
||||||
};
|
};
|
||||||
new AlertDialog.Builder(requireContext())
|
new AlertDialog.Builder(requireContext())
|
||||||
@@ -152,6 +160,8 @@ public class DashboardFragment extends MCFragment {
|
|||||||
} else if (which == 1) {
|
} else if (which == 1) {
|
||||||
showAddCollectionPicker();
|
showAddCollectionPicker();
|
||||||
} else if (which == 2) {
|
} else if (which == 2) {
|
||||||
|
showRemoveMonsterPicker();
|
||||||
|
} else if (which == 3) {
|
||||||
clearDashboard();
|
clearDashboard();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -159,6 +169,68 @@ public class DashboardFragment extends MCFragment {
|
|||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showRemoveMonsterPicker() {
|
||||||
|
MonsterRepository repository = getMonsterRepository();
|
||||||
|
mDisposables.add(repository.getDashboardMonsters()
|
||||||
|
.firstOrError()
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(monsters -> {
|
||||||
|
if (monsters.isEmpty()) {
|
||||||
|
View view = getView();
|
||||||
|
if (view != null) {
|
||||||
|
SnackbarHelper.showLong(view, getString(R.string.snackbar_dashboard_already_empty));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String[] names = new String[monsters.size()];
|
||||||
|
for (int i = 0; i < monsters.size(); i++) {
|
||||||
|
names[i] = monsters.get(i).name;
|
||||||
|
}
|
||||||
|
new AlertDialog.Builder(requireContext())
|
||||||
|
.setTitle(R.string.action_remove_single_monster)
|
||||||
|
.setItems(names, (dialog, which) -> {
|
||||||
|
Monster selected = monsters.get(which);
|
||||||
|
removeMonsterFromDashboard(selected);
|
||||||
|
})
|
||||||
|
.setNegativeButton(R.string.dialog_cancel, null)
|
||||||
|
.show();
|
||||||
|
}, Logger::logError));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showCardOptionsMenu(@NonNull com.majinnaibu.monstercards.models.DashboardMonsterWithMonster item) {
|
||||||
|
String[] options = new String[]{
|
||||||
|
getString(R.string.action_view_details),
|
||||||
|
getString(R.string.action_remove_from_dashboard)
|
||||||
|
};
|
||||||
|
new AlertDialog.Builder(requireContext())
|
||||||
|
.setTitle(item.monster.name)
|
||||||
|
.setItems(options, (dialog, which) -> {
|
||||||
|
if (which == 0) {
|
||||||
|
navigateToMonsterDetail(item.monster);
|
||||||
|
} else if (which == 1) {
|
||||||
|
removeDashboardMonsterEntry(item);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(R.string.dialog_cancel, null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeDashboardMonsterEntry(@NonNull com.majinnaibu.monstercards.models.DashboardMonsterWithMonster item) {
|
||||||
|
MonsterRepository repository = getMonsterRepository();
|
||||||
|
mDisposables.add(repository.removeDashboardMonsterById(item.dashboardEntry.id)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(() -> {
|
||||||
|
View view = getView();
|
||||||
|
if (view != null) {
|
||||||
|
SnackbarHelper.makeLong(view, getString(R.string.snackbar_removed_from_dashboard, item.monster.name))
|
||||||
|
.setAction(R.string.action_undo, v -> addMonsterToDashboard(item.monster))
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
}, Logger::logError));
|
||||||
|
}
|
||||||
|
|
||||||
private void showAddMonsterPicker() {
|
private void showAddMonsterPicker() {
|
||||||
MonsterRepository repository = getMonsterRepository();
|
MonsterRepository repository = getMonsterRepository();
|
||||||
mDisposables.add(repository.getMonsters()
|
mDisposables.add(repository.getMonsters()
|
||||||
@@ -169,7 +241,7 @@ public class DashboardFragment extends MCFragment {
|
|||||||
if (monsters.isEmpty()) {
|
if (monsters.isEmpty()) {
|
||||||
View view = getView();
|
View view = getView();
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
Snackbar.make(view, getString(R.string.no_monsters_available), Snackbar.LENGTH_LONG).show();
|
SnackbarHelper.showLong(view, getString(R.string.no_monsters_available));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -198,7 +270,7 @@ public class DashboardFragment extends MCFragment {
|
|||||||
if (collections.isEmpty()) {
|
if (collections.isEmpty()) {
|
||||||
View view = getView();
|
View view = getView();
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
Snackbar.make(view, getString(R.string.no_collections_available), Snackbar.LENGTH_LONG).show();
|
SnackbarHelper.showLong(view, getString(R.string.no_collections_available));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -225,7 +297,7 @@ public class DashboardFragment extends MCFragment {
|
|||||||
.subscribe(() -> {
|
.subscribe(() -> {
|
||||||
View view = getView();
|
View view = getView();
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
Snackbar.make(view, getString(R.string.snackbar_added_to_dashboard, monster.name), Snackbar.LENGTH_LONG).show();
|
SnackbarHelper.showLong(view, getString(R.string.snackbar_added_to_dashboard, monster.name));
|
||||||
}
|
}
|
||||||
}, Logger::logError));
|
}, Logger::logError));
|
||||||
}
|
}
|
||||||
@@ -238,7 +310,7 @@ public class DashboardFragment extends MCFragment {
|
|||||||
.subscribe(() -> {
|
.subscribe(() -> {
|
||||||
View view = getView();
|
View view = getView();
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
Snackbar.make(view, getString(R.string.snackbar_collection_added_to_dashboard, collection.name), Snackbar.LENGTH_LONG).show();
|
SnackbarHelper.showLong(view, getString(R.string.snackbar_collection_added_to_dashboard, collection.name));
|
||||||
}
|
}
|
||||||
}, Logger::logError));
|
}, Logger::logError));
|
||||||
}
|
}
|
||||||
@@ -248,7 +320,14 @@ public class DashboardFragment extends MCFragment {
|
|||||||
mDisposables.add(repository.removeMonsterFromDashboard(monster.id)
|
mDisposables.add(repository.removeMonsterFromDashboard(monster.id)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(() -> {}, Logger::logError));
|
.subscribe(() -> {
|
||||||
|
View view = getView();
|
||||||
|
if (view != null) {
|
||||||
|
SnackbarHelper.makeLong(view, getString(R.string.snackbar_removed_from_dashboard, monster.name))
|
||||||
|
.setAction(R.string.action_undo, v -> addMonsterToDashboard(monster))
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
}, Logger::logError));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearDashboard() {
|
private void clearDashboard() {
|
||||||
@@ -259,7 +338,7 @@ public class DashboardFragment extends MCFragment {
|
|||||||
.subscribe(() -> {
|
.subscribe(() -> {
|
||||||
View view = getView();
|
View view = getView();
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
Snackbar.make(view, getString(R.string.snackbar_dashboard_cleared), Snackbar.LENGTH_LONG).show();
|
SnackbarHelper.showLong(view, getString(R.string.snackbar_dashboard_cleared));
|
||||||
}
|
}
|
||||||
}, Logger::logError));
|
}, Logger::logError));
|
||||||
}
|
}
|
||||||
@@ -283,6 +362,9 @@ public class DashboardFragment extends MCFragment {
|
|||||||
} else if (item.getItemId() == R.id.menu_action_add_collection_option) {
|
} else if (item.getItemId() == R.id.menu_action_add_collection_option) {
|
||||||
showAddCollectionPicker();
|
showAddCollectionPicker();
|
||||||
return true;
|
return true;
|
||||||
|
} else if (item.getItemId() == R.id.menu_action_remove_single_monster) {
|
||||||
|
showRemoveMonsterPicker();
|
||||||
|
return true;
|
||||||
} else if (item.getItemId() == R.id.menu_action_clear_dashboard) {
|
} else if (item.getItemId() == R.id.menu_action_clear_dashboard) {
|
||||||
clearDashboard();
|
clearDashboard();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -18,29 +18,44 @@ import com.majinnaibu.monstercards.data.enums.ChallengeRating;
|
|||||||
import com.majinnaibu.monstercards.data.enums.ProficiencyType;
|
import com.majinnaibu.monstercards.data.enums.ProficiencyType;
|
||||||
import com.majinnaibu.monstercards.databinding.CardMonsterBinding;
|
import com.majinnaibu.monstercards.databinding.CardMonsterBinding;
|
||||||
import com.majinnaibu.monstercards.helpers.CommonMarkHelper;
|
import com.majinnaibu.monstercards.helpers.CommonMarkHelper;
|
||||||
|
import com.majinnaibu.monstercards.models.DashboardMonsterWithMonster;
|
||||||
import com.majinnaibu.monstercards.models.Monster;
|
import com.majinnaibu.monstercards.models.Monster;
|
||||||
import com.majinnaibu.monstercards.models.Trait;
|
import com.majinnaibu.monstercards.models.Trait;
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
import com.majinnaibu.monstercards.utils.Logger;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public class DashboardRecyclerViewAdapter extends ListAdapter<Monster, DashboardRecyclerViewAdapter.ViewHolder> {
|
public class DashboardRecyclerViewAdapter extends ListAdapter<DashboardMonsterWithMonster, DashboardRecyclerViewAdapter.ViewHolder> {
|
||||||
private static final DiffUtil.ItemCallback<Monster> DIFF_CALLBACK = new DiffUtil.ItemCallback<Monster>() {
|
private static final DiffUtil.ItemCallback<DashboardMonsterWithMonster> DIFF_CALLBACK = new DiffUtil.ItemCallback<DashboardMonsterWithMonster>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean areItemsTheSame(@NonNull Monster oldItem, @NonNull Monster newItem) {
|
public boolean areItemsTheSame(@NonNull DashboardMonsterWithMonster oldItem, @NonNull DashboardMonsterWithMonster newItem) {
|
||||||
return oldItem.id.equals(newItem.id);
|
if (oldItem.dashboardEntry != null && newItem.dashboardEntry != null) {
|
||||||
|
return oldItem.dashboardEntry.id == newItem.dashboardEntry.id;
|
||||||
|
}
|
||||||
|
return oldItem.monster.id.equals(newItem.monster.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean areContentsTheSame(@NonNull Monster oldItem, @NonNull Monster newItem) {
|
public boolean areContentsTheSame(@NonNull DashboardMonsterWithMonster oldItem, @NonNull DashboardMonsterWithMonster newItem) {
|
||||||
return oldItem.equals(newItem);
|
if (oldItem.dashboardEntry != null && newItem.dashboardEntry != null) {
|
||||||
|
return oldItem.dashboardEntry.id == newItem.dashboardEntry.id
|
||||||
|
&& oldItem.dashboardEntry.ordinal == newItem.dashboardEntry.ordinal
|
||||||
|
&& (oldItem.monster != null && oldItem.monster.equals(newItem.monster));
|
||||||
|
}
|
||||||
|
return (oldItem.monster != null && oldItem.monster.equals(newItem.monster));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
private final ItemCallback mOnClick;
|
private final ItemCallback mOnClick;
|
||||||
|
private final ItemCallback mOnLongClick;
|
||||||
|
|
||||||
public DashboardRecyclerViewAdapter(ItemCallback onClick) {
|
public DashboardRecyclerViewAdapter(ItemCallback onClick, ItemCallback onLongClick) {
|
||||||
super(DIFF_CALLBACK);
|
super(DIFF_CALLBACK);
|
||||||
mOnClick = onClick;
|
mOnClick = onClick;
|
||||||
|
mOnLongClick = onLongClick;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DashboardRecyclerViewAdapter(ItemCallback onClick) {
|
||||||
|
this(onClick, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -52,7 +67,9 @@ public class DashboardRecyclerViewAdapter extends ListAdapter<Monster, Dashboard
|
|||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||||
Logger.logUnimplementedMethod();
|
Logger.logUnimplementedMethod();
|
||||||
Monster monster = getItem(position);
|
DashboardMonsterWithMonster item = getItem(position);
|
||||||
|
Monster monster = item.monster;
|
||||||
|
holder.item = item;
|
||||||
holder.monster = monster;
|
holder.monster = monster;
|
||||||
holder.name.setText(monster.name);
|
holder.name.setText(monster.name);
|
||||||
holder.meta.setText(monster.getMeta());
|
holder.meta.setText(monster.getMeta());
|
||||||
@@ -120,16 +137,25 @@ public class DashboardRecyclerViewAdapter extends ListAdapter<Monster, Dashboard
|
|||||||
|
|
||||||
holder.itemView.setOnClickListener(v -> {
|
holder.itemView.setOnClickListener(v -> {
|
||||||
if (mOnClick != null) {
|
if (mOnClick != null) {
|
||||||
mOnClick.onItemCallback(holder.monster);
|
mOnClick.onItemCallback(holder.item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
holder.itemView.setOnLongClickListener(v -> {
|
||||||
|
if (mOnLongClick != null) {
|
||||||
|
mOnLongClick.onItemCallback(holder.item);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ItemCallback {
|
public interface ItemCallback {
|
||||||
void onItemCallback(Monster monster);
|
void onItemCallback(DashboardMonsterWithMonster item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
public DashboardMonsterWithMonster item;
|
||||||
public final TextView name;
|
public final TextView name;
|
||||||
public final TextView meta;
|
public final TextView meta;
|
||||||
public final View action1Group;
|
public final View action1Group;
|
||||||
|
|||||||
@@ -4,23 +4,23 @@ import androidx.lifecycle.LiveData;
|
|||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
import androidx.lifecycle.ViewModel;
|
import androidx.lifecycle.ViewModel;
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.models.Monster;
|
import com.majinnaibu.monstercards.models.DashboardMonsterWithMonster;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class DashboardViewModel extends ViewModel {
|
public class DashboardViewModel extends ViewModel {
|
||||||
private final MutableLiveData<List<Monster>> mMonsters;
|
private final MutableLiveData<List<DashboardMonsterWithMonster>> mMonsters;
|
||||||
|
|
||||||
public DashboardViewModel() {
|
public DashboardViewModel() {
|
||||||
mMonsters = new MutableLiveData<>(new ArrayList<>());
|
mMonsters = new MutableLiveData<>(new ArrayList<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<List<Monster>> getMonsters() {
|
public LiveData<List<DashboardMonsterWithMonster>> getMonsters() {
|
||||||
return mMonsters;
|
return mMonsters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMonsters(List<Monster> monsters) {
|
public void setMonsters(List<DashboardMonsterWithMonster> monsters) {
|
||||||
mMonsters.setValue(monsters);
|
mMonsters.setValue(monsters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import androidx.navigation.NavController;
|
|||||||
import androidx.navigation.NavDirections;
|
import androidx.navigation.NavDirections;
|
||||||
import androidx.navigation.fragment.NavHostFragment;
|
import androidx.navigation.fragment.NavHostFragment;
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
|
||||||
import com.majinnaibu.monstercards.R;
|
import com.majinnaibu.monstercards.R;
|
||||||
import com.majinnaibu.monstercards.data.MonsterRepository;
|
import com.majinnaibu.monstercards.data.MonsterRepository;
|
||||||
import com.majinnaibu.monstercards.data.enums.StringType;
|
import com.majinnaibu.monstercards.data.enums.StringType;
|
||||||
@@ -26,6 +25,7 @@ import com.majinnaibu.monstercards.data.enums.TraitType;
|
|||||||
import com.majinnaibu.monstercards.models.Monster;
|
import com.majinnaibu.monstercards.models.Monster;
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
import com.majinnaibu.monstercards.utils.Logger;
|
||||||
|
import com.majinnaibu.monstercards.utils.SnackbarHelper;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -124,8 +124,7 @@ public class EditMonsterFragment extends MCFragment {
|
|||||||
public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
|
public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
|
||||||
Logger.logError("Error saving monster", e);
|
Logger.logError("Error saving monster", e);
|
||||||
assert view != null;
|
assert view != null;
|
||||||
Snackbar.make(view, getString(R.string.snackbar_failed_to_create_monster), Snackbar.LENGTH_LONG)
|
SnackbarHelper.showLong(view, getString(R.string.snackbar_failed_to_create_monster));
|
||||||
.setAction("Action", null).show();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
|||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
|
||||||
import com.majinnaibu.monstercards.MainActivity;
|
import com.majinnaibu.monstercards.MainActivity;
|
||||||
import com.majinnaibu.monstercards.R;
|
import com.majinnaibu.monstercards.R;
|
||||||
import com.majinnaibu.monstercards.data.MonsterRepository;
|
import com.majinnaibu.monstercards.data.MonsterRepository;
|
||||||
@@ -35,6 +34,7 @@ import com.majinnaibu.monstercards.ui.monster.MonsterDetailFragmentDirections;
|
|||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
||||||
import com.majinnaibu.monstercards.ui.shared.SwipeToDeleteCallback;
|
import com.majinnaibu.monstercards.ui.shared.SwipeToDeleteCallback;
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
import com.majinnaibu.monstercards.utils.Logger;
|
||||||
|
import com.majinnaibu.monstercards.utils.SnackbarHelper;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@@ -206,7 +206,7 @@ public class LibraryFragment extends MCFragment {
|
|||||||
Logger.logError("Error creating monster", e);
|
Logger.logError("Error creating monster", e);
|
||||||
View view = getView();
|
View view = getView();
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
Snackbar.make(view, getString(R.string.snackbar_failed_to_create_monster), Snackbar.LENGTH_LONG).show();
|
SnackbarHelper.showLong(view, getString(R.string.snackbar_failed_to_create_monster));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import androidx.lifecycle.ViewModelProvider;
|
|||||||
import androidx.navigation.NavDirections;
|
import androidx.navigation.NavDirections;
|
||||||
import androidx.navigation.Navigation;
|
import androidx.navigation.Navigation;
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
|
||||||
import com.majinnaibu.monstercards.R;
|
import com.majinnaibu.monstercards.R;
|
||||||
import com.majinnaibu.monstercards.data.MonsterRepository;
|
import com.majinnaibu.monstercards.data.MonsterRepository;
|
||||||
import com.majinnaibu.monstercards.helpers.CommonMarkHelper;
|
import com.majinnaibu.monstercards.helpers.CommonMarkHelper;
|
||||||
@@ -40,6 +39,7 @@ import com.majinnaibu.monstercards.models.Collection;
|
|||||||
import com.majinnaibu.monstercards.models.Monster;
|
import com.majinnaibu.monstercards.models.Monster;
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
import com.majinnaibu.monstercards.utils.Logger;
|
||||||
|
import com.majinnaibu.monstercards.utils.SnackbarHelper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -252,7 +252,7 @@ public class MonsterDetailFragment extends MCFragment {
|
|||||||
Logger.logError("Failed to share monster", e);
|
Logger.logError("Failed to share monster", e);
|
||||||
View view = getView();
|
View view = getView();
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
Snackbar.make(view, R.string.failed_to_share_monster, Snackbar.LENGTH_LONG).show();
|
SnackbarHelper.showLong(view, R.string.failed_to_share_monster);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -270,7 +270,7 @@ public class MonsterDetailFragment extends MCFragment {
|
|||||||
View view = getView();
|
View view = getView();
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
String monsterName = mViewModel.getName().getValue();
|
String monsterName = mViewModel.getName().getValue();
|
||||||
Snackbar.make(view, getString(R.string.snackbar_added_to_dashboard, monsterName), Snackbar.LENGTH_LONG).show();
|
SnackbarHelper.showLong(view, getString(R.string.snackbar_added_to_dashboard, monsterName));
|
||||||
}
|
}
|
||||||
}, Logger::logError);
|
}, Logger::logError);
|
||||||
}
|
}
|
||||||
@@ -291,7 +291,7 @@ public class MonsterDetailFragment extends MCFragment {
|
|||||||
if (collections.isEmpty()) {
|
if (collections.isEmpty()) {
|
||||||
View view = getView();
|
View view = getView();
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
Snackbar.make(view, getString(R.string.no_collections_available), Snackbar.LENGTH_LONG).show();
|
SnackbarHelper.showLong(view, getString(R.string.no_collections_available));
|
||||||
}
|
}
|
||||||
dispose();
|
dispose();
|
||||||
return;
|
return;
|
||||||
@@ -330,11 +330,7 @@ public class MonsterDetailFragment extends MCFragment {
|
|||||||
View view = getView();
|
View view = getView();
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
String monsterName = mViewModel.getName().getValue();
|
String monsterName = mViewModel.getName().getValue();
|
||||||
Snackbar.make(
|
SnackbarHelper.showLong(view, getString(R.string.snackbar_monster_added_to_collection, monsterName, collection.name));
|
||||||
view,
|
|
||||||
getString(R.string.snackbar_monster_added_to_collection, monsterName, collection.name),
|
|
||||||
Snackbar.LENGTH_LONG)
|
|
||||||
.show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import androidx.navigation.NavController;
|
|||||||
import androidx.navigation.NavDirections;
|
import androidx.navigation.NavDirections;
|
||||||
import androidx.navigation.Navigation;
|
import androidx.navigation.Navigation;
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
|
||||||
import com.majinnaibu.monstercards.MonsterCardsApplication;
|
import com.majinnaibu.monstercards.MonsterCardsApplication;
|
||||||
import com.majinnaibu.monstercards.R;
|
import com.majinnaibu.monstercards.R;
|
||||||
import com.majinnaibu.monstercards.data.MonsterRepository;
|
import com.majinnaibu.monstercards.data.MonsterRepository;
|
||||||
@@ -34,6 +33,7 @@ import com.majinnaibu.monstercards.models.Monster;
|
|||||||
import com.majinnaibu.monstercards.ui.library.LibraryFragmentDirections;
|
import com.majinnaibu.monstercards.ui.library.LibraryFragmentDirections;
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
import com.majinnaibu.monstercards.utils.Logger;
|
||||||
|
import com.majinnaibu.monstercards.utils.SnackbarHelper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -174,7 +174,7 @@ public class MonsterImportFragment extends MCFragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
|
public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
|
||||||
Logger.logError("Error creating monster", e);
|
Logger.logError("Error creating monster", e);
|
||||||
Snackbar.make(mHolder.root, getString(R.string.snackbar_failed_to_create_monster), Snackbar.LENGTH_LONG).show();
|
SnackbarHelper.showLong(mHolder.root, getString(R.string.snackbar_failed_to_create_monster));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ import androidx.appcompat.app.ActionBar;
|
|||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
|
||||||
import com.majinnaibu.monstercards.MonsterCardsApplication;
|
import com.majinnaibu.monstercards.MonsterCardsApplication;
|
||||||
import com.majinnaibu.monstercards.R;
|
import com.majinnaibu.monstercards.R;
|
||||||
import com.majinnaibu.monstercards.data.MonsterRepository;
|
import com.majinnaibu.monstercards.data.MonsterRepository;
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
import com.majinnaibu.monstercards.utils.Logger;
|
||||||
|
import com.majinnaibu.monstercards.utils.SnackbarHelper;
|
||||||
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@@ -87,7 +87,7 @@ public class MCFragment extends Fragment {
|
|||||||
Logger.logError("Failed to launch document creation picker", e);
|
Logger.logError("Failed to launch document creation picker", e);
|
||||||
View view = getView();
|
View view = getView();
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
Snackbar.make(view, R.string.snackbar_export_failed, Snackbar.LENGTH_LONG).show();
|
SnackbarHelper.showLong(view, R.string.snackbar_export_failed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,14 +103,14 @@ public class MCFragment extends Fragment {
|
|||||||
if (view != null) {
|
if (view != null) {
|
||||||
String fileName = getFileNameFromUri(context, uri);
|
String fileName = getFileNameFromUri(context, uri);
|
||||||
String message = getString(R.string.snackbar_export_success, fileName);
|
String message = getString(R.string.snackbar_export_success, fileName);
|
||||||
Snackbar.make(view, message, Snackbar.LENGTH_LONG).show();
|
SnackbarHelper.showLong(view, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Logger.logError("Failed to write export content to URI", e);
|
Logger.logError("Failed to write export content to URI", e);
|
||||||
View view = getView();
|
View view = getView();
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
Snackbar.make(view, R.string.snackbar_export_failed, Snackbar.LENGTH_LONG).show();
|
SnackbarHelper.showLong(view, R.string.snackbar_export_failed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.majinnaibu.monstercards.utils;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
|
|
||||||
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Centralized helper for managing Snackbar notifications and durations across the app.
|
||||||
|
*/
|
||||||
|
public class SnackbarHelper {
|
||||||
|
// Configurable default durations in milliseconds
|
||||||
|
public static int DEFAULT_SHORT_DURATION = 2500; // 2.5 seconds
|
||||||
|
public static int DEFAULT_LONG_DURATION = 4000; // 4.0 seconds (e.g. for Undo or action messages)
|
||||||
|
|
||||||
|
public static Snackbar makeShort(@NonNull View view, @StringRes int resId) {
|
||||||
|
return make(view, view.getContext().getString(resId), DEFAULT_SHORT_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Snackbar makeShort(@NonNull View view, @NonNull CharSequence message) {
|
||||||
|
return make(view, message, DEFAULT_SHORT_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Snackbar makeLong(@NonNull View view, @StringRes int resId) {
|
||||||
|
return make(view, view.getContext().getString(resId), DEFAULT_LONG_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Snackbar makeLong(@NonNull View view, @NonNull CharSequence message) {
|
||||||
|
return make(view, message, DEFAULT_LONG_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Snackbar make(@NonNull View view, @NonNull CharSequence message, int durationMs) {
|
||||||
|
return Snackbar.make(view, message, durationMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showShort(@NonNull View view, @StringRes int resId) {
|
||||||
|
makeShort(view, resId).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showShort(@NonNull View view, @NonNull CharSequence message) {
|
||||||
|
makeShort(view, message).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showLong(@NonNull View view, @StringRes int resId) {
|
||||||
|
makeLong(view, resId).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showLong(@NonNull View view, @NonNull CharSequence message) {
|
||||||
|
makeLong(view, message).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.majinnaibu.monstercards.utils;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Centralized helper for managing Toast notifications and durations across the app.
|
||||||
|
*/
|
||||||
|
public class ToastHelper {
|
||||||
|
// Configurable default durations
|
||||||
|
public static int DEFAULT_SHORT_DURATION = Toast.LENGTH_SHORT; // ~2.0 seconds
|
||||||
|
public static int DEFAULT_LONG_DURATION = Toast.LENGTH_LONG; // ~3.5 seconds
|
||||||
|
|
||||||
|
private static Toast sCurrentToast;
|
||||||
|
|
||||||
|
public static void showShort(@NonNull Context context, @StringRes int resId) {
|
||||||
|
show(context, context.getString(resId), DEFAULT_SHORT_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showShort(@NonNull Context context, @NonNull String message) {
|
||||||
|
show(context, message, DEFAULT_SHORT_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showLong(@NonNull Context context, @StringRes int resId) {
|
||||||
|
show(context, context.getString(resId), DEFAULT_LONG_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showLong(@NonNull Context context, @NonNull String message) {
|
||||||
|
show(context, message, DEFAULT_LONG_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void show(@NonNull Context context, @NonNull String message, int duration) {
|
||||||
|
if (sCurrentToast != null) {
|
||||||
|
sCurrentToast.cancel();
|
||||||
|
}
|
||||||
|
sCurrentToast = Toast.makeText(context.getApplicationContext(), message, duration);
|
||||||
|
sCurrentToast.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,11 @@
|
|||||||
android:title="@string/action_add_collection_option"
|
android:title="@string/action_add_collection_option"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_action_remove_single_monster"
|
||||||
|
android:title="@string/action_remove_single_monster"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_action_clear_dashboard"
|
android:id="@+id/menu_action_clear_dashboard"
|
||||||
android:title="@string/action_clear_dashboard"
|
android:title="@string/action_clear_dashboard"
|
||||||
|
|||||||
@@ -188,4 +188,14 @@
|
|||||||
<string name="empty_library_title">Your Library is Empty</string>
|
<string name="empty_library_title">Your Library is Empty</string>
|
||||||
<string name="empty_library_subtitle">Create new monster cards or import them from D&D Beyond or Open5e.</string>
|
<string name="empty_library_subtitle">Create new monster cards or import them from D&D Beyond or Open5e.</string>
|
||||||
<string name="app_title_splash">Monster Cards</string>
|
<string name="app_title_splash">Monster Cards</string>
|
||||||
|
|
||||||
|
<string name="action_remove_single_monster">Remove Monster...</string>
|
||||||
|
<string name="action_remove">Remove</string>
|
||||||
|
<string name="action_undo">Undo</string>
|
||||||
|
<string name="action_view_details">View Details</string>
|
||||||
|
<string name="action_remove_from_dashboard">Remove from Dashboard</string>
|
||||||
|
<string name="snackbar_removed_from_dashboard">Removed %1$s from Dashboard</string>
|
||||||
|
<string name="snackbar_dashboard_already_empty">Dashboard is already empty</string>
|
||||||
|
<string name="dialog_remove_from_dashboard_title">Remove %1$s?</string>
|
||||||
|
<string name="dialog_remove_from_dashboard_message">Remove %1$s from your dashboard?</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user