mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-24 00:37:47 +00:00
Connect migrated expiry to settings ui
This commit is contained in:
parent
b3e9708649
commit
3bb19e4df8
@ -1,88 +0,0 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.session.libsession.utilities.ExpirationUtil;
|
||||
|
||||
import cn.carbswang.android.numberpickerview.library.NumberPickerView;
|
||||
import network.loki.messenger.R;
|
||||
|
||||
public class ExpirationDialog extends AlertDialog {
|
||||
|
||||
protected ExpirationDialog(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
protected ExpirationDialog(Context context, int theme) {
|
||||
super(context, theme);
|
||||
}
|
||||
|
||||
protected ExpirationDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
|
||||
super(context, cancelable, cancelListener);
|
||||
}
|
||||
|
||||
public static void show(final Context context,
|
||||
final int currentExpiration,
|
||||
final @NonNull OnClickListener listener)
|
||||
{
|
||||
final View view = createNumberPickerView(context, currentExpiration);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(context.getString(R.string.ExpirationDialog_disappearing_messages));
|
||||
builder.setView(view);
|
||||
builder.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
int selected = ((NumberPickerView)view.findViewById(R.id.expiration_number_picker)).getValue();
|
||||
listener.onClick(context.getResources().getIntArray(R.array.expiration_times)[selected]);
|
||||
});
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private static View createNumberPickerView(final Context context, final int currentExpiration) {
|
||||
final LayoutInflater inflater = LayoutInflater.from(context);
|
||||
final View view = inflater.inflate(R.layout.expiration_dialog, null);
|
||||
final NumberPickerView numberPickerView = view.findViewById(R.id.expiration_number_picker);
|
||||
final TextView textView = view.findViewById(R.id.expiration_details);
|
||||
final int[] expirationTimes = context.getResources().getIntArray(R.array.expiration_times);
|
||||
final String[] expirationDisplayValues = new String[expirationTimes.length];
|
||||
|
||||
int selectedIndex = expirationTimes.length - 1;
|
||||
|
||||
for (int i=0;i<expirationTimes.length;i++) {
|
||||
expirationDisplayValues[i] = ExpirationUtil.getExpirationDisplayValue(context, expirationTimes[i]);
|
||||
|
||||
if ((currentExpiration >= expirationTimes[i]) &&
|
||||
(i == expirationTimes.length -1 || currentExpiration < expirationTimes[i+1])) {
|
||||
selectedIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
numberPickerView.setDisplayedValues(expirationDisplayValues);
|
||||
numberPickerView.setMinValue(0);
|
||||
numberPickerView.setMaxValue(expirationTimes.length-1);
|
||||
|
||||
NumberPickerView.OnValueChangeListener listener = (picker, oldVal, newVal) -> {
|
||||
if (newVal == 0) {
|
||||
textView.setText(R.string.ExpirationDialog_your_messages_will_not_expire);
|
||||
} else {
|
||||
textView.setText(context.getString(R.string.ExpirationDialog_your_messages_will_disappear_s_after_they_have_been_seen, picker.getDisplayedValues()[newVal]));
|
||||
}
|
||||
};
|
||||
|
||||
numberPickerView.setOnValueChangedListener(listener);
|
||||
numberPickerView.setValue(selectedIndex);
|
||||
listener.onValueChange(numberPickerView, selectedIndex, selectedIndex);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
public interface OnClickListener {
|
||||
public void onClick(int expirationTime);
|
||||
}
|
||||
|
||||
}
|
@ -112,6 +112,9 @@ class ExpirationSettingsActivity: PassphraseRequiredActionBarActivity() {
|
||||
}
|
||||
})
|
||||
}
|
||||
binding.buttonSet.setOnClickListener {
|
||||
viewModel.onSetClick()
|
||||
}
|
||||
lifecycleScope.launchWhenStarted {
|
||||
launch {
|
||||
viewModel.selectedExpirationType.collect { type ->
|
||||
@ -119,6 +122,12 @@ class ExpirationSettingsActivity: PassphraseRequiredActionBarActivity() {
|
||||
deleteTypeOptionAdapter.setSelectedPosition(max(0, position))
|
||||
}
|
||||
}
|
||||
launch {
|
||||
viewModel.selectedExpirationTimer.collect { expirationTimer ->
|
||||
val position = deleteTypeOptions.indexOfFirst { it.value.toIntOrNull() == expirationTimer }
|
||||
timerOptionAdapter.setSelectedPosition(max(0, position))
|
||||
}
|
||||
}
|
||||
launch {
|
||||
viewModel.expirationTimerOptions.collect { options ->
|
||||
binding.textViewTimer.isVisible = options.isNotEmpty() && viewModel.showExpirationTypeSelector
|
||||
|
@ -11,8 +11,10 @@ import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import org.session.libsession.messaging.messages.ExpirationConfiguration
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType
|
||||
import org.thoughtcrime.securesms.database.Storage
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase
|
||||
import org.thoughtcrime.securesms.preferences.RadioOption
|
||||
|
||||
@ -20,29 +22,37 @@ class ExpirationSettingsViewModel(
|
||||
private val threadId: Long,
|
||||
private val afterReadOptions: List<RadioOption>,
|
||||
private val afterSendOptions: List<RadioOption>,
|
||||
private val threadDb: ThreadDatabase
|
||||
private val threadDb: ThreadDatabase,
|
||||
private val storage: Storage
|
||||
) : ViewModel() {
|
||||
|
||||
var showExpirationTypeSelector: Boolean = false
|
||||
private set
|
||||
|
||||
private var expirationConfig: ExpirationConfiguration? = null
|
||||
|
||||
private val _recipient = MutableStateFlow<Recipient?>(null)
|
||||
val recipient: StateFlow<Recipient?> = _recipient
|
||||
|
||||
private val _selectedExpirationType = MutableStateFlow<ExpirationType?>(null)
|
||||
val selectedExpirationType: StateFlow<ExpirationType?> = _selectedExpirationType
|
||||
|
||||
private val _selectedExpirationTimer = MutableStateFlow(0)
|
||||
val selectedExpirationTimer: StateFlow<Int> = _selectedExpirationTimer
|
||||
|
||||
private val _expirationTimerOptions = MutableStateFlow<List<RadioOption>>(emptyList())
|
||||
val expirationTimerOptions: StateFlow<List<RadioOption>> = _expirationTimerOptions
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
expirationConfig = storage.getExpirationConfiguration(threadId)
|
||||
val recipient = threadDb.getRecipientForThreadId(threadId)
|
||||
_recipient.value = recipient
|
||||
showExpirationTypeSelector = recipient?.isContactRecipient == true && recipient.isLocalNumber == false
|
||||
}
|
||||
if (recipient.value?.isLocalNumber == true || recipient.value?.isClosedGroupRecipient == true) {
|
||||
_selectedExpirationType.value = ExpirationType.DELETE_AFTER_SEND
|
||||
if (recipient?.isLocalNumber == true || recipient?.isClosedGroupRecipient == true) {
|
||||
_selectedExpirationType.value = ExpirationType.DELETE_AFTER_SEND
|
||||
}
|
||||
_selectedExpirationTimer.value = expirationConfig?.durationSeconds ?: 0
|
||||
}
|
||||
selectedExpirationType.mapLatest {
|
||||
when (it) {
|
||||
@ -60,7 +70,14 @@ class ExpirationSettingsViewModel(
|
||||
}
|
||||
|
||||
fun onExpirationTimerSelected(option: RadioOption) {
|
||||
_selectedExpirationTimer.value = option.value.toIntOrNull() ?: 0
|
||||
}
|
||||
|
||||
fun onSetClick() = viewModelScope.launch {
|
||||
val expiresIn = _selectedExpirationTimer.value
|
||||
val expiryType = _selectedExpirationType.value?.number ?: 0
|
||||
val expiryChangeTimestamp = System.currentTimeMillis()
|
||||
threadDb.updateExpiryConfig(threadId, expiresIn, expiryType, expiryChangeTimestamp)
|
||||
}
|
||||
|
||||
@dagger.assisted.AssistedFactory
|
||||
@ -77,7 +94,8 @@ class ExpirationSettingsViewModel(
|
||||
@Assisted private val threadId: Long,
|
||||
@Assisted("afterRead") private val afterReadOptions: List<RadioOption>,
|
||||
@Assisted("afterSend") private val afterSendOptions: List<RadioOption>,
|
||||
private val threadDb: ThreadDatabase
|
||||
private val threadDb: ThreadDatabase,
|
||||
private val storage: Storage
|
||||
) : ViewModelProvider.Factory {
|
||||
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
@ -85,7 +103,8 @@ class ExpirationSettingsViewModel(
|
||||
threadId,
|
||||
afterReadOptions,
|
||||
afterSendOptions,
|
||||
threadDb
|
||||
threadDb,
|
||||
storage
|
||||
) as T
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import org.session.libsession.messaging.jobs.Job
|
||||
import org.session.libsession.messaging.jobs.JobQueue
|
||||
import org.session.libsession.messaging.jobs.MessageReceiveJob
|
||||
import org.session.libsession.messaging.jobs.MessageSendJob
|
||||
import org.session.libsession.messaging.messages.ExpirationSettingsConfiguration
|
||||
import org.session.libsession.messaging.messages.ExpirationConfiguration
|
||||
import org.session.libsession.messaging.messages.Message
|
||||
import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
||||
import org.session.libsession.messaging.messages.control.MessageRequestResponse
|
||||
@ -962,12 +962,31 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
||||
return recipientDb.blockedContacts
|
||||
}
|
||||
|
||||
override fun getExpirationSettingsConfiguration(threadId: Long): ExpirationSettingsConfiguration? {
|
||||
override fun getExpirationConfiguration(threadId: Long): ExpirationConfiguration? {
|
||||
val threadDb = DatabaseComponent.get(context).threadDatabase()
|
||||
threadDb.readerFor(threadDb.conversationList).use { reader ->
|
||||
while (reader.next != null) {
|
||||
val thread = reader.current
|
||||
if (thread.recipient.isClosedGroupRecipient || thread.recipient.isContactRecipient) {
|
||||
return ExpirationConfiguration(
|
||||
thread.threadId,
|
||||
thread.expiresIn.toInt(),
|
||||
thread.expiryType,
|
||||
thread.expiryChangeTimestamp
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun addExpirationSettingsConfiguration(config: ExpirationSettingsConfiguration) {
|
||||
|
||||
override fun updateExpirationConfiguration(config: ExpirationConfiguration) {
|
||||
DatabaseComponent.get(context).threadDatabase().updateExpiryConfig(
|
||||
config.threadId,
|
||||
config.durationSeconds,
|
||||
config.expirationType?.number ?: 0,
|
||||
config.lastChangeTimestampMs
|
||||
)
|
||||
}
|
||||
|
||||
override fun getExpiringMessages(messageIds: LongArray): List<Pair<String, Int>> {
|
||||
|
@ -18,6 +18,7 @@
|
||||
package org.thoughtcrime.securesms.database;
|
||||
|
||||
import static org.session.libsession.utilities.GroupUtil.CLOSED_GROUP_PREFIX;
|
||||
import static org.session.libsession.utilities.GroupUtil.OPEN_GROUP_INBOX_PREFIX;
|
||||
import static org.session.libsession.utilities.GroupUtil.OPEN_GROUP_PREFIX;
|
||||
import static org.thoughtcrime.securesms.database.GroupDatabase.GROUP_ID;
|
||||
|
||||
@ -96,6 +97,8 @@ public class ThreadDatabase extends Database {
|
||||
public static final String DELIVERY_RECEIPT_COUNT = "delivery_receipt_count";
|
||||
public static final String READ_RECEIPT_COUNT = "read_receipt_count";
|
||||
public static final String EXPIRES_IN = "expires_in";
|
||||
public static final String EXPIRY_TYPE = "expiry_type";
|
||||
public static final String EXPIRY_CHANGE_TIMESTAMP= "expiry_change_timestamp";
|
||||
public static final String LAST_SEEN = "last_seen";
|
||||
public static final String HAS_SENT = "has_sent";
|
||||
public static final String IS_PINNED = "is_pinned";
|
||||
@ -118,7 +121,8 @@ public class ThreadDatabase extends Database {
|
||||
|
||||
private static final String[] THREAD_PROJECTION = {
|
||||
ID, DATE, MESSAGE_COUNT, ADDRESS, SNIPPET, SNIPPET_CHARSET, READ, UNREAD_COUNT, TYPE, ERROR, SNIPPET_TYPE,
|
||||
SNIPPET_URI, ARCHIVED, STATUS, DELIVERY_RECEIPT_COUNT, EXPIRES_IN, LAST_SEEN, READ_RECEIPT_COUNT, IS_PINNED
|
||||
SNIPPET_URI, ARCHIVED, STATUS, DELIVERY_RECEIPT_COUNT, EXPIRES_IN, LAST_SEEN, READ_RECEIPT_COUNT, IS_PINNED,
|
||||
EXPIRY_TYPE, EXPIRY_CHANGE_TIMESTAMP
|
||||
};
|
||||
|
||||
private static final List<String> TYPED_THREAD_PROJECTION = Stream.of(THREAD_PROJECTION)
|
||||
@ -135,6 +139,30 @@ public class ThreadDatabase extends Database {
|
||||
"ADD COLUMN " + IS_PINNED + " INTEGER DEFAULT 0;";
|
||||
}
|
||||
|
||||
public static String getCreateExpiryTypeCommand() {
|
||||
return "ALTER TABLE "+ TABLE_NAME + " " +
|
||||
"ADD COLUMN " + EXPIRY_TYPE + " INTEGER DEFAULT 0;";
|
||||
}
|
||||
|
||||
public static String getCreateExpiryChangeTimestampCommand() {
|
||||
return "ALTER TABLE "+ TABLE_NAME + " " +
|
||||
"ADD COLUMN " + EXPIRY_CHANGE_TIMESTAMP + " INTEGER DEFAULT 0;";
|
||||
}
|
||||
|
||||
public static String getUpdateGroupConversationExpiryTypeCommand() {
|
||||
return "UPDATE " + TABLE_NAME + " SET " + EXPIRY_TYPE + " = 1 " +
|
||||
"WHERE " + ADDRESS + " LIKE '" + CLOSED_GROUP_PREFIX + "%'" +
|
||||
"AND " + EXPIRES_IN + " > 0";
|
||||
}
|
||||
|
||||
public static String getUpdateOneToOneConversationExpiryTypeCommand() {
|
||||
return "UPDATE " + TABLE_NAME + " SET " + EXPIRY_TYPE + " = 2 " +
|
||||
"WHERE " + ADDRESS + " NOT LIKE '" + CLOSED_GROUP_PREFIX + "%'" +
|
||||
"AND " + ADDRESS + " NOT LIKE '" + OPEN_GROUP_PREFIX + "%'" +
|
||||
"AND " + ADDRESS + " NOT LIKE '" + OPEN_GROUP_INBOX_PREFIX + "%'" +
|
||||
"AND " + EXPIRES_IN + " > 0";
|
||||
}
|
||||
|
||||
public ThreadDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
|
||||
super(context, databaseHelper);
|
||||
}
|
||||
@ -200,6 +228,18 @@ public class ThreadDatabase extends Database {
|
||||
notifyConversationListListeners();
|
||||
}
|
||||
|
||||
public void updateExpiryConfig(long threadId, int expiresIn, int expiryType, long expiryChangeTimestamp) {
|
||||
ContentValues contentValues = new ContentValues(3);
|
||||
|
||||
contentValues.put(EXPIRES_IN, expiresIn);
|
||||
contentValues.put(EXPIRY_TYPE, expiryType);
|
||||
contentValues.put(EXPIRY_CHANGE_TIMESTAMP, expiryChangeTimestamp);
|
||||
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
db.update(TABLE_NAME, contentValues, ID + " = ?", new String[] {threadId + ""});
|
||||
notifyConversationListListeners();
|
||||
}
|
||||
|
||||
private void deleteThread(long threadId) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
db.delete(TABLE_NAME, ID_WHERE, new String[] {threadId + ""});
|
||||
@ -909,6 +949,8 @@ public class ThreadDatabase extends Database {
|
||||
int deliveryReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.DELIVERY_RECEIPT_COUNT));
|
||||
int readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.READ_RECEIPT_COUNT));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.EXPIRES_IN));
|
||||
int expiryType = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.EXPIRY_TYPE));
|
||||
long expiryChangeTimestamp = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.EXPIRY_CHANGE_TIMESTAMP));
|
||||
long lastSeen = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.LAST_SEEN));
|
||||
Uri snippetUri = getSnippetUri(cursor);
|
||||
boolean pinned = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.IS_PINNED)) != 0;
|
||||
@ -919,7 +961,7 @@ public class ThreadDatabase extends Database {
|
||||
|
||||
return new ThreadRecord(body, snippetUri, recipient, date, count,
|
||||
unreadCount, threadId, deliveryReceiptCount, status, type,
|
||||
distributionType, archived, expiresIn, lastSeen, readReceiptCount, pinned);
|
||||
distributionType, archived, expiresIn, lastSeen, readReceiptCount, pinned, expiryType, expiryChangeTimestamp);
|
||||
}
|
||||
|
||||
private @Nullable Uri getSnippetUri(Cursor cursor) {
|
||||
|
@ -75,9 +75,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
private static final int lokiV36 = 57;
|
||||
private static final int lokiV37 = 58;
|
||||
private static final int lokiV38 = 59;
|
||||
private static final int lokiV39 = 60;
|
||||
|
||||
// Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes
|
||||
private static final int DATABASE_VERSION = lokiV38;
|
||||
private static final int DATABASE_VERSION = lokiV39;
|
||||
private static final String DATABASE_NAME = "signal.db";
|
||||
|
||||
private final Context context;
|
||||
@ -180,6 +181,8 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
db.execSQL(LokiAPIDatabase.RESET_SEQ_NO); // probably not needed but consistent with all migrations
|
||||
db.execSQL(EmojiSearchDatabase.CREATE_EMOJI_SEARCH_TABLE_COMMAND);
|
||||
db.execSQL(ReactionDatabase.CREATE_REACTION_TABLE_COMMAND);
|
||||
db.execSQL(ThreadDatabase.getCreateExpiryTypeCommand());
|
||||
db.execSQL(ThreadDatabase.getCreateExpiryChangeTimestampCommand());
|
||||
|
||||
executeStatements(db, SmsDatabase.CREATE_INDEXS);
|
||||
executeStatements(db, MmsDatabase.CREATE_INDEXS);
|
||||
@ -414,6 +417,13 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
db.execSQL(EmojiSearchDatabase.CREATE_EMOJI_SEARCH_TABLE_COMMAND);
|
||||
}
|
||||
|
||||
if (oldVersion < lokiV39) {
|
||||
db.execSQL(ThreadDatabase.getCreateExpiryTypeCommand());
|
||||
db.execSQL(ThreadDatabase.getCreateExpiryChangeTimestampCommand());
|
||||
db.execSQL(ThreadDatabase.getUpdateGroupConversationExpiryTypeCommand());
|
||||
db.execSQL(ThreadDatabase.getUpdateOneToOneConversationExpiryTypeCommand());
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
|
@ -29,6 +29,7 @@ import androidx.annotation.Nullable;
|
||||
|
||||
import org.session.libsession.utilities.ExpirationUtil;
|
||||
import org.session.libsession.utilities.recipients.Recipient;
|
||||
import org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType;
|
||||
import org.thoughtcrime.securesms.database.MmsSmsColumns;
|
||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||
|
||||
@ -48,6 +49,8 @@ public class ThreadRecord extends DisplayRecord {
|
||||
private final int distributionType;
|
||||
private final boolean archived;
|
||||
private final long expiresIn;
|
||||
private final int expiryType;
|
||||
private final long expiryChangeTimestamp;
|
||||
private final long lastSeen;
|
||||
private final boolean pinned;
|
||||
private final int recipientHash;
|
||||
@ -56,7 +59,7 @@ public class ThreadRecord extends DisplayRecord {
|
||||
@NonNull Recipient recipient, long date, long count, int unreadCount,
|
||||
long threadId, int deliveryReceiptCount, int status, long snippetType,
|
||||
int distributionType, boolean archived, long expiresIn, long lastSeen,
|
||||
int readReceiptCount, boolean pinned)
|
||||
int readReceiptCount, boolean pinned, int expiryType, long expiryChangeTimestamp)
|
||||
{
|
||||
super(body, recipient, date, date, threadId, status, deliveryReceiptCount, snippetType, readReceiptCount);
|
||||
this.snippetUri = snippetUri;
|
||||
@ -65,6 +68,8 @@ public class ThreadRecord extends DisplayRecord {
|
||||
this.distributionType = distributionType;
|
||||
this.archived = archived;
|
||||
this.expiresIn = expiresIn;
|
||||
this.expiryType = expiryType;
|
||||
this.expiryChangeTimestamp = expiryChangeTimestamp;
|
||||
this.lastSeen = lastSeen;
|
||||
this.pinned = pinned;
|
||||
this.recipientHash = recipient.hashCode();
|
||||
@ -169,6 +174,15 @@ public class ThreadRecord extends DisplayRecord {
|
||||
return expiresIn;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ExpirationType getExpiryType() {
|
||||
return ExpirationType.valueOf(expiryType);
|
||||
}
|
||||
|
||||
public long getExpiryChangeTimestamp() {
|
||||
return expiryChangeTimestamp;
|
||||
}
|
||||
|
||||
public long getLastSeen() {
|
||||
return lastSeen;
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:background="?colorPrimary"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center">
|
||||
|
||||
<cn.carbswang.android.numberpickerview.library.NumberPickerView
|
||||
android:id="@+id/expiration_number_picker"
|
||||
android:layout_alignParentTop="true"
|
||||
app:npv_WrapSelectorWheel="false"
|
||||
app:npv_DividerColor="#cbc8ea"
|
||||
app:npv_TextColorNormal="?android:textColorPrimary"
|
||||
app:npv_TextColorSelected="?android:textColorPrimary"
|
||||
app:npv_ItemPaddingVertical="20dp"
|
||||
app:npv_TextColorHint="@color/grey_600"
|
||||
app:npv_TextSizeNormal="16sp"
|
||||
app:npv_TextSizeSelected="16sp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/expiration_details"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/expiration_number_picker"
|
||||
android:minLines="3"
|
||||
android:padding="20dp"
|
||||
tools:text="Your messages will not expire."/>
|
||||
|
||||
</RelativeLayout>
|
@ -8,7 +8,7 @@ import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsession.messaging.jobs.AttachmentUploadJob
|
||||
import org.session.libsession.messaging.jobs.Job
|
||||
import org.session.libsession.messaging.jobs.MessageSendJob
|
||||
import org.session.libsession.messaging.messages.ExpirationSettingsConfiguration
|
||||
import org.session.libsession.messaging.messages.ExpirationConfiguration
|
||||
import org.session.libsession.messaging.messages.Message
|
||||
import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
||||
import org.session.libsession.messaging.messages.control.MessageRequestResponse
|
||||
@ -199,7 +199,7 @@ interface StorageProtocol {
|
||||
fun deleteReactions(messageId: Long, mms: Boolean)
|
||||
fun unblock(toUnblock: List<Recipient>)
|
||||
fun blockedContacts(): List<Recipient>
|
||||
fun getExpirationSettingsConfiguration(threadId: Long): ExpirationSettingsConfiguration?
|
||||
fun addExpirationSettingsConfiguration(config: ExpirationSettingsConfiguration)
|
||||
fun getExpirationConfiguration(threadId: Long): ExpirationConfiguration?
|
||||
fun updateExpirationConfiguration(config: ExpirationConfiguration)
|
||||
fun getExpiringMessages(messageIds: LongArray): List<Pair<String, Int>>
|
||||
}
|
||||
|
@ -2,10 +2,11 @@ package org.session.libsession.messaging.messages
|
||||
|
||||
import org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType
|
||||
|
||||
class ExpirationSettingsConfiguration(
|
||||
class ExpirationConfiguration(
|
||||
val threadId: Long = -1,
|
||||
val isEnabled: Boolean = false,
|
||||
val durationSeconds: Int = 0,
|
||||
val expirationType: ExpirationType? = null,
|
||||
val lastChangeTimestampMs: Long = 0
|
||||
)
|
||||
) {
|
||||
val isEnabled = durationSeconds > 0
|
||||
}
|
@ -41,7 +41,7 @@ abstract class Message {
|
||||
|
||||
fun setExpirationSettingsConfigIfNeeded(builder: SignalServiceProtos.Content.Builder) {
|
||||
val threadId = threadID ?: return
|
||||
val config = MessagingModuleConfiguration.shared.storage.getExpirationSettingsConfiguration(threadId) ?: return
|
||||
val config = MessagingModuleConfiguration.shared.storage.getExpirationConfiguration(threadId) ?: return
|
||||
builder.expirationTimer = config.durationSeconds
|
||||
if (config.isEnabled) {
|
||||
builder.expirationType = config.expirationType
|
||||
|
@ -227,7 +227,7 @@ object MessageSender {
|
||||
val address = if (isSyncMessage && message is VisibleMessage) message.syncTarget else message.recipient
|
||||
storage.getOrCreateThreadIdFor(address!!)
|
||||
}
|
||||
val config = storage.getExpirationSettingsConfiguration(threadId) ?: return null
|
||||
val config = storage.getExpirationConfiguration(threadId) ?: return null
|
||||
return if (config.isEnabled && (config.expirationType == ExpirationType.DELETE_AFTER_SEND || isSyncMessage)) {
|
||||
config.durationSeconds * 1000L
|
||||
} else null
|
||||
|
@ -5,7 +5,7 @@ import org.session.libsession.avatars.AvatarHelper
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.jobs.BackgroundGroupAddJob
|
||||
import org.session.libsession.messaging.jobs.JobQueue
|
||||
import org.session.libsession.messaging.messages.ExpirationSettingsConfiguration
|
||||
import org.session.libsession.messaging.messages.ExpirationConfiguration
|
||||
import org.session.libsession.messaging.messages.Message
|
||||
import org.session.libsession.messaging.messages.control.CallMessage
|
||||
import org.session.libsession.messaging.messages.control.ClosedGroupControlMessage
|
||||
@ -60,7 +60,7 @@ internal fun MessageReceiver.isBlocked(publicKey: String): Boolean {
|
||||
}
|
||||
|
||||
fun MessageReceiver.handle(message: Message, proto: SignalServiceProtos.Content, openGroupID: String?) {
|
||||
updateExpirationSettingsConfigIfNeeded(message, proto, openGroupID)
|
||||
updateExpirationConfigurationIfNeeded(message, proto, openGroupID)
|
||||
when (message) {
|
||||
is ReadReceipt -> handleReadReceipt(message)
|
||||
is TypingIndicator -> handleTypingIndicator(message)
|
||||
@ -80,24 +80,22 @@ fun MessageReceiver.handle(message: Message, proto: SignalServiceProtos.Content,
|
||||
}
|
||||
}
|
||||
|
||||
fun updateExpirationSettingsConfigIfNeeded(message: Message, proto: SignalServiceProtos.Content, openGroupID: String?) {
|
||||
fun updateExpirationConfigurationIfNeeded(message: Message, proto: SignalServiceProtos.Content, openGroupID: String?) {
|
||||
if (!proto.hasLastDisappearingMessageChangeTimestamp()) return
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
val threadID = storage.getOrCreateThreadIdFor(message.sender!!, message.groupPublicKey, openGroupID)
|
||||
if (threadID <= 0) return
|
||||
val localConfig = storage.getExpirationSettingsConfiguration(threadID)
|
||||
val localConfig = storage.getExpirationConfiguration(threadID)
|
||||
if (localConfig == null || localConfig.lastChangeTimestampMs < proto.lastDisappearingMessageChangeTimestamp) return
|
||||
val durationSeconds = if (proto.hasExpirationTimer()) proto.expirationTimer else 0
|
||||
val isEnabled = durationSeconds != 0
|
||||
val type = if (proto.hasExpirationType()) proto.expirationType else null
|
||||
val remoteConfig = ExpirationSettingsConfiguration(
|
||||
val remoteConfig = ExpirationConfiguration(
|
||||
threadID,
|
||||
isEnabled,
|
||||
durationSeconds,
|
||||
type,
|
||||
proto.lastDisappearingMessageChangeTimestamp
|
||||
)
|
||||
storage.addExpirationSettingsConfiguration(remoteConfig)
|
||||
storage.updateExpirationConfiguration(remoteConfig)
|
||||
}
|
||||
|
||||
// region Control Messages
|
||||
@ -116,7 +114,7 @@ private fun MessageReceiver.handleSyncedExpiriesMessage(message: SyncedExpiriesM
|
||||
val userPublicKey = storage.getUserPublicKey() ?: return
|
||||
if (userPublicKey != message.sender) return
|
||||
message.conversationExpiries.forEach { (syncTarget, syncedExpiries) ->
|
||||
val config = storage.getExpirationSettingsConfiguration(storage.getOrCreateThreadIdFor(syncTarget)) ?: return@forEach
|
||||
val config = storage.getExpirationConfiguration(storage.getOrCreateThreadIdFor(syncTarget)) ?: return@forEach
|
||||
syncedExpiries.forEach { syncedExpiry ->
|
||||
val startedAtMs = syncedExpiry.expirationTimestamp!! - config.durationSeconds * 1000
|
||||
SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(startedAtMs, syncTarget)
|
||||
|
Loading…
x
Reference in New Issue
Block a user