-
-
Notifications
You must be signed in to change notification settings - Fork 6k
/
ConversationViewModel.java
136 lines (107 loc) · 5.44 KB
/
ConversationViewModel.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package org.thoughtcrime.securesms.conversation;
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.arch.core.util.Function;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MediatorLiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import androidx.lifecycle.Transformations;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.paging.DataSource;
import androidx.paging.LivePagedListBuilder;
import androidx.paging.PagedList;
import org.thoughtcrime.securesms.conversation.ConversationDataSource.Invalidator;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mediasend.Media;
import org.thoughtcrime.securesms.mediasend.MediaRepository;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import org.whispersystems.libsignal.util.Pair;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
class ConversationViewModel extends ViewModel {
private static final String TAG = Log.tag(ConversationViewModel.class);
private final Application context;
private final MediaRepository mediaRepository;
private final ConversationRepository conversationRepository;
private final MutableLiveData<List<Media>> recentMedia;
private final MutableLiveData<Long> threadId;
private final LiveData<PagedList<MessageRecord>> messages;
private final LiveData<ConversationData> conversationMetadata;
private final Invalidator invalidator;
private int jumpToPosition;
private ConversationViewModel() {
this.context = ApplicationDependencies.getApplication();
this.mediaRepository = new MediaRepository();
this.conversationRepository = new ConversationRepository();
this.recentMedia = new MutableLiveData<>();
this.threadId = new MutableLiveData<>();
this.invalidator = new Invalidator();
LiveData<ConversationData> metadata = Transformations.switchMap(threadId, thread -> {
LiveData<ConversationData> conversationData = conversationRepository.getConversationData(thread, jumpToPosition);
jumpToPosition = -1;
return conversationData;
});
LiveData<Pair<Long, PagedList<MessageRecord>>> messagesForThreadId = Transformations.switchMap(metadata, data -> {
DataSource.Factory<Integer, MessageRecord> factory = new ConversationDataSource.Factory(context, data.getThreadId(), invalidator);
PagedList.Config config = new PagedList.Config.Builder()
.setPageSize(25)
.setInitialLoadSizeHint(25)
.build();
final int startPosition;
if (data.shouldJumpToMessage()) {
startPosition = data.getJumpToPosition();
} else {
startPosition = data.getLastSeenPosition();
}
Log.d(TAG, "Starting at position " + startPosition + " :: " + data.getJumpToPosition() + " :: " + data.getLastSeenPosition());
return Transformations.map(new LivePagedListBuilder<>(factory, config).setFetchExecutor(ConversationDataSource.EXECUTOR)
.setInitialLoadKey(Math.max(startPosition, 0))
.build(),
input -> new Pair<>(data.getThreadId(), input));
});
this.messages = Transformations.map(messagesForThreadId, Pair::second);
LiveData<Long> distinctThread = Transformations.distinctUntilChanged(threadId);
conversationMetadata = Transformations.switchMap(distinctThread, thread -> metadata);
}
void onAttachmentKeyboardOpen() {
mediaRepository.getMediaInBucket(context, Media.ALL_MEDIA_BUCKET_ID, recentMedia::postValue);
}
void onConversationDataAvailable(long threadId, int startingPosition) {
Log.d(TAG, "[onConversationDataAvailable] threadId: " + threadId + ", startingPosition: " + startingPosition);
this.jumpToPosition = startingPosition;
this.threadId.setValue(threadId);
}
@NonNull LiveData<List<Media>> getRecentMedia() {
return recentMedia;
}
@NonNull LiveData<ConversationData> getConversationMetadata() {
return conversationMetadata;
}
@NonNull LiveData<PagedList<MessageRecord>> getMessages() {
return messages;
}
long getLastSeen() {
return conversationMetadata.getValue() != null ? conversationMetadata.getValue().getLastSeen() : 0;
}
int getLastSeenPosition() {
return conversationMetadata.getValue() != null ? conversationMetadata.getValue().getLastSeenPosition() : 0;
}
@Override
protected void onCleared() {
super.onCleared();
invalidator.invalidate();
}
static class Factory extends ViewModelProvider.NewInstanceFactory {
@Override
public @NonNull<T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection ConstantConditions
return modelClass.cast(new ConversationViewModel());
}
}
}