mirror of
https://github.com/oxen-io/session-android.git
synced 2023-12-14 02:53:01 +01:00
feat: add clear messages and media dialogs and change db to not use message count == 0 in conversations
This commit is contained in:
parent
e70b0ee606
commit
ca200c4f2e
|
@ -52,9 +52,18 @@ import androidx.viewpager.widget.ViewPager;
|
|||
import com.codewaves.stickyheadergrid.StickyHeaderGridLayoutManager;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration;
|
||||
import org.session.libsession.messaging.messages.control.DataExtractionNotification;
|
||||
import org.session.libsession.messaging.sending_receiving.MessageSender;
|
||||
import org.session.libsession.utilities.Address;
|
||||
import org.session.libsession.utilities.GroupRecord;
|
||||
import org.session.libsession.utilities.TextSecurePreferences;
|
||||
import org.session.libsession.utilities.Util;
|
||||
import org.session.libsession.utilities.ViewUtil;
|
||||
import org.session.libsession.utilities.recipients.Recipient;
|
||||
import org.session.libsession.utilities.task.ProgressDialogAsyncTask;
|
||||
import org.session.libsignal.utilities.Log;
|
||||
import org.thoughtcrime.securesms.conversation.settings.ClearAllMediaDialog;
|
||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
||||
import org.thoughtcrime.securesms.database.MediaDatabase;
|
||||
import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader;
|
||||
|
@ -62,25 +71,22 @@ import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader.Buc
|
|||
import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.session.libsession.utilities.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.AttachmentUtil;
|
||||
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
|
||||
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
|
||||
import org.session.libsession.utilities.Util;
|
||||
import org.session.libsession.utilities.ViewUtil;
|
||||
import org.session.libsession.utilities.task.ProgressDialogAsyncTask;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import kotlin.Unit;
|
||||
import network.loki.messenger.R;
|
||||
|
||||
/**
|
||||
* Activity for displaying media attachments in-app
|
||||
*/
|
||||
public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity {
|
||||
public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity implements View.OnClickListener {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final static String TAG = MediaOverviewActivity.class.getSimpleName();
|
||||
|
@ -132,6 +138,20 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity {
|
|||
this.recipient.addListener(recipient -> {
|
||||
Util.runOnMain(() -> actionBar.setTitle(recipient.toShortString()));
|
||||
});
|
||||
View clearButton = toolbar.findViewById(R.id.clearMedia);
|
||||
if (!this.recipient.isClosedGroupRecipient()) {
|
||||
clearButton.setVisibility(View.GONE);
|
||||
} else {
|
||||
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
|
||||
GroupRecord groupRecord = MessagingModuleConfiguration.getShared().getStorage().getGroup(this.recipient.getAddress().toGroupString());
|
||||
if (userPublicKey == null || groupRecord == null) {
|
||||
clearButton.setVisibility(View.GONE);
|
||||
} else {
|
||||
boolean isUserAdmin = groupRecord.getAdmins().contains(Address.fromSerialized(userPublicKey));
|
||||
clearButton.setVisibility(isUserAdmin ? View.VISIBLE : View.GONE);
|
||||
clearButton.setOnClickListener(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onEnterMultiSelect() {
|
||||
|
@ -139,6 +159,18 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity {
|
|||
viewPager.setEnabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (v.getId() == R.id.clearMedia) {
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
ClearAllMediaDialog dialog = new ClearAllMediaDialog(() -> {
|
||||
Log.d("Loki", "Clear all the media");
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
dialog.show(fm, "ClearAllMedia");
|
||||
}
|
||||
}
|
||||
|
||||
public void onExitMultiSelect() {
|
||||
tabLayout.setEnabled(true);
|
||||
viewPager.setEnabled(true);
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package org.thoughtcrime.securesms.conversation.settings
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import network.loki.messenger.databinding.DialogClearAllMediaBinding
|
||||
import org.thoughtcrime.securesms.conversation.v2.utilities.BaseDialog
|
||||
|
||||
class ClearAllMediaDialog(private val callback: ()->Unit): BaseDialog(), View.OnClickListener {
|
||||
|
||||
private lateinit var binding: DialogClearAllMediaBinding
|
||||
|
||||
override fun setContentView(builder: AlertDialog.Builder) {
|
||||
super.setContentView(builder)
|
||||
binding = DialogClearAllMediaBinding.inflate(LayoutInflater.from(requireContext()))
|
||||
with (binding) {
|
||||
clear.setOnClickListener(this@ClearAllMediaDialog)
|
||||
cancel.setOnClickListener(this@ClearAllMediaDialog)
|
||||
}
|
||||
builder.setView(binding.root)
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
when {
|
||||
v === binding.cancel -> dismiss()
|
||||
v === binding.clear -> {
|
||||
callback()
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package org.thoughtcrime.securesms.conversation.settings
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isVisible
|
||||
import network.loki.messenger.databinding.DialogClearAllMessagesBinding
|
||||
import org.thoughtcrime.securesms.conversation.v2.utilities.BaseDialog
|
||||
|
||||
class ClearAllMessagesDialog(private val isUserAdmin: Boolean, private val callback: (Option) -> Unit): BaseDialog(), View.OnClickListener {
|
||||
|
||||
enum class Option {
|
||||
FOR_ME,
|
||||
FOR_EVERYONE
|
||||
}
|
||||
|
||||
private lateinit var binding: DialogClearAllMessagesBinding
|
||||
|
||||
override fun setContentView(builder: AlertDialog.Builder) {
|
||||
super.setContentView(builder)
|
||||
binding = DialogClearAllMessagesBinding.inflate(LayoutInflater.from(requireContext()))
|
||||
with (binding) {
|
||||
forEveryone.isVisible = isUserAdmin
|
||||
forEveryone.setOnClickListener(this@ClearAllMessagesDialog)
|
||||
forMe.isVisible = isUserAdmin
|
||||
forMe.setOnClickListener(this@ClearAllMessagesDialog)
|
||||
close.isVisible = isUserAdmin
|
||||
close.setOnClickListener(this@ClearAllMessagesDialog)
|
||||
|
||||
cancel.isVisible = !isUserAdmin
|
||||
cancel.setOnClickListener(this@ClearAllMessagesDialog)
|
||||
clear.isVisible = !isUserAdmin
|
||||
clear.setOnClickListener(this@ClearAllMessagesDialog)
|
||||
}
|
||||
builder.setView(binding.root)
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
when {
|
||||
v === binding.cancel ||
|
||||
v === binding.close -> dismiss()
|
||||
v === binding.forMe ||
|
||||
v === binding.clear -> {
|
||||
callback(Option.FOR_ME)
|
||||
dismiss()
|
||||
}
|
||||
v === binding.forEveryone -> {
|
||||
callback(Option.FOR_EVERYONE)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ import network.loki.messenger.databinding.ActivityConversationSettingsBinding
|
|||
import org.session.libsignal.utilities.Log
|
||||
import org.thoughtcrime.securesms.MediaOverviewActivity
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.conversation.settings.ClearAllMessagesDialog.Option
|
||||
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
|
||||
import org.thoughtcrime.securesms.database.LokiThreadDatabase
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase
|
||||
|
@ -61,6 +62,7 @@ class ConversationSettingsActivity: PassphraseRequiredActionBarActivity(), View.
|
|||
binding.profilePictureView.root.glide = GlideApp.with(this)
|
||||
updateRecipientDisplay()
|
||||
binding.searchConversation.setOnClickListener(this)
|
||||
binding.clearMessages.setOnClickListener(this)
|
||||
binding.allMedia.setOnClickListener(this)
|
||||
binding.pinConversation.setOnClickListener(this)
|
||||
binding.notificationSettings.setOnClickListener(this)
|
||||
|
@ -144,6 +146,11 @@ class ConversationSettingsActivity: PassphraseRequiredActionBarActivity(), View.
|
|||
notificationActivityCallback.launch(viewModel.threadId)
|
||||
}
|
||||
v === binding.back -> onBackPressed()
|
||||
v === binding.clearMessages -> {
|
||||
ClearAllMessagesDialog(viewModel.isUserGroupAdmin()) { option ->
|
||||
viewModel.clearMessages(option == Option.FOR_EVERYONE)
|
||||
}.show(supportFragmentManager, "Clear messages dialog")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,12 +32,27 @@ class ConversationSettingsViewModel(
|
|||
}
|
||||
|
||||
fun isUserGroupAdmin(): Boolean = recipient?.let { recipient ->
|
||||
if (!recipient.isGroupRecipient) return@let false
|
||||
if (!recipient.isClosedGroupRecipient) return@let false
|
||||
val localUserAddress = prefs.getLocalNumber() ?: return@let false
|
||||
val group = storage.getGroup(recipient.address.toGroupString())
|
||||
group?.admins?.contains(Address.fromSerialized(localUserAddress)) ?: false // this will have to be replaced for new closed groups
|
||||
} ?: false
|
||||
|
||||
fun clearMessages(forAll: Boolean) {
|
||||
if (forAll && !isUserGroupAdmin()) return
|
||||
|
||||
if (!forAll) {
|
||||
viewModelScope.launch {
|
||||
storage.clearMessages(threadId)
|
||||
}
|
||||
} else {
|
||||
// do a send message here and on success do a clear messages
|
||||
viewModelScope.launch {
|
||||
storage.clearMessages(threadId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DI-related
|
||||
@dagger.assisted.AssistedFactory
|
||||
interface AssistedFactory {
|
||||
|
|
|
@ -731,6 +731,16 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
|||
return threadDb.getPinned(threadID)
|
||||
}
|
||||
|
||||
override fun clearMessages(threadID: Long): Boolean {
|
||||
val smsDb = DatabaseComponent.get(context).smsDatabase()
|
||||
val mmsDb = DatabaseComponent.get(context).mmsDatabase()
|
||||
val threadDb = DatabaseComponent.get(context).threadDatabase()
|
||||
smsDb.deleteThread(threadID)
|
||||
mmsDb.deleteThread(threadID) // threadDB update called from within
|
||||
threadDb.update(threadID, false)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getAttachmentDataUri(attachmentId: AttachmentId): Uri {
|
||||
return PartAuthority.getAttachmentDataUri(attachmentId)
|
||||
}
|
||||
|
|
|
@ -466,7 +466,7 @@ public class ThreadDatabase extends Database {
|
|||
}
|
||||
|
||||
public Cursor getApprovedConversationList() {
|
||||
String where = "((" + MESSAGE_COUNT + " != 0 AND (" + HAS_SENT + " = 1 OR " + RecipientDatabase.APPROVED + " = 1 OR "+ GroupDatabase.TABLE_NAME +"."+GROUP_ID+" LIKE '"+CLOSED_GROUP_PREFIX+"%')) OR " + GroupDatabase.TABLE_NAME + "." + GROUP_ID + " LIKE '" + OPEN_GROUP_PREFIX + "%') " +
|
||||
String where = "((" + HAS_SENT + " = 1 OR " + RecipientDatabase.APPROVED + " = 1 OR "+ GroupDatabase.TABLE_NAME +"."+GROUP_ID+" LIKE '"+CLOSED_GROUP_PREFIX+"%') OR " + GroupDatabase.TABLE_NAME + "." + GROUP_ID + " LIKE '" + OPEN_GROUP_PREFIX + "%') " +
|
||||
"AND " + ARCHIVED + " = 0 ";
|
||||
return getConversationList(where);
|
||||
}
|
||||
|
@ -692,6 +692,8 @@ public class ThreadDatabase extends Database {
|
|||
deleteThread(threadId);
|
||||
notifyConversationListListeners();
|
||||
return true;
|
||||
} else {
|
||||
updateThread(threadId, 0, "", null, System.currentTimeMillis(), 0, 0, 0, false, 0, 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -731,8 +733,9 @@ public class ThreadDatabase extends Database {
|
|||
}
|
||||
|
||||
private boolean deleteThreadOnEmpty(long threadId) {
|
||||
Recipient threadRecipient = getRecipientForThreadId(threadId);
|
||||
return threadRecipient != null && !threadRecipient.isOpenGroupRecipient();
|
||||
return false; // TODO: test the deletion / clearing logic here to make sure this is the desired functionality
|
||||
// Recipient threadRecipient = getRecipientForThreadId(threadId);
|
||||
// return threadRecipient != null && !threadRecipient.isOpenGroupRecipient();
|
||||
}
|
||||
|
||||
private @NonNull String getFormattedBodyFor(@NonNull MessageRecord messageRecord) {
|
||||
|
|
65
app/src/main/res/layout/dialog_clear_all_media.xml
Normal file
65
app/src/main/res/layout/dialog_clear_all_media.xml
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:elevation="4dp"
|
||||
android:padding="@dimen/medium_spacing">
|
||||
|
||||
<TextView
|
||||
android:layout_gravity="center"
|
||||
android:layout_margin="@dimen/small_spacing"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/dialog_clear_all_media_title"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textStyle="bold"
|
||||
android:textSize="@dimen/medium_font_size" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dialogDescriptionText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:text="@string/dialog_clear_all_media_message"
|
||||
android:textAlignment="center"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/small_font_size" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Dialog.DestructiveText"
|
||||
android:id="@+id/clear"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/small_button_height"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginEnd="@dimen/medium_spacing"
|
||||
android:text="@string/dialog_clear_all_data_clear" />
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Dialog.UnimportantText"
|
||||
android:id="@+id/cancel"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/small_button_height"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/dialog_clear_all_messages_cancel" />
|
||||
|
||||
<com.github.ybq.android.spinkit.SpinKitView
|
||||
style="@style/SpinKitView.Small.ThreeBounce"
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/small_button_height"
|
||||
android:layout_weight="1"
|
||||
app:SpinKit_Color="?colorAccent"
|
||||
android:visibility="gone" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
97
app/src/main/res/layout/dialog_clear_all_messages.xml
Normal file
97
app/src/main/res/layout/dialog_clear_all_messages.xml
Normal file
|
@ -0,0 +1,97 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:elevation="4dp"
|
||||
android:padding="@dimen/medium_spacing">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_gravity="center"
|
||||
android:layout_margin="@dimen/small_spacing"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/dialog_clear_all_messages_title"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textStyle="bold"
|
||||
android:textSize="@dimen/medium_font_size" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/close"
|
||||
android:src="@drawable/ic_baseline_close_24"
|
||||
android:layout_gravity="end|top"
|
||||
android:layout_marginHorizontal="@dimen/small_spacing"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
app:tint="?android:textColorPrimary" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dialogDescriptionText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:text="@string/dialog_clear_all_messages_message"
|
||||
android:textAlignment="center"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/small_font_size" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Dialog.DestructiveText"
|
||||
android:id="@+id/clear"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/small_button_height"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginEnd="@dimen/medium_spacing"
|
||||
android:text="@string/dialog_clear_all_data_clear" />
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Dialog.UnimportantText"
|
||||
android:id="@+id/cancel"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/small_button_height"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/dialog_clear_all_messages_cancel" />
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Dialog.DestructiveText"
|
||||
android:id="@+id/forEveryone"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/small_button_height"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginEnd="@dimen/medium_spacing"
|
||||
android:text="@string/dialog_clear_all_messages_for_everyone" />
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Dialog.UnimportantText"
|
||||
android:id="@+id/forMe"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/small_button_height"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/dialog_clear_all_messages_for_me" />
|
||||
|
||||
<com.github.ybq.android.spinkit.SpinKitView
|
||||
style="@style/SpinKitView.Small.ThreeBounce"
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/small_button_height"
|
||||
android:layout_weight="1"
|
||||
app:SpinKit_Color="?colorAccent"
|
||||
android:visibility="gone" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
|
@ -17,7 +17,17 @@
|
|||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?android:attr/actionBarSize"
|
||||
app:layout_scrollFlags="scroll|enterAlways"/>
|
||||
app:layout_scrollFlags="scroll|enterAlways">
|
||||
<TextView
|
||||
android:visibility="gone"
|
||||
android:layout_marginHorizontal="@dimen/medium_spacing"
|
||||
android:textColor="@color/destructive"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:id="@+id/clearMedia"
|
||||
android:text="@string/media_overview_activity__clear_media"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</androidx.appcompat.widget.Toolbar>
|
||||
|
||||
<org.thoughtcrime.securesms.components.ControllableTabLayout
|
||||
android:id="@+id/tab_layout"
|
||||
|
|
|
@ -882,4 +882,14 @@
|
|||
<string name="conversation_settings_delete_group">Delete Group</string>
|
||||
<string name="image">image</string>
|
||||
<string name="video">video</string>
|
||||
<string name="dialog_clear_all_messages_title">Clear All Messages</string>
|
||||
<string name="dialog_clear_all_media_title">Clear All Media</string>
|
||||
<string name="dialog_clear_all_messages_message">Are you sure you want to clear all group messages?</string>
|
||||
<string name="dialog_clear_all_media_message">Are you sure you want to clear all media and files? This will also delete all messages with attachments.</string>
|
||||
<string name="dialog_clear_all_messages_local_message">Are you sure you want to clear %s messages from your device?</string>
|
||||
<string name="dialog_clear_all_messages_for_me">For Me</string>
|
||||
<string name="dialog_clear_all_messages_for_everyone">For Everyone</string>
|
||||
<string name="dialog_clear_all_messages_clear">Clear</string>
|
||||
<string name="dialog_clear_all_messages_cancel">Cancel</string>
|
||||
<string name="media_overview_activity__clear_media">Clear All</string>
|
||||
</resources>
|
||||
|
|
|
@ -1,6 +1,81 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<style name="Base.Theme.Session" parent="@style/Theme.AppCompat.DayNight">
|
||||
|
||||
<!-- Main styles -->
|
||||
<item name="sessionLogoTint">@color/classic_dark_6</item>
|
||||
<item name="colorPrimary">@color/classic_dark_0</item>
|
||||
<item name="colorPrimaryDark">@color/classic_dark_0</item>
|
||||
<item name="colorControlNormal">?android:textColorPrimary</item>
|
||||
<item name="colorControlActivated">?colorAccent</item>
|
||||
<item name="android:colorControlHighlight">?colorAccent</item>
|
||||
<item name="android:textColorPrimary">@color/classic_dark_6</item>
|
||||
<item name="android:textColorSecondary">?android:textColorPrimary</item>
|
||||
<item name="android:textColorTertiary">@color/classic_dark_5</item>
|
||||
<item name="android:textColor">?android:textColorPrimary</item>
|
||||
<item name="android:textColorHint">@color/gray27</item>
|
||||
<item name="android:windowBackground">?colorPrimary</item>
|
||||
<item name="android:navigationBarColor">@color/compose_view_background</item>
|
||||
<item name="dialog_background_color">@color/classic_dark_1</item>
|
||||
<item name="bottomSheetDialogTheme">@style/Classic.Dark.BottomSheet</item>
|
||||
<item name="actionMenuTextColor">?android:textColorPrimary</item>
|
||||
<item name="popupTheme">?actionBarPopupTheme</item>
|
||||
<item name="colorCellBackground">@color/classic_dark_1</item>
|
||||
<item name="colorSettingsBackground">@color/classic_dark_1</item>
|
||||
<item name="colorDividerBackground">@color/classic_dark_3</item>
|
||||
<item name="colorCellRipple">@color/classic_dark_3</item>
|
||||
<item name="actionBarPopupTheme">@style/Dark.Popup</item>
|
||||
<item name="actionBarWidgetTheme">@null</item>
|
||||
<item name="actionBarTheme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>
|
||||
<item name="actionBarStyle">@style/Widget.Session.ActionBar</item>
|
||||
<item name="prominentButtonColor">?colorAccent</item>
|
||||
<item name="elementBorderColor">@color/classic_dark_3</item>
|
||||
|
||||
<!-- Home screen -->
|
||||
<item name="searchBackgroundColor">#1B1B1B</item>
|
||||
<item name="searchIconColor">#E5E5E8</item>
|
||||
<item name="searchHintColor">@color/classic_dark_5</item>
|
||||
<item name="searchTextColor">?android:textColorPrimary</item>
|
||||
<item name="searchHighlightTint">?colorAccent</item>
|
||||
<item name="home_gradient_start">#00000000</item>
|
||||
<item name="home_gradient_end">@color/classic_dark_1</item>
|
||||
<item name="conversation_pinned_background_color">?colorCellBackground</item>
|
||||
<item name="conversation_unread_background_color">@color/classic_dark_2</item>
|
||||
<item name="conversation_pinned_icon_color">@color/classic_dark_4</item>
|
||||
<item name="unreadIndicatorBackgroundColor">@color/classic_dark_3</item>
|
||||
<item name="unreadIndicatorTextColor">@color/classic_dark_0</item>
|
||||
|
||||
<!-- New conversation button -->
|
||||
<item name="conversation_color_non_main">@color/classic_dark_2</item>
|
||||
<item name="conversation_shadow_non_main">@color/transparent_black_30</item>
|
||||
<item name="conversation_shadow_main">?colorAccent</item>
|
||||
<item name="conversation_menu_background_color">@color/classic_dark_1</item>
|
||||
<item name="conversation_menu_cell_color">?conversation_menu_background_color</item>
|
||||
<item name="conversation_menu_border_color">@color/classic_dark_3</item>
|
||||
<item name="conversationMenuSearchBackgroundColor">@color/classic_dark_0</item>
|
||||
|
||||
<!-- Conversation -->
|
||||
<item name="message_received_background_color">@color/classic_dark_2</item>
|
||||
<item name="message_received_text_color">@color/classic_dark_6</item>
|
||||
<item name="message_sent_background_color">?colorAccent</item>
|
||||
<item name="message_sent_text_color">@color/classic_dark_0</item>
|
||||
<item name="input_bar_background">@color/classic_dark_1</item>
|
||||
<item name="input_bar_text_hint">@color/classic_dark_5</item>
|
||||
<item name="input_bar_text_user">@color/classic_dark_6</item>
|
||||
<item name="input_bar_border">@color/classic_dark_3</item>
|
||||
<item name="input_bar_button_background">@color/classic_dark_2</item>
|
||||
<item name="input_bar_button_text_color">@color/classic_dark_6</item>
|
||||
<item name="input_bar_button_background_opaque">@color/classic_dark_2</item>
|
||||
<item name="input_bar_button_background_opaque_border">@color/classic_dark_3</item>
|
||||
<item name="input_bar_lock_view_background">@color/classic_dark_2</item>
|
||||
<item name="input_bar_lock_view_border">@color/classic_dark_3</item>
|
||||
<item name="mention_candidates_view_background">@color/classic_dark_2</item>
|
||||
<item name="mention_candidates_view_background_ripple">@color/classic_dark_3</item>
|
||||
<item name="scroll_to_bottom_button_background">@color/classic_dark_1</item>
|
||||
<item name="scroll_to_bottom_button_border">@color/classic_dark_3</item>
|
||||
<item name="conversation_unread_count_indicator_background">@color/classic_dark_4</item>
|
||||
<item name="message_selected">@color/classic_dark_1</item>
|
||||
|
||||
<item name="actionModeBackground">?colorPrimary</item>
|
||||
<item name="android:colorBackground">?colorPrimary</item>
|
||||
<item name="dialog_background_color">?colorPrimary</item>
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
package org.thoughtcrime.securesms.conversation.v2
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.kotlin.anyOrNull
|
||||
import org.mockito.kotlin.never
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.whenever
|
||||
import org.session.libsession.database.StorageProtocol
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.GroupRecord
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.BaseViewModelTest
|
||||
import org.thoughtcrime.securesms.conversation.settings.ConversationSettingsViewModel
|
||||
|
||||
class ConversationSettingsViewModelTest: BaseViewModelTest() {
|
||||
|
||||
companion object {
|
||||
const val TEST_THREAD_ID = 1L
|
||||
const val TEST_LOCAL_ID = "1234"
|
||||
}
|
||||
|
||||
|
||||
private val mockedStorage = mock(StorageProtocol::class.java)
|
||||
private val mockedPrefs = mock(TextSecurePreferences::class.java)
|
||||
private val mockedRecipient = mock(Recipient::class.java)
|
||||
|
||||
private val viewModel = ConversationSettingsViewModel(TEST_THREAD_ID, mockedStorage, mockedPrefs)
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
whenever(mockedStorage.getRecipientForThread(TEST_THREAD_ID)).thenReturn(mockedRecipient)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `it should get a mocked recipient`() {
|
||||
assertEquals(mockedRecipient, viewModel.recipient)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `it should report correct pin status`() {
|
||||
whenever(mockedStorage.isThreadPinned(TEST_THREAD_ID)).thenReturn(true)
|
||||
val pinStatus = viewModel.isPinned()
|
||||
verify(mockedStorage).isThreadPinned(TEST_THREAD_ID)
|
||||
assertTrue(pinStatus)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `it should auto download attachments`() {
|
||||
whenever(mockedStorage.shouldAutoDownloadAttachments(mockedRecipient)).thenReturn(true)
|
||||
val shouldDownload = viewModel.autoDownloadAttachments()
|
||||
verify(mockedStorage).shouldAutoDownloadAttachments(mockedRecipient)
|
||||
assertTrue(shouldDownload)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `it should not auto download if recipient null`() {
|
||||
whenever(mockedStorage.getRecipientForThread(TEST_THREAD_ID)).thenReturn(null)
|
||||
val shouldDownload = viewModel.autoDownloadAttachments()
|
||||
verify(mockedStorage, never()).shouldAutoDownloadAttachments(anyOrNull())
|
||||
assertFalse(shouldDownload)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `it should call storage for if user is an admin`() {
|
||||
val groupAddress = Address.fromSerialized("__textsecure_group__!1234")
|
||||
whenever(mockedRecipient.isClosedGroupRecipient).thenReturn(true)
|
||||
whenever(mockedRecipient.address).thenReturn(groupAddress)
|
||||
whenever(mockedPrefs.getLocalNumber()).thenReturn(TEST_LOCAL_ID)
|
||||
val mockedGroup = mock(GroupRecord::class.java).apply {
|
||||
whenever(this.admins).thenReturn(listOf(Address.fromSerialized(TEST_LOCAL_ID)))
|
||||
}
|
||||
whenever(mockedStorage.getGroup(groupAddress.serialize())).thenReturn(mockedGroup)
|
||||
val isUserAdmin = viewModel.isUserGroupAdmin()
|
||||
assertTrue(isUserAdmin)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `it should not call storage for group admin when we aren't in a group`() {
|
||||
whenever(mockedRecipient.isClosedGroupRecipient).thenReturn(false)
|
||||
val isUserAdmin = viewModel.isUserGroupAdmin()
|
||||
assertFalse(isUserAdmin)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `it should `() {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -155,6 +155,7 @@ interface StorageProtocol {
|
|||
fun getMessageCount(threadID: Long): Long
|
||||
fun setThreadPinned(threadID: Long, isPinned: Boolean)
|
||||
fun isThreadPinned(threadID: Long): Boolean
|
||||
fun clearMessages(threadID: Long): Boolean
|
||||
|
||||
// Contacts
|
||||
fun getContactWithSessionID(sessionID: String): Contact?
|
||||
|
|
Loading…
Reference in a new issue