From e063eec76717f3b168203c43f9fc12e903404478 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 18 May 2022 11:42:45 +0200 Subject: [PATCH] Fix issue #28 & #61 --- .../app/fedilab/android/BaseMainActivity.java | 148 +++++++++----- .../activities/ReorderTimelinesActivity.java | 53 ++++- .../android/client/entities/BottomMenu.java | 183 +++++++++++------ .../android/client/entities/Pinned.java | 19 ++ .../app/fedilab/android/helper/Helper.java | 2 + .../android/helper/PinnedTimelineHelper.java | 20 +- .../ui/drawer/ReorderBottomMenuAdapter.java | 184 ++++++++++++++++++ .../android/ui/drawer/ReorderTabAdapter.java | 9 +- .../ui/pageadapter/FedilabPageAdapter.java | 73 ++++--- .../android/viewmodel/mastodon/ReorderVM.java | 21 +- .../main/res/layout/activity_reorder_tabs.xml | 120 +++++++----- 11 files changed, 616 insertions(+), 216 deletions(-) create mode 100644 app/src/main/java/app/fedilab/android/ui/drawer/ReorderBottomMenuAdapter.java diff --git a/app/src/main/java/app/fedilab/android/BaseMainActivity.java b/app/src/main/java/app/fedilab/android/BaseMainActivity.java index eae375dd..4bf7bb5e 100644 --- a/app/src/main/java/app/fedilab/android/BaseMainActivity.java +++ b/app/src/main/java/app/fedilab/android/BaseMainActivity.java @@ -136,6 +136,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt private Pinned pinned; public static boolean show_boosts, show_replies, show_art_nsfw; public static String regex_home, regex_local, regex_public; + private BottomMenu bottomMenu; private final BroadcastReceiver broadcast_data = new BroadcastReceiver() { @Override @@ -145,6 +146,51 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt if (b.getBoolean(Helper.RECEIVE_REDRAW_TOPBAR, false)) { List mastodonLists = (List) b.getSerializable(Helper.RECEIVE_MASTODON_LIST); redrawPinned(mastodonLists); + } + if (b.getBoolean(Helper.RECEIVE_REDRAW_BOTTOM, false)) { + bottomMenu = new BottomMenu(BaseMainActivity.this).hydrate(account, binding.bottomNavView); + if (bottomMenu != null) { + //ManageClick on bottom menu items + if (binding.bottomNavView.findViewById(R.id.nav_home) != null) { + binding.bottomNavView.findViewById(R.id.nav_home).setOnLongClickListener(view -> { + int position = BottomMenu.getPosition(bottomMenu, R.id.nav_home); + if (position >= 0) { + manageFilters(position); + } + return false; + }); + } + if (binding.bottomNavView.findViewById(R.id.nav_local) != null) { + binding.bottomNavView.findViewById(R.id.nav_local).setOnLongClickListener(view -> { + int position = BottomMenu.getPosition(bottomMenu, R.id.nav_local); + if (position >= 0) { + manageFilters(position); + } + return false; + }); + } + if (binding.bottomNavView.findViewById(R.id.nav_public) != null) { + binding.bottomNavView.findViewById(R.id.nav_public).setOnLongClickListener(view -> { + int position = BottomMenu.getPosition(bottomMenu, R.id.nav_public); + if (position >= 0) { + manageFilters(position); + } + return false; + }); + } + binding.bottomNavView.setOnItemSelectedListener(item -> { + int itemId = item.getItemId(); + int position = BottomMenu.getPosition(bottomMenu, itemId); + if (position >= 0) { + if (binding.viewPager.getCurrentItem() == position) { + scrollToTop(); + } else { + binding.viewPager.setCurrentItem(position); + } + } + return true; + }); + } } else if (b.getBoolean(Helper.RECEIVE_RECREATE_ACTIVITY, false)) { Cyanea.getInstance().edit().apply().recreate(BaseMainActivity.this); } else if (b.getBoolean(Helper.RECEIVE_NEW_MESSAGE, false)) { @@ -179,8 +225,6 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt private void mamageNewIntent(Intent intent) { if (intent == null) return; - String action = intent.getAction(); - String type = intent.getType(); Bundle extras = intent.getExtras(); String userIdIntent, instanceIntent; if (extras != null && extras.containsKey(Helper.INTENT_ACTION)) { @@ -251,59 +295,10 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt binding.tabLayout.setTabIconTint(ThemeHelper.getColorStateList(BaseMainActivity.this)); binding.compose.setOnClickListener(v -> startActivity(new Intent(this, ComposeActivity.class))); headerMenuOpen = false; - new BottomMenu(BaseMainActivity.this).hydrate(account, binding.bottomNavView); binding.bottomNavView.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary))); binding.navView.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary))); - //ManageClick on bottom menu items - binding.bottomNavView.findViewById(R.id.nav_home).setOnLongClickListener(view -> { - manageFilters(0); - return false; - }); - binding.bottomNavView.findViewById(R.id.nav_local).setOnLongClickListener(view -> { - manageFilters(1); - return false; - }); - binding.bottomNavView.findViewById(R.id.nav_public).setOnLongClickListener(view -> { - manageFilters(2); - return false; - }); - binding.bottomNavView.setOnItemSelectedListener(item -> { - int itemId = item.getItemId(); - if (itemId == R.id.nav_home) { - if (binding.viewPager.getCurrentItem() == 0) { - scrollToTop(); - } else { - binding.viewPager.setCurrentItem(0); - } - } else if (itemId == R.id.nav_local) { - if (binding.viewPager.getCurrentItem() == 1) { - scrollToTop(); - } else { - binding.viewPager.setCurrentItem(1); - } - } else if (itemId == R.id.nav_public) { - if (binding.viewPager.getCurrentItem() == 2) { - scrollToTop(); - } else { - binding.viewPager.setCurrentItem(2); - } - } else if (itemId == R.id.nav_notifications) { - if (binding.viewPager.getCurrentItem() == 3) { - scrollToTop(); - } else { - binding.viewPager.setCurrentItem(3); - } - } else if (itemId == R.id.nav_privates) { - if (binding.viewPager.getCurrentItem() == 4) { - scrollToTop(); - } else { - binding.viewPager.setCurrentItem(4); - } - } - return true; - }); // Passing each menu ID as a set of Ids because each @@ -567,6 +562,51 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt finish(); return; } + bottomMenu = new BottomMenu(BaseMainActivity.this).hydrate(account, binding.bottomNavView); + + if (bottomMenu != null) { + //ManageClick on bottom menu items + if (binding.bottomNavView.findViewById(R.id.nav_home) != null) { + binding.bottomNavView.findViewById(R.id.nav_home).setOnLongClickListener(view -> { + int position = BottomMenu.getPosition(bottomMenu, R.id.nav_home); + if (position >= 0) { + manageFilters(position); + } + return false; + }); + } + if (binding.bottomNavView.findViewById(R.id.nav_local) != null) { + binding.bottomNavView.findViewById(R.id.nav_local).setOnLongClickListener(view -> { + int position = BottomMenu.getPosition(bottomMenu, R.id.nav_local); + if (position >= 0) { + manageFilters(position); + } + return false; + }); + } + if (binding.bottomNavView.findViewById(R.id.nav_public) != null) { + binding.bottomNavView.findViewById(R.id.nav_public).setOnLongClickListener(view -> { + int position = BottomMenu.getPosition(bottomMenu, R.id.nav_public); + if (position >= 0) { + manageFilters(position); + } + return false; + }); + } + binding.bottomNavView.setOnItemSelectedListener(item -> { + int itemId = item.getItemId(); + int position = BottomMenu.getPosition(bottomMenu, itemId); + if (position >= 0) { + if (binding.viewPager.getCurrentItem() == position) { + scrollToTop(); + } else { + binding.viewPager.setCurrentItem(position); + } + } + return true; + }); + } + currentInstance = account.instance; currentUserID = account.user_id; show_boosts = sharedpreferences.getBoolean(getString(R.string.SET_SHOW_BOOSTS) + currentUserID + currentInstance, true); @@ -611,11 +651,11 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt .observe(this, pinned -> { this.pinned = pinned; //First it's taken from db (last stored values) - PinnedTimelineHelper.redrawTopBarPinned(BaseMainActivity.this, binding, pinned, null); + PinnedTimelineHelper.redrawTopBarPinned(BaseMainActivity.this, binding, pinned, bottomMenu, null); //Fetch remote lists for the authenticated account and update them new ViewModelProvider(BaseMainActivity.this).get(TimelinesVM.class).getLists(currentInstance, currentToken) .observe(this, mastodonLists -> - PinnedTimelineHelper.redrawTopBarPinned(BaseMainActivity.this, binding, pinned, mastodonLists) + PinnedTimelineHelper.redrawTopBarPinned(BaseMainActivity.this, binding, pinned, bottomMenu, mastodonLists) ); }); }; @@ -850,7 +890,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt .observe(this, pinned -> { this.pinned = pinned; //First it's taken from db (last stored values) - PinnedTimelineHelper.redrawTopBarPinned(BaseMainActivity.this, binding, pinned, mastodonLists); + PinnedTimelineHelper.redrawTopBarPinned(BaseMainActivity.this, binding, pinned, bottomMenu, mastodonLists); binding.viewPager.setCurrentItem(currentItem); }); } diff --git a/app/src/main/java/app/fedilab/android/activities/ReorderTimelinesActivity.java b/app/src/main/java/app/fedilab/android/activities/ReorderTimelinesActivity.java index 8d6e6561..be55801a 100644 --- a/app/src/main/java/app/fedilab/android/activities/ReorderTimelinesActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ReorderTimelinesActivity.java @@ -15,6 +15,7 @@ package app.fedilab.android.activities; * see . */ +import static app.fedilab.android.helper.PinnedTimelineHelper.sortMenuItem; import static app.fedilab.android.helper.PinnedTimelineHelper.sortPositionAsc; import android.content.Intent; @@ -47,6 +48,7 @@ import java.util.ArrayList; import java.util.concurrent.TimeUnit; import app.fedilab.android.R; +import app.fedilab.android.client.entities.BottomMenu; import app.fedilab.android.client.entities.InstanceSocial; import app.fedilab.android.client.entities.Pinned; import app.fedilab.android.client.entities.Timeline; @@ -60,6 +62,7 @@ import app.fedilab.android.helper.ThemeHelper; import app.fedilab.android.helper.itemtouchhelper.OnStartDragListener; import app.fedilab.android.helper.itemtouchhelper.OnUndoListener; import app.fedilab.android.helper.itemtouchhelper.SimpleItemTouchHelperCallback; +import app.fedilab.android.ui.drawer.ReorderBottomMenuAdapter; import app.fedilab.android.ui.drawer.ReorderTabAdapter; import app.fedilab.android.viewmodel.mastodon.InstanceSocialVM; import app.fedilab.android.viewmodel.mastodon.ReorderVM; @@ -75,12 +78,23 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra private ItemTouchHelper touchHelper; - private ReorderTabAdapter adapter; + private ReorderTabAdapter reorderTabAdapter; + private ReorderBottomMenuAdapter reorderBottomMenuAdapter; private boolean searchInstanceRunning; private String oldSearch; private Pinned pinned; + private BottomMenu bottomMenu; private ActivityReorderTabsBinding binding; private boolean changes; + private boolean bottomChanges; + + public void setChanges(boolean changes) { + this.changes = changes; + } + + public void setBottomChanges(boolean bottomChanges) { + this.bottomChanges = bottomChanges; + } @Override protected void onCreate(Bundle savedInstanceState) { @@ -95,6 +109,7 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra } changes = false; + bottomChanges = false; ReorderVM reorderVM = new ViewModelProvider(ReorderTimelinesActivity.this).get(ReorderVM.class); reorderVM.getPinned().observe(ReorderTimelinesActivity.this, _pinned -> { this.pinned = _pinned; @@ -103,16 +118,31 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra this.pinned.pinnedTimelines = new ArrayList<>(); } sortPositionAsc(this.pinned.pinnedTimelines); - adapter = new ReorderTabAdapter(this.pinned, ReorderTimelinesActivity.this, ReorderTimelinesActivity.this); + reorderTabAdapter = new ReorderTabAdapter(this.pinned, ReorderTimelinesActivity.this, ReorderTimelinesActivity.this); ItemTouchHelper.Callback callback = - new SimpleItemTouchHelperCallback(adapter); + new SimpleItemTouchHelperCallback(reorderTabAdapter); touchHelper = new ItemTouchHelper(callback); touchHelper.attachToRecyclerView(binding.lvReorderTabs); - binding.lvReorderTabs.setAdapter(adapter); + binding.lvReorderTabs.setAdapter(reorderTabAdapter); LinearLayoutManager mLayoutManager = new LinearLayoutManager(ReorderTimelinesActivity.this); binding.lvReorderTabs.setLayoutManager(mLayoutManager); }); - + reorderVM.getBottomMenu().observe(ReorderTimelinesActivity.this, _bottomMenu -> { + this.bottomMenu = _bottomMenu; + if (this.bottomMenu == null) { + this.bottomMenu = new BottomMenu(getApplicationContext()).defaultBottomMenu(); + this.bottomMenu.bottom_menu = new ArrayList<>(); + } + sortMenuItem(this.bottomMenu.bottom_menu); + reorderBottomMenuAdapter = new ReorderBottomMenuAdapter(this.bottomMenu, ReorderTimelinesActivity.this); + ItemTouchHelper.Callback callback = + new SimpleItemTouchHelperCallback(reorderBottomMenuAdapter); + touchHelper = new ItemTouchHelper(callback); + touchHelper.attachToRecyclerView(binding.lvReorderBottom); + binding.lvReorderBottom.setAdapter(reorderBottomMenuAdapter); + LinearLayoutManager mLayoutManager = new LinearLayoutManager(ReorderTimelinesActivity.this); + binding.lvReorderBottom.setLayoutManager(mLayoutManager); + }); } @Override @@ -209,7 +239,7 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra try { new Pinned(ReorderTimelinesActivity.this).updatePinned(pinned); changes = true; - adapter.notifyItemInserted(pinned.pinnedTimelines.size()); + reorderTabAdapter.notifyItemInserted(pinned.pinnedTimelines.size()); } catch (DBException e) { e.printStackTrace(); } @@ -299,6 +329,13 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra intentBD.putExtras(b); LocalBroadcastManager.getInstance(ReorderTimelinesActivity.this).sendBroadcast(intentBD); } + if (bottomChanges) { + Bundle b = new Bundle(); + b.putBoolean(Helper.RECEIVE_REDRAW_BOTTOM, true); + Intent intentBD = new Intent(Helper.BROADCAST_DATA); + intentBD.putExtras(b); + LocalBroadcastManager.getInstance(ReorderTimelinesActivity.this).sendBroadcast(intentBD); + } } @Override @@ -329,7 +366,7 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra pinned.pinnedTimelines.get(i).position -= 1; } pinned.pinnedTimelines.remove(pinnedTimeline); - adapter.notifyItemRemoved(position); + reorderTabAdapter.notifyItemRemoved(position); try { new Pinned(ReorderTimelinesActivity.this).updatePinned(pinned); changes = true; @@ -341,7 +378,7 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra handler.postDelayed(runnable, 4000); binding.undoAction.setOnClickListener(v -> { pinned.pinnedTimelines.add(position, pinnedTimeline); - adapter.notifyItemInserted(position); + reorderTabAdapter.notifyItemInserted(position); binding.undoContainer.setVisibility(View.GONE); handler.removeCallbacks(runnable); }); diff --git a/app/src/main/java/app/fedilab/android/client/entities/BottomMenu.java b/app/src/main/java/app/fedilab/android/client/entities/BottomMenu.java index 9ee4b3b9..ff121e30 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/BottomMenu.java +++ b/app/src/main/java/app/fedilab/android/client/entities/BottomMenu.java @@ -20,6 +20,8 @@ import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.view.Menu; +import androidx.annotation.IdRes; + import com.google.android.material.bottomnavigation.BottomNavigationView; import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; @@ -31,6 +33,7 @@ import java.util.List; import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; +import app.fedilab.android.activities.MainActivity; import app.fedilab.android.exception.DBException; import app.fedilab.android.sqlite.Sqlite; @@ -89,59 +92,62 @@ public class BottomMenu implements Serializable { } } - public void hydrate(Account account, BottomNavigationView bottomNavigationView) { + public static int getPosition(BottomMenu bottomMenu, @IdRes int idRes) { + for (MenuItem menuItem : bottomMenu.bottom_menu) { + if (idRes == R.id.nav_home && menuItem.item_menu_type == ItemMenuType.HOME) { + return menuItem.position; + } else if (idRes == R.id.nav_local && menuItem.item_menu_type == ItemMenuType.LOCAL) { + return menuItem.position; + } else if (idRes == R.id.nav_public && menuItem.item_menu_type == ItemMenuType.PUBLIC) { + return menuItem.position; + } else if (idRes == R.id.nav_notifications && menuItem.item_menu_type == ItemMenuType.NOTIFICATION) { + return menuItem.position; + } else if (idRes == R.id.nav_privates && menuItem.item_menu_type == ItemMenuType.DIRECT) { + return menuItem.position; + } + } + return -1; + } + + public static ItemMenuType getType(BottomMenu bottomMenu, int position) { + if (bottomMenu == null || bottomMenu.bottom_menu == null || bottomMenu.bottom_menu.size() < position) { + return null; + } + return bottomMenu.bottom_menu.get(position).item_menu_type; + } + + public BottomMenu hydrate(Account account, BottomNavigationView bottomNavigationView) { bottomNavigationView.getMenu().clear(); BottomMenu bottomMenu; try { - bottomMenu = getBottomMenu(account); + bottomMenu = getAllBottomMenu(account); } catch (DBException e) { bottomMenu = defaultBottomMenu(); } for (BottomMenu.MenuItem menuItem : bottomMenu.bottom_menu) { - if (menuItem.visible) { - switch (menuItem.item_menu_type) { - case HOME: - bottomNavigationView.getMenu().add(Menu.NONE, R.id.nav_home, menuItem.position, context.getString(R.string.home_menu)).setIcon(R.drawable.ic_baseline_home_24); - break; - case LOCAL: - bottomNavigationView.getMenu().add(Menu.NONE, R.id.nav_local, menuItem.position, context.getString(R.string.local_menu)).setIcon(R.drawable.ic_baseline_people_alt_24); - break; - case PUBLIC: - bottomNavigationView.getMenu().add(Menu.NONE, R.id.nav_public, menuItem.position, context.getString(R.string.v_public)).setIcon(R.drawable.ic_baseline_public_24); - break; - case NOTIFICATION: - bottomNavigationView.getMenu().add(Menu.NONE, R.id.nav_notifications, menuItem.position, context.getString(R.string.notifications)).setIcon(R.drawable.ic_baseline_notifications_24); - break; - case DIRECT: - bottomNavigationView.getMenu().add(Menu.NONE, R.id.nav_privates, menuItem.position, context.getString(R.string.v_private)).setIcon(R.drawable.ic_baseline_mail_24); - break; - } + android.view.MenuItem menuItemLoop = null; + switch (menuItem.item_menu_type) { + case HOME: + menuItemLoop = bottomNavigationView.getMenu().add(Menu.NONE, R.id.nav_home, menuItem.position, context.getString(R.string.home_menu)).setIcon(R.drawable.ic_baseline_home_24); + break; + case LOCAL: + menuItemLoop = bottomNavigationView.getMenu().add(Menu.NONE, R.id.nav_local, menuItem.position, context.getString(R.string.local_menu)).setIcon(R.drawable.ic_baseline_people_alt_24); + break; + case PUBLIC: + menuItemLoop = bottomNavigationView.getMenu().add(Menu.NONE, R.id.nav_public, menuItem.position, context.getString(R.string.v_public)).setIcon(R.drawable.ic_baseline_public_24); + break; + case NOTIFICATION: + menuItemLoop = bottomNavigationView.getMenu().add(Menu.NONE, R.id.nav_notifications, menuItem.position, context.getString(R.string.notifications)).setIcon(R.drawable.ic_baseline_notifications_24); + break; + case DIRECT: + menuItemLoop = bottomNavigationView.getMenu().add(Menu.NONE, R.id.nav_privates, menuItem.position, context.getString(R.string.v_private)).setIcon(R.drawable.ic_baseline_mail_24); + break; + } + if (menuItemLoop != null && !menuItem.visible) { + menuItemLoop.setVisible(false); } } - } - - /** - * Insert or update instance - * - * @param bottomMenu {@link BottomMenu} - * @return long - db id - * @throws DBException exception with database - */ - public long insertOrUpdate(BottomMenu bottomMenu) throws DBException { - if (db == null) { - throw new DBException("db is null. Wrong initialization."); - } - if (bottomMenu == null) { - return -1; - } - boolean exists = bottomMenuExists(bottomMenu); - long idReturned; - if (exists) { - idReturned = updateBottomMenu(bottomMenu); - } else { - idReturned = insertBottomMenu(bottomMenu); - } - return idReturned; + return bottomMenu; } /** @@ -192,13 +198,60 @@ public class BottomMenu implements Serializable { } } + /** + * Insert or update instance + * + * @param bottomMenu {@link BottomMenu} + * @return long - db id + * @throws DBException exception with database + */ + public long insertOrUpdate(BottomMenu bottomMenu) throws DBException { + if (db == null) { + throw new DBException("db is null. Wrong initialization."); + } + if (bottomMenu == null) { + return -1; + } + if (bottomMenu.user_id == null) { + bottomMenu.user_id = MainActivity.currentUserID; + bottomMenu.instance = MainActivity.currentInstance; + } + boolean exists = bottomMenuExists(bottomMenu); + long idReturned; + if (exists) { + idReturned = updateBottomMenu(bottomMenu); + } else { + idReturned = insertBottomMenu(bottomMenu); + } + return idReturned; + } + /** * Returns the bottom menu for an account * * @param account Account - * @return Pinned - {@link BottomMenu} + * @return BottomMenu - {@link BottomMenu} */ - private BottomMenu getBottomMenu(Account account) throws DBException { + public BottomMenu getAllBottomMenu(Account account) throws DBException { + if (db == null) { + throw new DBException("db is null. Wrong initialization."); + } + try { + Cursor c = db.query(Sqlite.TABLE_BOTTOM_MENU, null, Sqlite.COL_INSTANCE + " = '" + account.instance + "' AND " + Sqlite.COL_USER_ID + " = '" + account.user_id + "'", null, null, null, Sqlite.COL_ID + " DESC", "1"); + return cursorToBottomMenu(c); + } catch (Exception e) { + e.printStackTrace(); + return defaultBottomMenu(); + } + } + + /** + * Returns the bottom menu for an account + * + * @param account Account + * @return BottomMenu - {@link BottomMenu} + */ + public BottomMenu getBottomMenu(Account account) throws DBException { if (db == null) { throw new DBException("db is null. Wrong initialization."); } @@ -207,9 +260,12 @@ public class BottomMenu implements Serializable { BottomMenu bottomMenu = cursorToBottomMenu(c); List menuItemList = new ArrayList<>(); if (bottomMenu != null) { + int inc = 0; for (MenuItem menuItem : bottomMenu.bottom_menu) { if (menuItem.visible) { - menuItemList.add(menuItem.position, menuItem); + menuItem.position = inc; + menuItemList.add(menuItem); + inc++; } } bottomMenu.bottom_menu = menuItemList; @@ -219,11 +275,24 @@ public class BottomMenu implements Serializable { } return bottomMenu; } catch (Exception e) { + e.printStackTrace(); return defaultBottomMenu(); } } - private BottomMenu defaultBottomMenu() { + public boolean bottomMenuExists(BottomMenu bottomMenu) throws DBException { + if (db == null) { + throw new DBException("db is null. Wrong initialization."); + } + Cursor mCount = db.rawQuery("select count(*) from " + Sqlite.TABLE_BOTTOM_MENU + + " where " + Sqlite.COL_INSTANCE + " = '" + bottomMenu.instance + "' AND " + Sqlite.COL_USER_ID + " = '" + bottomMenu.user_id + "'", null); + mCount.moveToFirst(); + int count = mCount.getInt(0); + mCount.close(); + return (count > 0); + } + + public BottomMenu defaultBottomMenu() { BottomMenu bottomMenu = new BottomMenu(); bottomMenu.bottom_menu = new ArrayList<>(); MenuItem menuItemHome = new MenuItem(); @@ -254,18 +323,6 @@ public class BottomMenu implements Serializable { return bottomMenu; } - public boolean bottomMenuExists(BottomMenu bottomMenu) throws DBException { - if (db == null) { - throw new DBException("db is null. Wrong initialization."); - } - Cursor mCount = db.rawQuery("select count(*) from " + Sqlite.TABLE_BOTTOM_MENU - + " where " + Sqlite.COL_INSTANCE + " = '" + bottomMenu.instance + "' AND " + Sqlite.COL_USER_ID + " = '" + bottomMenu.user_id + "'", null); - mCount.moveToFirst(); - int count = mCount.getInt(0); - mCount.close(); - return (count > 0); - } - /** * Restore pinned from db * @@ -325,10 +382,10 @@ public class BottomMenu implements Serializable { public static class MenuItem { @SerializedName("position") - int position; + public int position; @SerializedName("item_menu_type") - ItemMenuType item_menu_type; + public ItemMenuType item_menu_type; @SerializedName("visible") - boolean visible; + public boolean visible; } } diff --git a/app/src/main/java/app/fedilab/android/client/entities/Pinned.java b/app/src/main/java/app/fedilab/android/client/entities/Pinned.java index 91277aaf..3057956e 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/Pinned.java +++ b/app/src/main/java/app/fedilab/android/client/entities/Pinned.java @@ -172,6 +172,25 @@ public class Pinned implements Serializable { } } + + /** + * Returns the pinned timeline for an account + * + * @param account Account + * @return Pinned - {@link Pinned} + */ + public Pinned getAllPinned(Account account) throws DBException { + if (db == null) { + throw new DBException("db is null. Wrong initialization."); + } + try { + Cursor c = db.query(Sqlite.TABLE_PINNED_TIMELINES, null, Sqlite.COL_INSTANCE + " = '" + account.instance + "' AND " + Sqlite.COL_USER_ID + " = '" + account.user_id + "'", null, null, null, Sqlite.COL_UPDATED_AT + " DESC", "1"); + return cursorToPined(c); + } catch (Exception e) { + return null; + } + } + public boolean pinnedExist(Pinned pinned) throws DBException { if (db == null) { throw new DBException("db is null. Wrong initialization."); diff --git a/app/src/main/java/app/fedilab/android/helper/Helper.java b/app/src/main/java/app/fedilab/android/helper/Helper.java index 1a54553a..17399903 100644 --- a/app/src/main/java/app/fedilab/android/helper/Helper.java +++ b/app/src/main/java/app/fedilab/android/helper/Helper.java @@ -163,6 +163,8 @@ public class Helper { public static final String BROADCAST_DATA = "BROADCAST_DATA"; public static final String RECEIVE_REDRAW_TOPBAR = "RECEIVE_REDRAW_TOPBAR"; + public static final String RECEIVE_REDRAW_BOTTOM = "RECEIVE_REDRAW_BOTTOM"; + public static final String RECEIVE_STATUS_ACTION = "RECEIVE_STATUS_ACTION"; public static final String RECEIVE_RECREATE_ACTIVITY = "RECEIVE_RECREATE_ACTIVITY"; diff --git a/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java b/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java index 979af166..5b0b8545 100644 --- a/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java @@ -43,6 +43,7 @@ import java.util.List; import app.fedilab.android.BaseMainActivity; import app.fedilab.android.R; +import app.fedilab.android.client.entities.BottomMenu; import app.fedilab.android.client.entities.Pinned; import app.fedilab.android.client.entities.Timeline; import app.fedilab.android.client.entities.app.PinnedTimeline; @@ -63,7 +64,12 @@ public class PinnedTimelineHelper { Collections.sort(pinnedTimelineList, (obj1, obj2) -> Integer.compare(obj1.position, obj2.position)); } - public synchronized static void redrawTopBarPinned(BaseMainActivity activity, ActivityMainBinding activityMainBinding, Pinned pinned, List mastodonLists) { + public static void sortMenuItem(List menuItemList) { + //noinspection ComparatorCombinators + Collections.sort(menuItemList, (obj1, obj2) -> Integer.compare(obj1.position, obj2.position)); + } + + public synchronized static void redrawTopBarPinned(BaseMainActivity activity, ActivityMainBinding activityMainBinding, Pinned pinned, BottomMenu bottomMenu, List mastodonLists) { //Values must be initialized if there is no records in db if (pinned == null) { pinned = new Pinned(); @@ -93,16 +99,16 @@ public class PinnedTimelineHelper { if (!present) { pinnedToRemove.add(pinnedTimeline); needRedraw = true; //Something changed, redraw must be done - try { - new Pinned(activity).updatePinned(pinned); - } catch (DBException e) { - e.printStackTrace(); - } } } } if (pinnedToRemove.size() > 0) { pinned.pinnedTimelines.removeAll(pinnedToRemove); + try { + new Pinned(activity).updatePinned(pinned); + } catch (DBException e) { + e.printStackTrace(); + } } for (MastodonList mastodonList : mastodonLists) { @@ -197,7 +203,7 @@ public class PinnedTimelineHelper { activityMainBinding.viewPager.clearOnPageChangeListeners(); activityMainBinding.tabLayout.clearOnTabSelectedListeners(); - FedilabPageAdapter fedilabPageAdapter = new FedilabPageAdapter(activity.getSupportFragmentManager(), pinned); + FedilabPageAdapter fedilabPageAdapter = new FedilabPageAdapter(activity.getSupportFragmentManager(), pinned, bottomMenu); activityMainBinding.viewPager.setAdapter(fedilabPageAdapter); activityMainBinding.viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(activityMainBinding.tabLayout)); activityMainBinding.viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ReorderBottomMenuAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ReorderBottomMenuAdapter.java new file mode 100644 index 00000000..8278e269 --- /dev/null +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ReorderBottomMenuAdapter.java @@ -0,0 +1,184 @@ +package app.fedilab.android.ui.drawer; +/* Copyright 2022 Thomas Schneider + * + * This file is a part of Fedilab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Fedilab; if not, + * see . */ + + +import android.annotation.SuppressLint; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.ViewGroup; +import android.widget.Toast; + +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.RecyclerView; + +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; + +import app.fedilab.android.R; +import app.fedilab.android.activities.ReorderTimelinesActivity; +import app.fedilab.android.client.entities.BottomMenu; +import app.fedilab.android.databinding.DrawerReorderBinding; +import app.fedilab.android.exception.DBException; +import app.fedilab.android.helper.itemtouchhelper.ItemTouchHelperAdapter; +import app.fedilab.android.helper.itemtouchhelper.ItemTouchHelperViewHolder; +import app.fedilab.android.helper.itemtouchhelper.OnStartDragListener; +import es.dmoral.toasty.Toasty; + + +/** + * Simple RecyclerView.Adapter that implements {@link ItemTouchHelperAdapter} to respond to move and + * dismiss events from a {@link androidx.recyclerview.widget.ItemTouchHelper}. + * + * @author Paul Burke (ipaulpro) + */ +public class ReorderBottomMenuAdapter extends RecyclerView.Adapter implements ItemTouchHelperAdapter { + + private final OnStartDragListener mDragStartListener; + private final BottomMenu bottomMenu; + private Context context; + + public ReorderBottomMenuAdapter(BottomMenu bottomMenu, OnStartDragListener dragStartListener) { + this.mDragStartListener = dragStartListener; + this.bottomMenu = bottomMenu; + } + + @NotNull + @Override + public ReorderViewHolder onCreateViewHolder(@NotNull ViewGroup parent, int viewType) { + context = parent.getContext(); + DrawerReorderBinding itemBinding = DrawerReorderBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); + return new ReorderViewHolder(itemBinding); + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public void onBindViewHolder(@NotNull final RecyclerView.ViewHolder viewHolder, int position) { + + ReorderViewHolder holder = (ReorderViewHolder) viewHolder; + String title = ""; + switch (bottomMenu.bottom_menu.get(position).item_menu_type) { + case HOME: + holder.binding.icon.setImageResource(R.drawable.ic_baseline_home_24); + title = context.getString(R.string.home_menu); + break; + case LOCAL: + holder.binding.icon.setImageResource(R.drawable.ic_baseline_people_alt_24); + title = context.getString(R.string.local); + break; + case PUBLIC: + holder.binding.icon.setImageResource(R.drawable.ic_baseline_public_24); + title = context.getString(R.string.v_public); + break; + case NOTIFICATION: + holder.binding.icon.setImageResource(R.drawable.ic_baseline_notifications_24); + title = context.getString(R.string.notifications); + break; + case DIRECT: + holder.binding.icon.setImageResource(R.drawable.ic_baseline_mail_24); + title = context.getString(R.string.v_private); + break; + } + holder.binding.text.setText(title); + + if (bottomMenu.bottom_menu.get(position).visible) { + holder.binding.hide.setImageResource(R.drawable.ic_baseline_visibility_24); + } else { + holder.binding.hide.setImageResource(R.drawable.ic_baseline_visibility_off_24); + } + + holder.binding.hide.setOnClickListener(v -> { + bottomMenu.bottom_menu.get(position).visible = !bottomMenu.bottom_menu.get(position).visible; + if (bottomMenu.bottom_menu.get(position).visible) { + holder.binding.hide.setImageResource(R.drawable.ic_baseline_visibility_24); + } else { + holder.binding.hide.setImageResource(R.drawable.ic_baseline_visibility_off_24); + } + new Thread(() -> { + try { + new BottomMenu(context).insertOrUpdate(bottomMenu); + ((ReorderTimelinesActivity) context).setBottomChanges(true); + } catch (DBException e) { + e.printStackTrace(); + } + }).start(); + }); + + // Start a drag whenever the handle view it touched + holder.binding.handle.setOnTouchListener((v, event) -> { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + mDragStartListener.onStartDrag(holder); + return true; + } + return false; + }); + + } + + @Override + public void onItemDismiss(int position) { + BottomMenu.MenuItem menuItem = bottomMenu.bottom_menu.get(position); + notifyItemChanged(position); + Toasty.info(context, context.getString(R.string.warning_main_timeline), Toast.LENGTH_SHORT).show(); + } + + @Override + public boolean onItemMove(int fromPosition, int toPosition) { + Collections.swap(bottomMenu.bottom_menu, fromPosition, toPosition); + //update position value + for (int j = 0; j < bottomMenu.bottom_menu.size(); j++) { + bottomMenu.bottom_menu.get(j).position = j; + } + notifyItemMoved(fromPosition, toPosition); + try { + new BottomMenu(context).insertOrUpdate(bottomMenu); + ((ReorderTimelinesActivity) context).setBottomChanges(true); + } catch (DBException e) { + e.printStackTrace(); + } + return true; + } + + @Override + public int getItemCount() { + return bottomMenu.bottom_menu.size(); + } + + /** + * Simple example of a view holder that implements {@link ItemTouchHelperViewHolder} and has a + * "handle" view that initiates a drag event when touched. + */ + public class ReorderViewHolder extends RecyclerView.ViewHolder implements ItemTouchHelperViewHolder { + + DrawerReorderBinding binding; + + ReorderViewHolder(DrawerReorderBinding itemView) { + super(itemView.getRoot()); + binding = itemView; + } + + @Override + public void onItemSelected() { + itemView.setBackgroundColor(ContextCompat.getColor(context, R.color.mastodonC3)); + } + + @Override + public void onItemClear() { + itemView.setBackgroundColor(0); + } + } +} diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ReorderTabAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ReorderTabAdapter.java index 83effc89..82bf356f 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ReorderTabAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ReorderTabAdapter.java @@ -30,6 +30,7 @@ import org.jetbrains.annotations.NotNull; import java.util.Collections; import app.fedilab.android.R; +import app.fedilab.android.activities.ReorderTimelinesActivity; import app.fedilab.android.client.entities.Pinned; import app.fedilab.android.client.entities.Timeline; import app.fedilab.android.client.entities.app.PinnedTimeline; @@ -121,14 +122,11 @@ public class ReorderTabAdapter extends RecyclerView.Adapter { pinned.pinnedTimelines.get(position).displayed = !pinned.pinnedTimelines.get(position).displayed; - if (pinned.pinnedTimelines.get(position).displayed) { - holder.binding.hide.setImageResource(R.drawable.ic_baseline_visibility_24); - } else { - holder.binding.hide.setImageResource(R.drawable.ic_baseline_visibility_off_24); - } + notifyItemChanged(position); new Thread(() -> { try { new Pinned(context).updatePinned(pinned); + ((ReorderTimelinesActivity) context).setChanges(true); } catch (DBException e) { e.printStackTrace(); } @@ -169,6 +167,7 @@ public class ReorderTabAdapter extends RecyclerView.Adapter resultsMutableLiveData; private MutableLiveData pinnedMutableLiveData; + private MutableLiveData bottomMenuMutableLiveData; public ReorderVM(@NonNull Application application) { super(application); @@ -67,7 +69,7 @@ public class ReorderVM extends AndroidViewModel { new Thread(() -> { Pinned pinned = null; try { - pinned = new Pinned(getApplication().getApplicationContext()).getPinned(BaseMainActivity.accountWeakReference.get()); + pinned = new Pinned(getApplication().getApplicationContext()).getAllPinned(BaseMainActivity.accountWeakReference.get()); } catch (DBException e) { e.printStackTrace(); } @@ -80,6 +82,23 @@ public class ReorderVM extends AndroidViewModel { } + public LiveData getBottomMenu() { + bottomMenuMutableLiveData = new MutableLiveData<>(); + new Thread(() -> { + BottomMenu bottomMenu = null; + try { + bottomMenu = new BottomMenu(getApplication().getApplicationContext()).getAllBottomMenu(BaseMainActivity.accountWeakReference.get()); + } catch (DBException e) { + e.printStackTrace(); + } + Handler mainHandler = new Handler(Looper.getMainLooper()); + BottomMenu finalBottomMenu = bottomMenu; + Runnable myRunnable = () -> bottomMenuMutableLiveData.setValue(finalBottomMenu); + mainHandler.post(myRunnable); + }).start(); + return bottomMenuMutableLiveData; + } + /** * Search for content in accounts, statuses and hashtags with API v2 * diff --git a/app/src/main/res/layout/activity_reorder_tabs.xml b/app/src/main/res/layout/activity_reorder_tabs.xml index 9a076925..72127e90 100644 --- a/app/src/main/res/layout/activity_reorder_tabs.xml +++ b/app/src/main/res/layout/activity_reorder_tabs.xml @@ -14,60 +14,84 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see . --> - - + android:layout_height="wrap_content"> - - - - - + android:layout_marginTop="20dp" + app:layout_constraintTop_toTopOf="parent"> - + + + + - - + android:layout_marginTop="20dp" + app:layout_constraintTop_toBottomOf="@+id/lv_reorder_bottom_container"> + + + + + + + + + + + + +