mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 02:15:35 +03:00
Merge branch 'develop' into feature/mention_display_name
This commit is contained in:
commit
013f51f0c4
38 changed files with 348 additions and 175 deletions
|
@ -5,11 +5,15 @@ Features ✨:
|
||||||
-
|
-
|
||||||
|
|
||||||
Improvements 🙌:
|
Improvements 🙌:
|
||||||
-
|
- Add long click gesture to copy userId, user display name, room name, room topic and room alias (#1774)
|
||||||
|
|
||||||
Bugfix 🐛:
|
Bugfix 🐛:
|
||||||
- Display name not shown under Settings/General (#1926)
|
- Display name not shown under Settings/General (#1926)
|
||||||
- Words containing my name should not trigger notifications (#1781)
|
- Words containing my name should not trigger notifications (#1781)
|
||||||
|
- Fix changing language issue
|
||||||
|
- Fix FontSize issue (#1483, #1787)
|
||||||
|
- Fix bad color for settings icon on Android < 24 (#1786)
|
||||||
|
- Change user or room avatar: when selecting Gallery, I'm not proposed to crop the selected image (#1590)
|
||||||
|
|
||||||
Translations 🗣:
|
Translations 🗣:
|
||||||
-
|
-
|
||||||
|
@ -21,7 +25,8 @@ Build 🧱:
|
||||||
- Some dependencies have been upgraded (coroutine, recyclerView, appCompat, core-ktx, firebase-messaging)
|
- Some dependencies have been upgraded (coroutine, recyclerView, appCompat, core-ktx, firebase-messaging)
|
||||||
|
|
||||||
Other changes:
|
Other changes:
|
||||||
-
|
- Use File extension functions to make code more concise (#1996)
|
||||||
|
- Create a script to import SAS strings (#1909)
|
||||||
|
|
||||||
Changes in Element 1.0.5 (2020-08-21)
|
Changes in Element 1.0.5 (2020-08-21)
|
||||||
===================================================
|
===================================================
|
||||||
|
|
|
@ -29,7 +29,6 @@ import org.junit.FixMethodOrder
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.junit.runners.MethodSorters
|
import org.junit.runners.MethodSorters
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,7 +45,7 @@ class AttachmentEncryptionTest {
|
||||||
val inputStream: InputStream
|
val inputStream: InputStream
|
||||||
|
|
||||||
inputStream = if (`in`.isEmpty()) {
|
inputStream = if (`in`.isEmpty()) {
|
||||||
ByteArrayInputStream(`in`)
|
`in`.inputStream()
|
||||||
} else {
|
} else {
|
||||||
val memoryFile = MemoryFile("file" + System.currentTimeMillis(), `in`.size)
|
val memoryFile = MemoryFile("file" + System.currentTimeMillis(), `in`.size)
|
||||||
memoryFile.outputStream.write(`in`)
|
memoryFile.outputStream.write(`in`)
|
||||||
|
|
|
@ -21,7 +21,6 @@ import android.util.Base64
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo
|
import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileKey
|
import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileKey
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
|
@ -179,7 +178,7 @@ internal object MXEncryptedAttachments {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return ByteArrayInputStream(outputStream.toByteArray())
|
return outputStream.toByteArray().inputStream()
|
||||||
.also { Timber.v("Decrypt in ${System.currentTimeMillis() - t0}ms") }
|
.also { Timber.v("Decrypt in ${System.currentTimeMillis() - t0}ms") }
|
||||||
} catch (oom: OutOfMemoryError) {
|
} catch (oom: OutOfMemoryError) {
|
||||||
Timber.e(oom, "## decryptAttachment() failed: OOM")
|
Timber.e(oom, "## decryptAttachment() failed: OOM")
|
||||||
|
|
|
@ -21,7 +21,6 @@ import android.util.Base64
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.RealmConfiguration
|
import io.realm.RealmConfiguration
|
||||||
import io.realm.RealmObject
|
import io.realm.RealmObject
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.ObjectOutputStream
|
import java.io.ObjectOutputStream
|
||||||
import java.util.zip.GZIPInputStream
|
import java.util.zip.GZIPInputStream
|
||||||
|
@ -96,7 +95,7 @@ fun <T> deserializeFromRealm(string: String?): T? {
|
||||||
}
|
}
|
||||||
val decodedB64 = Base64.decode(string.toByteArray(), Base64.DEFAULT)
|
val decodedB64 = Base64.decode(string.toByteArray(), Base64.DEFAULT)
|
||||||
|
|
||||||
val bais = ByteArrayInputStream(decodedB64)
|
val bais = decodedB64.inputStream()
|
||||||
val gzis = GZIPInputStream(bais)
|
val gzis = GZIPInputStream(bais)
|
||||||
val ois = SafeObjectInputStream(gzis)
|
val ois = SafeObjectInputStream(gzis)
|
||||||
return ois.use {
|
return ois.use {
|
||||||
|
|
|
@ -42,10 +42,7 @@ import org.matrix.android.sdk.internal.worker.SessionWorkerParams
|
||||||
import org.matrix.android.sdk.internal.worker.WorkerParamsFactory
|
import org.matrix.android.sdk.internal.worker.WorkerParamsFactory
|
||||||
import org.matrix.android.sdk.internal.worker.getSessionComponent
|
import org.matrix.android.sdk.internal.worker.getSessionComponent
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
|
||||||
import java.io.FileOutputStream
|
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -130,7 +127,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
|
||||||
val contentUploadResponse = if (params.isEncrypted) {
|
val contentUploadResponse = if (params.isEncrypted) {
|
||||||
Timber.v("Encrypt thumbnail")
|
Timber.v("Encrypt thumbnail")
|
||||||
notifyTracker(params) { contentUploadStateTracker.setEncryptingThumbnail(it) }
|
notifyTracker(params) { contentUploadStateTracker.setEncryptingThumbnail(it) }
|
||||||
val encryptionResult = MXEncryptedAttachments.encryptAttachment(ByteArrayInputStream(thumbnailData.bytes), thumbnailData.mimeType)
|
val encryptionResult = MXEncryptedAttachments.encryptAttachment(thumbnailData.bytes.inputStream(), thumbnailData.mimeType)
|
||||||
uploadedThumbnailEncryptedFileInfo = encryptionResult.encryptedFileInfo
|
uploadedThumbnailEncryptedFileInfo = encryptionResult.encryptedFileInfo
|
||||||
fileUploader.uploadByteArray(encryptionResult.encryptedByteArray,
|
fileUploader.uploadByteArray(encryptionResult.encryptedByteArray,
|
||||||
"thumb_${attachment.name}",
|
"thumb_${attachment.name}",
|
||||||
|
@ -176,7 +173,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
|
||||||
cacheFile.createNewFile()
|
cacheFile.createNewFile()
|
||||||
cacheFile.deleteOnExit()
|
cacheFile.deleteOnExit()
|
||||||
|
|
||||||
val outputStream = FileOutputStream(cacheFile)
|
val outputStream = cacheFile.outputStream()
|
||||||
outputStream.use {
|
outputStream.use {
|
||||||
inputStream.copyTo(outputStream)
|
inputStream.copyTo(outputStream)
|
||||||
}
|
}
|
||||||
|
@ -203,7 +200,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
|
||||||
Timber.v("Encrypt file")
|
Timber.v("Encrypt file")
|
||||||
notifyTracker(params) { contentUploadStateTracker.setEncrypting(it) }
|
notifyTracker(params) { contentUploadStateTracker.setEncrypting(it) }
|
||||||
|
|
||||||
val encryptionResult = MXEncryptedAttachments.encryptAttachment(FileInputStream(cacheFile), attachment.getSafeMimeType())
|
val encryptionResult = MXEncryptedAttachments.encryptAttachment(cacheFile.inputStream(), attachment.getSafeMimeType())
|
||||||
uploadedFileEncryptedFileInfo = encryptionResult.encryptedFileInfo
|
uploadedFileEncryptedFileInfo = encryptionResult.encryptedFileInfo
|
||||||
|
|
||||||
fileUploader
|
fileUploader
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.internal.session.room.membership
|
package org.matrix.android.sdk.internal.session.room.membership
|
||||||
|
|
||||||
import android.content.Context
|
import io.realm.Realm
|
||||||
import org.matrix.android.sdk.R
|
import org.matrix.android.sdk.R
|
||||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||||
|
@ -34,13 +34,14 @@ import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
||||||
import org.matrix.android.sdk.internal.database.query.getOrNull
|
import org.matrix.android.sdk.internal.database.query.getOrNull
|
||||||
import org.matrix.android.sdk.internal.database.query.where
|
import org.matrix.android.sdk.internal.database.query.where
|
||||||
import org.matrix.android.sdk.internal.di.UserId
|
import org.matrix.android.sdk.internal.di.UserId
|
||||||
import io.realm.Realm
|
import org.matrix.android.sdk.internal.util.StringProvider
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class computes room display name
|
* This class computes room display name
|
||||||
*/
|
*/
|
||||||
internal class RoomDisplayNameResolver @Inject constructor(private val context: Context,
|
internal class RoomDisplayNameResolver @Inject constructor(
|
||||||
|
private val stringProvider: StringProvider,
|
||||||
@UserId private val userId: String
|
@UserId private val userId: String
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@ -89,7 +90,7 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context:
|
||||||
.findFirst()
|
.findFirst()
|
||||||
?.displayName
|
?.displayName
|
||||||
} else {
|
} else {
|
||||||
context.getString(R.string.room_displayname_room_invite)
|
stringProvider.getString(R.string.room_displayname_room_invite)
|
||||||
}
|
}
|
||||||
} else if (roomEntity?.membership == Membership.JOIN) {
|
} else if (roomEntity?.membership == Membership.JOIN) {
|
||||||
val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst()
|
val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst()
|
||||||
|
@ -108,13 +109,13 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context:
|
||||||
}
|
}
|
||||||
val otherMembersCount = otherMembersSubset.count()
|
val otherMembersCount = otherMembersSubset.count()
|
||||||
name = when (otherMembersCount) {
|
name = when (otherMembersCount) {
|
||||||
0 -> context.getString(R.string.room_displayname_empty_room)
|
0 -> stringProvider.getString(R.string.room_displayname_empty_room)
|
||||||
1 -> resolveRoomMemberName(otherMembersSubset[0], roomMembers)
|
1 -> resolveRoomMemberName(otherMembersSubset[0], roomMembers)
|
||||||
2 -> context.getString(R.string.room_displayname_two_members,
|
2 -> stringProvider.getString(R.string.room_displayname_two_members,
|
||||||
resolveRoomMemberName(otherMembersSubset[0], roomMembers),
|
resolveRoomMemberName(otherMembersSubset[0], roomMembers),
|
||||||
resolveRoomMemberName(otherMembersSubset[1], roomMembers)
|
resolveRoomMemberName(otherMembersSubset[1], roomMembers)
|
||||||
)
|
)
|
||||||
else -> context.resources.getQuantityString(R.plurals.room_displayname_three_and_more_members,
|
else -> stringProvider.getQuantityString(R.plurals.room_displayname_three_and_more_members,
|
||||||
roomMembers.getNumberOfJoinedMembers() - 1,
|
roomMembers.getNumberOfJoinedMembers() - 1,
|
||||||
resolveRoomMemberName(otherMembersSubset[0], roomMembers),
|
resolveRoomMemberName(otherMembersSubset[0], roomMembers),
|
||||||
roomMembers.getNumberOfJoinedMembers() - 1)
|
roomMembers.getNumberOfJoinedMembers() - 1)
|
||||||
|
|
|
@ -219,7 +219,7 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
@RequiresApi(Build.VERSION_CODES.M)
|
||||||
private fun decryptStringM(encryptedChunk: ByteArray, keyAlias: String): String {
|
private fun decryptStringM(encryptedChunk: ByteArray, keyAlias: String): String {
|
||||||
val (iv, encryptedText) = formatMExtract(ByteArrayInputStream(encryptedChunk))
|
val (iv, encryptedText) = formatMExtract(encryptedChunk.inputStream())
|
||||||
|
|
||||||
val secretKey = getOrGenerateSymmetricKeyForAliasM(keyAlias)
|
val secretKey = getOrGenerateSymmetricKeyForAliasM(keyAlias)
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ package org.matrix.android.sdk.internal.util
|
||||||
|
|
||||||
import androidx.annotation.WorkerThread
|
import androidx.annotation.WorkerThread
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,7 +26,7 @@ import java.io.InputStream
|
||||||
*/
|
*/
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
fun writeToFile(inputStream: InputStream, outputFile: File) {
|
fun writeToFile(inputStream: InputStream, outputFile: File) {
|
||||||
FileOutputStream(outputFile).use {
|
outputFile.outputStream().use {
|
||||||
inputStream.copyTo(it)
|
inputStream.copyTo(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
package org.matrix.android.sdk.internal.util
|
package org.matrix.android.sdk.internal.util
|
||||||
|
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import androidx.annotation.ArrayRes
|
|
||||||
import androidx.annotation.NonNull
|
import androidx.annotation.NonNull
|
||||||
|
import androidx.annotation.PluralsRes
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import dagger.Reusable
|
import dagger.Reusable
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -56,8 +56,8 @@ internal class StringProvider @Inject constructor(private val resources: Resourc
|
||||||
return resources.getString(resId, *formatArgs)
|
return resources.getString(resId, *formatArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(Resources.NotFoundException::class)
|
@NonNull
|
||||||
fun getStringArray(@ArrayRes id: Int): Array<String> {
|
fun getQuantityString(@PluralsRes resId: Int, quantity: Int, vararg formatArgs: Any?): String {
|
||||||
return resources.getStringArray(id)
|
return resources.getQuantityString(resId, quantity, *formatArgs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
103
tools/import_sas_strings.py
Executable file
103
tools/import_sas_strings.py
Executable file
|
@ -0,0 +1,103 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Copyright (c) 2020 New Vector Ltd
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
# Run `pip3 install requests` if not installed yet
|
||||||
|
import requests
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='Download sas string from matrix-doc.')
|
||||||
|
parser.add_argument('-v',
|
||||||
|
'--verbose',
|
||||||
|
help="increase output verbosity.",
|
||||||
|
action="store_true")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.verbose:
|
||||||
|
print("Argument:")
|
||||||
|
print(args)
|
||||||
|
|
||||||
|
base_url = "https://raw.githubusercontent.com/matrix-org/matrix-doc/master/data-definitions/sas-emoji.json"
|
||||||
|
|
||||||
|
print("Downloading " + base_url + "…")
|
||||||
|
|
||||||
|
r0 = requests.get(base_url)
|
||||||
|
data0 = json.loads(r0.content.decode())
|
||||||
|
|
||||||
|
if args.verbose:
|
||||||
|
print("Json data:")
|
||||||
|
print(data0)
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
# emoji -> translation
|
||||||
|
default = dict()
|
||||||
|
# Language -> emoji -> translation
|
||||||
|
cumul = dict()
|
||||||
|
|
||||||
|
for emoji in data0:
|
||||||
|
description = emoji["description"]
|
||||||
|
if args.verbose:
|
||||||
|
print("Description: " + description)
|
||||||
|
default[description] = description
|
||||||
|
|
||||||
|
for lang in emoji["translated_descriptions"]:
|
||||||
|
if args.verbose:
|
||||||
|
print("Lang: " + lang)
|
||||||
|
if not (lang in cumul):
|
||||||
|
cumul[lang] = dict()
|
||||||
|
cumul[lang][description] = emoji["translated_descriptions"][lang]
|
||||||
|
|
||||||
|
if args.verbose:
|
||||||
|
print(default)
|
||||||
|
print(cumul)
|
||||||
|
|
||||||
|
def write_file(file, dict):
|
||||||
|
print("Writing file " + file)
|
||||||
|
if args.verbose:
|
||||||
|
print("With")
|
||||||
|
print(dict)
|
||||||
|
os.makedirs(os.path.dirname(file), exist_ok=True)
|
||||||
|
with open(file, mode="w", encoding="utf8") as o:
|
||||||
|
o.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
|
||||||
|
o.write("<resources>\n")
|
||||||
|
o.write(" <!-- Generated file, do not edit -->\n")
|
||||||
|
for key in dict:
|
||||||
|
if dict[key] is None:
|
||||||
|
continue
|
||||||
|
o.write(" <string name=\"verification_emoji_" + key.lower().replace(" ", "_") + "\">" + dict[key].replace("'", "\\'") + "</string>\n")
|
||||||
|
o.write("</resources>\n")
|
||||||
|
|
||||||
|
scripts_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
data_defs_dir = os.path.join(scripts_dir, "../matrix-sdk-android/src/main/res")
|
||||||
|
|
||||||
|
# Write default file
|
||||||
|
write_file(os.path.join(data_defs_dir, "values/strings_sas.xml"), default)
|
||||||
|
|
||||||
|
# Write each language file
|
||||||
|
for lang in cumul:
|
||||||
|
androidLang = lang\
|
||||||
|
.replace("_", "-r")\
|
||||||
|
.replace("zh-rHans", "zh-rCN")
|
||||||
|
write_file(os.path.join(data_defs_dir, "values-" + androidLang + "/strings_sas.xml"), cumul[lang])
|
||||||
|
|
||||||
|
print()
|
||||||
|
print("Success!")
|
|
@ -378,7 +378,7 @@ dependencies {
|
||||||
implementation "com.github.bumptech.glide:glide:$glide_version"
|
implementation "com.github.bumptech.glide:glide:$glide_version"
|
||||||
kapt "com.github.bumptech.glide:compiler:$glide_version"
|
kapt "com.github.bumptech.glide:compiler:$glide_version"
|
||||||
implementation 'com.danikula:videocache:2.7.1'
|
implementation 'com.danikula:videocache:2.7.1'
|
||||||
implementation 'com.github.yalantis:ucrop:2.2.4'
|
implementation 'com.github.yalantis:ucrop:2.2.6'
|
||||||
|
|
||||||
// Badge for compatibility
|
// Badge for compatibility
|
||||||
implementation 'me.leolin:ShortcutBadger:1.1.22@aar'
|
implementation 'me.leolin:ShortcutBadger:1.1.22@aar'
|
||||||
|
|
|
@ -32,10 +32,6 @@ import com.airbnb.epoxy.EpoxyAsyncUtil
|
||||||
import com.airbnb.epoxy.EpoxyController
|
import com.airbnb.epoxy.EpoxyController
|
||||||
import com.facebook.stetho.Stetho
|
import com.facebook.stetho.Stetho
|
||||||
import com.gabrielittner.threetenbp.LazyThreeTen
|
import com.gabrielittner.threetenbp.LazyThreeTen
|
||||||
import org.matrix.android.sdk.api.Matrix
|
|
||||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
|
||||||
import org.matrix.android.sdk.api.auth.AuthenticationService
|
|
||||||
import org.matrix.android.sdk.api.legacy.LegacySessionImporter
|
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.di.DaggerVectorComponent
|
import im.vector.app.core.di.DaggerVectorComponent
|
||||||
import im.vector.app.core.di.HasVectorInjector
|
import im.vector.app.core.di.HasVectorInjector
|
||||||
|
@ -50,16 +46,21 @@ import im.vector.app.features.notifications.NotificationUtils
|
||||||
import im.vector.app.features.pin.PinLocker
|
import im.vector.app.features.pin.PinLocker
|
||||||
import im.vector.app.features.popup.PopupAlertManager
|
import im.vector.app.features.popup.PopupAlertManager
|
||||||
import im.vector.app.features.rageshake.VectorUncaughtExceptionHandler
|
import im.vector.app.features.rageshake.VectorUncaughtExceptionHandler
|
||||||
|
import im.vector.app.features.settings.VectorLocale
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
import im.vector.app.features.version.VersionProvider
|
import im.vector.app.features.version.VersionProvider
|
||||||
import im.vector.app.push.fcm.FcmHelper
|
import im.vector.app.push.fcm.FcmHelper
|
||||||
|
import org.matrix.android.sdk.api.Matrix
|
||||||
|
import org.matrix.android.sdk.api.MatrixConfiguration
|
||||||
|
import org.matrix.android.sdk.api.auth.AuthenticationService
|
||||||
|
import org.matrix.android.sdk.api.legacy.LegacySessionImporter
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
import androidx.work.Configuration as WorkConfiguration
|
import androidx.work.Configuration as WorkConfiguration
|
||||||
|
|
||||||
class VectorApplication :
|
class VectorApplication :
|
||||||
|
@ -119,7 +120,9 @@ class VectorApplication :
|
||||||
R.array.com_google_android_gms_fonts_certs
|
R.array.com_google_android_gms_fonts_certs
|
||||||
)
|
)
|
||||||
FontsContractCompat.requestFont(this, fontRequest, emojiCompatFontProvider, getFontThreadHandler())
|
FontsContractCompat.requestFont(this, fontRequest, emojiCompatFontProvider, getFontThreadHandler())
|
||||||
vectorConfiguration.initConfiguration()
|
VectorLocale.init(this)
|
||||||
|
ThemeUtils.init(this)
|
||||||
|
vectorConfiguration.applyToApplicationContext()
|
||||||
|
|
||||||
emojiCompatWrapper.init(fontRequest)
|
emojiCompatWrapper.init(fontRequest)
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,7 @@ import im.vector.app.features.settings.devtools.OutgoingKeyRequestListFragment
|
||||||
import im.vector.app.features.settings.ignored.VectorSettingsIgnoredUsersFragment
|
import im.vector.app.features.settings.ignored.VectorSettingsIgnoredUsersFragment
|
||||||
import im.vector.app.features.settings.locale.LocalePickerFragment
|
import im.vector.app.features.settings.locale.LocalePickerFragment
|
||||||
import im.vector.app.features.settings.push.PushGatewaysFragment
|
import im.vector.app.features.settings.push.PushGatewaysFragment
|
||||||
|
import im.vector.app.features.settings.push.PushRulesFragment
|
||||||
import im.vector.app.features.share.IncomingShareFragment
|
import im.vector.app.features.share.IncomingShareFragment
|
||||||
import im.vector.app.features.signout.soft.SoftLogoutFragment
|
import im.vector.app.features.signout.soft.SoftLogoutFragment
|
||||||
import im.vector.app.features.terms.ReviewTermsFragment
|
import im.vector.app.features.terms.ReviewTermsFragment
|
||||||
|
@ -282,6 +283,11 @@ interface FragmentModule {
|
||||||
@FragmentKey(VectorSettingsLabsFragment::class)
|
@FragmentKey(VectorSettingsLabsFragment::class)
|
||||||
fun bindVectorSettingsLabsFragment(fragment: VectorSettingsLabsFragment): Fragment
|
fun bindVectorSettingsLabsFragment(fragment: VectorSettingsLabsFragment): Fragment
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@FragmentKey(PushRulesFragment::class)
|
||||||
|
fun bindPushRulesFragment(fragment: PushRulesFragment): Fragment
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@FragmentKey(VectorSettingsPreferencesFragment::class)
|
@FragmentKey(VectorSettingsPreferencesFragment::class)
|
||||||
|
|
|
@ -24,7 +24,9 @@ import android.widget.TextView
|
||||||
import androidx.annotation.AttrRes
|
import androidx.annotation.AttrRes
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.utils.copyToClipboard
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,3 +70,18 @@ fun TextView.setTextWithColoredPart(@StringRes fullTextRes: Int,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set long click listener to copy the current text of the TextView to the clipboard and show a Snackbar
|
||||||
|
*/
|
||||||
|
fun TextView.copyOnLongClick() {
|
||||||
|
setOnLongClickListener { view ->
|
||||||
|
(view as? TextView)
|
||||||
|
?.text
|
||||||
|
?.let { text ->
|
||||||
|
copyToClipboard(view.context, text, false)
|
||||||
|
Snackbar.make(view, view.resources.getString(R.string.copied_to_clipboard), Snackbar.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -31,7 +31,6 @@ import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
|
@ -97,7 +96,7 @@ class VectorGlideDataFetcher(private val activeSessionHolder: ActiveSessionHolde
|
||||||
Timber.v("Load data: $data")
|
Timber.v("Load data: $data")
|
||||||
if (data.isLocalFile() && data.url != null) {
|
if (data.isLocalFile() && data.url != null) {
|
||||||
val initialFile = File(data.url)
|
val initialFile = File(data.url)
|
||||||
callback.onDataReady(FileInputStream(initialFile))
|
callback.onDataReady(initialFile.inputStream())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver()
|
val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver()
|
||||||
|
|
|
@ -60,6 +60,7 @@ import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
|
||||||
import im.vector.app.core.extensions.exhaustive
|
import im.vector.app.core.extensions.exhaustive
|
||||||
import im.vector.app.core.extensions.observeEvent
|
import im.vector.app.core.extensions.observeEvent
|
||||||
import im.vector.app.core.extensions.observeNotNull
|
import im.vector.app.core.extensions.observeNotNull
|
||||||
|
import im.vector.app.core.extensions.restart
|
||||||
import im.vector.app.core.extensions.vectorComponent
|
import im.vector.app.core.extensions.vectorComponent
|
||||||
import im.vector.app.core.utils.toast
|
import im.vector.app.core.utils.toast
|
||||||
import im.vector.app.features.MainActivity
|
import im.vector.app.features.MainActivity
|
||||||
|
@ -75,14 +76,15 @@ import im.vector.app.features.rageshake.BugReportActivity
|
||||||
import im.vector.app.features.rageshake.BugReporter
|
import im.vector.app.features.rageshake.BugReporter
|
||||||
import im.vector.app.features.rageshake.RageShake
|
import im.vector.app.features.rageshake.RageShake
|
||||||
import im.vector.app.features.session.SessionListener
|
import im.vector.app.features.session.SessionListener
|
||||||
|
import im.vector.app.features.settings.FontScale
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import im.vector.app.features.themes.ActivityOtherThemes
|
import im.vector.app.features.themes.ActivityOtherThemes
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
import im.vector.app.receivers.DebugReceiver
|
import im.vector.app.receivers.DebugReceiver
|
||||||
import org.matrix.android.sdk.api.failure.GlobalError
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import io.reactivex.disposables.Disposable
|
import io.reactivex.disposables.Disposable
|
||||||
|
import org.matrix.android.sdk.api.failure.GlobalError
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
|
@ -198,8 +200,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
||||||
configurationViewModel.activityRestarter.observe(this, Observer {
|
configurationViewModel.activityRestarter.observe(this, Observer {
|
||||||
if (!it.hasBeenHandled) {
|
if (!it.hasBeenHandled) {
|
||||||
// Recreate the Activity because configuration has changed
|
// Recreate the Activity because configuration has changed
|
||||||
startActivity(intent)
|
restart()
|
||||||
finish()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
pinLocker.getLiveState().observeNotNull(this) {
|
pinLocker.getLiveState().observeNotNull(this) {
|
||||||
|
@ -219,6 +220,9 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
||||||
|
|
||||||
doBeforeSetContentView()
|
doBeforeSetContentView()
|
||||||
|
|
||||||
|
// Hack for font size
|
||||||
|
applyFontSize()
|
||||||
|
|
||||||
if (getLayoutRes() != -1) {
|
if (getLayoutRes() != -1) {
|
||||||
setContentView(getLayoutRes())
|
setContentView(getLayoutRes())
|
||||||
}
|
}
|
||||||
|
@ -239,6 +243,16 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method has to be called for the font size setting be supported correctly.
|
||||||
|
*/
|
||||||
|
private fun applyFontSize() {
|
||||||
|
resources.configuration.fontScale = FontScale.getFontScaleValue(this).scale
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
resources.updateConfiguration(resources.configuration, resources.displayMetrics)
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleGlobalError(globalError: GlobalError) {
|
private fun handleGlobalError(globalError: GlobalError) {
|
||||||
when (globalError) {
|
when (globalError) {
|
||||||
is GlobalError.InvalidToken ->
|
is GlobalError.InvalidToken ->
|
||||||
|
|
|
@ -20,7 +20,6 @@ import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.RadioGroup
|
import android.widget.RadioGroup
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.preference.PreferenceViewHolder
|
import androidx.preference.PreferenceViewHolder
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import org.matrix.android.sdk.api.pushrules.Action
|
import org.matrix.android.sdk.api.pushrules.Action
|
||||||
|
@ -164,7 +163,7 @@ class PushRulePreference : VectorPreference {
|
||||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||||
super.onBindViewHolder(holder)
|
super.onBindViewHolder(holder)
|
||||||
|
|
||||||
holder.itemView.findViewById<TextView>(android.R.id.summary)?.visibility = View.GONE
|
holder.findViewById(android.R.id.summary)?.visibility = View.GONE
|
||||||
holder.itemView.setOnClickListener(null)
|
holder.itemView.setOnClickListener(null)
|
||||||
holder.itemView.setOnLongClickListener(null)
|
holder.itemView.setOnLongClickListener(null)
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ class VectorEditTextPreference : EditTextPreference {
|
||||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||||
// display the title in multi-line to avoid ellipsis.
|
// display the title in multi-line to avoid ellipsis.
|
||||||
try {
|
try {
|
||||||
holder.itemView.findViewById<TextView>(android.R.id.title)?.isSingleLine = false
|
(holder.findViewById(android.R.id.title) as? TextView)?.isSingleLine = false
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "onBindView")
|
Timber.e(e, "onBindView")
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,12 +20,15 @@ import android.animation.Animator
|
||||||
import android.animation.ArgbEvaluator
|
import android.animation.ArgbEvaluator
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.core.animation.doOnEnd
|
import androidx.core.animation.doOnEnd
|
||||||
|
import androidx.core.widget.ImageViewCompat
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceViewHolder
|
import androidx.preference.PreferenceViewHolder
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
@ -76,6 +79,12 @@ open class VectorPreference : Preference {
|
||||||
notifyChanged()
|
notifyChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var tintIcon = false
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
notifyChanged()
|
||||||
|
}
|
||||||
|
|
||||||
var currentHighlightAnimator: Animator? = null
|
var currentHighlightAnimator: Animator? = null
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||||
|
@ -84,15 +93,23 @@ open class VectorPreference : Preference {
|
||||||
|
|
||||||
// display the title in multi-line to avoid ellipsis.
|
// display the title in multi-line to avoid ellipsis.
|
||||||
try {
|
try {
|
||||||
val title = itemView.findViewById<TextView>(android.R.id.title)
|
val title = holder.findViewById(android.R.id.title) as? TextView
|
||||||
val summary = itemView.findViewById<TextView>(android.R.id.summary)
|
val summary = holder.findViewById(android.R.id.summary) as? TextView
|
||||||
if (title != null) {
|
if (title != null) {
|
||||||
title.isSingleLine = false
|
title.isSingleLine = false
|
||||||
title.setTypeface(null, mTypeface)
|
title.setTypeface(null, mTypeface)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (title !== summary) {
|
summary?.setTypeface(null, mTypeface)
|
||||||
summary.setTypeface(null, mTypeface)
|
|
||||||
|
if (tintIcon) {
|
||||||
|
// Tint icons (See #1786)
|
||||||
|
val icon = holder.findViewById(android.R.id.icon) as? ImageView
|
||||||
|
|
||||||
|
icon?.let {
|
||||||
|
val color = ThemeUtils.getColor(context, R.attr.riotx_header_panel_text_secondary)
|
||||||
|
ImageViewCompat.setImageTintList(it, ColorStateList.valueOf(color))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// cancel existing animation (find a way to resume if happens during anim?)
|
// cancel existing animation (find a way to resume if happens during anim?)
|
||||||
|
|
|
@ -45,7 +45,7 @@ class VectorPreferenceCategory : PreferenceCategory {
|
||||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||||
super.onBindViewHolder(holder)
|
super.onBindViewHolder(holder)
|
||||||
|
|
||||||
val titleTextView = holder.itemView.findViewById<TextView>(android.R.id.title)
|
val titleTextView = holder.findViewById(android.R.id.title) as? TextView
|
||||||
|
|
||||||
titleTextView?.setTypeface(null, Typeface.BOLD)
|
titleTextView?.setTypeface(null, Typeface.BOLD)
|
||||||
titleTextView?.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_primary))
|
titleTextView?.setTextColor(ThemeUtils.getColor(context, R.attr.riotx_text_primary))
|
||||||
|
|
|
@ -58,7 +58,7 @@ class VectorSwitchPreference : SwitchPreference {
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||||
// display the title in multi-line to avoid ellipsis.
|
// display the title in multi-line to avoid ellipsis.
|
||||||
holder.itemView.findViewById<TextView>(android.R.id.title)?.isSingleLine = false
|
(holder.findViewById(android.R.id.title) as? TextView)?.isSingleLine = false
|
||||||
|
|
||||||
// cancel existing animation (find a way to resume if happens during anim?)
|
// cancel existing animation (find a way to resume if happens during anim?)
|
||||||
currentHighlightAnimator?.cancel()
|
currentHighlightAnimator?.cancel()
|
||||||
|
|
|
@ -17,8 +17,10 @@
|
||||||
package im.vector.app.core.services
|
package im.vector.app.core.services
|
||||||
|
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
import im.vector.app.core.extensions.vectorComponent
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,6 +33,10 @@ abstract class VectorService : Service() {
|
||||||
*/
|
*/
|
||||||
private var mIsSelfDestroyed = false
|
private var mIsSelfDestroyed = false
|
||||||
|
|
||||||
|
override fun attachBaseContext(base: Context) {
|
||||||
|
super.attachBaseContext(vectorComponent().vectorConfiguration().getLocalisedContext(base))
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
||||||
|
|
|
@ -518,8 +518,8 @@ fun saveFileIntoLegacy(sourceFile: File, dstDirPath: File, outputFilename: Strin
|
||||||
var outputStream: FileOutputStream? = null
|
var outputStream: FileOutputStream? = null
|
||||||
try {
|
try {
|
||||||
dstFile.createNewFile()
|
dstFile.createNewFile()
|
||||||
inputStream = FileInputStream(sourceFile)
|
inputStream = sourceFile.inputStream()
|
||||||
outputStream = FileOutputStream(dstFile)
|
outputStream = dstFile.outputStream()
|
||||||
val buffer = ByteArray(1024 * 10)
|
val buffer = ByteArray(1024 * 10)
|
||||||
var len: Int
|
var len: Int
|
||||||
while (inputStream.read(buffer).also { len = it } != -1) {
|
while (inputStream.read(buffer).also { len = it } != -1) {
|
||||||
|
|
|
@ -21,8 +21,6 @@ import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import im.vector.app.core.di.HasVectorInjector
|
import im.vector.app.core.di.HasVectorInjector
|
||||||
import im.vector.app.features.call.WebRtcPeerConnectionManager
|
import im.vector.app.features.call.WebRtcPeerConnectionManager
|
||||||
import im.vector.app.features.notifications.NotificationUtils
|
|
||||||
import im.vector.app.features.settings.VectorLocale.context
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
class CallHeadsUpActionReceiver : BroadcastReceiver() {
|
class CallHeadsUpActionReceiver : BroadcastReceiver() {
|
||||||
|
@ -32,20 +30,14 @@ class CallHeadsUpActionReceiver : BroadcastReceiver() {
|
||||||
const val CALL_ACTION_REJECT = 0
|
const val CALL_ACTION_REJECT = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var peerConnectionManager: WebRtcPeerConnectionManager
|
|
||||||
private lateinit var notificationUtils: NotificationUtils
|
|
||||||
|
|
||||||
init {
|
|
||||||
val appContext = context.applicationContext
|
|
||||||
if (appContext is HasVectorInjector) {
|
|
||||||
peerConnectionManager = appContext.injector().webRtcPeerConnectionManager()
|
|
||||||
notificationUtils = appContext.injector().notificationUtils()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent?) {
|
override fun onReceive(context: Context, intent: Intent?) {
|
||||||
|
val peerConnectionManager = (context.applicationContext as? HasVectorInjector)
|
||||||
|
?.injector()
|
||||||
|
?.webRtcPeerConnectionManager()
|
||||||
|
?: return
|
||||||
|
|
||||||
when (intent?.getIntExtra(EXTRA_CALL_ACTION_KEY, 0)) {
|
when (intent?.getIntExtra(EXTRA_CALL_ACTION_KEY, 0)) {
|
||||||
CALL_ACTION_REJECT -> onCallRejectClicked()
|
CALL_ACTION_REJECT -> onCallRejectClicked(peerConnectionManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not sure why this should be needed
|
// Not sure why this should be needed
|
||||||
|
@ -56,7 +48,7 @@ class CallHeadsUpActionReceiver : BroadcastReceiver() {
|
||||||
// context.stopService(Intent(context, CallHeadsUpService::class.java))
|
// context.stopService(Intent(context, CallHeadsUpService::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onCallRejectClicked() {
|
private fun onCallRejectClicked(peerConnectionManager: WebRtcPeerConnectionManager) {
|
||||||
Timber.d("onCallRejectClicked")
|
Timber.d("onCallRejectClicked")
|
||||||
peerConnectionManager.endCall()
|
peerConnectionManager.endCall()
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,11 @@
|
||||||
|
|
||||||
package im.vector.app.features.configuration
|
package im.vector.app.features.configuration
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.os.LocaleList
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
import im.vector.app.features.settings.FontScale
|
import im.vector.app.features.settings.FontScale
|
||||||
import im.vector.app.features.settings.VectorLocale
|
import im.vector.app.features.settings.VectorLocale
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
|
@ -40,14 +41,9 @@ class VectorConfiguration @Inject constructor(private val context: Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
fun applyToApplicationContext() {
|
||||||
* Init the configuration from the saved one
|
|
||||||
*/
|
|
||||||
fun initConfiguration() {
|
|
||||||
VectorLocale.init(context)
|
|
||||||
val locale = VectorLocale.applicationLocale
|
val locale = VectorLocale.applicationLocale
|
||||||
val fontScale = FontScale.getFontScaleValue(context)
|
val fontScale = FontScale.getFontScaleValue(context)
|
||||||
val theme = ThemeUtils.getApplicationTheme(context)
|
|
||||||
|
|
||||||
Locale.setDefault(locale)
|
Locale.setDefault(locale)
|
||||||
val config = Configuration(context.resources.configuration)
|
val config = Configuration(context.resources.configuration)
|
||||||
|
@ -56,9 +52,6 @@ class VectorConfiguration @Inject constructor(private val context: Context) {
|
||||||
config.fontScale = fontScale.scale
|
config.fontScale = fontScale.scale
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
context.resources.updateConfiguration(config, context.resources.displayMetrics)
|
context.resources.updateConfiguration(config, context.resources.displayMetrics)
|
||||||
|
|
||||||
// init the theme
|
|
||||||
ThemeUtils.setApplicationTheme(context, theme)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,26 +60,22 @@ class VectorConfiguration @Inject constructor(private val context: Context) {
|
||||||
* @param context the context
|
* @param context the context
|
||||||
* @return the localised context
|
* @return the localised context
|
||||||
*/
|
*/
|
||||||
@SuppressLint("NewApi")
|
|
||||||
fun getLocalisedContext(context: Context): Context {
|
fun getLocalisedContext(context: Context): Context {
|
||||||
try {
|
try {
|
||||||
val resources = context.resources
|
|
||||||
val locale = VectorLocale.applicationLocale
|
val locale = VectorLocale.applicationLocale
|
||||||
val configuration = resources.configuration
|
|
||||||
|
// create new configuration passing old configuration from original Context
|
||||||
|
val configuration = Configuration(context.resources.configuration)
|
||||||
|
|
||||||
configuration.fontScale = FontScale.getFontScaleValue(context).scale
|
configuration.fontScale = FontScale.getFontScaleValue(context).scale
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
setLocaleForApi24(configuration, locale)
|
||||||
|
} else {
|
||||||
configuration.setLocale(locale)
|
configuration.setLocale(locale)
|
||||||
|
}
|
||||||
configuration.setLayoutDirection(locale)
|
configuration.setLayoutDirection(locale)
|
||||||
return context.createConfigurationContext(configuration)
|
return context.createConfigurationContext(configuration)
|
||||||
} else {
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
configuration.locale = locale
|
|
||||||
configuration.setLayoutDirection(locale)
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
resources.updateConfiguration(configuration, resources.displayMetrics)
|
|
||||||
return context
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "## getLocalisedContext() failed")
|
Timber.e(e, "## getLocalisedContext() failed")
|
||||||
}
|
}
|
||||||
|
@ -94,6 +83,20 @@ class VectorConfiguration @Inject constructor(private val context: Context) {
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.N)
|
||||||
|
private fun setLocaleForApi24(config: Configuration, locale: Locale) {
|
||||||
|
val set: MutableSet<Locale> = LinkedHashSet()
|
||||||
|
// bring the user locale to the front of the list
|
||||||
|
set.add(locale)
|
||||||
|
val all = LocaleList.getDefault()
|
||||||
|
for (i in 0 until all.size()) {
|
||||||
|
// append other locales supported by the user
|
||||||
|
set.add(all[i])
|
||||||
|
}
|
||||||
|
val locales = set.toTypedArray()
|
||||||
|
config.setLocales(LocaleList(*locales))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the locale status value
|
* Compute the locale status value
|
||||||
* @return the local status value
|
* @return the local status value
|
||||||
|
|
|
@ -144,9 +144,7 @@ class BigImageViewerActivity : VectorBaseActivity() {
|
||||||
.get(MultiPicker.IMAGE)
|
.get(MultiPicker.IMAGE)
|
||||||
.getSelectedFiles(this, requestCode, resultCode, data)
|
.getSelectedFiles(this, requestCode, resultCode, data)
|
||||||
.firstOrNull()?.let {
|
.firstOrNull()?.let {
|
||||||
// TODO. UCrop library cannot read from Gallery. For now, we will set avatar as it is.
|
onRoomAvatarSelected(it)
|
||||||
// onRoomAvatarSelected(it)
|
|
||||||
onAvatarCropped(it.contentUri)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) }
|
UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) }
|
||||||
|
|
|
@ -32,7 +32,6 @@ import org.matrix.android.sdk.api.session.content.ContentUrlResolver
|
||||||
import me.gujun.android.span.span
|
import me.gujun.android.span.span
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
@ -494,7 +493,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
|
||||||
try {
|
try {
|
||||||
val file = File(context.applicationContext.cacheDir, ROOMS_NOTIFICATIONS_FILE_NAME)
|
val file = File(context.applicationContext.cacheDir, ROOMS_NOTIFICATIONS_FILE_NAME)
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
FileInputStream(file).use {
|
file.inputStream().use {
|
||||||
val events: ArrayList<NotifiableEvent>? = currentSession?.loadSecureSecret(it, KEY_ALIAS_SECRET_STORAGE)
|
val events: ArrayList<NotifiableEvent>? = currentSession?.loadSecureSecret(it, KEY_ALIAS_SECRET_STORAGE)
|
||||||
if (events != null) {
|
if (events != null) {
|
||||||
return events.toMutableList()
|
return events.toMutableList()
|
||||||
|
|
|
@ -35,6 +35,7 @@ import im.vector.app.core.animations.MatrixItemAppBarStateChangeListener
|
||||||
import im.vector.app.core.dialogs.ConfirmationDialogBuilder
|
import im.vector.app.core.dialogs.ConfirmationDialogBuilder
|
||||||
import im.vector.app.core.extensions.cleanup
|
import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
|
import im.vector.app.core.extensions.copyOnLongClick
|
||||||
import im.vector.app.core.extensions.exhaustive
|
import im.vector.app.core.extensions.exhaustive
|
||||||
import im.vector.app.core.extensions.setTextOrHide
|
import im.vector.app.core.extensions.setTextOrHide
|
||||||
import im.vector.app.core.platform.StateView
|
import im.vector.app.core.platform.StateView
|
||||||
|
@ -44,11 +45,11 @@ import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
import im.vector.app.features.roommemberprofile.devices.DeviceListBottomSheet
|
import im.vector.app.features.roommemberprofile.devices.DeviceListBottomSheet
|
||||||
import im.vector.app.features.roommemberprofile.powerlevel.EditPowerLevelDialogs
|
import im.vector.app.features.roommemberprofile.powerlevel.EditPowerLevelDialogs
|
||||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
|
||||||
import org.matrix.android.sdk.api.util.MatrixItem
|
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
import kotlinx.android.synthetic.main.fragment_matrix_profile.*
|
import kotlinx.android.synthetic.main.fragment_matrix_profile.*
|
||||||
import kotlinx.android.synthetic.main.view_stub_room_member_profile_header.*
|
import kotlinx.android.synthetic.main.view_stub_room_member_profile_header.*
|
||||||
|
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||||
|
import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
|
@ -110,6 +111,12 @@ class RoomMemberProfileFragment @Inject constructor(
|
||||||
is RoomMemberProfileViewEvents.OnInviteActionSuccess -> Unit
|
is RoomMemberProfileViewEvents.OnInviteActionSuccess -> Unit
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
}
|
}
|
||||||
|
setupLongClicks()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupLongClicks() {
|
||||||
|
memberProfileNameView.copyOnLongClick()
|
||||||
|
memberProfileIdView.copyOnLongClick()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleShowPowerLevelDemoteWarning(event: RoomMemberProfileViewEvents.ShowPowerLevelDemoteWarning) {
|
private fun handleShowPowerLevelDemoteWarning(event: RoomMemberProfileViewEvents.ShowPowerLevelDemoteWarning) {
|
||||||
|
|
|
@ -34,16 +34,12 @@ import com.airbnb.mvrx.args
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import com.yalantis.ucrop.UCrop
|
import com.yalantis.ucrop.UCrop
|
||||||
import im.vector.lib.multipicker.MultiPicker
|
|
||||||
import im.vector.lib.multipicker.entity.MultiPickerImageType
|
|
||||||
import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
|
|
||||||
import org.matrix.android.sdk.api.util.MatrixItem
|
|
||||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.animations.AppBarStateChangeListener
|
import im.vector.app.core.animations.AppBarStateChangeListener
|
||||||
import im.vector.app.core.animations.MatrixItemAppBarStateChangeListener
|
import im.vector.app.core.animations.MatrixItemAppBarStateChangeListener
|
||||||
import im.vector.app.core.extensions.cleanup
|
import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
|
import im.vector.app.core.extensions.copyOnLongClick
|
||||||
import im.vector.app.core.extensions.exhaustive
|
import im.vector.app.core.extensions.exhaustive
|
||||||
import im.vector.app.core.extensions.setTextOrHide
|
import im.vector.app.core.extensions.setTextOrHide
|
||||||
import im.vector.app.core.intent.getFilenameFromUri
|
import im.vector.app.core.intent.getFilenameFromUri
|
||||||
|
@ -62,9 +58,14 @@ import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedA
|
||||||
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
|
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
|
||||||
import im.vector.app.features.media.BigImageViewerActivity
|
import im.vector.app.features.media.BigImageViewerActivity
|
||||||
import im.vector.app.features.media.createUCropWithDefaultSettings
|
import im.vector.app.features.media.createUCropWithDefaultSettings
|
||||||
|
import im.vector.lib.multipicker.MultiPicker
|
||||||
|
import im.vector.lib.multipicker.entity.MultiPickerImageType
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
import kotlinx.android.synthetic.main.fragment_matrix_profile.*
|
import kotlinx.android.synthetic.main.fragment_matrix_profile.*
|
||||||
import kotlinx.android.synthetic.main.view_stub_room_profile_header.*
|
import kotlinx.android.synthetic.main.view_stub_room_profile_header.*
|
||||||
|
import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
|
||||||
|
import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
|
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -120,6 +121,13 @@ class RoomProfileFragment @Inject constructor(
|
||||||
.observe()
|
.observe()
|
||||||
.subscribe { handleQuickActions(it) }
|
.subscribe { handleQuickActions(it) }
|
||||||
.disposeOnDestroyView()
|
.disposeOnDestroyView()
|
||||||
|
setupLongClicks()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupLongClicks() {
|
||||||
|
roomProfileNameView.copyOnLongClick()
|
||||||
|
roomProfileAliasView.copyOnLongClick()
|
||||||
|
roomProfileTopicView.copyOnLongClick()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
@ -301,9 +309,7 @@ class RoomProfileFragment @Inject constructor(
|
||||||
.get(MultiPicker.IMAGE)
|
.get(MultiPicker.IMAGE)
|
||||||
.getSelectedFiles(requireContext(), requestCode, resultCode, data)
|
.getSelectedFiles(requireContext(), requestCode, resultCode, data)
|
||||||
.firstOrNull()?.let {
|
.firstOrNull()?.let {
|
||||||
// TODO. UCrop library cannot read from Gallery. For now, we will set avatar as it is.
|
onRoomAvatarSelected(it)
|
||||||
// onRoomAvatarSelected(it)
|
|
||||||
onAvatarCropped(it.contentUri)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) }
|
UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) }
|
||||||
|
|
|
@ -52,7 +52,7 @@ object VectorLocale {
|
||||||
var applicationLocale = defaultLocale
|
var applicationLocale = defaultLocale
|
||||||
private set
|
private set
|
||||||
|
|
||||||
lateinit var context: Context
|
private lateinit var context: Context
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init this object
|
* Init this object
|
||||||
|
|
|
@ -356,8 +356,7 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
|
||||||
.get(MultiPicker.IMAGE)
|
.get(MultiPicker.IMAGE)
|
||||||
.getSelectedFiles(requireContext(), requestCode, resultCode, data)
|
.getSelectedFiles(requireContext(), requestCode, resultCode, data)
|
||||||
.firstOrNull()?.let {
|
.firstOrNull()?.let {
|
||||||
// TODO. UCrop library cannot read from Gallery. For now, we will set avatar as it is.
|
onAvatarSelected(it)
|
||||||
onAvatarCropped(it.contentUri)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) }
|
UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) }
|
||||||
|
|
|
@ -168,6 +168,7 @@ class VectorSettingsPreferencesFragment @Inject constructor(
|
||||||
v.setOnClickListener {
|
v.setOnClickListener {
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
FontScale.updateFontScale(activity, i)
|
FontScale.updateFontScale(activity, i)
|
||||||
|
vectorConfiguration.applyToApplicationContext()
|
||||||
activity.restart()
|
activity.restart()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,9 @@
|
||||||
|
|
||||||
package im.vector.app.features.settings
|
package im.vector.app.features.settings
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.preference.VectorPreference
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class VectorSettingsRootFragment @Inject constructor() : VectorSettingsBaseFragment() {
|
class VectorSettingsRootFragment @Inject constructor() : VectorSettingsBaseFragment() {
|
||||||
|
@ -25,6 +27,15 @@ class VectorSettingsRootFragment @Inject constructor() : VectorSettingsBaseFragm
|
||||||
override val preferenceXmlRes = R.xml.vector_settings_root
|
override val preferenceXmlRes = R.xml.vector_settings_root
|
||||||
|
|
||||||
override fun bindPref() {
|
override fun bindPref() {
|
||||||
// Nothing to do
|
// Tint icon on API < 24
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
||||||
|
tintIcons()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tintIcons() {
|
||||||
|
for (i in 0 until preferenceScreen.preferenceCount) {
|
||||||
|
(preferenceScreen.getPreference(i) as? VectorPreference)?.let { it.tintIcon = true }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,13 @@ import com.squareup.inject.assisted.Assisted
|
||||||
import com.squareup.inject.assisted.AssistedInject
|
import com.squareup.inject.assisted.AssistedInject
|
||||||
import im.vector.app.core.extensions.exhaustive
|
import im.vector.app.core.extensions.exhaustive
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
|
import im.vector.app.features.configuration.VectorConfiguration
|
||||||
import im.vector.app.features.settings.VectorLocale
|
import im.vector.app.features.settings.VectorLocale
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class LocalePickerViewModel @AssistedInject constructor(
|
class LocalePickerViewModel @AssistedInject constructor(
|
||||||
@Assisted initialState: LocalePickerViewState
|
@Assisted initialState: LocalePickerViewState,
|
||||||
|
private val vectorConfiguration: VectorConfiguration
|
||||||
) : VectorViewModel<LocalePickerViewState, LocalePickerAction, LocalePickerViewEvents>(initialState) {
|
) : VectorViewModel<LocalePickerViewState, LocalePickerAction, LocalePickerViewEvents>(initialState) {
|
||||||
|
|
||||||
@AssistedInject.Factory
|
@AssistedInject.Factory
|
||||||
|
@ -70,6 +72,7 @@ class LocalePickerViewModel @AssistedInject constructor(
|
||||||
|
|
||||||
private fun handleSelectLocale(action: LocalePickerAction.SelectLocale) {
|
private fun handleSelectLocale(action: LocalePickerAction.SelectLocale) {
|
||||||
VectorLocale.saveApplicationLocale(action.locale)
|
VectorLocale.saveApplicationLocale(action.locale)
|
||||||
|
vectorConfiguration.applyToApplicationContext()
|
||||||
_viewEvents.post(LocalePickerViewEvents.RestartActivity)
|
_viewEvents.post(LocalePickerViewEvents.RestartActivity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.settings.push
|
||||||
|
|
||||||
|
import com.airbnb.epoxy.TypedEpoxyController
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.resources.StringProvider
|
||||||
|
import im.vector.app.core.ui.list.genericFooterItem
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class PushRulesController @Inject constructor(
|
||||||
|
private val stringProvider: StringProvider
|
||||||
|
) : TypedEpoxyController<PushRulesViewState>() {
|
||||||
|
|
||||||
|
override fun buildModels(data: PushRulesViewState?) {
|
||||||
|
data?.let {
|
||||||
|
it.rules.forEach {
|
||||||
|
pushRuleItem {
|
||||||
|
id(it.ruleId)
|
||||||
|
pushRule(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ?: run {
|
||||||
|
genericFooterItem {
|
||||||
|
id("footer")
|
||||||
|
text(stringProvider.getString(R.string.settings_push_rules_no_rules))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,6 @@ package im.vector.app.features.settings.push
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import com.airbnb.epoxy.TypedEpoxyController
|
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
@ -25,19 +24,18 @@ import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.resources.StringProvider
|
|
||||||
import im.vector.app.core.ui.list.genericFooterItem
|
|
||||||
import kotlinx.android.synthetic.main.fragment_generic_recycler.*
|
import kotlinx.android.synthetic.main.fragment_generic_recycler.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
// Referenced in vector_settings_notifications.xml
|
// Referenced in vector_settings_notifications.xml
|
||||||
class PushRulesFragment : VectorBaseFragment() {
|
class PushRulesFragment @Inject constructor(
|
||||||
|
private val epoxyController: PushRulesController
|
||||||
|
) : VectorBaseFragment() {
|
||||||
|
|
||||||
override fun getLayoutResId() = R.layout.fragment_generic_recycler
|
override fun getLayoutResId() = R.layout.fragment_generic_recycler
|
||||||
|
|
||||||
private val viewModel: PushRulesViewModel by fragmentViewModel(PushRulesViewModel::class)
|
private val viewModel: PushRulesViewModel by fragmentViewModel(PushRulesViewModel::class)
|
||||||
|
|
||||||
private val epoxyController by lazy { PushRulesController(StringProvider(requireContext().resources)) }
|
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
(activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_push_rules)
|
(activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_push_rules)
|
||||||
|
@ -56,23 +54,4 @@ class PushRulesFragment : VectorBaseFragment() {
|
||||||
override fun invalidate() = withState(viewModel) { state ->
|
override fun invalidate() = withState(viewModel) { state ->
|
||||||
epoxyController.setData(state)
|
epoxyController.setData(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
class PushRulesController(private val stringProvider: StringProvider) : TypedEpoxyController<PushRulesViewState>() {
|
|
||||||
|
|
||||||
override fun buildModels(data: PushRulesViewState?) {
|
|
||||||
data?.let {
|
|
||||||
it.rules.forEach {
|
|
||||||
pushRuleItem {
|
|
||||||
id(it.ruleId)
|
|
||||||
pushRule(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} ?: run {
|
|
||||||
genericFooterItem {
|
|
||||||
id("footer")
|
|
||||||
text(stringProvider.getString(R.string.settings_push_rules_no_rules))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,12 @@ object ThemeUtils {
|
||||||
|
|
||||||
private val mColorByAttr = HashMap<Int, Int>()
|
private val mColorByAttr = HashMap<Int, Int>()
|
||||||
|
|
||||||
|
// init the theme
|
||||||
|
fun init(context: Context) {
|
||||||
|
val theme = getApplicationTheme(context)
|
||||||
|
setApplicationTheme(context, theme)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if current theme is Light or Status
|
* @return true if current theme is Light or Status
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="163dp"
|
|
||||||
android:height="127dp"
|
|
||||||
android:viewportWidth="163"
|
|
||||||
android:viewportHeight="127">
|
|
||||||
<path
|
|
||||||
android:pathData="M113.569,169.348C129.753,185.532 153.161,188.363 165.853,175.671C178.545,162.979 175.715,139.57 159.531,123.386C143.347,107.203 44.653,8.372 44.653,8.372L35.819,18.975C35.819,18.975 39.221,27.764 37.204,30.186C35.186,32.608 24.684,32.34 24.684,32.34L6.34,54.358C6.34,54.358 4.89,60.67 6.106,61.885C41.927,97.706 77.748,133.527 113.569,169.348Z"
|
|
||||||
android:strokeWidth="1"
|
|
||||||
android:fillColor="#000000"
|
|
||||||
android:fillAlpha="0.147508741"
|
|
||||||
android:fillType="evenOdd"
|
|
||||||
android:strokeColor="#00000000"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M19.447,19.068L19.447,27.722L28.202,27.713C28.313,27.713 28.415,27.71 28.515,27.703C30.818,27.551 32.617,25.656 32.617,23.391C32.617,21.007 30.641,19.068 28.211,19.068L19.447,19.068ZM10.788,61.81C6.006,61.81 2.129,58.007 2.129,53.316L2.129,37.127C2.097,36.833 2.08,36.535 2.08,36.232C2.08,35.925 2.096,35.621 2.129,35.322L2.129,10.574C2.129,5.882 6.006,2.079 10.788,2.079L28.211,2.079C40.19,2.079 49.935,11.639 49.935,23.391C49.935,34.563 41.04,43.902 29.684,44.652C29.201,44.685 28.704,44.702 28.211,44.702L19.447,44.71L19.447,53.316C19.447,58.007 15.57,61.81 10.788,61.81L10.788,61.81Z"
|
|
||||||
android:strokeWidth="1"
|
|
||||||
android:fillColor="#A2DDEF"
|
|
||||||
android:fillType="evenOdd"
|
|
||||||
android:strokeColor="#00000000"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M19.447,19.068L19.447,27.722L28.202,27.713C28.313,27.713 28.415,27.71 28.515,27.703C30.818,27.551 32.617,25.656 32.617,23.391C32.617,21.007 30.641,19.068 28.211,19.068L19.447,19.068ZM10.788,61.81C6.006,61.81 2.129,58.007 2.129,53.316L2.129,10.574C2.129,5.882 6.006,2.079 10.788,2.079L28.211,2.079C40.19,2.079 49.935,11.639 49.935,23.391C49.935,34.563 41.04,43.902 29.684,44.652C29.201,44.685 28.704,44.702 28.211,44.702L19.447,44.71L19.447,53.316C19.447,58.007 15.57,61.81 10.788,61.81Z"
|
|
||||||
android:strokeWidth="1.52445396"
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:strokeColor="#368BD6"
|
|
||||||
android:fillType="evenOdd"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M10.788,53.315L10.788,10.574L28.211,10.574C35.426,10.574 41.276,16.312 41.276,23.39C41.276,30.175 35.902,35.729 29.102,36.178C28.807,36.197 28.51,36.207 28.211,36.207L10.788,36.207"
|
|
||||||
android:strokeWidth="1.52445396"
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:strokeColor="#368BD6"
|
|
||||||
android:fillType="evenOdd"
|
|
||||||
android:strokeLineCap="round"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M17.923,5.702C19.25,7.56 19.76,9.815 19.358,12.048C18.956,14.283 17.691,16.229 15.795,17.531C11.881,20.217 6.467,19.282 3.726,15.445C2.399,13.587 1.889,11.333 2.291,9.099C2.693,6.864 3.958,4.917 5.854,3.617C9.768,0.93 15.182,1.865 17.923,5.702ZM41.347,61.805C38.618,61.805 35.934,60.543 34.248,58.185L22.011,41.052C19.266,37.21 20.217,31.913 24.133,29.222C28.049,26.528 33.449,27.461 36.193,31.303L48.431,48.435C51.175,52.277 50.225,57.574 46.309,60.266C44.797,61.306 43.063,61.805 41.347,61.805Z"
|
|
||||||
android:strokeWidth="1"
|
|
||||||
android:fillColor="#368BD6"
|
|
||||||
android:fillType="evenOdd"
|
|
||||||
android:strokeColor="#00000000"/>
|
|
||||||
</vector>
|
|
Loading…
Reference in a new issue