Keep selected application on screen rotation

This commit is contained in:
Sternagfonkel
2022-01-30 10:02:28 +01:00
committed by GitHub
parent 8d36edc75e
commit 09ccd4d2e2
4 changed files with 185 additions and 84 deletions

View File

@@ -28,6 +28,7 @@ import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
@@ -61,7 +62,6 @@ import com.github.gotify.messages.provider.MessageDeletion;
import com.github.gotify.messages.provider.MessageFacade;
import com.github.gotify.messages.provider.MessageState;
import com.github.gotify.messages.provider.MessageWithImage;
import com.github.gotify.picasso.PicassoHandler;
import com.github.gotify.service.WebSocketService;
import com.github.gotify.settings.SettingsActivity;
import com.github.gotify.sharing.ShareActivity;
@@ -70,7 +70,6 @@ import com.google.android.material.snackbar.BaseTransientBottomBar;
import com.google.android.material.snackbar.Snackbar;
import com.squareup.picasso.Target;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -80,7 +79,7 @@ import static java.util.Collections.emptyList;
public class MessagesActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private BroadcastReceiver receiver =
private final BroadcastReceiver receiver =
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -90,7 +89,7 @@ public class MessagesActivity extends AppCompatActivity
}
};
private int APPLICATION_ORDER = 1;
private static final int APPLICATION_ORDER = 1;
@BindView(R.id.toolbar)
Toolbar toolbar;
@@ -110,51 +109,36 @@ public class MessagesActivity extends AppCompatActivity
@BindView(R.id.flipper)
ViewFlipper flipper;
private MessageFacade messages;
private ApiClient client;
private Settings settings;
protected ApplicationHolder appsHolder;
private long appId = MessageState.ALL_MESSAGES;
private MessagesModel viewModel;
private boolean isLoadMore = false;
private Long selectAppIdOnDrawerClose = null;
private PicassoHandler picassoHandler;
private Long updateAppOnDrawerClose = null;
private ListMessageAdapter listMessageAdapter;
// we need to keep the target references otherwise they get gc'ed before they can be called.
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private final List<Target> targetReferences = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messages);
ButterKnife.bind(this);
viewModel =
new ViewModelProvider(this, new MessagesModelFactory(this))
.get(MessagesModel.class);
Log.i("Entering " + getClass().getSimpleName());
settings = new Settings(this);
picassoHandler = new PicassoHandler(this, settings);
client =
ClientFactory.clientToken(settings.url(), settings.sslSettings(), settings.token());
appsHolder = new ApplicationHolder(this, client);
appsHolder.onUpdate(() -> onUpdateApps(appsHolder.get()));
appsHolder.request();
initDrawer();
messages = new MessageFacade(client.createService(MessageApi.class), appsHolder);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
DividerItemDecoration dividerItemDecoration =
new DividerItemDecoration(
messagesView.getContext(), layoutManager.getOrientation());
listMessageAdapter =
new ListMessageAdapter(
this, settings, picassoHandler.get(), emptyList(), this::scheduleDeletion);
this,
viewModel.getSettings(),
viewModel.getPicassoHandler().get(),
emptyList(),
this::scheduleDeletion);
messagesView.addItemDecoration(dividerItemDecoration);
messagesView.setHasFixedSize(true);
@@ -162,6 +146,11 @@ public class MessagesActivity extends AppCompatActivity
messagesView.addOnScrollListener(new MessageListOnScrollListener());
messagesView.setAdapter(listMessageAdapter);
ApplicationHolder appsHolder = viewModel.getAppsHolder();
appsHolder.onUpdate(() -> onUpdateApps(appsHolder.get()));
if (appsHolder.wasRequested()) onUpdateApps(appsHolder.get());
else appsHolder.request();
ItemTouchHelper itemTouchHelper =
new ItemTouchHelper(new SwipeToDeleteCallback(listMessageAdapter));
itemTouchHelper.attachToRecyclerView(messagesView);
@@ -171,11 +160,10 @@ public class MessagesActivity extends AppCompatActivity
new DrawerLayout.SimpleDrawerListener() {
@Override
public void onDrawerClosed(View drawerView) {
if (selectAppIdOnDrawerClose != null) {
appId = selectAppIdOnDrawerClose;
new SelectApplicationAndUpdateMessages(true)
.execute(selectAppIdOnDrawerClose);
selectAppIdOnDrawerClose = null;
if (updateAppOnDrawerClose != null) {
viewModel.setAppId(updateAppOnDrawerClose);
new UpdateMessagesForApplication(true).execute(updateAppOnDrawerClose);
updateAppOnDrawerClose = null;
invalidateOptionsMenu();
}
}
@@ -194,7 +182,7 @@ public class MessagesActivity extends AppCompatActivity
}
});
new SelectApplicationAndUpdateMessages(true).execute(appId);
new UpdateMessagesForApplication(true).execute(viewModel.getAppId());
}
public void onRefreshAll(View view) {
@@ -203,7 +191,7 @@ public class MessagesActivity extends AppCompatActivity
public void refreshAll() {
try {
picassoHandler.evict();
viewModel.getPicassoHandler().evict();
} catch (IOException e) {
Log.e("Problem evicting Picasso cache", e);
}
@@ -212,8 +200,8 @@ public class MessagesActivity extends AppCompatActivity
}
private void onRefresh() {
messages.clear();
new LoadMore().execute(appId);
viewModel.getMessages().clear();
new LoadMore().execute(viewModel.getAppId());
}
@OnClick(R.id.learn_gotify)
@@ -230,22 +218,29 @@ public class MessagesActivity extends AppCompatActivity
protected void onUpdateApps(List<Application> applications) {
Menu menu = navigationView.getMenu();
menu.removeGroup(R.id.apps);
targetReferences.clear();
updateMessagesAndStopLoading(messages.get(appId));
viewModel.getTargetReferences().clear();
updateMessagesAndStopLoading(viewModel.getMessages().get(viewModel.getAppId()));
MenuItem selectedItem = menu.findItem(R.id.nav_all_messages);
for (int i = 0; i < applications.size(); i++) {
Application app = applications.get(i);
MenuItem item = menu.add(R.id.apps, i, APPLICATION_ORDER, app.getName());
item.setCheckable(true);
if (app.getId() == viewModel.getAppId()) selectedItem = item;
Target t = Utils.toDrawable(getResources(), item::setIcon);
targetReferences.add(t);
picassoHandler
viewModel.getTargetReferences().add(t);
viewModel
.getPicassoHandler()
.get()
.load(Utils.resolveAbsoluteUrl(settings.url() + "/", app.getImage()))
.load(
Utils.resolveAbsoluteUrl(
viewModel.getSettings().url() + "/", app.getImage()))
.error(R.drawable.ic_alarm)
.placeholder(R.drawable.ic_placeholder)
.resize(100, 100)
.into(t);
}
selectAppInMenu(selectedItem);
}
private void initDrawer() {
@@ -264,6 +259,8 @@ public class MessagesActivity extends AppCompatActivity
navigationView.setNavigationItemSelectedListener(this);
View headerView = navigationView.getHeaderView(0);
Settings settings = viewModel.getSettings();
TextView user = headerView.findViewById(R.id.header_user);
user.setText(settings.user().getName());
@@ -288,19 +285,18 @@ public class MessagesActivity extends AppCompatActivity
}
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (item.getGroupId() == R.id.apps) {
Application app = appsHolder.get().get(id);
selectAppIdOnDrawerClose = app != null ? app.getId() : MessageState.ALL_MESSAGES;
Application app = viewModel.getAppsHolder().get().get(id);
updateAppOnDrawerClose = app != null ? app.getId() : MessageState.ALL_MESSAGES;
startLoading();
toolbar.setSubtitle(item.getTitle());
} else if (id == R.id.nav_all_messages) {
selectAppIdOnDrawerClose = MessageState.ALL_MESSAGES;
updateAppOnDrawerClose = MessageState.ALL_MESSAGES;
startLoading();
toolbar.setSubtitle("");
} else if (id == R.id.logout) {
@@ -349,20 +345,21 @@ public class MessagesActivity extends AppCompatActivity
IntentFilter filter = new IntentFilter();
filter.addAction(WebSocketService.NEW_MESSAGE_BROADCAST);
registerReceiver(receiver, filter);
new UpdateMissedMessages().execute(messages.getLastReceivedMessage());
new UpdateMissedMessages().execute(viewModel.getMessages().getLastReceivedMessage());
int selectedIndex = R.id.nav_all_messages;
long appId = viewModel.getAppId();
if (appId != MessageState.ALL_MESSAGES) {
for (int i = 0; i < appsHolder.get().size(); i++) {
if (appsHolder.get().get(i).getId() == appId) {
List<Application> apps = viewModel.getAppsHolder().get();
for (int i = 0; i < apps.size(); i++) {
if (apps.get(i).getId() == appId) {
selectedIndex = i;
}
}
}
listMessageAdapter.notifyDataSetChanged();
navigationView.getMenu().findItem(selectedIndex).setChecked(true);
selectAppInMenu(navigationView.getMenu().findItem(selectedIndex));
super.onResume();
}
@@ -372,17 +369,20 @@ public class MessagesActivity extends AppCompatActivity
super.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
picassoHandler.get().shutdown();
private void selectAppInMenu(MenuItem appItem) {
if (appItem != null) {
appItem.setChecked(true);
if (appItem.getItemId() != R.id.nav_all_messages)
toolbar.setSubtitle(appItem.getTitle());
}
}
private void scheduleDeletion(int position, Message message, boolean listAnimation) {
ListMessageAdapter adapter = (ListMessageAdapter) messagesView.getAdapter();
MessageFacade messages = viewModel.getMessages();
messages.deleteLocal(message);
adapter.setItems(messages.get(appId));
adapter.setItems(messages.get(viewModel.getAppId()));
if (listAnimation) adapter.notifyItemRemoved(position);
else adapter.notifyDataSetChanged();
@@ -391,10 +391,11 @@ public class MessagesActivity extends AppCompatActivity
}
private void undoDelete() {
MessageFacade messages = viewModel.getMessages();
MessageDeletion deletion = messages.undoDeleteLocal();
if (deletion != null) {
ListMessageAdapter adapter = (ListMessageAdapter) messagesView.getAdapter();
long appId = viewModel.getAppId();
adapter.setItems(messages.get(appId));
int insertPosition =
appId == MessageState.ALL_MESSAGES
@@ -428,7 +429,7 @@ public class MessagesActivity extends AppCompatActivity
}
private class SwipeToDeleteCallback extends ItemTouchHelper.SimpleCallback {
private ListMessageAdapter adapter;
private final ListMessageAdapter adapter;
private Drawable icon;
private final ColorDrawable background;
@@ -525,7 +526,7 @@ public class MessagesActivity extends AppCompatActivity
private class MessageListOnScrollListener extends RecyclerView.OnScrollListener {
@Override
public void onScrollStateChanged(RecyclerView view, int scrollState) {}
public void onScrollStateChanged(@NonNull RecyclerView view, int scrollState) {}
@Override
public void onScrolled(RecyclerView view, int dx, int dy) {
@@ -536,10 +537,10 @@ public class MessagesActivity extends AppCompatActivity
if (lastVisibleItem > totalItemCount - 15
&& totalItemCount != 0
&& messages.canLoadMore(appId)) {
&& viewModel.getMessages().canLoadMore(viewModel.getAppId())) {
if (!isLoadMore) {
isLoadMore = true;
new LoadMore().execute(appId);
new LoadMore().execute(viewModel.getAppId());
}
}
}
@@ -555,16 +556,16 @@ public class MessagesActivity extends AppCompatActivity
}
List<Message> newMessages =
new MissedMessageUtil(client.createService(MessageApi.class))
new MissedMessageUtil(viewModel.getClient().createService(MessageApi.class))
.missingMessages(id);
messages.addMessages(newMessages);
viewModel.getMessages().addMessages(newMessages);
return !newMessages.isEmpty();
}
@Override
protected void onPostExecute(Boolean update) {
if (update) {
new SelectApplicationAndUpdateMessages(true).execute(appId);
new UpdateMessagesForApplication(true).execute(viewModel.getAppId());
}
}
}
@@ -572,20 +573,22 @@ public class MessagesActivity extends AppCompatActivity
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.messages_action, menu);
menu.findItem(R.id.action_delete_app).setVisible(appId != MessageState.ALL_MESSAGES);
menu.findItem(R.id.action_delete_app)
.setVisible(viewModel.getAppId() != MessageState.ALL_MESSAGES);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_delete_all) {
new DeleteMessages().execute(appId);
new DeleteMessages().execute(viewModel.getAppId());
}
if (item.getItemId() == R.id.action_delete_app) {
android.app.AlertDialog.Builder alert = new android.app.AlertDialog.Builder(this);
alert.setTitle(R.string.delete_app);
alert.setMessage(R.string.ack);
alert.setPositiveButton(R.string.yes, (dialog, which) -> deleteApp(appId));
alert.setPositiveButton(
R.string.yes, (dialog, which) -> deleteApp(viewModel.getAppId()));
alert.setNegativeButton(R.string.no, (dialog, which) -> dialog.dismiss());
alert.show();
}
@@ -593,6 +596,7 @@ public class MessagesActivity extends AppCompatActivity
}
private void deleteApp(Long appId) {
Settings settings = viewModel.getSettings();
ApiClient client =
ClientFactory.clientToken(settings.url(), settings.sslSettings(), settings.token());
@@ -611,7 +615,7 @@ public class MessagesActivity extends AppCompatActivity
@Override
protected List<MessageWithImage> doInBackground(Long... appId) {
return messages.loadMore(first(appId));
return viewModel.getMessages().loadMore(first(appId));
}
@Override
@@ -620,9 +624,9 @@ public class MessagesActivity extends AppCompatActivity
}
}
private class SelectApplicationAndUpdateMessages extends AsyncTask<Long, Void, Long> {
private class UpdateMessagesForApplication extends AsyncTask<Long, Void, Long> {
private SelectApplicationAndUpdateMessages(boolean withLoadingSpinner) {
private UpdateMessagesForApplication(boolean withLoadingSpinner) {
if (withLoadingSpinner) {
startLoading();
}
@@ -631,13 +635,13 @@ public class MessagesActivity extends AppCompatActivity
@Override
protected Long doInBackground(Long... appIds) {
Long appId = first(appIds);
messages.loadMoreIfNotPresent(appId);
viewModel.getMessages().loadMoreIfNotPresent(appId);
return appId;
}
@Override
protected void onPostExecute(Long appId) {
updateMessagesAndStopLoading(messages.get(appId));
updateMessagesAndStopLoading(viewModel.getMessages().get(appId));
}
}
@@ -645,13 +649,13 @@ public class MessagesActivity extends AppCompatActivity
@Override
protected Void doInBackground(Message... newMessages) {
messages.addMessages(Arrays.asList(newMessages));
viewModel.getMessages().addMessages(Arrays.asList(newMessages));
return null;
}
@Override
protected void onPostExecute(Void data) {
new SelectApplicationAndUpdateMessages(false).execute(appId);
new UpdateMessagesForApplication(false).execute(viewModel.getAppId());
}
}
@@ -659,13 +663,13 @@ public class MessagesActivity extends AppCompatActivity
@Override
protected Void doInBackground(Void... messages) {
MessagesActivity.this.messages.commitDelete();
viewModel.getMessages().commitDelete();
return null;
}
@Override
protected void onPostExecute(Void data) {
new SelectApplicationAndUpdateMessages(false).execute(appId);
new UpdateMessagesForApplication(false).execute(viewModel.getAppId());
}
}
@@ -677,7 +681,7 @@ public class MessagesActivity extends AppCompatActivity
@Override
protected Boolean doInBackground(Long... appId) {
return messages.deleteAll(first(appId));
return viewModel.getMessages().deleteAll(first(appId));
}
@Override
@@ -685,7 +689,7 @@ public class MessagesActivity extends AppCompatActivity
if (!success) {
Utils.showSnackBar(MessagesActivity.this, "Delete failed :(");
}
new SelectApplicationAndUpdateMessages(false).execute(appId);
new UpdateMessagesForApplication(false).execute(viewModel.getAppId());
}
}
@@ -693,6 +697,7 @@ public class MessagesActivity extends AppCompatActivity
@Override
protected Void doInBackground(Void... ignore) {
Settings settings = viewModel.getSettings();
ClientApi api =
ClientFactory.clientToken(
settings.url(), settings.sslSettings(), settings.token())
@@ -724,7 +729,7 @@ public class MessagesActivity extends AppCompatActivity
@Override
protected void onPostExecute(Void aVoid) {
settings.clear();
viewModel.getSettings().clear();
startActivity(new Intent(MessagesActivity.this, LoginActivity.class));
finish();
super.onPostExecute(aVoid);