2018-10-20 14:42:03 +00:00
|
|
|
package eu.faircode.email;
|
|
|
|
|
2018-10-29 08:09:56 +00:00
|
|
|
/*
|
|
|
|
This file is part of FairEmail.
|
|
|
|
|
|
|
|
FairEmail 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.
|
|
|
|
|
2018-10-29 10:46:49 +00:00
|
|
|
FairEmail is distributed in the hope that it will be useful,
|
2018-10-29 08:09:56 +00:00
|
|
|
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
|
2018-10-29 10:46:49 +00:00
|
|
|
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
|
2018-10-29 08:09:56 +00:00
|
|
|
|
2018-12-31 08:04:33 +00:00
|
|
|
Copyright 2018-2019 by Marcel Bokhorst (M66B)
|
2018-10-29 08:09:56 +00:00
|
|
|
*/
|
|
|
|
|
2019-05-14 16:34:09 +00:00
|
|
|
import android.content.Context;
|
|
|
|
import android.content.SharedPreferences;
|
2019-07-28 08:09:00 +00:00
|
|
|
import android.os.Bundle;
|
2019-05-14 16:34:09 +00:00
|
|
|
import android.text.TextUtils;
|
|
|
|
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
import androidx.annotation.Nullable;
|
2019-01-12 10:45:57 +00:00
|
|
|
import androidx.lifecycle.Lifecycle;
|
|
|
|
import androidx.lifecycle.LifecycleObserver;
|
|
|
|
import androidx.lifecycle.LifecycleOwner;
|
|
|
|
import androidx.lifecycle.LiveData;
|
|
|
|
import androidx.lifecycle.Observer;
|
|
|
|
import androidx.lifecycle.OnLifecycleEvent;
|
2018-10-20 14:42:03 +00:00
|
|
|
import androidx.lifecycle.ViewModel;
|
2019-05-14 16:34:09 +00:00
|
|
|
import androidx.paging.LivePagedListBuilder;
|
2018-10-20 14:42:03 +00:00
|
|
|
import androidx.paging.PagedList;
|
2019-05-14 16:34:09 +00:00
|
|
|
import androidx.preference.PreferenceManager;
|
2019-07-28 08:09:00 +00:00
|
|
|
import androidx.room.paging.LimitOffsetDataSource;
|
2018-10-20 14:42:03 +00:00
|
|
|
|
2019-05-14 16:34:09 +00:00
|
|
|
import java.util.ArrayList;
|
2019-04-17 18:21:44 +00:00
|
|
|
import java.util.HashMap;
|
2019-07-28 08:09:00 +00:00
|
|
|
import java.util.List;
|
2019-04-17 18:21:44 +00:00
|
|
|
import java.util.Map;
|
2019-05-14 16:34:09 +00:00
|
|
|
import java.util.Objects;
|
|
|
|
import java.util.concurrent.ExecutorService;
|
2019-04-17 18:21:44 +00:00
|
|
|
|
2018-10-20 14:42:03 +00:00
|
|
|
public class ViewModelMessages extends ViewModel {
|
2019-05-14 16:34:09 +00:00
|
|
|
private AdapterMessage.ViewType last = AdapterMessage.ViewType.UNIFIED;
|
|
|
|
private Map<AdapterMessage.ViewType, Model> models = new HashMap<>();
|
|
|
|
|
2019-10-10 11:26:44 +00:00
|
|
|
private ExecutorService executor = Helper.getBackgroundExecutor(2, "model");
|
2019-05-14 16:34:09 +00:00
|
|
|
|
2019-11-18 08:05:38 +00:00
|
|
|
static final int LOCAL_PAGE_SIZE = 100;
|
2019-05-14 16:34:09 +00:00
|
|
|
private static final int REMOTE_PAGE_SIZE = 10;
|
2019-10-29 10:35:44 +00:00
|
|
|
private static final int SEARCH_PAGE_SIZE = 10;
|
2019-05-28 09:57:38 +00:00
|
|
|
private static final int LOW_MEM_MB = 32;
|
2019-05-14 16:34:09 +00:00
|
|
|
|
2019-05-15 15:05:11 +00:00
|
|
|
Model getModel(
|
2019-05-16 17:09:51 +00:00
|
|
|
final Context context, final LifecycleOwner owner,
|
2019-05-14 16:34:09 +00:00
|
|
|
final AdapterMessage.ViewType viewType,
|
2019-07-19 06:27:44 +00:00
|
|
|
String type, long account, long folder,
|
|
|
|
String thread, long id,
|
2019-05-15 15:05:11 +00:00
|
|
|
String query, boolean server) {
|
2019-05-14 16:34:09 +00:00
|
|
|
|
2019-09-09 07:46:54 +00:00
|
|
|
Args args = new Args(context, viewType, type, account, folder, thread, id, query, server);
|
2019-05-17 14:44:37 +00:00
|
|
|
Log.i("Get model=" + viewType + " " + args);
|
2019-05-14 16:34:09 +00:00
|
|
|
dump();
|
|
|
|
|
|
|
|
Model model = models.get(viewType);
|
|
|
|
if (model == null || !model.args.equals(args)) {
|
2019-05-17 14:44:37 +00:00
|
|
|
Log.i("Creating model=" + viewType + " replace=" + (model != null));
|
2019-01-12 10:45:57 +00:00
|
|
|
|
2019-08-09 17:29:17 +00:00
|
|
|
if (model != null)
|
2019-06-20 05:25:38 +00:00
|
|
|
model.list.removeObservers(owner);
|
2019-01-14 07:21:48 +00:00
|
|
|
|
2019-05-14 16:34:09 +00:00
|
|
|
DB db = DB.getInstance(context);
|
|
|
|
|
|
|
|
BoundaryCallbackMessages boundary = null;
|
2019-10-02 19:13:10 +00:00
|
|
|
if (viewType == AdapterMessage.ViewType.FOLDER)
|
2019-05-14 16:34:09 +00:00
|
|
|
boundary = new BoundaryCallbackMessages(context,
|
2019-10-02 19:13:10 +00:00
|
|
|
args.folder, true, args.query, REMOTE_PAGE_SIZE);
|
|
|
|
else if (viewType == AdapterMessage.ViewType.SEARCH)
|
|
|
|
boundary = new BoundaryCallbackMessages(context,
|
|
|
|
args.folder, args.server, args.query,
|
|
|
|
args.server ? REMOTE_PAGE_SIZE : SEARCH_PAGE_SIZE);
|
2019-05-14 16:34:09 +00:00
|
|
|
|
|
|
|
LivePagedListBuilder<Integer, TupleMessageEx> builder = null;
|
|
|
|
switch (viewType) {
|
|
|
|
case UNIFIED:
|
|
|
|
builder = new LivePagedListBuilder<>(
|
2019-07-19 06:27:44 +00:00
|
|
|
db.message().pagedUnified(
|
|
|
|
args.type,
|
2019-05-14 16:34:09 +00:00
|
|
|
args.threading,
|
2019-09-03 08:33:52 +00:00
|
|
|
args.sort, args.ascending,
|
2019-05-14 16:34:09 +00:00
|
|
|
args.filter_seen, args.filter_unflagged, args.filter_snoozed,
|
|
|
|
false,
|
|
|
|
args.debug),
|
|
|
|
LOCAL_PAGE_SIZE);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FOLDER:
|
|
|
|
PagedList.Config configFolder = new PagedList.Config.Builder()
|
2019-06-07 07:53:29 +00:00
|
|
|
.setInitialLoadSizeHint(LOCAL_PAGE_SIZE)
|
2019-05-14 16:34:09 +00:00
|
|
|
.setPageSize(LOCAL_PAGE_SIZE)
|
|
|
|
.setPrefetchDistance(REMOTE_PAGE_SIZE)
|
|
|
|
.build();
|
|
|
|
builder = new LivePagedListBuilder<>(
|
|
|
|
db.message().pagedFolder(
|
|
|
|
args.folder, args.threading,
|
2019-09-03 08:33:52 +00:00
|
|
|
args.sort, args.ascending,
|
2019-05-14 16:34:09 +00:00
|
|
|
args.filter_seen, args.filter_unflagged, args.filter_snoozed,
|
|
|
|
false,
|
|
|
|
args.debug),
|
|
|
|
configFolder);
|
|
|
|
builder.setBoundaryCallback(boundary);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case THREAD:
|
|
|
|
builder = new LivePagedListBuilder<>(
|
|
|
|
db.message().pagedThread(
|
|
|
|
args.account, args.thread,
|
|
|
|
args.threading ? null : args.id,
|
2019-09-09 06:56:33 +00:00
|
|
|
args.ascending,
|
2019-05-14 16:34:09 +00:00
|
|
|
args.debug), LOCAL_PAGE_SIZE);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SEARCH:
|
|
|
|
PagedList.Config configSearch = new PagedList.Config.Builder()
|
|
|
|
.setPageSize(LOCAL_PAGE_SIZE)
|
|
|
|
.setPrefetchDistance(REMOTE_PAGE_SIZE)
|
|
|
|
.build();
|
|
|
|
if (args.folder < 0)
|
|
|
|
builder = new LivePagedListBuilder<>(
|
2019-07-19 06:27:44 +00:00
|
|
|
db.message().pagedUnified(
|
|
|
|
null,
|
2019-05-14 16:34:09 +00:00
|
|
|
args.threading,
|
2019-09-03 08:33:52 +00:00
|
|
|
"time", false,
|
2019-05-14 16:34:09 +00:00
|
|
|
false, false, false,
|
|
|
|
true,
|
|
|
|
args.debug),
|
|
|
|
configSearch);
|
|
|
|
else
|
|
|
|
builder = new LivePagedListBuilder<>(
|
|
|
|
db.message().pagedFolder(
|
|
|
|
args.folder, args.threading,
|
2019-09-03 08:33:52 +00:00
|
|
|
"time", false,
|
2019-05-14 16:34:09 +00:00
|
|
|
false, false, false,
|
|
|
|
true,
|
|
|
|
args.debug),
|
|
|
|
configSearch);
|
|
|
|
builder.setBoundaryCallback(boundary);
|
|
|
|
break;
|
|
|
|
}
|
2019-02-05 08:15:05 +00:00
|
|
|
|
2019-05-14 16:34:09 +00:00
|
|
|
builder.setFetchExecutor(executor);
|
|
|
|
|
|
|
|
model = new Model(args, builder.build(), boundary);
|
|
|
|
models.put(viewType, model);
|
2019-01-31 08:57:28 +00:00
|
|
|
}
|
2019-01-12 10:45:57 +00:00
|
|
|
|
2019-05-17 14:44:37 +00:00
|
|
|
owner.getLifecycle().addObserver(new LifecycleObserver() {
|
|
|
|
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
|
|
|
|
public void onDestroyed() {
|
2019-05-22 13:41:54 +00:00
|
|
|
int free_mb = Log.getFreeMemMb();
|
2019-05-17 14:44:37 +00:00
|
|
|
boolean lowmem = (free_mb < LOW_MEM_MB);
|
|
|
|
|
|
|
|
Log.i("Destroy model=" + viewType +
|
2019-05-23 16:45:11 +00:00
|
|
|
" lowmem=" + lowmem + " free=" + free_mb + " MB");
|
2019-05-17 14:44:37 +00:00
|
|
|
|
|
|
|
Model model = models.get(viewType);
|
|
|
|
if (model != null) {
|
|
|
|
Log.i("Remove observer model=" + viewType);
|
|
|
|
model.list.removeObservers(owner);
|
|
|
|
}
|
|
|
|
|
2019-05-23 16:45:11 +00:00
|
|
|
if (viewType == AdapterMessage.ViewType.THREAD || lowmem) {
|
2019-05-17 14:44:37 +00:00
|
|
|
Log.i("Remove model=" + viewType);
|
2019-08-09 17:29:17 +00:00
|
|
|
models.remove(viewType);
|
2019-05-17 14:44:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dump();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2019-05-14 16:34:09 +00:00
|
|
|
if (viewType == AdapterMessage.ViewType.UNIFIED) {
|
2019-08-09 17:29:17 +00:00
|
|
|
models.remove(AdapterMessage.ViewType.FOLDER);
|
|
|
|
models.remove(AdapterMessage.ViewType.SEARCH);
|
2019-05-14 16:34:09 +00:00
|
|
|
} else if (viewType == AdapterMessage.ViewType.FOLDER)
|
2019-08-09 17:29:17 +00:00
|
|
|
models.remove(AdapterMessage.ViewType.SEARCH);
|
2019-01-12 10:45:57 +00:00
|
|
|
|
2019-05-16 09:24:58 +00:00
|
|
|
if (viewType != AdapterMessage.ViewType.THREAD) {
|
|
|
|
last = viewType;
|
|
|
|
Log.i("Last model=" + last);
|
|
|
|
}
|
2019-02-05 08:15:05 +00:00
|
|
|
|
2019-05-14 16:34:09 +00:00
|
|
|
Log.i("Returning model=" + viewType);
|
|
|
|
dump();
|
|
|
|
|
2019-05-15 15:05:11 +00:00
|
|
|
return model;
|
2019-01-12 10:45:57 +00:00
|
|
|
}
|
2018-10-20 14:42:03 +00:00
|
|
|
|
2018-10-21 14:07:45 +00:00
|
|
|
@Override
|
|
|
|
protected void onCleared() {
|
2019-05-14 16:34:09 +00:00
|
|
|
for (AdapterMessage.ViewType viewType : new ArrayList<>(models.keySet()))
|
|
|
|
models.remove(viewType);
|
|
|
|
}
|
|
|
|
|
|
|
|
void observePrevNext(LifecycleOwner owner, final long id, final IPrevNext intf) {
|
|
|
|
Log.i("Observe prev/next model=" + last);
|
2019-02-05 08:15:05 +00:00
|
|
|
|
2019-05-14 16:34:09 +00:00
|
|
|
Model model = models.get(last);
|
|
|
|
if (model == null) {
|
2019-07-28 08:09:00 +00:00
|
|
|
Log.w("Observe previous/next without model");
|
2019-01-26 14:32:52 +00:00
|
|
|
return;
|
2019-01-30 12:51:50 +00:00
|
|
|
}
|
2019-01-26 11:56:23 +00:00
|
|
|
|
2019-01-30 19:05:01 +00:00
|
|
|
Log.i("Observe previous/next id=" + id);
|
2019-05-14 16:34:09 +00:00
|
|
|
model.list.observe(owner, new Observer<PagedList<TupleMessageEx>>() {
|
2019-01-26 14:32:52 +00:00
|
|
|
@Override
|
2019-01-30 12:51:50 +00:00
|
|
|
public void onChanged(PagedList<TupleMessageEx> messages) {
|
2019-01-30 19:05:01 +00:00
|
|
|
Log.i("Observe previous/next id=" + id + " messages=" + messages.size());
|
2019-01-30 12:51:50 +00:00
|
|
|
|
|
|
|
for (int pos = 0; pos < messages.size(); pos++) {
|
|
|
|
TupleMessageEx item = messages.get(pos);
|
2019-01-30 19:05:01 +00:00
|
|
|
if (item != null && id == item.id) {
|
2019-01-30 12:51:50 +00:00
|
|
|
boolean load = false;
|
|
|
|
|
2019-01-26 14:32:52 +00:00
|
|
|
if (pos - 1 >= 0) {
|
2019-01-30 12:51:50 +00:00
|
|
|
TupleMessageEx next = messages.get(pos - 1);
|
2019-01-26 14:32:52 +00:00
|
|
|
if (next == null)
|
|
|
|
load = true;
|
2019-02-02 12:58:28 +00:00
|
|
|
intf.onNext(true, next == null ? null : next.id);
|
2019-01-26 14:32:52 +00:00
|
|
|
} else
|
2019-02-02 12:58:28 +00:00
|
|
|
intf.onNext(false, null);
|
2019-01-26 14:32:52 +00:00
|
|
|
|
2019-01-30 12:51:50 +00:00
|
|
|
if (pos + 1 < messages.size()) {
|
|
|
|
TupleMessageEx prev = messages.get(pos + 1);
|
2019-01-26 14:32:52 +00:00
|
|
|
if (prev == null)
|
|
|
|
load = true;
|
2019-02-02 12:58:28 +00:00
|
|
|
intf.onPrevious(true, prev == null ? null : prev.id);
|
2019-01-26 14:32:52 +00:00
|
|
|
} else
|
2019-02-02 12:58:28 +00:00
|
|
|
intf.onPrevious(false, null);
|
|
|
|
|
|
|
|
intf.onFound(pos, messages.size());
|
2019-01-26 14:32:52 +00:00
|
|
|
|
|
|
|
if (load)
|
2019-01-30 12:51:50 +00:00
|
|
|
messages.loadAround(pos);
|
2019-01-26 14:32:52 +00:00
|
|
|
|
2019-01-30 12:51:50 +00:00
|
|
|
return;
|
2019-01-26 14:32:52 +00:00
|
|
|
}
|
|
|
|
}
|
2019-01-30 12:51:50 +00:00
|
|
|
|
2019-01-30 19:05:01 +00:00
|
|
|
Log.w("Observe previous/next gone id=" + id);
|
2019-01-26 14:32:52 +00:00
|
|
|
}
|
|
|
|
});
|
2018-10-20 19:04:05 +00:00
|
|
|
}
|
|
|
|
|
2019-07-28 08:09:00 +00:00
|
|
|
void getIds(Context context, LifecycleOwner owner, final Observer<List<Long>> observer) {
|
|
|
|
final Model model = models.get(last);
|
|
|
|
if (model == null) {
|
|
|
|
Log.w("Get IDs without model");
|
|
|
|
observer.onChanged(new ArrayList<Long>());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
new SimpleTask<List<Long>>() {
|
|
|
|
@Override
|
|
|
|
protected List<Long> onExecute(Context context, Bundle args) {
|
|
|
|
List<Long> ids = new ArrayList<>();
|
|
|
|
|
2019-08-11 08:18:23 +00:00
|
|
|
PagedList<TupleMessageEx> plist = model.list.getValue();
|
|
|
|
if (plist == null)
|
|
|
|
return ids;
|
2019-10-04 17:17:33 +00:00
|
|
|
|
2019-08-11 08:18:23 +00:00
|
|
|
LimitOffsetDataSource<TupleMessageEx> ds = (LimitOffsetDataSource<TupleMessageEx>) plist.getDataSource();
|
2019-07-28 08:09:00 +00:00
|
|
|
int count = ds.countItems();
|
|
|
|
for (int i = 0; i < count; i += 100)
|
|
|
|
for (TupleMessageEx message : ds.loadRange(i, Math.min(100, count - i)))
|
2019-11-11 13:44:55 +00:00
|
|
|
if ((message.uid != null && !message.folderReadOnly) || message.accountPop)
|
2019-10-13 09:39:31 +00:00
|
|
|
ids.add(message.id);
|
2019-07-28 08:09:00 +00:00
|
|
|
|
|
|
|
Log.i("Loaded messages #" + ids.size());
|
|
|
|
return ids;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onExecuted(Bundle args, List<Long> ids) {
|
|
|
|
observer.onChanged(ids);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onException(Bundle args, Throwable ex) {
|
|
|
|
observer.onChanged(new ArrayList<Long>());
|
|
|
|
}
|
|
|
|
}.execute(context, owner, new Bundle(), "model:ids");
|
|
|
|
}
|
|
|
|
|
2019-05-14 16:34:09 +00:00
|
|
|
private class Args {
|
|
|
|
private long account;
|
2019-07-19 06:27:44 +00:00
|
|
|
private String type;
|
2019-05-14 16:34:09 +00:00
|
|
|
private long folder;
|
|
|
|
private String thread;
|
|
|
|
private long id;
|
|
|
|
private String query;
|
|
|
|
private boolean server;
|
|
|
|
|
|
|
|
private boolean threading;
|
|
|
|
private String sort;
|
2019-09-03 08:33:52 +00:00
|
|
|
private boolean ascending;
|
2019-05-14 16:34:09 +00:00
|
|
|
private boolean filter_seen;
|
|
|
|
private boolean filter_unflagged;
|
|
|
|
private boolean filter_snoozed;
|
|
|
|
private boolean debug;
|
|
|
|
|
|
|
|
Args(Context context,
|
2019-09-09 07:46:54 +00:00
|
|
|
AdapterMessage.ViewType viewType,
|
2019-07-19 06:27:44 +00:00
|
|
|
String type, long account, long folder,
|
|
|
|
String thread, long id,
|
2019-05-14 16:34:09 +00:00
|
|
|
String query, boolean server) {
|
|
|
|
|
2019-07-19 06:27:44 +00:00
|
|
|
this.type = type;
|
2019-05-14 16:34:09 +00:00
|
|
|
this.account = account;
|
|
|
|
this.folder = folder;
|
|
|
|
this.thread = thread;
|
|
|
|
this.id = id;
|
|
|
|
this.query = query;
|
|
|
|
this.server = server;
|
|
|
|
|
|
|
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
|
|
|
this.threading = prefs.getBoolean("threading", true);
|
|
|
|
this.sort = prefs.getString("sort", "time");
|
2019-09-09 07:46:54 +00:00
|
|
|
this.ascending = prefs.getBoolean(
|
|
|
|
viewType == AdapterMessage.ViewType.THREAD ? "ascending_thread" : "ascending_list", false);
|
2019-05-14 16:34:09 +00:00
|
|
|
this.filter_seen = prefs.getBoolean("filter_seen", false);
|
|
|
|
this.filter_unflagged = prefs.getBoolean("filter_unflagged", false);
|
|
|
|
this.filter_snoozed = prefs.getBoolean("filter_snoozed", true);
|
|
|
|
this.debug = prefs.getBoolean("debug", false);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean equals(@Nullable Object obj) {
|
|
|
|
if (obj instanceof Args) {
|
|
|
|
Args other = (Args) obj;
|
2019-07-19 06:27:44 +00:00
|
|
|
return (Objects.equals(this.type, other.type) &&
|
|
|
|
this.account == other.account &&
|
2019-05-14 16:34:09 +00:00
|
|
|
this.folder == other.folder &&
|
|
|
|
Objects.equals(this.thread, other.thread) &&
|
|
|
|
this.id == other.id &&
|
|
|
|
Objects.equals(this.query, other.query) &&
|
|
|
|
this.server == other.server &&
|
|
|
|
|
|
|
|
this.threading == other.threading &&
|
|
|
|
Objects.equals(this.sort, other.sort) &&
|
2019-09-03 08:33:52 +00:00
|
|
|
this.ascending == other.ascending &&
|
2019-05-14 16:34:09 +00:00
|
|
|
this.filter_seen == other.filter_seen &&
|
|
|
|
this.filter_unflagged == other.filter_unflagged &&
|
|
|
|
this.filter_snoozed == other.filter_snoozed &&
|
|
|
|
this.debug == other.debug);
|
|
|
|
} else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@NonNull
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
2019-07-19 06:27:44 +00:00
|
|
|
return "folder=" + type + ":" + account + ":" + folder +
|
|
|
|
" thread=" + thread + ":" + id +
|
2019-05-14 16:34:09 +00:00
|
|
|
" query=" + query + ":" + server + "" +
|
|
|
|
" threading=" + threading +
|
2019-09-03 08:33:52 +00:00
|
|
|
" sort=" + sort + ":" + ascending +
|
2019-05-14 16:34:09 +00:00
|
|
|
" filter seen=" + filter_seen + " unflagged=" + filter_unflagged + " snoozed=" + filter_snoozed +
|
|
|
|
" debug=" + debug;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void dump() {
|
|
|
|
Log.i("Current models=" + TextUtils.join(", ", models.keySet()));
|
|
|
|
}
|
|
|
|
|
2019-05-15 15:05:11 +00:00
|
|
|
class Model {
|
2019-05-14 16:34:09 +00:00
|
|
|
private Args args;
|
|
|
|
private LiveData<PagedList<TupleMessageEx>> list;
|
|
|
|
private BoundaryCallbackMessages boundary;
|
|
|
|
|
|
|
|
Model(Args args, LiveData<PagedList<TupleMessageEx>> list, BoundaryCallbackMessages boundary) {
|
|
|
|
this.args = args;
|
|
|
|
this.list = list;
|
|
|
|
this.boundary = boundary;
|
|
|
|
}
|
|
|
|
|
2019-08-09 17:29:17 +00:00
|
|
|
void setCallback(LifecycleOwner owner, BoundaryCallbackMessages.IBoundaryCallbackMessages callback) {
|
|
|
|
if (boundary != null) {
|
2019-05-15 15:05:11 +00:00
|
|
|
boundary.setCallback(callback);
|
2019-08-09 17:29:17 +00:00
|
|
|
|
|
|
|
owner.getLifecycle().addObserver(new LifecycleObserver() {
|
|
|
|
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
|
|
|
|
public void onDestroyed() {
|
|
|
|
boundary.close();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2019-05-15 15:05:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void setObserver(LifecycleOwner owner, @NonNull Observer<PagedList<TupleMessageEx>> observer) {
|
2019-05-16 09:24:58 +00:00
|
|
|
//list.removeObservers(owner);
|
2019-05-15 15:05:11 +00:00
|
|
|
list.observe(owner, observer);
|
|
|
|
}
|
2019-05-14 16:34:09 +00:00
|
|
|
}
|
|
|
|
|
2019-01-26 14:32:52 +00:00
|
|
|
interface IPrevNext {
|
2019-01-29 10:08:22 +00:00
|
|
|
void onPrevious(boolean exists, Long id);
|
2019-01-26 14:32:52 +00:00
|
|
|
|
2019-01-29 10:08:22 +00:00
|
|
|
void onNext(boolean exists, Long id);
|
2019-02-02 12:58:28 +00:00
|
|
|
|
|
|
|
void onFound(int position, int size);
|
2018-10-20 14:42:03 +00:00
|
|
|
}
|
|
|
|
}
|