Round out sms/mms export process.

fork-5.53.8
Cody Henthorne 2022-09-28 10:47:37 -04:00
rodzic 0e4bec3977
commit 31f31534ce
31 zmienionych plików z 792 dodań i 197 usunięć

Wyświetl plik

@ -683,6 +683,7 @@
<activity android:name=".exporter.flow.SmsExportActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:screenOrientation="portrait"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<service android:enabled="true" android:name=".exporter.SignalSmsExportService" android:foregroundServiceType="dataSync" />

Wyświetl plik

@ -141,14 +141,16 @@ class SmsSettingsFragment : DSLSettingsFragment(R.string.preferences__sms_mms) {
private fun showSmsRemovalDialog() {
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.RemoveSmsMessagesDialogFragment__remove_sms_messages)
.setMessage(R.string.RemoveSmsMessagesDialogFragment__you_have_changed)
.setPositiveButton(R.string.RemoveSmsMessagesDialogFragment__keep_messages) { _, _ -> }
.setMessage(R.string.RemoveSmsMessagesDialogFragment__you_can_now_remove_sms_messages_from_signal)
.setPositiveButton(R.string.RemoveSmsMessagesDialogFragment__keep_messages) { _, _ ->
Snackbar.make(requireView(), R.string.SmsSettingsFragment__you_can_remove_sms_messages_from_signal_in_settings, Snackbar.LENGTH_SHORT).show()
}
.setNegativeButton(R.string.RemoveSmsMessagesDialogFragment__remove_messages) { _, _ ->
SignalExecutors.BOUNDED.execute {
SignalDatabase.sms.deleteExportedMessages()
SignalDatabase.mms.deleteExportedMessages()
}
Snackbar.make(requireView(), R.string.SmsSettingsFragment__sms_messages_removed, Snackbar.LENGTH_SHORT).show()
Snackbar.make(requireView(), R.string.SmsSettingsFragment__removing_sms_messages_from_signal, Snackbar.LENGTH_SHORT).show()
}
.show()
}

Wyświetl plik

@ -3,10 +3,14 @@ package org.thoughtcrime.securesms.components.settings.app.chats.sms
import androidx.annotation.WorkerThread
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.schedulers.Schedulers
import org.thoughtcrime.securesms.database.MessageDatabase
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.util.FeatureFlags
class SmsSettingsRepository {
class SmsSettingsRepository(
private val smsDatabase: MessageDatabase = SignalDatabase.sms,
private val mmsDatabase: MessageDatabase = SignalDatabase.mms
) {
fun getSmsExportState(): Single<SmsSettingsState.SmsExportState> {
if (!FeatureFlags.smsExporter()) {
return Single.just(SmsSettingsState.SmsExportState.NOT_AVAILABLE)
@ -19,9 +23,7 @@ class SmsSettingsRepository {
@WorkerThread
private fun checkInsecureMessageCount(): SmsSettingsState.SmsExportState? {
val smsCount = SignalDatabase.sms.insecureMessageCount
val mmsCount = SignalDatabase.mms.insecureMessageCount
val totalSmsMmsCount = smsCount + mmsCount
val totalSmsMmsCount = smsDatabase.insecureMessageCount + mmsDatabase.insecureMessageCount
return if (totalSmsMmsCount == 0) {
SmsSettingsState.SmsExportState.NO_SMS_MESSAGES_IN_DATABASE
@ -32,9 +34,7 @@ class SmsSettingsRepository {
@WorkerThread
private fun checkUnexportedInsecureMessageCount(): SmsSettingsState.SmsExportState {
val unexportedSmsCount = SignalDatabase.sms.unexportedInsecureMessages.use { it.count }
val unexportedMmsCount = SignalDatabase.mms.unexportedInsecureMessages.use { it.count }
val totalUnexportedCount = unexportedSmsCount + unexportedMmsCount
val totalUnexportedCount = smsDatabase.unexportedInsecureMessagesCount + mmsDatabase.unexportedInsecureMessagesCount
return if (totalUnexportedCount > 0) {
SmsSettingsState.SmsExportState.HAS_UNEXPORTED_MESSAGES

Wyświetl plik

@ -96,7 +96,7 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns,
public abstract boolean isSent(long messageId);
public abstract List<MessageRecord> getProfileChangeDetailsRecords(long threadId, long afterTimestamp);
public abstract Set<Long> getAllRateLimitedMessageIds();
public abstract Cursor getUnexportedInsecureMessages();
public abstract Cursor getUnexportedInsecureMessages(int limit);
public abstract int getInsecureMessageCount();
public abstract void deleteExportedMessages();
@ -360,11 +360,22 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns,
}
protected String getInsecureMessageClause() {
String isSent = "(" + getTypeField() + " & " + Types.BASE_TYPE_MASK + ") = " + Types.BASE_SENT_TYPE;
String isReceived = "(" + getTypeField() + " & " + Types.BASE_TYPE_MASK + ") = " + Types.BASE_INBOX_TYPE;
String isSecure = "(" + getTypeField() + " & " + (Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT) + ")";
String isSent = "(" + getTypeField() + " & " + Types.BASE_TYPE_MASK + ") = " + Types.BASE_SENT_TYPE;
String isReceived = "(" + getTypeField() + " & " + Types.BASE_TYPE_MASK + ") = " + Types.BASE_INBOX_TYPE;
String isSecure = "(" + getTypeField() + " & " + (Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT) + ")";
String isNotSecure = "(" + getTypeField() + " <= " + (Types.BASE_TYPE_MASK | Types.MESSAGE_ATTRIBUTE_MASK) + ")";
return String.format(Locale.ENGLISH, "(%s OR %s) AND NOT %s", isSent, isReceived, isSecure);
return String.format(Locale.ENGLISH, "(%s OR %s) AND NOT %s AND %s", isSent, isReceived, isSecure, isNotSecure);
}
public int getUnexportedInsecureMessagesCount() {
try (Cursor cursor = getWritableDatabase().query(getTableName(), SqlUtil.COUNT, getInsecureMessageClause() + " AND NOT " + EXPORTED, null, null, null, null)) {
if (cursor.moveToFirst()) {
return cursor.getInt(0);
}
}
return 0;
}
public void setReactionsSeen(long threadId, long sinceTimestamp) {

Wyświetl plik

@ -54,7 +54,6 @@ import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
import org.thoughtcrime.securesms.database.model.Mention;
import org.thoughtcrime.securesms.database.model.MessageId;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord;
import org.thoughtcrime.securesms.database.model.ParentStoryId;
import org.thoughtcrime.securesms.database.model.Quote;
@ -2422,13 +2421,13 @@ public class MmsDatabase extends MessageDatabase {
}
@Override
public Cursor getUnexportedInsecureMessages() {
public Cursor getUnexportedInsecureMessages(int limit) {
return rawQuery(
SqlUtil.appendArg(MMS_PROJECTION, EXPORT_STATE),
getInsecureMessageClause() + " AND NOT " + EXPORTED,
null,
false,
0
limit
);
}

Wyświetl plik

@ -908,13 +908,13 @@ public class SmsDatabase extends MessageDatabase {
}
@Override
public Cursor getUnexportedInsecureMessages() {
public Cursor getUnexportedInsecureMessages(int limit) {
return queryMessages(
SqlUtil.appendArg(MESSAGE_PROJECTION, EXPORT_STATE),
getInsecureMessageClause() + " AND NOT " + EXPORTED,
null,
false,
-1
limit
);
}

Wyświetl plik

@ -1,136 +1,222 @@
package org.thoughtcrime.securesms.exporter
import android.database.Cursor
import org.signal.core.util.logging.Log
import org.signal.smsexporter.ExportableMessage
import org.signal.smsexporter.SmsExportState
import org.thoughtcrime.securesms.attachments.DatabaseAttachment
import org.thoughtcrime.securesms.database.MessageDatabase
import org.thoughtcrime.securesms.database.MmsDatabase
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.SmsDatabase
import org.thoughtcrime.securesms.database.model.MessageId
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExportState
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.JsonUtils
import java.io.Closeable
import kotlin.time.Duration.Companion.milliseconds
/**
* Reads through the SMS and MMS databases for insecure messages that haven't been exported. Due to cursor size limitations
* we "page" through the unexported messages to reduce chances of exceeding that limit.
*/
class SignalSmsExportReader(
smsCursor: Cursor,
mmsCursor: Cursor
private val smsDatabase: MessageDatabase = SignalDatabase.sms,
private val mmsDatabase: MessageDatabase = SignalDatabase.mms
) : Iterable<ExportableMessage>, Closeable {
private val smsReader = SmsDatabase.readerFor(smsCursor)
private val mmsReader = MmsDatabase.readerFor(mmsCursor)
companion object {
private val TAG = Log.tag(SignalSmsExportReader::class.java)
private const val CURSOR_LIMIT = 1000
}
private var smsReader: SmsDatabase.Reader? = null
private var smsDone: Boolean = false
private var mmsReader: MmsDatabase.Reader? = null
private var mmsDone: Boolean = false
override fun iterator(): Iterator<ExportableMessage> {
return ExportableMessageIterator()
}
fun getCount(): Int {
return smsReader.count + mmsReader.count
return smsDatabase.unexportedInsecureMessagesCount + mmsDatabase.unexportedInsecureMessagesCount
}
override fun close() {
smsReader.close()
mmsReader.close()
smsReader?.close()
mmsReader?.close()
}
private fun refreshReaders() {
if (!smsDone) {
smsReader?.close()
smsReader = null
val refreshedSmsReader = SmsDatabase.readerFor(smsDatabase.getUnexportedInsecureMessages(CURSOR_LIMIT))
if (refreshedSmsReader.count > 0) {
smsReader = refreshedSmsReader
return
} else {
refreshedSmsReader.close()
smsDone = true
}
}
if (!mmsDone) {
mmsReader?.close()
mmsReader = null
val refreshedMmsReader = MmsDatabase.readerFor(mmsDatabase.getUnexportedInsecureMessages(CURSOR_LIMIT))
if (refreshedMmsReader.count > 0) {
mmsReader = refreshedMmsReader
return
} else {
refreshedMmsReader.close()
mmsDone = true
}
}
}
private inner class ExportableMessageIterator : Iterator<ExportableMessage> {
private val smsIterator = smsReader.iterator()
private val mmsIterator = mmsReader.iterator()
private var smsIterator: Iterator<MessageRecord>? = null
private var mmsIterator: Iterator<MessageRecord>? = null
private fun refreshIterators() {
refreshReaders()
smsIterator = smsReader?.iterator()
mmsIterator = mmsReader?.iterator()
}
override fun hasNext(): Boolean {
return smsIterator.hasNext() || mmsIterator.hasNext()
if (smsIterator?.hasNext() == true) {
return true
} else if (!smsDone) {
refreshIterators()
if (smsIterator?.hasNext() == true) {
return true
}
}
if (mmsIterator?.hasNext() == true) {
return true
} else if (!mmsDone) {
refreshIterators()
if (mmsIterator?.hasNext() == true) {
return true
}
}
return false
}
override fun next(): ExportableMessage {
return if (smsIterator.hasNext()) {
readExportableSmsMessageFromRecord(smsIterator.next())
} else if (mmsIterator.hasNext()) {
readExportableMmsMessageFromRecord(mmsIterator.next())
var record: MessageRecord? = null
try {
return if (smsIterator?.hasNext() == true) {
record = smsIterator!!.next()
readExportableSmsMessageFromRecord(record, smsReader!!.messageExportStateForCurrentRecord)
} else if (mmsIterator?.hasNext() == true) {
record = mmsIterator!!.next()
readExportableMmsMessageFromRecord(record, mmsReader!!.messageExportStateForCurrentRecord)
} else {
throw NoSuchElementException()
}
} catch (e: Throwable) {
Log.w(TAG, "Error processing message: isMms: ${record?.isMms} type: ${record?.type}")
throw e
}
}
private fun readExportableMmsMessageFromRecord(record: MessageRecord, exportState: MessageExportState): ExportableMessage {
val threadRecipient: Recipient = SignalDatabase.threads.getRecipientForThreadId(record.threadId)!!
val addresses: Set<String> = if (threadRecipient.isMmsGroup) {
Recipient
.resolvedList(threadRecipient.participantIds)
.map { r -> r.smsExportAddress() }
.toSet()
} else {
throw NoSuchElementException()
setOf(threadRecipient.smsExportAddress())
}
}
}
private fun readExportableMmsMessageFromRecord(record: MessageRecord): ExportableMessage {
val threadRecipient = SignalDatabase.threads.getRecipientForThreadId(record.threadId)!!
val addresses = if (threadRecipient.isMmsGroup) {
Recipient.resolvedList(threadRecipient.participantIds).map { it.requireSmsAddress() }.toSet()
} else {
setOf(threadRecipient.requireSmsAddress())
}
val parts: MutableList<ExportableMessage.Mms.Part> = mutableListOf()
if (record.body.isNotBlank()) {
parts.add(ExportableMessage.Mms.Part.Text(record.body))
}
if (record is MmsMessageRecord) {
val slideDeck = record.slideDeck
slideDeck.slides.forEach {
parts.add(
ExportableMessage.Mms.Part.Stream(
id = JsonUtils.toJson((it.asAttachment() as DatabaseAttachment).attachmentId),
contentType = it.contentType
)
)
val parts: MutableList<ExportableMessage.Mms.Part> = mutableListOf()
if (record.body.isNotBlank()) {
parts.add(ExportableMessage.Mms.Part.Text(record.body))
}
}
val sender = if (record.isOutgoing) Recipient.self().requireSmsAddress() else record.individualRecipient.requireSmsAddress()
if (record is MmsMessageRecord) {
val slideDeck = record.slideDeck
slideDeck
.slides
.filter { it.asAttachment() is DatabaseAttachment }
.forEach {
parts.add(
ExportableMessage.Mms.Part.Stream(
id = JsonUtils.toJson((it.asAttachment() as DatabaseAttachment).attachmentId),
contentType = it.contentType
)
)
}
}
return ExportableMessage.Mms(
id = record.id.toString(),
exportState = mapExportState(mmsReader.messageExportStateForCurrentRecord),
addresses = addresses,
dateReceived = record.dateReceived.milliseconds,
dateSent = record.dateSent.milliseconds,
isRead = true,
isOutgoing = record.isOutgoing,
parts = parts,
sender = sender
)
}
val sender: String = if (record.isOutgoing) Recipient.self().smsExportAddress() else record.individualRecipient.smsExportAddress()
private fun readExportableSmsMessageFromRecord(record: MessageRecord): ExportableMessage {
val threadRecipient = SignalDatabase.threads.getRecipientForThreadId(record.threadId)!!
return if (threadRecipient.isMmsGroup) {
readExportableMmsMessageFromRecord(record)
} else {
ExportableMessage.Sms(
id = record.id.toString(),
exportState = mapExportState(smsReader.messageExportStateForCurrentRecord),
address = record.recipient.requireSmsAddress(),
return ExportableMessage.Mms(
id = MessageId(record.id, record.isMms),
exportState = mapExportState(exportState),
addresses = addresses,
dateReceived = record.dateReceived.milliseconds,
dateSent = record.dateSent.milliseconds,
isRead = true,
isOutgoing = record.isOutgoing,
body = record.body
parts = parts,
sender = sender
)
}
}
private fun mapExportState(messageExportState: MessageExportState): SmsExportState {
return SmsExportState(
messageId = messageExportState.messageId,
startedRecipients = messageExportState.startedRecipientsList.toSet(),
completedRecipients = messageExportState.completedRecipientsList.toSet(),
startedAttachments = messageExportState.startedAttachmentsList.toSet(),
completedAttachments = messageExportState.completedAttachmentsList.toSet(),
progress = messageExportState.progress.let {
when (it) {
MessageExportState.Progress.INIT -> SmsExportState.Progress.INIT
MessageExportState.Progress.STARTED -> SmsExportState.Progress.STARTED
MessageExportState.Progress.COMPLETED -> SmsExportState.Progress.COMPLETED
MessageExportState.Progress.UNRECOGNIZED -> SmsExportState.Progress.INIT
null -> SmsExportState.Progress.INIT
}
private fun readExportableSmsMessageFromRecord(record: MessageRecord, exportState: MessageExportState): ExportableMessage {
val threadRecipient = SignalDatabase.threads.getRecipientForThreadId(record.threadId)!!
return if (threadRecipient.isMmsGroup) {
readExportableMmsMessageFromRecord(record, exportState)
} else {
ExportableMessage.Sms(
id = MessageId(record.id, record.isMms),
exportState = mapExportState(exportState),
address = record.recipient.smsExportAddress(),
dateReceived = record.dateReceived.milliseconds,
dateSent = record.dateSent.milliseconds,
isRead = true,
isOutgoing = record.isOutgoing,
body = record.body
)
}
)
}
private fun mapExportState(messageExportState: MessageExportState): SmsExportState {
return SmsExportState(
messageId = messageExportState.messageId,
startedRecipients = messageExportState.startedRecipientsList.toSet(),
completedRecipients = messageExportState.completedRecipientsList.toSet(),
startedAttachments = messageExportState.startedAttachmentsList.toSet(),
completedAttachments = messageExportState.completedAttachmentsList.toSet(),
progress = messageExportState.progress.let {
when (it) {
MessageExportState.Progress.INIT -> SmsExportState.Progress.INIT
MessageExportState.Progress.STARTED -> SmsExportState.Progress.STARTED
MessageExportState.Progress.COMPLETED -> SmsExportState.Progress.COMPLETED
MessageExportState.Progress.UNRECOGNIZED -> SmsExportState.Progress.INIT
null -> SmsExportState.Progress.INIT
}
}
)
}
private fun Recipient.smsExportAddress(): String {
return smsAddress.orElseGet { getDisplayName(ApplicationDependencies.getApplication()) }
}
}
}

Wyświetl plik

@ -4,6 +4,7 @@ import android.content.Context
import android.content.Intent
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import app.cash.exhaustive.Exhaustive
import org.signal.smsexporter.ExportableMessage
import org.signal.smsexporter.SmsExportService
import org.thoughtcrime.securesms.R
@ -36,7 +37,7 @@ class SignalSmsExportService : SmsExportService() {
return ExportNotification(
NotificationIds.SMS_EXPORT_SERVICE,
NotificationCompat.Builder(this, NotificationChannels.BACKUPS)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setSmallIcon(R.drawable.ic_signal_backup)
.setContentTitle(getString(R.string.SignalSmsExportService__exporting_messages))
.setProgress(total, progress, false)
.build()
@ -126,18 +127,22 @@ class SignalSmsExportService : SmsExportService() {
}
private fun ExportableMessage.getMessageId(): MessageId {
return when (this) {
is ExportableMessage.Mms -> MessageId(id.toLong(), true)
is ExportableMessage.Sms -> MessageId(id.toLong(), false)
@Exhaustive
val messageId: Any = when (this) {
is ExportableMessage.Mms<*> -> id
is ExportableMessage.Sms<*> -> id
}
if (messageId is MessageId) {
return messageId
} else {
throw AssertionError("Exportable message id must be type MessageId. Type: ${messageId.javaClass}")
}
}
private fun ensureReader() {
if (reader == null) {
reader = SignalSmsExportReader(
smsCursor = SignalDatabase.sms.unexportedInsecureMessages,
mmsCursor = SignalDatabase.mms.unexportedInsecureMessages
)
reader = SignalSmsExportReader()
}
}
}

Wyświetl plik

@ -1,6 +1,7 @@
package org.thoughtcrime.securesms.exporter.flow
import android.app.Activity
import android.os.Build
import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
@ -23,6 +24,12 @@ class ChooseANewDefaultSmsAppFragment : Fragment(R.layout.choose_a_new_default_s
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val binding = ChooseANewDefaultSmsAppFragmentBinding.bind(view)
if (Build.VERSION.SDK_INT < 24) {
binding.bullet1Text.setText(R.string.ChooseANewDefaultSmsAppFragment__open_your_phones_settings_app)
binding.bullet2Text.setText(R.string.ChooseANewDefaultSmsAppFragment__navigate_to_apps_default_apps_sms_app)
binding.continueButton.setText(R.string.ChooseANewDefaultSmsAppFragment__done)
}
DefaultSmsHelper.releaseDefaultSms(requireContext()).either(
onSuccess = {
binding.continueButton.setOnClickListener { _ -> startActivity(it) }

Wyświetl plik

@ -1,10 +1,14 @@
package org.thoughtcrime.securesms.exporter.flow
import android.content.Context
import android.os.Bundle
import android.view.ContextThemeWrapper
import android.view.LayoutInflater
import android.view.View
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.disposables.Disposable
import org.signal.smsexporter.SmsExportProgress
import org.signal.smsexporter.SmsExportService
import org.thoughtcrime.securesms.R
@ -20,6 +24,30 @@ import org.thoughtcrime.securesms.util.navigation.safeNavigate
class ExportingSmsMessagesFragment : Fragment(R.layout.exporting_sms_messages_fragment) {
private val lifecycleDisposable = LifecycleDisposable()
private var navigationDisposable = Disposable.disposed()
override fun onGetLayoutInflater(savedInstanceState: Bundle?): LayoutInflater {
val inflater = super.onGetLayoutInflater(savedInstanceState)
val contextThemeWrapper: Context = ContextThemeWrapper(requireContext(), R.style.Signal_DayNight)
return inflater.cloneInContext(contextThemeWrapper)
}
override fun onResume() {
super.onResume()
navigationDisposable = SmsExportService
.progressState
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
if (it is SmsExportProgress.Done) {
findNavController().safeNavigate(ExportingSmsMessagesFragmentDirections.actionExportingSmsMessagesFragmentToChooseANewDefaultSmsAppFragment())
}
}
}
override fun onPause() {
super.onPause()
navigationDisposable.dispose()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val binding = ExportingSmsMessagesFragmentBinding.bind(view)
@ -27,9 +55,7 @@ class ExportingSmsMessagesFragment : Fragment(R.layout.exporting_sms_messages_fr
lifecycleDisposable.bindTo(viewLifecycleOwner)
lifecycleDisposable += SmsExportService.progressState.observeOn(AndroidSchedulers.mainThread()).subscribe {
when (it) {
SmsExportProgress.Done -> {
findNavController().safeNavigate(ExportingSmsMessagesFragmentDirections.actionExportingSmsMessagesFragmentToChooseANewDefaultSmsAppFragment())
}
SmsExportProgress.Done -> Unit
is SmsExportProgress.InProgress -> {
binding.progress.isIndeterminate = false
binding.progress.max = it.total

Wyświetl plik

@ -6,8 +6,15 @@ import androidx.fragment.app.Fragment
import androidx.navigation.fragment.NavHostFragment
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.FragmentWrapperActivity
import org.thoughtcrime.securesms.util.WindowUtil
class SmsExportActivity : FragmentWrapperActivity() {
override fun onResume() {
super.onResume()
WindowUtil.setLightStatusBarFromTheme(this)
}
override fun getFragment(): Fragment {
return NavHostFragment.create(R.navigation.sms_export)
}

Wyświetl plik

@ -0,0 +1,50 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:width="258dp"
android:height="240dp"
android:viewportWidth="258"
android:viewportHeight="240"
tools:ignore="VectorRaster">
<path
android:pathData="M9,40C9,17.91 26.91,0 49,0H209C231.09,0 249,17.91 249,40V200C249,222.09 231.09,240 209,240H49C26.91,240 9,222.09 9,200V40Z"
android:fillColor="#1B1C1F"/>
<path
android:pathData="M9,40C9,17.91 26.91,0 49,0H209C231.09,0 249,17.91 249,40V200C249,222.09 231.09,240 209,240H49C26.91,240 9,222.09 9,200V40Z"
android:fillColor="#B6C5FA"
android:fillAlpha="0.08"/>
<path
android:pathData="M209,6H49C30.22,6 15,21.22 15,40V200C15,218.78 30.22,234 49,234H209C227.78,234 243,218.78 243,200V40C243,21.22 227.78,6 209,6ZM49,0C26.91,0 9,17.91 9,40V200C9,222.09 26.91,240 49,240H209C231.09,240 249,222.09 249,200V40C249,17.91 231.09,0 209,0H49Z"
android:fillColor="#5C5E65"
android:fillType="evenOdd"/>
<path
android:pathData="M53,104m-18,0a18,18 0,1 1,36 0a18,18 0,1 1,-36 0"
android:fillColor="#3A76F0"/>
<path
android:pathData="M50.18,92.6L50.45,93.67C49.41,93.93 48.41,94.34 47.5,94.89L46.93,93.95C47.94,93.34 49.04,92.89 50.18,92.6V92.6ZM55.82,92.6L55.55,93.67C56.59,93.93 57.59,94.34 58.5,94.89L59.07,93.95C58.06,93.34 56.96,92.89 55.82,92.6V92.6ZM42.95,97.93C42.34,98.94 41.89,100.04 41.6,101.18L42.67,101.45C42.93,100.41 43.34,99.41 43.89,98.5L42.95,97.93ZM42.36,104C42.36,103.47 42.4,102.93 42.48,102.41L41.39,102.24C41.22,103.41 41.22,104.59 41.39,105.76L42.48,105.59C42.4,105.07 42.36,104.53 42.36,104V104ZM59.07,114.05L58.5,113.11C57.59,113.66 56.59,114.07 55.56,114.33L55.82,115.4C56.96,115.11 58.06,114.66 59.07,114.05V114.05ZM63.64,104C63.64,104.53 63.6,105.07 63.52,105.59L64.61,105.76C64.78,104.59 64.78,103.41 64.61,102.24L63.52,102.41C63.6,102.93 63.64,103.47 63.64,104V104ZM64.4,106.82L63.33,106.55C63.07,107.59 62.66,108.59 62.11,109.5L63.05,110.07C63.66,109.06 64.11,107.96 64.4,106.82V106.82ZM54.59,114.52C53.54,114.68 52.46,114.68 51.41,114.52L51.24,115.61C52.41,115.79 53.59,115.79 54.76,115.61L54.59,114.52ZM61.56,110.31C60.93,111.17 60.17,111.93 59.31,112.56L59.96,113.45C60.91,112.75 61.75,111.92 62.45,110.97L61.56,110.31ZM59.31,95.44C60.17,96.07 60.93,96.83 61.56,97.69L62.45,97.03C61.75,96.08 60.92,95.25 59.97,94.55L59.31,95.44ZM44.44,97.69C45.07,96.83 45.83,96.07 46.69,95.44L46.03,94.55C45.08,95.25 44.25,96.08 43.55,97.03L44.44,97.69ZM63.05,97.93L62.11,98.5C62.66,99.41 63.07,100.4 63.33,101.44L64.4,101.18C64.11,100.04 63.66,98.94 63.05,97.93V97.93ZM51.41,93.48C52.46,93.32 53.54,93.32 54.59,93.48L54.76,92.39C53.59,92.22 52.41,92.22 51.24,92.39L51.41,93.48ZM45,113.74L42.73,114.27L43.26,112L42.19,111.75L41.66,114.02C41.61,114.2 41.62,114.39 41.67,114.57C41.72,114.75 41.82,114.92 41.95,115.05C42.08,115.18 42.25,115.28 42.43,115.33C42.61,115.38 42.8,115.39 42.98,115.34L45.25,114.82L45,113.74ZM42.42,110.77L43.49,111.02L43.85,109.44C43.32,108.54 42.92,107.57 42.67,106.55L41.6,106.82C41.84,107.79 42.21,108.73 42.69,109.61L42.42,110.77ZM47.55,113.15L45.98,113.52L46.23,114.59L47.39,114.32C48.27,114.8 49.2,115.16 50.18,115.4L50.44,114.33C49.43,114.08 48.46,113.68 47.56,113.14L47.55,113.15ZM53,94.46C51.3,94.46 49.62,94.92 48.16,95.79C46.69,96.65 45.48,97.9 44.66,99.39C43.83,100.88 43.42,102.57 43.47,104.27C43.52,105.97 44.02,107.63 44.93,109.07L44.01,112.99L47.92,112.07C49.18,112.86 50.59,113.35 52.07,113.49C53.54,113.64 55.02,113.44 56.4,112.91C57.79,112.39 59.03,111.55 60.03,110.46C61.03,109.37 61.76,108.06 62.17,106.64C62.58,105.22 62.66,103.72 62.39,102.27C62.12,100.82 61.52,99.44 60.63,98.26C59.74,97.08 58.59,96.12 57.26,95.46C55.94,94.8 54.48,94.46 53,94.46V94.46Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M53,44m-16,0a16,16 0,1 1,32 0a16,16 0,1 1,-32 0"
android:fillColor="#5C5E65"/>
<path
android:pathData="M53,164m-16,0a16,16 0,1 1,32 0a16,16 0,1 1,-32 0"
android:fillColor="#5C5E65"/>
<path
android:pathData="M85,44C85,42.34 86.34,41 88,41H164C165.66,41 167,42.34 167,44C167,45.66 165.66,47 164,47H88C86.34,47 85,45.66 85,44Z"
android:fillColor="#5C5E65"/>
<path
android:pathData="M85,104C85,102.34 86.34,101 88,101H164C165.66,101 167,102.34 167,104C167,105.66 165.66,107 164,107H88C86.34,107 85,105.66 85,104Z"
android:fillColor="#5C5E65"/>
<path
android:pathData="M85,164C85,162.34 86.34,161 88,161H164C165.66,161 167,162.34 167,164C167,165.66 165.66,167 164,167H88C86.34,167 85,165.66 85,164Z"
android:fillColor="#5C5E65"/>
<path
android:pathData="M161,213C161,211.34 162.34,210 164,210H218C219.66,210 221,211.34 221,213C221,214.66 219.66,216 218,216H164C162.34,216 161,214.66 161,213Z"
android:fillColor="#5C5E65"/>
<path
android:pathData="M85,213C85,211.34 86.34,210 88,210H142C143.66,210 145,211.34 145,213C145,214.66 143.66,216 142,216H88C86.34,216 85,214.66 85,213Z"
android:fillColor="#5C5E65"/>
<path
android:pathData="M19,73H239C249.49,73 258,81.51 258,92V116C258,126.49 249.49,135 239,135H19C8.51,135 0,126.49 0,116V92C0,81.51 8.51,73 19,73ZM19,76C10.16,76 3,83.16 3,92V116C3,124.84 10.16,132 19,132H239C247.84,132 255,124.84 255,116V92C255,83.16 247.84,76 239,76H19Z"
android:fillColor="#3A76F0"
android:fillType="evenOdd"/>
</vector>

Wyświetl plik

@ -0,0 +1,37 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="134dp"
android:height="112dp"
android:viewportWidth="134"
android:viewportHeight="112">
<group>
<clip-path
android:pathData="M0,0h134v112h-134z"/>
<path
android:pathData="M67,56m-56,0a56,56 0,1 1,112 0a56,56 0,1 1,-112 0"
android:fillColor="#1B1C1F"/>
<path
android:pathData="M67,56m-56,0a56,56 0,1 1,112 0a56,56 0,1 1,-112 0"
android:fillColor="#B6C5FA"
android:fillAlpha="0.08"/>
<path
android:pathData="M33.3,16.1L6.9,16C3.1,16 -0,19.1 -0,22.9L-0.1,89C-0.1,92.8 3,95.9 6.8,95.9L33.1,96C36.9,96 40,92.9 40,89.1L40.2,23C40.2,19.2 37.1,16.1 33.3,16.1ZM36.8,89.1C36.8,91.1 35.1,92.8 33.1,92.8L6.7,92.7C4.7,92.7 3,91 3,89L3.1,22.9C3.1,20.9 4.8,19.2 6.8,19.2L33.2,19.3C35.2,19.3 36.9,21 36.9,23L36.8,89.1Z"
android:fillColor="#5C5E65"/>
<path
android:pathData="M36.8,89.1C36.8,91.1 35.1,92.8 33.1,92.8L6.7,92.7C4.7,92.7 3,91 3,89L3.1,22.9C3.1,20.9 4.8,19.2 6.8,19.2L33.2,19.3C35.2,19.3 36.9,21 36.9,23L36.8,89.1Z"
android:fillColor="#1B1C1F"/>
<path
android:pathData="M25.63,43C22.11,43 19.25,45.91 19.25,49.49V53.64C18.93,53.64 18.58,53.64 18.2,53.64H14.07C11.95,53.64 10.89,53.64 10.07,54.06C9.36,54.43 8.78,55.02 8.41,55.75C8,56.57 8,57.66 8,59.82V61.81C8,63.98 8,65.06 8.41,65.89C8.78,66.62 9.36,67.21 10.07,67.58C10.89,68 11.95,68 14.07,68H18.2C20.32,68 21.39,68 22.2,67.58C22.91,67.21 23.49,66.62 23.86,65.89C24.27,65.06 24.27,63.98 24.27,61.81V59.82C24.27,57.66 24.27,56.57 23.86,55.75C23.49,55.02 22.91,54.43 22.2,54.06C22.04,53.98 21.88,53.91 21.69,53.86V49.49C21.69,47.28 23.46,45.49 25.63,45.49C27.8,45.49 29.56,47.28 29.56,49.49V51.43C29.56,52.11 30.11,52.67 30.78,52.67C31.45,52.67 32,52.11 32,51.43V49.49C32,45.91 29.15,43 25.63,43ZM17.08,61.09C17.57,60.77 17.9,60.21 17.9,59.57C17.9,58.58 17.11,57.78 16.14,57.78C15.16,57.78 14.37,58.58 14.37,59.57C14.37,60.21 14.7,60.77 15.19,61.09V63.03C15.19,63.56 15.61,63.99 16.14,63.99C16.66,63.99 17.08,63.56 17.08,63.03V61.09Z"
android:fillColor="#3A76F0"
android:fillType="evenOdd"/>
<path
android:pathData="M127.3,16.1L100.9,16C97.1,16 94,19.1 94,22.9L93.9,89C93.9,92.8 97,95.9 100.8,95.9L127.2,96C131,96 134.1,92.9 134.1,89.1L134.2,23C134.2,19.2 131.1,16.1 127.3,16.1ZM130.8,89.1C130.8,91.1 129.1,92.8 127.1,92.8L100.7,92.7C98.7,92.7 97,91 97,89L97.1,22.9C97.1,20.9 98.8,19.2 100.8,19.2L127.2,19.3C129.2,19.3 130.9,21 130.9,23L130.8,89.1Z"
android:fillColor="#5C5E65"/>
<path
android:pathData="M130.8,89.1C130.8,91.1 129.1,92.8 127.1,92.8L100.7,92.7C98.7,92.7 97,91 97,89L97.1,22.9C97.1,20.9 98.8,19.2 100.8,19.2L127.2,19.3C129.2,19.3 130.9,21 130.9,23L130.8,89.1Z"
android:fillColor="#1B1C1F"/>
<path
android:pathData="M79.34,48.93L85.71,55.29C86.1,55.68 86.1,56.32 85.71,56.71L79.34,63.07C78.95,63.46 78.32,63.46 77.93,63.07C77.54,62.68 77.54,62.05 77.93,61.66L82.59,57L50,57C49.45,57 49,56.55 49,56C49,55.45 49.45,55 50,55L82.59,55L77.93,50.34C77.54,49.95 77.54,49.32 77.93,48.93C78.32,48.54 78.95,48.54 79.34,48.93Z"
android:fillColor="#3A76F0"
android:fillType="evenOdd"/>
</group>
</vector>

Wyświetl plik

@ -0,0 +1,25 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="134dp"
android:height="112dp"
android:viewportWidth="134"
android:viewportHeight="112">
<path
android:pathData="M67,56m-56,0a56,56 0,1 1,112 0a56,56 0,1 1,-112 0"
android:fillColor="#1B1C1F"/>
<path
android:pathData="M67,56m-56,0a56,56 0,1 1,112 0a56,56 0,1 1,-112 0"
android:fillColor="#B6C5FA"
android:fillAlpha="0.08"/>
<path
android:pathData="M15,32C8.37,32 3,37.37 3,44V68C3,74.63 8.37,80 15,80H19V93.17C19,94.95 21.15,95.85 22.41,94.59L37,80H119C125.63,80 131,74.63 131,68V44C131,37.37 125.63,32 119,32H15Z"
android:fillColor="#1B1C1F"
android:fillType="evenOdd"/>
<path
android:pathData="M0,44C0,35.72 6.72,29 15,29H119C127.28,29 134,35.72 134,44V68C134,76.28 127.28,83 119,83H38.24L24.54,96.71C21.39,99.86 16,97.63 16,93.17V83H15C6.72,83 0,76.28 0,68V44ZM15,80C8.37,80 3,74.63 3,68V44C3,37.37 8.37,32 15,32H119C125.63,32 131,37.37 131,44V68C131,74.63 125.63,80 119,80H37L22.41,94.59C21.15,95.85 19,94.95 19,93.17V80H15Z"
android:fillColor="#5C5E65"
android:fillType="evenOdd"/>
<path
android:pathData="M74.63,43C71.11,43 68.25,45.91 68.25,49.49V53.64C67.93,53.64 67.58,53.64 67.2,53.64H63.07C60.95,53.64 59.89,53.64 59.07,54.06C58.36,54.43 57.78,55.02 57.41,55.75C57,56.57 57,57.66 57,59.82V61.81C57,63.98 57,65.06 57.41,65.89C57.78,66.62 58.36,67.21 59.07,67.58C59.89,68 60.95,68 63.07,68H67.2C69.32,68 70.39,68 71.2,67.58C71.91,67.21 72.49,66.62 72.86,65.89C73.27,65.06 73.27,63.98 73.27,61.81V59.82C73.27,57.66 73.27,56.57 72.86,55.75C72.49,55.02 71.91,54.43 71.2,54.06C71.04,53.98 70.88,53.91 70.69,53.86V49.49C70.69,47.28 72.46,45.49 74.63,45.49C76.8,45.49 78.56,47.28 78.56,49.49V51.43C78.56,52.11 79.11,52.67 79.78,52.67C80.45,52.67 81,52.11 81,51.43V49.49C81,45.91 78.15,43 74.63,43ZM66.08,61.09C66.57,60.77 66.9,60.21 66.9,59.57C66.9,58.58 66.11,57.78 65.14,57.78C64.16,57.78 63.37,58.58 63.37,59.57C63.37,60.21 63.7,60.77 64.19,61.09V63.03C64.19,63.56 64.61,63.99 65.14,63.99C65.66,63.99 66.08,63.56 66.08,63.03V61.09Z"
android:fillColor="#3A76F0"
android:fillType="evenOdd"/>
</vector>

Wyświetl plik

@ -0,0 +1,46 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:width="258dp"
android:height="240dp"
android:viewportWidth="258"
android:viewportHeight="240"
tools:ignore="VectorRaster">
<path
android:pathData="M9,40C9,17.91 26.91,0 49,0H209C231.09,0 249,17.91 249,40V200C249,222.09 231.09,240 209,240H49C26.91,240 9,222.09 9,200V40Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M209,6H49C30.22,6 15,21.22 15,40V200C15,218.78 30.22,234 49,234H209C227.78,234 243,218.78 243,200V40C243,21.22 227.78,6 209,6ZM49,0C26.91,0 9,17.91 9,40V200C9,222.09 26.91,240 49,240H209C231.09,240 249,222.09 249,200V40C249,17.91 231.09,0 209,0H49Z"
android:fillColor="#D6D9DF"
android:fillType="evenOdd"/>
<path
android:pathData="M53,104m-18,0a18,18 0,1 1,36 0a18,18 0,1 1,-36 0"
android:fillColor="#3A76F0"/>
<path
android:pathData="M50.18,92.6L50.45,93.67C49.41,93.93 48.41,94.34 47.5,94.89L46.93,93.95C47.94,93.34 49.04,92.89 50.18,92.6ZM55.82,92.6L55.55,93.67C56.59,93.93 57.59,94.34 58.5,94.89L59.07,93.95C58.06,93.34 56.96,92.89 55.82,92.6ZM42.95,97.93C42.34,98.94 41.89,100.04 41.6,101.18L42.67,101.45C42.93,100.41 43.34,99.41 43.89,98.5L42.95,97.93ZM42.36,104C42.36,103.47 42.4,102.93 42.48,102.41L41.39,102.24C41.22,103.41 41.22,104.59 41.39,105.76L42.48,105.59C42.4,105.07 42.36,104.53 42.36,104ZM59.07,114.05L58.5,113.11C57.59,113.66 56.59,114.07 55.56,114.33L55.82,115.4C56.96,115.11 58.06,114.66 59.07,114.05ZM63.64,104C63.64,104.53 63.6,105.07 63.52,105.59L64.61,105.76C64.78,104.59 64.78,103.41 64.61,102.24L63.52,102.41C63.6,102.93 63.64,103.47 63.64,104ZM64.4,106.82L63.33,106.55C63.07,107.59 62.66,108.59 62.11,109.5L63.05,110.07C63.66,109.06 64.11,107.96 64.4,106.82ZM54.59,114.52C53.54,114.68 52.46,114.68 51.41,114.52L51.24,115.61C52.41,115.79 53.59,115.79 54.76,115.61L54.59,114.52ZM61.56,110.31C60.93,111.17 60.17,111.93 59.31,112.56L59.96,113.45C60.91,112.75 61.75,111.92 62.45,110.97L61.56,110.31ZM59.31,95.44C60.17,96.07 60.93,96.83 61.56,97.69L62.45,97.03C61.75,96.08 60.92,95.25 59.97,94.55L59.31,95.44ZM44.44,97.69C45.07,96.83 45.83,96.07 46.69,95.44L46.03,94.55C45.08,95.25 44.25,96.08 43.55,97.03L44.44,97.69ZM63.05,97.93L62.11,98.5C62.66,99.41 63.07,100.4 63.33,101.44L64.4,101.18C64.11,100.04 63.66,98.94 63.05,97.93ZM51.41,93.48C52.46,93.32 53.54,93.32 54.59,93.48L54.76,92.39C53.59,92.22 52.41,92.22 51.24,92.39L51.41,93.48ZM45,113.74L42.73,114.27L43.26,112L42.19,111.75L41.66,114.02C41.61,114.2 41.62,114.39 41.67,114.57C41.72,114.75 41.82,114.92 41.95,115.05C42.08,115.18 42.25,115.28 42.43,115.33C42.61,115.38 42.8,115.39 42.98,115.34L45.25,114.82L45,113.74ZM42.42,110.77L43.49,111.02L43.85,109.44C43.32,108.54 42.92,107.57 42.67,106.55L41.6,106.82C41.84,107.79 42.21,108.73 42.69,109.61L42.42,110.77ZM47.55,113.15L45.98,113.52L46.23,114.59L47.39,114.32C48.26,114.8 49.2,115.16 50.18,115.4L50.44,114.33C49.43,114.08 48.46,113.68 47.56,113.14L47.55,113.15ZM53,94.46C51.3,94.46 49.62,94.92 48.16,95.79C46.69,96.65 45.48,97.9 44.66,99.39C43.83,100.88 43.42,102.57 43.47,104.27C43.52,105.97 44.02,107.63 44.93,109.07L44.01,112.99L47.92,112.07C49.18,112.86 50.59,113.35 52.06,113.49C53.54,113.64 55.02,113.44 56.4,112.91C57.79,112.39 59.03,111.55 60.03,110.46C61.03,109.37 61.76,108.06 62.17,106.64C62.58,105.22 62.66,103.72 62.39,102.27C62.12,100.82 61.52,99.44 60.63,98.26C59.74,97.08 58.58,96.12 57.26,95.46C55.94,94.8 54.48,94.46 53,94.46Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M53,44m-16,0a16,16 0,1 1,32 0a16,16 0,1 1,-32 0"
android:fillColor="#D6D9DF"/>
<path
android:pathData="M53,164m-16,0a16,16 0,1 1,32 0a16,16 0,1 1,-32 0"
android:fillColor="#D6D9DF"/>
<path
android:pathData="M85,44C85,42.34 86.34,41 88,41H164C165.66,41 167,42.34 167,44C167,45.66 165.66,47 164,47H88C86.34,47 85,45.66 85,44Z"
android:fillColor="#D6D9DF"/>
<path
android:pathData="M85,104C85,102.34 86.34,101 88,101H164C165.66,101 167,102.34 167,104C167,105.66 165.66,107 164,107H88C86.34,107 85,105.66 85,104Z"
android:fillColor="#D6D9DF"/>
<path
android:pathData="M85,164C85,162.34 86.34,161 88,161H164C165.66,161 167,162.34 167,164C167,165.66 165.66,167 164,167H88C86.34,167 85,165.66 85,164Z"
android:fillColor="#D6D9DF"/>
<path
android:pathData="M161,213C161,211.34 162.34,210 164,210H218C219.66,210 221,211.34 221,213C221,214.66 219.66,216 218,216H164C162.34,216 161,214.66 161,213Z"
android:fillColor="#D6D9DF"/>
<path
android:pathData="M85,213C85,211.34 86.34,210 88,210H142C143.66,210 145,211.34 145,213C145,214.66 143.66,216 142,216H88C86.34,216 85,214.66 85,213Z"
android:fillColor="#D6D9DF"/>
<path
android:pathData="M19,73H239C249.49,73 258,81.51 258,92V116C258,126.49 249.49,135 239,135H19C8.51,135 0,126.49 0,116V92C0,81.51 8.51,73 19,73ZM19,76C10.16,76 3,83.16 3,92V116C3,124.84 10.16,132 19,132H239C247.84,132 255,124.84 255,116V92C255,83.16 247.84,76 239,76H19Z"
android:fillColor="#3A76F0"
android:fillType="evenOdd"/>
</vector>

Wyświetl plik

@ -0,0 +1,37 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="134dp"
android:height="112dp"
android:viewportWidth="134"
android:viewportHeight="112">
<group>
<clip-path
android:pathData="M0,0h134v112h-134z"/>
<path
android:pathData="M67,56m-56,0a56,56 0,1 1,112 0a56,56 0,1 1,-112 0"
android:fillColor="#FBFCFE"/>
<path
android:pathData="M67,56m-56,0a56,56 0,1 1,112 0a56,56 0,1 1,-112 0"
android:fillColor="#50679F"
android:fillAlpha="0.08"/>
<path
android:pathData="M33.3,16.1L6.9,16C3.1,16 -0,19.1 -0,22.9L-0.1,89C-0.1,92.8 3,95.9 6.8,95.9L33.1,96C36.9,96 40,92.9 40,89.1L40.2,23C40.2,19.2 37.1,16.1 33.3,16.1ZM36.8,89.1C36.8,91.1 35.1,92.8 33.1,92.8L6.7,92.7C4.7,92.7 3,91 3,89L3.1,22.9C3.1,20.9 4.8,19.2 6.8,19.2L33.2,19.3C35.2,19.3 36.9,21 36.9,23L36.8,89.1Z"
android:fillColor="#D6D9DF"/>
<path
android:pathData="M36.8,89.1C36.8,91.1 35.1,92.8 33.1,92.8L6.7,92.7C4.7,92.7 3,91 3,89L3.1,22.9C3.1,20.9 4.8,19.2 6.8,19.2L33.2,19.3C35.2,19.3 36.9,21 36.9,23L36.8,89.1Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M25.63,43C22.11,43 19.25,45.91 19.25,49.49V53.64C18.93,53.64 18.58,53.64 18.2,53.64H14.07C11.95,53.64 10.89,53.64 10.07,54.06C9.36,54.43 8.78,55.02 8.41,55.75C8,56.57 8,57.66 8,59.82V61.81C8,63.98 8,65.06 8.41,65.89C8.78,66.62 9.36,67.21 10.07,67.58C10.89,68 11.95,68 14.07,68H18.2C20.32,68 21.39,68 22.2,67.58C22.91,67.21 23.49,66.62 23.86,65.89C24.27,65.06 24.27,63.98 24.27,61.81V59.82C24.27,57.66 24.27,56.57 23.86,55.75C23.49,55.02 22.91,54.43 22.2,54.06C22.04,53.98 21.88,53.91 21.69,53.86V49.49C21.69,47.28 23.46,45.49 25.63,45.49C27.8,45.49 29.56,47.28 29.56,49.49V51.43C29.56,52.11 30.11,52.67 30.78,52.67C31.45,52.67 32,52.11 32,51.43V49.49C32,45.91 29.15,43 25.63,43ZM17.08,61.09C17.57,60.77 17.9,60.21 17.9,59.57C17.9,58.58 17.11,57.78 16.14,57.78C15.16,57.78 14.37,58.58 14.37,59.57C14.37,60.21 14.7,60.77 15.19,61.09V63.03C15.19,63.56 15.61,63.99 16.14,63.99C16.66,63.99 17.08,63.56 17.08,63.03V61.09Z"
android:fillColor="#3A76F0"
android:fillType="evenOdd"/>
<path
android:pathData="M127.3,16.1L100.9,16C97.1,16 94,19.1 94,22.9L93.9,89C93.9,92.8 97,95.9 100.8,95.9L127.2,96C131,96 134.1,92.9 134.1,89.1L134.2,23C134.2,19.2 131.1,16.1 127.3,16.1ZM130.8,89.1C130.8,91.1 129.1,92.8 127.1,92.8L100.7,92.7C98.7,92.7 97,91 97,89L97.1,22.9C97.1,20.9 98.8,19.2 100.8,19.2L127.2,19.3C129.2,19.3 130.9,21 130.9,23L130.8,89.1Z"
android:fillColor="#D6D9DF"/>
<path
android:pathData="M130.8,89.1C130.8,91.1 129.1,92.8 127.1,92.8L100.7,92.7C98.7,92.7 97,91 97,89L97.1,22.9C97.1,20.9 98.8,19.2 100.8,19.2L127.2,19.3C129.2,19.3 130.9,21 130.9,23L130.8,89.1Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M79.34,48.93L85.71,55.29C86.1,55.68 86.1,56.32 85.71,56.71L79.34,63.07C78.95,63.46 78.32,63.46 77.93,63.07C77.54,62.68 77.54,62.05 77.93,61.66L82.59,57L50,57C49.45,57 49,56.55 49,56C49,55.45 49.45,55 50,55L82.59,55L77.93,50.34C77.54,49.95 77.54,49.32 77.93,48.93C78.32,48.54 78.95,48.54 79.34,48.93Z"
android:fillColor="#3A76F0"
android:fillType="evenOdd"/>
</group>
</vector>

Wyświetl plik

@ -0,0 +1,25 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="134dp"
android:height="112dp"
android:viewportWidth="134"
android:viewportHeight="112">
<path
android:pathData="M67,56m-56,0a56,56 0,1 1,112 0a56,56 0,1 1,-112 0"
android:fillColor="#FBFCFE"/>
<path
android:pathData="M67,56m-56,0a56,56 0,1 1,112 0a56,56 0,1 1,-112 0"
android:fillColor="#50679F"
android:fillAlpha="0.08"/>
<path
android:pathData="M15,32C8.37,32 3,37.37 3,44V68C3,74.63 8.37,80 15,80H19V93.17C19,94.95 21.15,95.85 22.41,94.59L37,80H119C125.63,80 131,74.63 131,68V44C131,37.37 125.63,32 119,32H15Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
<path
android:pathData="M0,44C0,35.72 6.72,29 15,29H119C127.28,29 134,35.72 134,44V68C134,76.28 127.28,83 119,83H38.24L24.54,96.71C21.39,99.86 16,97.63 16,93.17V83H15C6.72,83 0,76.28 0,68V44ZM15,80C8.37,80 3,74.63 3,68V44C3,37.37 8.37,32 15,32H119C125.63,32 131,37.37 131,44V68C131,74.63 125.63,80 119,80H37L22.41,94.59C21.15,95.85 19,94.95 19,93.17V80H15Z"
android:fillColor="#D6D9DF"
android:fillType="evenOdd"/>
<path
android:pathData="M74.63,43C71.11,43 68.25,45.91 68.25,49.49V53.64C67.93,53.64 67.58,53.64 67.2,53.64H63.07C60.95,53.64 59.89,53.64 59.07,54.06C58.36,54.43 57.78,55.02 57.41,55.75C57,56.57 57,57.66 57,59.82V61.81C57,63.98 57,65.06 57.41,65.89C57.78,66.62 58.36,67.21 59.07,67.58C59.89,68 60.95,68 63.07,68H67.2C69.32,68 70.39,68 71.2,67.58C71.91,67.21 72.49,66.62 72.86,65.89C73.27,65.06 73.27,63.98 73.27,61.81V59.82C73.27,57.66 73.27,56.57 72.86,55.75C72.49,55.02 71.91,54.43 71.2,54.06C71.04,53.98 70.88,53.91 70.69,53.86V49.49C70.69,47.28 72.46,45.49 74.63,45.49C76.8,45.49 78.56,47.28 78.56,49.49V51.43C78.56,52.11 79.11,52.67 79.78,52.67C80.45,52.67 81,52.11 81,51.43V49.49C81,45.91 78.15,43 74.63,43ZM66.08,61.09C66.57,60.77 66.9,60.21 66.9,59.57C66.9,58.58 66.11,57.78 65.14,57.78C64.16,57.78 63.37,58.58 63.37,59.57C63.37,60.21 63.7,60.77 64.19,61.09V63.03C64.19,63.56 64.61,63.99 65.14,63.99C65.66,63.99 66.08,63.56 66.08,63.03V61.09Z"
android:fillColor="#3A76F0"
android:fillType="evenOdd"/>
</vector>

Wyświetl plik

@ -1,57 +1,259 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<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:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:fillViewport="true">
<ImageView
android:id="@+id/hero"
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="84dp"
android:importantForAccessibility="no"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
android:layout_height="wrap_content">
<TextView
android:id="@+id/headline"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="32dp"
android:layout_marginTop="40dp"
android:gravity="center"
android:text="@string/ChooseANewDefaultSmsAppFragment__choose_a_new"
android:textAppearance="@style/Signal.Text.HeadlineLarge"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/hero" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/hero"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="84dp"
android:importantForAccessibility="no"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/export_sms" />
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="32dp"
android:layout_marginTop="24dp"
android:gravity="center"
android:textAppearance="@style/Signal.Text.BodyLarge"
android:textColor="@color/signal_colorOnSurfaceVariant"
app:layout_constraintTop_toBottomOf="@id/headline"
tools:text="An explanation about choosing a new default sms app. This will remove SMS conversations from Signal." />
<TextView
android:id="@+id/headline"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="32dp"
android:layout_marginTop="40dp"
android:gravity="center"
android:text="@string/ChooseANewDefaultSmsAppFragment__choose_a_new"
android:textAppearance="@style/Signal.Text.HeadlineLarge"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/hero" />
<com.google.android.material.button.MaterialButton
android:id="@+id/continue_button"
style="@style/Signal.Widget.Button.Large.Tonal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="44dp"
android:minWidth="221dp"
android:text="@string/ChooseANewDefaultSmsAppFragment__continue"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/description"
app:layout_constraintVertical_bias="1" />
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@drawable/circle_tintable"
android:backgroundTint="@color/signal_colorSurface3"
app:layout_constraintBottom_toBottomOf="@+id/bullet_1"
app:layout_constraintEnd_toEndOf="@+id/bullet_1"
app:layout_constraintStart_toStartOf="@+id/bullet_1"
app:layout_constraintTop_toTopOf="@+id/bullet_1" />
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/bullet_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="24dp"
android:gravity="center"
android:minWidth="28dp"
android:minHeight="28dp"
android:padding="4dp"
android:text="@string/ChooseANewDefaultSmsAppFragment__bullet_1"
android:textAppearance="@style/Signal.Text.BodyMedium"
android:textStyle="bold"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/headline" />
<TextView
android:id="@+id/bullet_1_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="32dp"
android:minWidth="28dp"
android:minHeight="28dp"
android:padding="4dp"
android:text="@string/ChooseANewDefaultSmsAppFragment__tap_continue_to_open_the_defaults_apps_screen_in_settings"
android:textAlignment="viewStart"
android:textAppearance="@style/Signal.Text.BodyLarge"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/bullet_1"
app:layout_constraintTop_toBottomOf="@id/headline" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/bullet_1_barrier"
android:layout_width="match_parent"
android:layout_height="1dp"
android:orientation="horizontal"
app:barrierDirection="bottom"
app:constraint_referenced_ids="bullet_1,bullet_1_text" />
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@drawable/circle_tintable"
android:backgroundTint="@color/signal_colorSurface3"
app:layout_constraintBottom_toBottomOf="@+id/bullet_2"
app:layout_constraintEnd_toEndOf="@+id/bullet_2"
app:layout_constraintStart_toStartOf="@+id/bullet_2"
app:layout_constraintTop_toTopOf="@+id/bullet_2" />
<TextView
android:id="@+id/bullet_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="24dp"
android:gravity="center"
android:minWidth="28dp"
android:minHeight="28dp"
android:padding="4dp"
android:text="@string/ChooseANewDefaultSmsAppFragment__bullet_2"
android:textAppearance="@style/Signal.Text.BodyMedium"
android:textStyle="bold"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bullet_1_barrier" />
<TextView
android:id="@+id/bullet_2_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="32dp"
android:minWidth="28dp"
android:minHeight="28dp"
android:padding="4dp"
android:text="@string/ChooseANewDefaultSmsAppFragment__select_sms_app_from_the_list"
android:textAlignment="viewStart"
android:textAppearance="@style/Signal.Text.BodyLarge"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/bullet_2"
app:layout_constraintTop_toBottomOf="@id/bullet_1_barrier" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/bullet_2_barrier"
android:layout_width="match_parent"
android:layout_height="1dp"
android:orientation="horizontal"
app:barrierDirection="bottom"
app:constraint_referenced_ids="bullet_2,bullet_2_text" />
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@drawable/circle_tintable"
android:backgroundTint="@color/signal_colorSurface3"
app:layout_constraintBottom_toBottomOf="@+id/bullet_3"
app:layout_constraintEnd_toEndOf="@+id/bullet_3"
app:layout_constraintStart_toStartOf="@+id/bullet_3"
app:layout_constraintTop_toTopOf="@+id/bullet_3" />
<TextView
android:id="@+id/bullet_3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="24dp"
android:gravity="center"
android:minWidth="28dp"
android:minHeight="28dp"
android:padding="4dp"
android:text="@string/ChooseANewDefaultSmsAppFragment__bullet_3"
android:textAppearance="@style/Signal.Text.BodyMedium"
android:textStyle="bold"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bullet_2_barrier" />
<TextView
android:id="@+id/bullet_3_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="32dp"
android:minWidth="28dp"
android:minHeight="28dp"
android:padding="4dp"
android:text="@string/ChooseANewDefaultSmsAppFragment__choose_another_app_to_use_for_sms_messaging"
android:textAlignment="viewStart"
android:textAppearance="@style/Signal.Text.BodyLarge"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/bullet_3"
app:layout_constraintTop_toBottomOf="@id/bullet_2_barrier" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/bullet_3_barrier"
android:layout_width="match_parent"
android:layout_height="1dp"
android:orientation="horizontal"
app:barrierDirection="bottom"
app:constraint_referenced_ids="bullet_3,bullet_3_text" />
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@drawable/circle_tintable"
android:backgroundTint="@color/signal_colorSurface3"
app:layout_constraintBottom_toBottomOf="@+id/bullet_4"
app:layout_constraintEnd_toEndOf="@+id/bullet_4"
app:layout_constraintStart_toStartOf="@+id/bullet_4"
app:layout_constraintTop_toTopOf="@+id/bullet_4" />
<TextView
android:id="@+id/bullet_4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="24dp"
android:gravity="center"
android:minWidth="28dp"
android:minHeight="28dp"
android:padding="4dp"
android:text="@string/ChooseANewDefaultSmsAppFragment__bullet_4"
android:textAppearance="@style/Signal.Text.BodyMedium"
android:textStyle="bold"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bullet_3_barrier" />
<TextView
android:id="@+id/bullet_4_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="32dp"
android:minWidth="28dp"
android:minHeight="28dp"
android:padding="4dp"
android:text="@string/ChooseANewDefaultSmsAppFragment__return_to_signal"
android:textAlignment="viewStart"
android:textAppearance="@style/Signal.Text.BodyLarge"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/bullet_4"
app:layout_constraintTop_toBottomOf="@id/bullet_3_barrier" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/bullet_4_barrier"
android:layout_width="match_parent"
android:layout_height="1dp"
android:orientation="horizontal"
app:barrierDirection="bottom"
app:constraint_referenced_ids="bullet_4,bullet_4_text" />
<com.google.android.material.button.MaterialButton
android:id="@+id/continue_button"
style="@style/Signal.Widget.Button.Large.Tonal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="44dp"
android:minWidth="221dp"
android:text="@string/ChooseANewDefaultSmsAppFragment__continue"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bullet_4_barrier"
app:layout_constraintVertical_bias="1" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

Wyświetl plik

@ -13,14 +13,14 @@
app:layout_constraintTop_toTopOf="parent"
app:navigationIcon="@drawable/ic_arrow_left_24" />
<!-- TODO [alex] - Image -->
<ImageView
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:importantForAccessibility="no"
android:scaleType="centerInside"
app:srcCompat="@drawable/sms_message"
app:layout_constraintTop_toBottomOf="@id/toolbar" />
<TextView
@ -41,7 +41,7 @@
android:layout_marginHorizontal="32dp"
android:layout_marginTop="24dp"
android:gravity="center"
tools:text="WIP Placeholder text"
android:text="@string/ExportYourSmsMessagesFragment__you_can_export_your_sms_messages_to_your_phones_sms_database"
android:textColor="@color/signal_colorOnSurfaceVariant"
android:textAppearance="@style/Signal.Text.BodyLarge"
app:layout_constraintTop_toBottomOf="@id/headline" />

Wyświetl plik

@ -26,7 +26,7 @@
android:layout_marginHorizontal="32dp"
android:layout_marginTop="24dp"
android:gravity="center"
tools:text="Please don't close the app..."
tools:text="[WIP]"
android:textAppearance="@style/Signal.Text.BodyLarge"
android:textColor="@color/signal_colorOnSurfaceVariant"
app:layout_constraintEnd_toEndOf="parent"

Wyświetl plik

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent">
@ -13,8 +12,7 @@
app:layout_constraintTop_toTopOf="parent"
app:navigationIcon="@drawable/ic_arrow_left_24" />
<!-- TODO [alex] - Image -->
<ImageView
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -23,7 +21,8 @@
android:scaleType="centerInside"
app:layout_constraintBottom_toTopOf="@id/continue_button"
app:layout_constraintTop_toBottomOf="@id/description"
app:layout_constraintVertical_bias="0" />
app:layout_constraintVertical_bias="0"
app:srcCompat="@drawable/choose_signal" />
<TextView
android:id="@+id/headline"
@ -31,7 +30,7 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="32dp"
android:gravity="center"
android:text="@string/SetSignalAsDefaultSmsAppFragment__first_set_signal_as_the_default_sms_app"
android:text="@string/SetSignalAsDefaultSmsAppFragment__set_signal_as_the_default_sms_app"
android:textAppearance="@style/Signal.Text.HeadlineLarge"
app:layout_constraintTop_toBottomOf="@id/toolbar" />
@ -42,10 +41,10 @@
android:layout_marginHorizontal="32dp"
android:layout_marginTop="24dp"
android:gravity="center"
android:text="@string/SetSignalAsDefaultSmsAppFragment__to_export_your_sms_messages"
android:textAppearance="@style/Signal.Text.BodyLarge"
android:textColor="@color/signal_colorOnSurfaceVariant"
app:layout_constraintTop_toBottomOf="@id/headline"
tools:text="WIP Placeholder text" />
app:layout_constraintTop_toBottomOf="@id/headline" />
<com.google.android.material.button.MaterialButton
android:id="@+id/continue_button"

Wyświetl plik

@ -3948,7 +3948,9 @@
<!-- Preference title to delete sms -->
<string name="SmsSettingsFragment__remove_sms_messages">Remove SMS messages</string>
<!-- Snackbar text to confirm deletion -->
<string name="SmsSettingsFragment__sms_messages_removed">SMS messages removed</string>
<string name="SmsSettingsFragment__removing_sms_messages_from_signal">Removing SMS messages from Signal…</string>
<!-- Snackbar text to indicate can delete later -->
<string name="SmsSettingsFragment__you_can_remove_sms_messages_from_signal_in_settings">You can remove SMS messages from Signal in Settings at any time.</string>
<!-- NotificationsSettingsFragment -->
<string name="NotificationsSettingsFragment__messages">Messages</string>
@ -5231,6 +5233,8 @@
<!-- ExportYourSmsMessagesFragment -->
<!-- Title of the screen -->
<string name="ExportYourSmsMessagesFragment__export_your_sms_messages">Export your SMS messages</string>
<!-- Message of the screen -->
<string name="ExportYourSmsMessagesFragment__you_can_export_your_sms_messages_to_your_phones_sms_database">You can export your SMS messages to your phone\'s SMS database. This allows other SMS apps on your phone to access and import them. This does not create a shareable file of your SMS message history.</string>
<!-- Button label to begin export -->
<string name="ExportYourSmsMessagesFragment__continue">Continue</string>
@ -5245,6 +5249,28 @@
<string name="ChooseANewDefaultSmsAppFragment__choose_a_new">Choose a new default SMS app</string>
<!-- Button label to launch picker -->
<string name="ChooseANewDefaultSmsAppFragment__continue">Continue</string>
<!-- Button label for when done with changing default SMS app -->
<string name="ChooseANewDefaultSmsAppFragment__done">Done</string>
<!-- First step number/bullet for choose new default sms app instructions -->
<string name="ChooseANewDefaultSmsAppFragment__bullet_1">1</string>
<!-- Second step number/bullet for choose new default sms app instructions -->
<string name="ChooseANewDefaultSmsAppFragment__bullet_2">2</string>
<!-- Third step number/bullet for choose new default sms app instructions -->
<string name="ChooseANewDefaultSmsAppFragment__bullet_3">3</string>
<!-- Fourth step number/bullet for choose new default sms app instructions -->
<string name="ChooseANewDefaultSmsAppFragment__bullet_4">4</string>
<!-- Instruction step for choosing a new default sms app -->
<string name="ChooseANewDefaultSmsAppFragment__tap_continue_to_open_the_defaults_apps_screen_in_settings">Tap \"Continue\" to open the \"Default apps\" screen in Settings</string>
<!-- Instruction step for choosing a new default sms app -->
<string name="ChooseANewDefaultSmsAppFragment__select_sms_app_from_the_list">Select \"SMS app\" from the list</string>
<!-- Instruction step for choosing a new default sms app -->
<string name="ChooseANewDefaultSmsAppFragment__choose_another_app_to_use_for_sms_messaging">Choose another app to use for SMS messaging</string>
<!-- Instruction step for choosing a new default sms app -->
<string name="ChooseANewDefaultSmsAppFragment__return_to_signal">Return to Signal</string>
<!-- Instruction step for choosing a new default sms app -->
<string name="ChooseANewDefaultSmsAppFragment__open_your_phones_settings_app">Open your phone\'s Settings app</string>
<!-- Instruction step for choosing a new default sms app -->
<string name="ChooseANewDefaultSmsAppFragment__navigate_to_apps_default_apps_sms_app">Navigate to \"Apps\" > \"Default apps\" > \"SMS app\"</string>
<!-- RemoveSmsMessagesDialogFragment -->
<!-- Action button to keep messages -->
@ -5254,11 +5280,13 @@
<!-- Title of dialog -->
<string name="RemoveSmsMessagesDialogFragment__remove_sms_messages">Remove SMS messages from Signal?</string>
<!-- Message of dialog -->
<string name="RemoveSmsMessagesDialogFragment__you_have_changed">You have changed the default SMS app, do you want to remove SMS messages from Signal?</string>
<string name="RemoveSmsMessagesDialogFragment__you_can_now_remove_sms_messages_from_signal">You can now remove SMS messages from Signal to clear up storage space. They will still be available to other SMS apps on your phone even if you remove them.</string>
<!-- SetSignalAsDefaultSmsAppFragment -->
<!-- Title of the screen -->
<string name="SetSignalAsDefaultSmsAppFragment__first_set_signal_as_the_default_sms_app">First, set Signal as the default SMS app</string>
<string name="SetSignalAsDefaultSmsAppFragment__set_signal_as_the_default_sms_app">Set Signal as the default SMS app</string>
<!-- Message of the screen -->
<string name="SetSignalAsDefaultSmsAppFragment__to_export_your_sms_messages">To export your SMS messages, you need to set Signal as the default SMS app.</string>
<!-- Button label to start export -->
<string name="SetSignalAsDefaultSmsAppFragment__next">Next</string>

Wyświetl plik

@ -124,7 +124,7 @@ class TestSmsExportService : SmsExportService() {
return message
}
private fun getMmsMessage(it: Int): ExportableMessage.Mms {
private fun getMmsMessage(it: Int): ExportableMessage.Mms<*> {
val me = "+15065550101"
val addresses = setOf(me, "+15065550102", "+15065550121")
val address = addresses.random()
@ -144,7 +144,7 @@ class TestSmsExportService : SmsExportService() {
)
}
private fun getSmsMessage(it: Int): ExportableMessage.Sms {
private fun getSmsMessage(it: Int): ExportableMessage.Sms<*> {
return ExportableMessage.Sms(
id = it.toString(),
exportState = SmsExportState(),

Wyświetl plik

@ -16,8 +16,8 @@ sealed interface ExportableMessage {
/**
* An exportable SMS message
*/
data class Sms(
val id: String,
data class Sms<out ID : Any>(
val id: ID,
override val exportState: SmsExportState,
val address: String,
val dateReceived: Duration,
@ -30,8 +30,8 @@ sealed interface ExportableMessage {
/**
* An exportable MMS message
*/
data class Mms(
val id: String,
data class Mms<out ID : Any>(
val id: ID,
override val exportState: SmsExportState,
val addresses: Set<String>,
val dateReceived: Duration,

Wyświetl plik

@ -65,12 +65,14 @@ abstract class SmsExportService : Service() {
val exportState = message.exportState
if (exportState.progress != SmsExportState.Progress.COMPLETED) {
when (message) {
is ExportableMessage.Sms -> exportSms(exportState, message)
is ExportableMessage.Mms -> exportMms(exportState, message)
is ExportableMessage.Sms<*> -> exportSms(exportState, message)
is ExportableMessage.Mms<*> -> exportMms(exportState, message)
}
progress++
updateNotification(progress, totalCount)
if (progress == 1 || progress.mod(100) == 0) {
updateNotification(progress, totalCount)
}
progressState.onNext(SmsExportProgress.InProgress(progress, totalCount))
}
}
@ -177,7 +179,7 @@ abstract class SmsExportService : Service() {
startForeground(exportNotification.id, exportNotification.notification)
}
private fun exportSms(smsExportState: SmsExportState, sms: ExportableMessage.Sms) {
private fun exportSms(smsExportState: SmsExportState, sms: ExportableMessage.Sms<*>) {
onMessageExportStarted(sms)
val mayAlreadyExist = smsExportState.progress == SmsExportState.Progress.STARTED
ExportSmsMessagesUseCase.execute(this, sms, mayAlreadyExist).either(onSuccess = {
@ -187,7 +189,7 @@ abstract class SmsExportService : Service() {
})
}
private fun exportMms(smsExportState: SmsExportState, mms: ExportableMessage.Mms) {
private fun exportMms(smsExportState: SmsExportState, mms: ExportableMessage.Mms<*>) {
onMessageExportStarted(mms)
val threadIdOutput: GetOrCreateMmsThreadIdsUseCase.Output? = getThreadId(mms)
val exportMmsOutput: ExportMmsMessagesUseCase.Output? = threadIdOutput?.let { exportMms(smsExportState, it) }
@ -207,7 +209,7 @@ abstract class SmsExportService : Service() {
}
}
private fun getThreadId(mms: ExportableMessage.Mms): GetOrCreateMmsThreadIdsUseCase.Output? {
private fun getThreadId(mms: ExportableMessage.Mms<*>): GetOrCreateMmsThreadIdsUseCase.Output? {
return GetOrCreateMmsThreadIdsUseCase.execute(this, mms, threadCache).either(
onSuccess = { output ->
output

Wyświetl plik

@ -17,7 +17,7 @@ internal object ExportMmsMessagesUseCase {
private val TAG = Log.tag(ExportMmsMessagesUseCase::class.java)
internal fun getTransactionId(mms: ExportableMessage.Mms): String {
internal fun getTransactionId(mms: ExportableMessage.Mms<*>): String {
return "signal:T${mms.id}"
}
@ -82,7 +82,7 @@ internal object ExportMmsMessagesUseCase {
}
data class Output(
val mms: ExportableMessage.Mms,
val mms: ExportableMessage.Mms<*>,
val messageId: Long
)
}

Wyświetl plik

@ -14,7 +14,7 @@ import org.signal.smsexporter.ExportableMessage
internal object GetOrCreateMmsThreadIdsUseCase {
fun execute(
context: Context,
mms: ExportableMessage.Mms,
mms: ExportableMessage.Mms<*>,
threadCache: MutableMap<Set<String>, Long>
): Try<Output> {
return try {
@ -37,7 +37,7 @@ internal object GetOrCreateMmsThreadIdsUseCase {
}
}
private fun getRecipientSet(mms: ExportableMessage.Mms): Set<String> {
private fun getRecipientSet(mms: ExportableMessage.Mms<*>): Set<String> {
val recipients = mms.addresses
if (recipients.isEmpty()) {
error("Expected non-empty recipient count.")
@ -46,5 +46,5 @@ internal object GetOrCreateMmsThreadIdsUseCase {
return HashSet(recipients.map { it })
}
data class Output(val mms: ExportableMessage.Mms, val threadId: Long)
data class Output(val mms: ExportableMessage.Mms<*>, val threadId: Long)
}

Wyświetl plik

@ -12,7 +12,7 @@ import java.lang.Exception
* Returns nothing.
*/
internal object ExportSmsMessagesUseCase {
fun execute(context: Context, sms: ExportableMessage.Sms, checkForExistence: Boolean): Try<Unit> {
fun execute(context: Context, sms: ExportableMessage.Sms<*>, checkForExistence: Boolean): Try<Unit> {
try {
if (checkForExistence) {
val exists = context.contentResolver.query(

Wyświetl plik

@ -15,7 +15,7 @@ object TestUtils {
isRead: Boolean = false,
isOutgoing: Boolean = false,
body: String = "Hello, $id"
): ExportableMessage.Sms {
): ExportableMessage.Sms<*> {
return ExportableMessage.Sms(id, SmsExportState(), address, dateReceived, dateSent, isRead, isOutgoing, body)
}
@ -28,7 +28,7 @@ object TestUtils {
isOutgoing: Boolean = false,
parts: List<ExportableMessage.Mms.Part> = listOf(ExportableMessage.Mms.Part.Text("Hello, $id")),
sender: CharSequence = "+15555060177"
): ExportableMessage.Mms {
): ExportableMessage.Mms<*> {
return ExportableMessage.Mms(id, SmsExportState(), addresses, dateReceived, dateSent, isRead, isOutgoing, parts, sender)
}

Wyświetl plik

@ -104,7 +104,7 @@ class ExportMmsMessagesUseCaseTest {
}
private fun validateExportedMessage(
mms: ExportableMessage.Mms,
mms: ExportableMessage.Mms<*>,
expectedRowCount: Int = 1,
threadId: Long = 1L
) {

Wyświetl plik

@ -101,7 +101,7 @@ class ExportSmsMessagesUseCaseTest {
)
}
private fun validateExportedMessage(sms: ExportableMessage.Sms, expectedRowCount: Int = 1) {
private fun validateExportedMessage(sms: ExportableMessage.Sms<*>, expectedRowCount: Int = 1) {
// 1. Grab the SMS record from the content resolver
val context: Context = ApplicationProvider.getApplicationContext()
val baseUri: Uri = Telephony.Sms.CONTENT_URI