Add expiration settings screen

This commit is contained in:
charles 2022-10-26 19:27:22 +11:00
parent e6d854a4ea
commit 63f372b45c
7 changed files with 274 additions and 11 deletions

View File

@ -172,6 +172,9 @@
android:screenOrientation="portrait" />
<activity android:name="org.thoughtcrime.securesms.preferences.appearance.AppearanceSettingsActivity"
android:screenOrientation="portrait"/>
<activity android:name="org.thoughtcrime.securesms.conversation.expiration.ExpirationSettingsActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.Session.DayNight.NoActionBar" />
<activity
android:name="org.thoughtcrime.securesms.ShareActivity"

View File

@ -0,0 +1,96 @@
package org.thoughtcrime.securesms.conversation.expiration
import android.os.Bundle
import android.os.Parcelable
import android.util.SparseArray
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.RecyclerView
import dagger.hilt.android.AndroidEntryPoint
import network.loki.messenger.R
import network.loki.messenger.databinding.ActivityExpirationSettingsBinding
import org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.preferences.RadioOption
import org.thoughtcrime.securesms.preferences.RadioOptionAdapter
@AndroidEntryPoint
class ExpirationSettingsActivity: PassphraseRequiredActionBarActivity() {
private lateinit var binding : ActivityExpirationSettingsBinding
private val expirationType: ExpirationType? by lazy {
ExpirationType.valueOf(intent.getIntExtra(EXTRA_EXPIRATION_TYPE, -1))
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
val scrollParcelArray = SparseArray<Parcelable>()
binding.scrollView.saveHierarchyState(scrollParcelArray)
outState.putSparseParcelableArray(SCROLL_PARCEL, scrollParcelArray)
}
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
super.onCreate(savedInstanceState, ready)
binding = ActivityExpirationSettingsBinding.inflate(layoutInflater)
setContentView(binding.root)
setUpToolbar()
savedInstanceState?.let { bundle ->
val scrollStateParcel = bundle.getSparseParcelableArray<Parcelable>(SCROLL_PARCEL)
if (scrollStateParcel != null) {
binding.scrollView.restoreHierarchyState(scrollStateParcel)
}
}
val options = if (expirationType == ExpirationType.DELETE_AFTER_SEND) {
val values = resources.getIntArray(R.array.send_expiration_time_values).map(Int::toString)
val names = resources.getStringArray(R.array.send_expiration_time_names)
values.zip(names) { value, name -> RadioOption(value, name)}
} else {
listOf(
RadioOption("off", getString(R.string.expiration_off)),
RadioOption("read", getString(R.string.expiration_type_disappear_after_read)),
RadioOption("send", getString(R.string.expiration_type_disappear_after_send))
)
}
val optionAdapter = RadioOptionAdapter {
}
binding.textViewDeleteType.isVisible = expirationType == null
binding.textViewTimer.isVisible = expirationType == null
binding.layoutTimer.isVisible = expirationType == null
binding.recyclerView.apply {
adapter = optionAdapter
addItemDecoration(ContextCompat.getDrawable(this@ExpirationSettingsActivity, R.drawable.conversation_menu_divider)!!.let {
DividerItemDecoration(this@ExpirationSettingsActivity, RecyclerView.VERTICAL).apply {
setDrawable(it)
}
})
setHasFixedSize(true)
}
optionAdapter.submitList(options)
}
private fun setUpToolbar() {
setSupportActionBar(binding.toolbar)
val actionBar = supportActionBar ?: return
actionBar.title = getString(R.string.activity_expiration_settings_title)
actionBar.subtitle = if (expirationType == ExpirationType.DELETE_AFTER_SEND) {
getString(R.string.activity_expiration_settings_subtitle_sent)
} else {
getString(R.string.activity_expiration_settings_subtitle)
}
actionBar.setDisplayHomeAsUpEnabled(true)
actionBar.setHomeButtonEnabled(true)
}
companion object {
private const val SCROLL_PARCEL = "scroll_parcel"
const val EXTRA_EXPIRATION_TYPE = "expiration_type"
const val EXTRA_READ_ONLY = "read_only"
}
}

View File

@ -56,7 +56,6 @@ import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.mentions.Mention
import org.session.libsession.messaging.mentions.MentionsManager
import org.session.libsession.messaging.messages.control.DataExtractionNotification
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage
import org.session.libsession.messaging.messages.signal.OutgoingTextMessage
import org.session.libsession.messaging.messages.visible.Reaction
@ -78,18 +77,19 @@ import org.session.libsession.utilities.concurrent.SimpleTask
import org.session.libsession.utilities.recipients.Recipient
import org.session.libsession.utilities.recipients.RecipientModifiedListener
import org.session.libsignal.crypto.MnemonicCodec
import org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType
import org.session.libsignal.utilities.IdPrefix
import org.session.libsignal.utilities.ListenableFuture
import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.guava.Optional
import org.session.libsignal.utilities.hexEncodedPrivateKey
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.ExpirationDialog
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.attachments.ScreenshotObserver
import org.thoughtcrime.securesms.audio.AudioRecorder
import org.thoughtcrime.securesms.contacts.SelectContactsActivity.Companion.selectedContactsKey
import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher
import org.thoughtcrime.securesms.conversation.expiration.ExpirationSettingsActivity
import org.thoughtcrime.securesms.conversation.v2.ConversationReactionOverlay.OnActionSelectedListener
import org.thoughtcrime.securesms.conversation.v2.ConversationReactionOverlay.OnReactionSelectedListener
import org.thoughtcrime.securesms.conversation.v2.dialogs.BlockedDialog
@ -154,6 +154,7 @@ import org.thoughtcrime.securesms.util.DateUtils
import org.thoughtcrime.securesms.util.MediaUtil
import org.thoughtcrime.securesms.util.SaveAttachmentTask
import org.thoughtcrime.securesms.util.push
import org.thoughtcrime.securesms.util.show
import org.thoughtcrime.securesms.util.toPx
import java.util.Locale
import java.util.concurrent.ExecutionException
@ -988,16 +989,11 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
val group = groupDb.getGroup(thread.address.toGroupString()).orNull()
if (group?.isActive == false) { return }
}
ExpirationDialog.show(this, thread.expireMessages) { expirationTime: Int ->
recipientDb.setExpireMessages(thread, expirationTime)
val message = ExpirationTimerUpdate(expirationTime)
message.recipient = thread.address.serialize()
message.sentTimestamp = System.currentTimeMillis()
val expiringMessageManager = ApplicationContext.getInstance(this).expiringMessageManager
expiringMessageManager.setExpirationTimer(message)
MessageSender.send(message, thread.address)
invalidateOptionsMenu()
val expirationIntent = Intent(this, ExpirationSettingsActivity::class.java)
if (thread.isLocalNumber || thread.isClosedGroupRecipient) {
expirationIntent.putExtra(ExpirationSettingsActivity.EXTRA_EXPIRATION_TYPE, ExpirationType.DELETE_AFTER_SEND_VALUE)
}
show(expirationIntent, true)
}
override fun unblock() {

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?colorPrimary"
app:contentInsetStart="0dp"
app:subtitle="@string/activity_expiration_settings_subtitle"
app:subtitleTextAppearance="@style/TextAppearance.Session.ToolbarSubtitle"
app:title="@string/activity_expiration_settings_title" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/toolbar"
android:orientation="vertical">
<TextView
android:id="@+id/text_view_delete_type"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="@dimen/large_spacing"
android:paddingVertical="@dimen/small_spacing"
android:text="@string/activity_expiration_settings_delete_type"
android:textColor="?android:textColorTertiary"
android:textSize="@dimen/medium_font_size" />
<LinearLayout
android:id="@+id/theme_option_classic_dark"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/preference_top"
android:orientation="horizontal"
android:paddingHorizontal="@dimen/large_spacing"
android:paddingVertical="@dimen/medium_spacing">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="6"
tools:listitem="@layout/item_selectable" />
</LinearLayout>
<TextView
android:id="@+id/text_view_timer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="@dimen/large_spacing"
android:paddingVertical="@dimen/small_spacing"
android:text="@string/activity_expiration_settings_timer"
android:textColor="?android:textColorTertiary"
android:textSize="@dimen/medium_font_size" />
<LinearLayout
android:id="@+id/layout_timer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/massive_spacing"
android:background="@drawable/preference_single"
android:gravity="center"
android:padding="@dimen/medium_spacing">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingHorizontal="@dimen/large_spacing"
android:paddingVertical="@dimen/small_spacing"
android:text="@string/activity_appearance_follow_system_explanation"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/medium_font_size"
android:textStyle="bold" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/system_settings_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="@dimen/large_spacing" />
</LinearLayout>
</LinearLayout>
<Button
android:id="@+id/button_set"
style="@style/Widget.Session.Button.Common.ProminentOutline"
android:layout_width="196dp"
android:layout_height="@dimen/medium_button_height"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/medium_spacing"
android:layout_marginBottom="@dimen/massive_spacing"
android:text="@string/expiration_settings_set_button_title" />
</RelativeLayout>
</ScrollView>

View File

@ -236,4 +236,40 @@
<item>@string/notify_type_mentions</item>
</string-array>
<integer-array name="read_expiration_time_names">
<item>@string/arrays__off</item>
<item>@string/arrays__five_minutes</item>
<item>@string/arrays__one_hour</item>
<item>@string/arrays__twelve_hours</item>
<item>@string/arrays__one_day</item>
<item>@string/arrays__one_week</item>
<item>@string/arrays__two_weeks</item>
</integer-array>
<integer-array name="read_expiration_time_values">
<item>0</item>
<item>300</item>
<item>3600</item>
<item>43200</item>
<item>86400</item>
<item>604800</item>
<item>1209600</item>
</integer-array>
<integer-array name="send_expiration_time_names">
<item>@string/arrays__off</item>
<item>@string/arrays__twelve_hours</item>
<item>@string/arrays__one_day</item>
<item>@string/arrays__one_week</item>
<item>@string/arrays__two_weeks</item>
</integer-array>
<integer-array name="send_expiration_time_values">
<item>0</item>
<item>43200</item>
<item>86400</item>
<item>604800</item>
<item>1209600</item>
</integer-array>
</resources>

View File

@ -404,6 +404,13 @@
<string name="arrays__default">Default</string>
<string name="arrays__high">High</string>
<string name="arrays__max">Max</string>
<string name="arrays__off">Off</string>
<string name="arrays__five_minutes">5 Minutes</string>
<string name="arrays__one_hour">1 Hour</string>
<string name="arrays__twelve_hours">12 Hours</string>
<string name="arrays__one_day">1 Day</string>
<string name="arrays__one_week">1 Week</string>
<string name="arrays__two_weeks">2 Weeks</string>
<!-- plurals.xml -->
<plurals name="hours_ago">
<item quantity="one">%d hour</item>
@ -864,4 +871,12 @@
<string name="fragment_enter_community_url_join_button_title">Join</string>
<string name="new_conversation_dialog_back_button_content_description">Navigate Back</string>
<string name="new_conversation_dialog_close_button_content_description">Close Dialog</string>
<string name="activity_expiration_settings_title">Disappearing Messages</string>
<string name="activity_expiration_settings_subtitle">This setting applies to everyone in this conversation.</string>
<string name="activity_expiration_settings_subtitle_sent">Messages disappear after they have been sent.</string>
<string name="expiration_type_disappear_after_read">Disappear After Read</string>
<string name="expiration_type_disappear_after_send">Disappear After Send</string>
<string name="expiration_settings_set_button_title">Set</string>
<string name="activity_expiration_settings_delete_type">Delete Type</string>
<string name="activity_expiration_settings_timer">Timer</string>
</resources>

View File

@ -80,6 +80,10 @@
<item name="android:textColor">@color/emoji_tab_text_color</item>
</style>
<style name="TextAppearance.Session.ToolbarSubtitle" parent="TextAppearance.MaterialComponents.Caption">
<item name="android:textSize">11dp</item>
</style>
<!-- TODO These button styles require proper background selectors for up/down visual state. -->
<style name="Widget.Session.Button.Common" parent="">
<item name="android:textAllCaps">false</item>