Rename package `im.vector.riotx` to `im.vector.app` (IDE)
This commit is contained in:
parent
67fc2feacb
commit
a1f90abcd2
|
@ -23,6 +23,7 @@ Other changes:
|
|||
- Hide Flair settings, this is not implemented yet.
|
||||
- Rename package `im.vector.riotx.attachmentviewer` to `im.vector.lib.attachmentviewer`
|
||||
- Rename package `im.vector.riotx.multipicker` to `im.vector.lib.multipicker`
|
||||
- Rename package `im.vector.riotx` to `im.vector.app`
|
||||
|
||||
Changes in Element 1.0.4 (2020-08-03)
|
||||
===================================================
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
-keep class im.vector.riotx.features.** { *; }
|
||||
-keep class im.vector.app.features.** { *; }
|
||||
|
||||
## print all the rules in a file
|
||||
# -printconfiguration ../proguard_files/full-r8-config.txt
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
import android.content.Context
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import im.vector.app.test.shared.createTimberTestRule
|
||||
import org.junit.Rule
|
||||
|
||||
interface InstrumentedTest {
|
||||
|
||||
@Rule
|
||||
fun timberTestRule() = createTimberTestRule()
|
||||
|
||||
fun context(): Context {
|
||||
return ApplicationProvider.getApplicationContext()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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.core.utils
|
||||
|
||||
import org.amshove.kluent.shouldBe
|
||||
import org.junit.Test
|
||||
import java.lang.Thread.sleep
|
||||
|
||||
class TemporaryStoreTest {
|
||||
|
||||
@Test
|
||||
fun testTemporaryStore() {
|
||||
// Keep the data 30 millis
|
||||
val store = TemporaryStore<String>(30)
|
||||
|
||||
store.data = "test"
|
||||
store.data shouldBe "test"
|
||||
sleep(15)
|
||||
store.data shouldBe "test"
|
||||
sleep(20)
|
||||
store.data shouldBe null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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.reactions.data
|
||||
|
||||
import im.vector.app.InstrumentedTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
import org.junit.runners.MethodSorters
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
@RunWith(JUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
class EmojiDataSourceTest : InstrumentedTest {
|
||||
|
||||
@Test
|
||||
fun checkParsingTime() {
|
||||
val time = measureTimeMillis {
|
||||
EmojiDataSource(context().resources)
|
||||
}
|
||||
|
||||
assertTrue("Too long to parse", time < 100)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkNumberOfResult() {
|
||||
val emojiDataSource = EmojiDataSource(context().resources)
|
||||
|
||||
assertEquals("Wrong number of emojis", 1545, emojiDataSource.rawData.emojis.size)
|
||||
assertEquals("Wrong number of categories", 8, emojiDataSource.rawData.categories.size)
|
||||
assertEquals("Wrong number of aliases", 57, emojiDataSource.rawData.aliases.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun searchTestEmptySearch() {
|
||||
val emojiDataSource = EmojiDataSource(context().resources)
|
||||
|
||||
assertEquals("Empty search should return 1545 results", 1545, emojiDataSource.filterWith("").size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun searchTestNoResult() {
|
||||
val emojiDataSource = EmojiDataSource(context().resources)
|
||||
|
||||
assertTrue("Should not have result", emojiDataSource.filterWith("noresult").isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun searchTestOneResult() {
|
||||
val emojiDataSource = EmojiDataSource(context().resources)
|
||||
|
||||
assertEquals("Should have 1 result", 1, emojiDataSource.filterWith("france").size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun searchTestManyResult() {
|
||||
val emojiDataSource = EmojiDataSource(context().resources)
|
||||
|
||||
assertTrue("Should have many result", emojiDataSource.filterWith("fra").size > 1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTada() {
|
||||
val emojiDataSource = EmojiDataSource(context().resources)
|
||||
|
||||
val result = emojiDataSource.filterWith("tada")
|
||||
|
||||
assertEquals("Should find tada emoji", 1, result.size)
|
||||
assertEquals("Should find tada emoji", "🎉", result[0].emoji)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testQuickReactions() {
|
||||
val emojiDataSource = EmojiDataSource(context().resources)
|
||||
|
||||
assertEquals("Should have 8 quick reactions", 8, emojiDataSource.getQuickReactions().size)
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* 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.riotx
|
||||
|
||||
import android.content.Context
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import im.vector.riotx.test.shared.createTimberTestRule
|
||||
import org.junit.Rule
|
||||
|
||||
interface InstrumentedTest {
|
||||
|
||||
@Rule
|
||||
fun timberTestRule() = createTimberTestRule()
|
||||
|
||||
fun context(): Context {
|
||||
return ApplicationProvider.getApplicationContext()
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* 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.riotx.core.utils
|
||||
|
||||
import org.amshove.kluent.shouldBe
|
||||
import org.junit.Test
|
||||
import java.lang.Thread.sleep
|
||||
|
||||
class TemporaryStoreTest {
|
||||
|
||||
@Test
|
||||
fun testTemporaryStore() {
|
||||
// Keep the data 30 millis
|
||||
val store = TemporaryStore<String>(30)
|
||||
|
||||
store.data = "test"
|
||||
store.data shouldBe "test"
|
||||
sleep(15)
|
||||
store.data shouldBe "test"
|
||||
sleep(20)
|
||||
store.data shouldBe null
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
* 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.riotx.features.reactions.data
|
||||
|
||||
import im.vector.riotx.InstrumentedTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
import org.junit.runners.MethodSorters
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
@RunWith(JUnit4::class)
|
||||
@FixMethodOrder(MethodSorters.JVM)
|
||||
class EmojiDataSourceTest : InstrumentedTest {
|
||||
|
||||
@Test
|
||||
fun checkParsingTime() {
|
||||
val time = measureTimeMillis {
|
||||
EmojiDataSource(context().resources)
|
||||
}
|
||||
|
||||
assertTrue("Too long to parse", time < 100)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkNumberOfResult() {
|
||||
val emojiDataSource = EmojiDataSource(context().resources)
|
||||
|
||||
assertEquals("Wrong number of emojis", 1545, emojiDataSource.rawData.emojis.size)
|
||||
assertEquals("Wrong number of categories", 8, emojiDataSource.rawData.categories.size)
|
||||
assertEquals("Wrong number of aliases", 57, emojiDataSource.rawData.aliases.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun searchTestEmptySearch() {
|
||||
val emojiDataSource = EmojiDataSource(context().resources)
|
||||
|
||||
assertEquals("Empty search should return 1545 results", 1545, emojiDataSource.filterWith("").size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun searchTestNoResult() {
|
||||
val emojiDataSource = EmojiDataSource(context().resources)
|
||||
|
||||
assertTrue("Should not have result", emojiDataSource.filterWith("noresult").isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun searchTestOneResult() {
|
||||
val emojiDataSource = EmojiDataSource(context().resources)
|
||||
|
||||
assertEquals("Should have 1 result", 1, emojiDataSource.filterWith("france").size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun searchTestManyResult() {
|
||||
val emojiDataSource = EmojiDataSource(context().resources)
|
||||
|
||||
assertTrue("Should have many result", emojiDataSource.filterWith("fra").size > 1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTada() {
|
||||
val emojiDataSource = EmojiDataSource(context().resources)
|
||||
|
||||
val result = emojiDataSource.filterWith("tada")
|
||||
|
||||
assertEquals("Should find tada emoji", 1, result.size)
|
||||
assertEquals("Should find tada emoji", "🎉", result[0].emoji)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testQuickReactions() {
|
||||
val emojiDataSource = EmojiDataSource(context().resources)
|
||||
|
||||
assertEquals("Should have 8 quick reactions", 8, emojiDataSource.getQuickReactions().size)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="im.vector.riotx">
|
||||
package="im.vector.app">
|
||||
|
||||
<application>
|
||||
<activity android:name=".features.debug.TestLinkifyActivity" />
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright 2019 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.debug
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.utils.toast
|
||||
import kotlinx.android.synthetic.debug.activity_test_material_theme.*
|
||||
|
||||
// Rendering is not the same with VectorBaseActivity
|
||||
abstract class DebugMaterialThemeActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_test_material_theme)
|
||||
|
||||
debugShowSnackbar.setOnClickListener {
|
||||
Snackbar.make(debugMaterialCoordinator, "Snackbar!", Snackbar.LENGTH_SHORT)
|
||||
.setAction("Action") { }
|
||||
.show()
|
||||
}
|
||||
|
||||
debugShowToast.setOnClickListener {
|
||||
toast("Toast")
|
||||
}
|
||||
|
||||
debugShowDialog.setOnClickListener {
|
||||
AlertDialog.Builder(this)
|
||||
.setMessage("Dialog content")
|
||||
.setIcon(R.drawable.ic_settings_x)
|
||||
.setPositiveButton("Positive", null)
|
||||
.setNegativeButton("Negative", null)
|
||||
.setNeutralButton("Neutral", null)
|
||||
.show()
|
||||
}
|
||||
|
||||
debugShowBottomSheet.setOnClickListener {
|
||||
BottomSheetDialogFragment().show(supportFragmentManager, "TAG")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.home, menu)
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright 2019 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.debug
|
||||
|
||||
class DebugMaterialThemeDarkActivity : DebugMaterialThemeActivity()
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright 2019 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.debug
|
||||
|
||||
class DebugMaterialThemeLightActivity : DebugMaterialThemeActivity()
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* Copyright 2019 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.debug
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.Person
|
||||
import butterknife.OnClick
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.di.ScreenComponent
|
||||
import im.vector.app.core.platform.VectorBaseActivity
|
||||
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||
import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA
|
||||
import im.vector.app.core.utils.allGranted
|
||||
import im.vector.app.core.utils.checkPermissions
|
||||
import im.vector.app.core.utils.toast
|
||||
import im.vector.app.features.debug.sas.DebugSasEmojiActivity
|
||||
import im.vector.app.features.qrcode.QrCodeScannerActivity
|
||||
import im.vector.matrix.android.internal.crypto.verification.qrcode.toQrCodeData
|
||||
import kotlinx.android.synthetic.debug.activity_debug_menu.*
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class DebugMenuActivity : VectorBaseActivity() {
|
||||
|
||||
override fun getLayoutRes() = R.layout.activity_debug_menu
|
||||
|
||||
@Inject
|
||||
lateinit var activeSessionHolder: ActiveSessionHolder
|
||||
|
||||
override fun injectWith(injector: ScreenComponent) {
|
||||
injector.inject(this)
|
||||
}
|
||||
|
||||
private lateinit var buffer: ByteArray
|
||||
|
||||
override fun initUiAndData() {
|
||||
// renderQrCode("https://www.example.org")
|
||||
|
||||
buffer = ByteArray(256)
|
||||
for (i in buffer.indices) {
|
||||
buffer[i] = i.toByte()
|
||||
}
|
||||
|
||||
val string = buffer.toString(Charsets.ISO_8859_1)
|
||||
|
||||
renderQrCode(string)
|
||||
}
|
||||
|
||||
private fun renderQrCode(text: String) {
|
||||
debug_qr_code.setData(text, true)
|
||||
}
|
||||
|
||||
@OnClick(R.id.debug_test_text_view_link)
|
||||
fun testTextViewLink() {
|
||||
startActivity(Intent(this, TestLinkifyActivity::class.java))
|
||||
}
|
||||
|
||||
@OnClick(R.id.debug_show_sas_emoji)
|
||||
fun showSasEmoji() {
|
||||
startActivity(Intent(this, DebugSasEmojiActivity::class.java))
|
||||
}
|
||||
|
||||
@OnClick(R.id.debug_test_notification)
|
||||
fun testNotification() {
|
||||
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
// Create channel first
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val channel =
|
||||
NotificationChannel(
|
||||
"CHAN",
|
||||
"Channel name",
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
)
|
||||
|
||||
channel.description = "Channel description"
|
||||
(getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).createNotificationChannel(channel)
|
||||
|
||||
val channel2 =
|
||||
NotificationChannel(
|
||||
"CHAN2",
|
||||
"Channel name 2",
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
)
|
||||
|
||||
channel2.description = "Channel description 2"
|
||||
(getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).createNotificationChannel(channel2)
|
||||
}
|
||||
|
||||
val builder = NotificationCompat.Builder(this, "CHAN")
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setContentTitle("Title")
|
||||
.setContentText("Content")
|
||||
// No effect because it's a group summary notif
|
||||
.setNumber(33)
|
||||
.setSmallIcon(R.drawable.ic_status_bar)
|
||||
// This provocate the badge issue: no badge for group notification
|
||||
.setGroup("GroupKey")
|
||||
.setGroupSummary(true)
|
||||
|
||||
val messagingStyle1 = NotificationCompat.MessagingStyle(
|
||||
Person.Builder()
|
||||
.setName("User name")
|
||||
.build()
|
||||
)
|
||||
.addMessage("Message 1 - 1", System.currentTimeMillis(), Person.Builder().setName("user 1-1").build())
|
||||
.addMessage("Message 1 - 2", System.currentTimeMillis(), Person.Builder().setName("user 1-2").build())
|
||||
|
||||
val messagingStyle2 = NotificationCompat.MessagingStyle(
|
||||
Person.Builder()
|
||||
.setName("User name 2")
|
||||
.build()
|
||||
)
|
||||
.addMessage("Message 2 - 1", System.currentTimeMillis(), Person.Builder().setName("user 1-1").build())
|
||||
.addMessage("Message 2 - 2", System.currentTimeMillis(), Person.Builder().setName("user 1-2").build())
|
||||
|
||||
notificationManager.notify(10, builder.build())
|
||||
|
||||
notificationManager.notify(
|
||||
11,
|
||||
NotificationCompat.Builder(this, "CHAN")
|
||||
.setChannelId("CHAN")
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setContentTitle("Title 1")
|
||||
.setContentText("Content 1")
|
||||
// For shortcut on long press on launcher icon
|
||||
.setBadgeIconType(NotificationCompat.BADGE_ICON_NONE)
|
||||
.setStyle(messagingStyle1)
|
||||
.setSmallIcon(R.drawable.ic_status_bar)
|
||||
.setGroup("GroupKey")
|
||||
.build()
|
||||
)
|
||||
|
||||
notificationManager.notify(
|
||||
12,
|
||||
NotificationCompat.Builder(this, "CHAN2")
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setContentTitle("Title 2")
|
||||
.setContentText("Content 2")
|
||||
.setStyle(messagingStyle2)
|
||||
.setSmallIcon(R.drawable.ic_status_bar)
|
||||
.setGroup("GroupKey")
|
||||
.build()
|
||||
)
|
||||
}
|
||||
|
||||
@OnClick(R.id.debug_test_material_theme_light)
|
||||
fun testMaterialThemeLight() {
|
||||
startActivity(Intent(this, DebugMaterialThemeLightActivity::class.java))
|
||||
}
|
||||
|
||||
@OnClick(R.id.debug_test_material_theme_dark)
|
||||
fun testMaterialThemeDark() {
|
||||
startActivity(Intent(this, DebugMaterialThemeDarkActivity::class.java))
|
||||
}
|
||||
|
||||
@OnClick(R.id.debug_test_crash)
|
||||
fun testCrash() {
|
||||
throw RuntimeException("Application crashed from user demand")
|
||||
}
|
||||
|
||||
@OnClick(R.id.debug_scan_qr_code)
|
||||
fun scanQRCode() {
|
||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) {
|
||||
doScanQRCode()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
|
||||
if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA && allGranted(grantResults)) {
|
||||
doScanQRCode()
|
||||
}
|
||||
}
|
||||
|
||||
private fun doScanQRCode() {
|
||||
QrCodeScannerActivity.startForResult(this)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
QrCodeScannerActivity.QR_CODE_SCANNER_REQUEST_CODE -> {
|
||||
toast("QrCode: " + QrCodeScannerActivity.getResultText(data) + " is QRCode: " + QrCodeScannerActivity.getResultIsQrCode(data))
|
||||
|
||||
// Also update the current QR Code (reverse operation)
|
||||
// renderQrCode(QrCodeScannerActivity.getResultText(data) ?: "")
|
||||
val result = QrCodeScannerActivity.getResultText(data)!!
|
||||
|
||||
val qrCodeData = result.toQrCodeData()
|
||||
Timber.e("qrCodeData: $qrCodeData")
|
||||
|
||||
if (result.length != buffer.size) {
|
||||
Timber.e("Error, length are not the same")
|
||||
} else {
|
||||
// Convert to ByteArray
|
||||
val byteArrayResult = result.toByteArray(Charsets.ISO_8859_1)
|
||||
for (i in byteArrayResult.indices) {
|
||||
if (buffer[i] != byteArrayResult[i]) {
|
||||
Timber.e("Error for byte $i, expecting ${buffer[i]} and get ${byteArrayResult[i]}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Copyright 2019 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.debug
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import im.vector.app.R
|
||||
|
||||
class TestLinkifyActivity : AppCompatActivity() {
|
||||
|
||||
@BindView(R.id.test_linkify_content_view)
|
||||
lateinit var scrollContent: LinearLayout
|
||||
|
||||
@BindView(R.id.test_linkify_coordinator)
|
||||
lateinit var coordinatorLayout: CoordinatorLayout
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_test_linkify)
|
||||
ButterKnife.bind(this)
|
||||
|
||||
scrollContent.removeAllViews()
|
||||
|
||||
listOf(
|
||||
"https://www.html5rocks.com/en/tutorials/webrtc/basics/ |",
|
||||
"https://www.html5rocks.com/en/tutorials/webrtc/basics/",
|
||||
"mailto mailto:test@toto.com test@toto.com",
|
||||
"Here is the link.www.test.com/foo/?23=35 you got it?",
|
||||
"www.lemonde.fr",
|
||||
" /www.lemonde.fr",
|
||||
"://www.lemonde.fr",
|
||||
"file:///dev/null ",
|
||||
" ansible/xoxys.matrix#2c0b65eb",
|
||||
"foo.ansible/xoxys.matrix#2c0b65eb",
|
||||
"foo.ansible.fpo/xoxys.matrix#2c0b65eb",
|
||||
"https://foo.ansible.fpo/xoxys.matrix#2c0b65eb",
|
||||
"@vf:matrix.org",
|
||||
"+44 207 123 1234",
|
||||
"+33141437940",
|
||||
"1234",
|
||||
"3456.34,089",
|
||||
"ksks9808",
|
||||
"For example: geo:48.85828,2.29449?z=16 should be clickable",
|
||||
"geo:37.786971,-122.399677;u=35",
|
||||
"37.786971,-122.399677;u=35",
|
||||
"48.107864,-1.712153",
|
||||
"synchrone peut tenir la route la",
|
||||
"that.is.some.sexy.link",
|
||||
"test overlap 48.107864,0673728392 geo + pn?",
|
||||
"test overlap 0673728392,48.107864 geo + pn?",
|
||||
"If I add a link in brackets like (help for Riot: https://about.riot.im/help), the link is usable on Riot for Desktop",
|
||||
"(help for Riot: https://about.riot.im/help)",
|
||||
"http://example.com/test(1).html",
|
||||
"http://example.com/test(1)",
|
||||
"https://about.riot.im/help)",
|
||||
"(http://example.com/test(1))",
|
||||
"http://example.com/test1)",
|
||||
"http://example.com/test1/, et ca",
|
||||
"www.example.com/, et ca",
|
||||
"foo.ansible.toplevel/xoxys.matrix#2c0b65eb",
|
||||
"foo.ansible.ninja/xoxys.matrix#2c0b65eb",
|
||||
"in brackets like (help for Riot: https://www.exemple/com/find(1)) , the link is usable ",
|
||||
"""
|
||||
In brackets like (help for Riot: https://about.riot.im/help) , the link is usable,
|
||||
But you can call +44 207 123 1234 and come to 37.786971,-122.399677;u=35 then
|
||||
see if this mail jhon@riot.im is active but this should not 12345
|
||||
""".trimIndent()
|
||||
)
|
||||
.forEach { textContent ->
|
||||
val item = LayoutInflater.from(this)
|
||||
.inflate(R.layout.item_test_linkify, scrollContent, false)
|
||||
|
||||
item.findViewById<TextView>(R.id.test_linkify_auto_text)
|
||||
?.apply {
|
||||
text = textContent
|
||||
/* TODO Use BetterLinkMovementMethod when the other PR is merged
|
||||
movementMethod = MatrixLinkMovementMethod(object : MockMessageAdapterActionListener() {
|
||||
override fun onURLClick(uri: Uri?) {
|
||||
Snackbar.make(coordinatorLayout, "URI Clicked: $uri", Snackbar.LENGTH_LONG)
|
||||
.setAction("open") {
|
||||
openUrlInExternalBrowser(this@TestLinkifyActivity, uri)
|
||||
}
|
||||
.show()
|
||||
}
|
||||
})
|
||||
*/
|
||||
}
|
||||
|
||||
item.findViewById<TextView>(R.id.test_linkify_custom_text)
|
||||
?.apply {
|
||||
text = textContent
|
||||
/* TODO Use BetterLinkMovementMethod when the other PR is merged
|
||||
movementMethod = MatrixLinkMovementMethod(object : MockMessageAdapterActionListener() {
|
||||
override fun onURLClick(uri: Uri?) {
|
||||
Snackbar.make(coordinatorLayout, "URI Clicked: $uri", Snackbar.LENGTH_LONG)
|
||||
.setAction("open") {
|
||||
openUrlInExternalBrowser(this@TestLinkifyActivity, uri)
|
||||
}
|
||||
.show()
|
||||
}
|
||||
})
|
||||
*/
|
||||
|
||||
// TODO Call VectorLinkify.addLinks(text)
|
||||
}
|
||||
|
||||
scrollContent.addView(item, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2019 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.debug.sas
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.configureWith
|
||||
import im.vector.matrix.android.api.crypto.getAllVerificationEmojis
|
||||
import kotlinx.android.synthetic.main.fragment_generic_recycler.*
|
||||
|
||||
class DebugSasEmojiActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.fragment_generic_recycler)
|
||||
val controller = SasEmojiController()
|
||||
recyclerView.configureWith(controller)
|
||||
controller.setData(SasState(getAllVerificationEmojis()))
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
recyclerView.cleanup()
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2019 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.debug.sas
|
||||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import im.vector.matrix.android.api.session.crypto.verification.EmojiRepresentation
|
||||
|
||||
data class SasState(
|
||||
val emojiList: List<EmojiRepresentation>
|
||||
)
|
||||
|
||||
class SasEmojiController : TypedEpoxyController<SasState>() {
|
||||
|
||||
override fun buildModels(data: SasState?) {
|
||||
if (data == null) return
|
||||
|
||||
data.emojiList.forEachIndexed { idx, emojiRepresentation ->
|
||||
sasEmojiItem {
|
||||
id(idx)
|
||||
index(idx)
|
||||
emojiRepresentation(emojiRepresentation)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2019 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.debug.sas
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.matrix.android.api.session.crypto.verification.EmojiRepresentation
|
||||
import me.gujun.android.span.image
|
||||
import me.gujun.android.span.span
|
||||
|
||||
@EpoxyModelClass(layout = im.vector.app.R.layout.item_sas_emoji)
|
||||
abstract class SasEmojiItem : VectorEpoxyModel<SasEmojiItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
var index: Int = 0
|
||||
@EpoxyAttribute
|
||||
lateinit var emojiRepresentation: EmojiRepresentation
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.indexView.text = "$index:"
|
||||
holder.emojiView.text = span {
|
||||
+emojiRepresentation.emoji
|
||||
emojiRepresentation.drawableRes?.let {
|
||||
image(ContextCompat.getDrawable(holder.view.context, it)!!)
|
||||
}
|
||||
}
|
||||
holder.textView.setText(emojiRepresentation.nameResId)
|
||||
holder.idView.text = holder.idView.resources.getResourceEntryName(emojiRepresentation.nameResId)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val indexView by bind<TextView>(im.vector.app.R.id.sas_emoji_index)
|
||||
val emojiView by bind<TextView>(im.vector.app.R.id.sas_emoji)
|
||||
val textView by bind<TextView>(im.vector.app.R.id.sas_emoji_text)
|
||||
val idView by bind<TextView>(im.vector.app.R.id.sas_emoji_text_id)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright 2019 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.receivers
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import im.vector.app.core.utils.lsFiles
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* Receiver to handle some command from ADB
|
||||
*/
|
||||
class DebugReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
Timber.v("Received debug action: ${intent.action}")
|
||||
|
||||
intent.action?.let {
|
||||
when {
|
||||
it.endsWith(DEBUG_ACTION_DUMP_FILESYSTEM) -> lsFiles(context)
|
||||
it.endsWith(DEBUG_ACTION_DUMP_PREFERENCES) -> dumpPreferences(context)
|
||||
it.endsWith(DEBUG_ACTION_ALTER_SCALAR_TOKEN) -> alterScalarToken(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun dumpPreferences(context: Context) {
|
||||
logPrefs("DefaultSharedPreferences", PreferenceManager.getDefaultSharedPreferences(context))
|
||||
}
|
||||
|
||||
private fun logPrefs(name: String, sharedPreferences: SharedPreferences?) {
|
||||
Timber.v("SharedPreferences $name:")
|
||||
|
||||
sharedPreferences?.let { prefs ->
|
||||
prefs.all.keys.forEach { key ->
|
||||
Timber.v("$key : ${prefs.all[key]}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun alterScalarToken(context: Context) {
|
||||
PreferenceManager.getDefaultSharedPreferences(context).edit {
|
||||
// putString("SCALAR_TOKEN_PREFERENCE_KEY" + Matrix.getInstance(context).defaultSession.myUserId, "bad_token")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val DEBUG_ACTION_DUMP_FILESYSTEM = ".DEBUG_ACTION_DUMP_FILESYSTEM"
|
||||
private const val DEBUG_ACTION_DUMP_PREFERENCES = ".DEBUG_ACTION_DUMP_PREFERENCES"
|
||||
private const val DEBUG_ACTION_ALTER_SCALAR_TOKEN = ".DEBUG_ACTION_ALTER_SCALAR_TOKEN"
|
||||
|
||||
fun getIntentFilter(context: Context) = IntentFilter().apply {
|
||||
addAction(context.packageName + DEBUG_ACTION_DUMP_FILESYSTEM)
|
||||
addAction(context.packageName + DEBUG_ACTION_DUMP_PREFERENCES)
|
||||
addAction(context.packageName + DEBUG_ACTION_ALTER_SCALAR_TOKEN)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 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.riotx.features.debug
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.utils.toast
|
||||
import kotlinx.android.synthetic.debug.activity_test_material_theme.*
|
||||
|
||||
// Rendering is not the same with VectorBaseActivity
|
||||
abstract class DebugMaterialThemeActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_test_material_theme)
|
||||
|
||||
debugShowSnackbar.setOnClickListener {
|
||||
Snackbar.make(debugMaterialCoordinator, "Snackbar!", Snackbar.LENGTH_SHORT)
|
||||
.setAction("Action") { }
|
||||
.show()
|
||||
}
|
||||
|
||||
debugShowToast.setOnClickListener {
|
||||
toast("Toast")
|
||||
}
|
||||
|
||||
debugShowDialog.setOnClickListener {
|
||||
AlertDialog.Builder(this)
|
||||
.setMessage("Dialog content")
|
||||
.setIcon(R.drawable.ic_settings_x)
|
||||
.setPositiveButton("Positive", null)
|
||||
.setNegativeButton("Negative", null)
|
||||
.setNeutralButton("Neutral", null)
|
||||
.show()
|
||||
}
|
||||
|
||||
debugShowBottomSheet.setOnClickListener {
|
||||
BottomSheetDialogFragment().show(supportFragmentManager, "TAG")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.home, menu)
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 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.riotx.features.debug
|
||||
|
||||
class DebugMaterialThemeDarkActivity : DebugMaterialThemeActivity()
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 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.riotx.features.debug
|
||||
|
||||
class DebugMaterialThemeLightActivity : DebugMaterialThemeActivity()
|
|
@ -1,231 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 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.riotx.features.debug
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.Person
|
||||
import butterknife.OnClick
|
||||
import im.vector.matrix.android.internal.crypto.verification.qrcode.toQrCodeData
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.di.ActiveSessionHolder
|
||||
import im.vector.riotx.core.di.ScreenComponent
|
||||
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||
import im.vector.riotx.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||
import im.vector.riotx.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA
|
||||
import im.vector.riotx.core.utils.allGranted
|
||||
import im.vector.riotx.core.utils.checkPermissions
|
||||
import im.vector.riotx.core.utils.toast
|
||||
import im.vector.riotx.features.debug.sas.DebugSasEmojiActivity
|
||||
import im.vector.riotx.features.qrcode.QrCodeScannerActivity
|
||||
import kotlinx.android.synthetic.debug.activity_debug_menu.*
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class DebugMenuActivity : VectorBaseActivity() {
|
||||
|
||||
override fun getLayoutRes() = R.layout.activity_debug_menu
|
||||
|
||||
@Inject
|
||||
lateinit var activeSessionHolder: ActiveSessionHolder
|
||||
|
||||
override fun injectWith(injector: ScreenComponent) {
|
||||
injector.inject(this)
|
||||
}
|
||||
|
||||
private lateinit var buffer: ByteArray
|
||||
|
||||
override fun initUiAndData() {
|
||||
// renderQrCode("https://www.example.org")
|
||||
|
||||
buffer = ByteArray(256)
|
||||
for (i in buffer.indices) {
|
||||
buffer[i] = i.toByte()
|
||||
}
|
||||
|
||||
val string = buffer.toString(Charsets.ISO_8859_1)
|
||||
|
||||
renderQrCode(string)
|
||||
}
|
||||
|
||||
private fun renderQrCode(text: String) {
|
||||
debug_qr_code.setData(text, true)
|
||||
}
|
||||
|
||||
@OnClick(R.id.debug_test_text_view_link)
|
||||
fun testTextViewLink() {
|
||||
startActivity(Intent(this, TestLinkifyActivity::class.java))
|
||||
}
|
||||
|
||||
@OnClick(R.id.debug_show_sas_emoji)
|
||||
fun showSasEmoji() {
|
||||
startActivity(Intent(this, DebugSasEmojiActivity::class.java))
|
||||
}
|
||||
|
||||
@OnClick(R.id.debug_test_notification)
|
||||
fun testNotification() {
|
||||
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
// Create channel first
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val channel =
|
||||
NotificationChannel(
|
||||
"CHAN",
|
||||
"Channel name",
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
)
|
||||
|
||||
channel.description = "Channel description"
|
||||
(getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).createNotificationChannel(channel)
|
||||
|
||||
val channel2 =
|
||||
NotificationChannel(
|
||||
"CHAN2",
|
||||
"Channel name 2",
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
)
|
||||
|
||||
channel2.description = "Channel description 2"
|
||||
(getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).createNotificationChannel(channel2)
|
||||
}
|
||||
|
||||
val builder = NotificationCompat.Builder(this, "CHAN")
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setContentTitle("Title")
|
||||
.setContentText("Content")
|
||||
// No effect because it's a group summary notif
|
||||
.setNumber(33)
|
||||
.setSmallIcon(R.drawable.ic_status_bar)
|
||||
// This provocate the badge issue: no badge for group notification
|
||||
.setGroup("GroupKey")
|
||||
.setGroupSummary(true)
|
||||
|
||||
val messagingStyle1 = NotificationCompat.MessagingStyle(
|
||||
Person.Builder()
|
||||
.setName("User name")
|
||||
.build()
|
||||
)
|
||||
.addMessage("Message 1 - 1", System.currentTimeMillis(), Person.Builder().setName("user 1-1").build())
|
||||
.addMessage("Message 1 - 2", System.currentTimeMillis(), Person.Builder().setName("user 1-2").build())
|
||||
|
||||
val messagingStyle2 = NotificationCompat.MessagingStyle(
|
||||
Person.Builder()
|
||||
.setName("User name 2")
|
||||
.build()
|
||||
)
|
||||
.addMessage("Message 2 - 1", System.currentTimeMillis(), Person.Builder().setName("user 1-1").build())
|
||||
.addMessage("Message 2 - 2", System.currentTimeMillis(), Person.Builder().setName("user 1-2").build())
|
||||
|
||||
notificationManager.notify(10, builder.build())
|
||||
|
||||
notificationManager.notify(
|
||||
11,
|
||||
NotificationCompat.Builder(this, "CHAN")
|
||||
.setChannelId("CHAN")
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setContentTitle("Title 1")
|
||||
.setContentText("Content 1")
|
||||
// For shortcut on long press on launcher icon
|
||||
.setBadgeIconType(NotificationCompat.BADGE_ICON_NONE)
|
||||
.setStyle(messagingStyle1)
|
||||
.setSmallIcon(R.drawable.ic_status_bar)
|
||||
.setGroup("GroupKey")
|
||||
.build()
|
||||
)
|
||||
|
||||
notificationManager.notify(
|
||||
12,
|
||||
NotificationCompat.Builder(this, "CHAN2")
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setContentTitle("Title 2")
|
||||
.setContentText("Content 2")
|
||||
.setStyle(messagingStyle2)
|
||||
.setSmallIcon(R.drawable.ic_status_bar)
|
||||
.setGroup("GroupKey")
|
||||
.build()
|
||||
)
|
||||
}
|
||||
|
||||
@OnClick(R.id.debug_test_material_theme_light)
|
||||
fun testMaterialThemeLight() {
|
||||
startActivity(Intent(this, DebugMaterialThemeLightActivity::class.java))
|
||||
}
|
||||
|
||||
@OnClick(R.id.debug_test_material_theme_dark)
|
||||
fun testMaterialThemeDark() {
|
||||
startActivity(Intent(this, DebugMaterialThemeDarkActivity::class.java))
|
||||
}
|
||||
|
||||
@OnClick(R.id.debug_test_crash)
|
||||
fun testCrash() {
|
||||
throw RuntimeException("Application crashed from user demand")
|
||||
}
|
||||
|
||||
@OnClick(R.id.debug_scan_qr_code)
|
||||
fun scanQRCode() {
|
||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) {
|
||||
doScanQRCode()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
|
||||
if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA && allGranted(grantResults)) {
|
||||
doScanQRCode()
|
||||
}
|
||||
}
|
||||
|
||||
private fun doScanQRCode() {
|
||||
QrCodeScannerActivity.startForResult(this)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
QrCodeScannerActivity.QR_CODE_SCANNER_REQUEST_CODE -> {
|
||||
toast("QrCode: " + QrCodeScannerActivity.getResultText(data) + " is QRCode: " + QrCodeScannerActivity.getResultIsQrCode(data))
|
||||
|
||||
// Also update the current QR Code (reverse operation)
|
||||
// renderQrCode(QrCodeScannerActivity.getResultText(data) ?: "")
|
||||
val result = QrCodeScannerActivity.getResultText(data)!!
|
||||
|
||||
val qrCodeData = result.toQrCodeData()
|
||||
Timber.e("qrCodeData: $qrCodeData")
|
||||
|
||||
if (result.length != buffer.size) {
|
||||
Timber.e("Error, length are not the same")
|
||||
} else {
|
||||
// Convert to ByteArray
|
||||
val byteArrayResult = result.toByteArray(Charsets.ISO_8859_1)
|
||||
for (i in byteArrayResult.indices) {
|
||||
if (buffer[i] != byteArrayResult[i]) {
|
||||
Timber.e("Error for byte $i, expecting ${buffer[i]} and get ${byteArrayResult[i]}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,131 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 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.riotx.features.debug
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import im.vector.riotx.R
|
||||
|
||||
class TestLinkifyActivity : AppCompatActivity() {
|
||||
|
||||
@BindView(R.id.test_linkify_content_view)
|
||||
lateinit var scrollContent: LinearLayout
|
||||
|
||||
@BindView(R.id.test_linkify_coordinator)
|
||||
lateinit var coordinatorLayout: CoordinatorLayout
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_test_linkify)
|
||||
ButterKnife.bind(this)
|
||||
|
||||
scrollContent.removeAllViews()
|
||||
|
||||
listOf(
|
||||
"https://www.html5rocks.com/en/tutorials/webrtc/basics/ |",
|
||||
"https://www.html5rocks.com/en/tutorials/webrtc/basics/",
|
||||
"mailto mailto:test@toto.com test@toto.com",
|
||||
"Here is the link.www.test.com/foo/?23=35 you got it?",
|
||||
"www.lemonde.fr",
|
||||
" /www.lemonde.fr",
|
||||
"://www.lemonde.fr",
|
||||
"file:///dev/null ",
|
||||
" ansible/xoxys.matrix#2c0b65eb",
|
||||
"foo.ansible/xoxys.matrix#2c0b65eb",
|
||||
"foo.ansible.fpo/xoxys.matrix#2c0b65eb",
|
||||
"https://foo.ansible.fpo/xoxys.matrix#2c0b65eb",
|
||||
"@vf:matrix.org",
|
||||
"+44 207 123 1234",
|
||||
"+33141437940",
|
||||
"1234",
|
||||
"3456.34,089",
|
||||
"ksks9808",
|
||||
"For example: geo:48.85828,2.29449?z=16 should be clickable",
|
||||
"geo:37.786971,-122.399677;u=35",
|
||||
"37.786971,-122.399677;u=35",
|
||||
"48.107864,-1.712153",
|
||||
"synchrone peut tenir la route la",
|
||||
"that.is.some.sexy.link",
|
||||
"test overlap 48.107864,0673728392 geo + pn?",
|
||||
"test overlap 0673728392,48.107864 geo + pn?",
|
||||
"If I add a link in brackets like (help for Riot: https://about.riot.im/help), the link is usable on Riot for Desktop",
|
||||
"(help for Riot: https://about.riot.im/help)",
|
||||
"http://example.com/test(1).html",
|
||||
"http://example.com/test(1)",
|
||||
"https://about.riot.im/help)",
|
||||
"(http://example.com/test(1))",
|
||||
"http://example.com/test1)",
|
||||
"http://example.com/test1/, et ca",
|
||||
"www.example.com/, et ca",
|
||||
"foo.ansible.toplevel/xoxys.matrix#2c0b65eb",
|
||||
"foo.ansible.ninja/xoxys.matrix#2c0b65eb",
|
||||
"in brackets like (help for Riot: https://www.exemple/com/find(1)) , the link is usable ",
|
||||
"""
|
||||
In brackets like (help for Riot: https://about.riot.im/help) , the link is usable,
|
||||
But you can call +44 207 123 1234 and come to 37.786971,-122.399677;u=35 then
|
||||
see if this mail jhon@riot.im is active but this should not 12345
|
||||
""".trimIndent()
|
||||
)
|
||||
.forEach { textContent ->
|
||||
val item = LayoutInflater.from(this)
|
||||
.inflate(R.layout.item_test_linkify, scrollContent, false)
|
||||
|
||||
item.findViewById<TextView>(R.id.test_linkify_auto_text)
|
||||
?.apply {
|
||||
text = textContent
|
||||
/* TODO Use BetterLinkMovementMethod when the other PR is merged
|
||||
movementMethod = MatrixLinkMovementMethod(object : MockMessageAdapterActionListener() {
|
||||
override fun onURLClick(uri: Uri?) {
|
||||
Snackbar.make(coordinatorLayout, "URI Clicked: $uri", Snackbar.LENGTH_LONG)
|
||||
.setAction("open") {
|
||||
openUrlInExternalBrowser(this@TestLinkifyActivity, uri)
|
||||
}
|
||||
.show()
|
||||
}
|
||||
})
|
||||
*/
|
||||
}
|
||||
|
||||
item.findViewById<TextView>(R.id.test_linkify_custom_text)
|
||||
?.apply {
|
||||
text = textContent
|
||||
/* TODO Use BetterLinkMovementMethod when the other PR is merged
|
||||
movementMethod = MatrixLinkMovementMethod(object : MockMessageAdapterActionListener() {
|
||||
override fun onURLClick(uri: Uri?) {
|
||||
Snackbar.make(coordinatorLayout, "URI Clicked: $uri", Snackbar.LENGTH_LONG)
|
||||
.setAction("open") {
|
||||
openUrlInExternalBrowser(this@TestLinkifyActivity, uri)
|
||||
}
|
||||
.show()
|
||||
}
|
||||
})
|
||||
*/
|
||||
|
||||
// TODO Call VectorLinkify.addLinks(text)
|
||||
}
|
||||
|
||||
scrollContent.addView(item, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 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.riotx.features.debug.sas
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import im.vector.matrix.android.api.crypto.getAllVerificationEmojis
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.extensions.cleanup
|
||||
import im.vector.riotx.core.extensions.configureWith
|
||||
import kotlinx.android.synthetic.main.fragment_generic_recycler.*
|
||||
|
||||
class DebugSasEmojiActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.fragment_generic_recycler)
|
||||
val controller = SasEmojiController()
|
||||
recyclerView.configureWith(controller)
|
||||
controller.setData(SasState(getAllVerificationEmojis()))
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
recyclerView.cleanup()
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 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.riotx.features.debug.sas
|
||||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import im.vector.matrix.android.api.session.crypto.verification.EmojiRepresentation
|
||||
|
||||
data class SasState(
|
||||
val emojiList: List<EmojiRepresentation>
|
||||
)
|
||||
|
||||
class SasEmojiController : TypedEpoxyController<SasState>() {
|
||||
|
||||
override fun buildModels(data: SasState?) {
|
||||
if (data == null) return
|
||||
|
||||
data.emojiList.forEachIndexed { idx, emojiRepresentation ->
|
||||
sasEmojiItem {
|
||||
id(idx)
|
||||
index(idx)
|
||||
emojiRepresentation(emojiRepresentation)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 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.riotx.features.debug.sas
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.matrix.android.api.session.crypto.verification.EmojiRepresentation
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||
import me.gujun.android.span.image
|
||||
import me.gujun.android.span.span
|
||||
|
||||
@EpoxyModelClass(layout = im.vector.riotx.R.layout.item_sas_emoji)
|
||||
abstract class SasEmojiItem : VectorEpoxyModel<SasEmojiItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
var index: Int = 0
|
||||
@EpoxyAttribute
|
||||
lateinit var emojiRepresentation: EmojiRepresentation
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.indexView.text = "$index:"
|
||||
holder.emojiView.text = span {
|
||||
+emojiRepresentation.emoji
|
||||
emojiRepresentation.drawableRes?.let {
|
||||
image(ContextCompat.getDrawable(holder.view.context, it)!!)
|
||||
}
|
||||
}
|
||||
holder.textView.setText(emojiRepresentation.nameResId)
|
||||
holder.idView.text = holder.idView.resources.getResourceEntryName(emojiRepresentation.nameResId)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val indexView by bind<TextView>(im.vector.riotx.R.id.sas_emoji_index)
|
||||
val emojiView by bind<TextView>(im.vector.riotx.R.id.sas_emoji)
|
||||
val textView by bind<TextView>(im.vector.riotx.R.id.sas_emoji_text)
|
||||
val idView by bind<TextView>(im.vector.riotx.R.id.sas_emoji_text_id)
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 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.riotx.receivers
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.SharedPreferences
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.core.content.edit
|
||||
import im.vector.riotx.core.utils.lsFiles
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* Receiver to handle some command from ADB
|
||||
*/
|
||||
class DebugReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
Timber.v("Received debug action: ${intent.action}")
|
||||
|
||||
intent.action?.let {
|
||||
when {
|
||||
it.endsWith(DEBUG_ACTION_DUMP_FILESYSTEM) -> lsFiles(context)
|
||||
it.endsWith(DEBUG_ACTION_DUMP_PREFERENCES) -> dumpPreferences(context)
|
||||
it.endsWith(DEBUG_ACTION_ALTER_SCALAR_TOKEN) -> alterScalarToken(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun dumpPreferences(context: Context) {
|
||||
logPrefs("DefaultSharedPreferences", PreferenceManager.getDefaultSharedPreferences(context))
|
||||
}
|
||||
|
||||
private fun logPrefs(name: String, sharedPreferences: SharedPreferences?) {
|
||||
Timber.v("SharedPreferences $name:")
|
||||
|
||||
sharedPreferences?.let { prefs ->
|
||||
prefs.all.keys.forEach { key ->
|
||||
Timber.v("$key : ${prefs.all[key]}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun alterScalarToken(context: Context) {
|
||||
PreferenceManager.getDefaultSharedPreferences(context).edit {
|
||||
// putString("SCALAR_TOKEN_PREFERENCE_KEY" + Matrix.getInstance(context).defaultSession.myUserId, "bad_token")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val DEBUG_ACTION_DUMP_FILESYSTEM = ".DEBUG_ACTION_DUMP_FILESYSTEM"
|
||||
private const val DEBUG_ACTION_DUMP_PREFERENCES = ".DEBUG_ACTION_DUMP_PREFERENCES"
|
||||
private const val DEBUG_ACTION_ALTER_SCALAR_TOKEN = ".DEBUG_ACTION_ALTER_SCALAR_TOKEN"
|
||||
|
||||
fun getIntentFilter(context: Context) = IntentFilter().apply {
|
||||
addAction(context.packageName + DEBUG_ACTION_DUMP_FILESYSTEM)
|
||||
addAction(context.packageName + DEBUG_ACTION_DUMP_PREFERENCES)
|
||||
addAction(context.packageName + DEBUG_ACTION_ALTER_SCALAR_TOKEN)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="im.vector.riotx.features.debug.DebugMenuActivity"
|
||||
tools:context="im.vector.app.features.debug.DebugMenuActivity"
|
||||
tools:ignore="HardcodedText">
|
||||
|
||||
<ScrollView
|
||||
|
@ -68,7 +68,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:text="Scan QR-code" />
|
||||
|
||||
<im.vector.riotx.core.ui.views.QrCodeImageView
|
||||
<im.vector.app.core.ui.views.QrCodeImageView
|
||||
android:id="@+id/debug_qr_code"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="200dp"
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/riot_secondary_text_color_status"
|
||||
tools:context="im.vector.riotx.features.debug.TestLinkifyActivity">
|
||||
tools:context="im.vector.app.features.debug.TestLinkifyActivity">
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="im.vector.riotx">
|
||||
package="im.vector.app">
|
||||
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 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
|
||||
|
||||
import android.content.Context
|
||||
|
||||
// No op
|
||||
fun openOssLicensesMenuActivity(@Suppress("UNUSED_PARAMETER") context: Context) = Unit
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2018 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.fdroid.features.settings.troubleshoot
|
||||
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import im.vector.app.features.settings.troubleshoot.TroubleshootTest
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Test that the application is started on boot
|
||||
*/
|
||||
class TestAutoStartBoot @Inject constructor(private val vectorPreferences: VectorPreferences,
|
||||
private val stringProvider: StringProvider)
|
||||
: TroubleshootTest(R.string.settings_troubleshoot_test_service_boot_title) {
|
||||
|
||||
override fun perform() {
|
||||
if (vectorPreferences.autoStartOnBoot()) {
|
||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_service_boot_success)
|
||||
status = TestStatus.SUCCESS
|
||||
quickFix = null
|
||||
} else {
|
||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_service_boot_failed)
|
||||
quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_service_boot_quickfix) {
|
||||
override fun doFix() {
|
||||
vectorPreferences.setAutoStartOnBoot(true)
|
||||
manager?.retry()
|
||||
}
|
||||
}
|
||||
status = TestStatus.FAILED
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright 2018 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.fdroid.features.settings.troubleshoot
|
||||
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.net.ConnectivityManagerCompat
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.settings.troubleshoot.TroubleshootTest
|
||||
import javax.inject.Inject
|
||||
|
||||
class TestBackgroundRestrictions @Inject constructor(private val context: AppCompatActivity,
|
||||
private val stringProvider: StringProvider)
|
||||
: TroubleshootTest(R.string.settings_troubleshoot_test_bg_restricted_title) {
|
||||
|
||||
override fun perform() {
|
||||
(context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).apply {
|
||||
// Checks if the device is on a metered network
|
||||
if (isActiveNetworkMetered) {
|
||||
// Checks user’s Data Saver settings.
|
||||
when (ConnectivityManagerCompat.getRestrictBackgroundStatus(this)) {
|
||||
ConnectivityManagerCompat.RESTRICT_BACKGROUND_STATUS_ENABLED -> {
|
||||
// Background data usage is blocked for this app. Wherever possible,
|
||||
// the app should also use less data in the foreground.
|
||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_bg_restricted_failed,
|
||||
"RESTRICT_BACKGROUND_STATUS_ENABLED")
|
||||
status = TestStatus.FAILED
|
||||
quickFix = null
|
||||
}
|
||||
ConnectivityManagerCompat.RESTRICT_BACKGROUND_STATUS_WHITELISTED -> {
|
||||
// The app is whitelisted. Wherever possible,
|
||||
// the app should use less data in the foreground and background.
|
||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_bg_restricted_success,
|
||||
"RESTRICT_BACKGROUND_STATUS_WHITELISTED")
|
||||
status = TestStatus.SUCCESS
|
||||
quickFix = null
|
||||
}
|
||||
ConnectivityManagerCompat.RESTRICT_BACKGROUND_STATUS_DISABLED -> {
|
||||
// Data Saver is disabled. Since the device is connected to a
|
||||
// metered network, the app should use less data wherever possible.
|
||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_bg_restricted_success,
|
||||
"RESTRICT_BACKGROUND_STATUS_DISABLED")
|
||||
status = TestStatus.SUCCESS
|
||||
quickFix = null
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The device is not on a metered network.
|
||||
// Use data as required to perform syncs, downloads, and updates.
|
||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_bg_restricted_success, "")
|
||||
status = TestStatus.SUCCESS
|
||||
quickFix = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2018 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.fdroid.features.settings.troubleshoot
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.utils.isIgnoringBatteryOptimizations
|
||||
import im.vector.app.core.utils.requestDisablingBatteryOptimization
|
||||
import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager
|
||||
import im.vector.app.features.settings.troubleshoot.TroubleshootTest
|
||||
|
||||
// Not used anymore
|
||||
class TestBatteryOptimization(val fragment: Fragment) : TroubleshootTest(R.string.settings_troubleshoot_test_battery_title) {
|
||||
|
||||
override fun perform() {
|
||||
val context = fragment.context
|
||||
if (context != null && isIgnoringBatteryOptimizations(context)) {
|
||||
description = fragment.getString(R.string.settings_troubleshoot_test_battery_success)
|
||||
status = TestStatus.SUCCESS
|
||||
quickFix = null
|
||||
} else {
|
||||
description = fragment.getString(R.string.settings_troubleshoot_test_battery_failed)
|
||||
quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_battery_quickfix) {
|
||||
override fun doFix() {
|
||||
fragment.activity?.let {
|
||||
requestDisablingBatteryOptimization(it, fragment, NotificationTroubleshootTestManager.REQ_CODE_FIX)
|
||||
}
|
||||
}
|
||||
}
|
||||
status = TestStatus.FAILED
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright 2019 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Code exclusively used by the FDroid build and not referenced on the main source code
|
||||
*/
|
||||
package im.vector.app.fdroid
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright 2019 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.fdroid.receiver
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.PowerManager
|
||||
import androidx.core.content.ContextCompat
|
||||
import im.vector.app.core.di.HasVectorInjector
|
||||
import im.vector.app.core.services.VectorSyncService
|
||||
import im.vector.matrix.android.internal.session.sync.job.SyncService
|
||||
import timber.log.Timber
|
||||
|
||||
class AlarmSyncBroadcastReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val appContext = context.applicationContext
|
||||
if (appContext is HasVectorInjector) {
|
||||
val activeSession = appContext.injector().activeSessionHolder().getSafeActiveSession()
|
||||
if (activeSession == null) {
|
||||
Timber.v("No active session don't launch sync service.")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Acquire a lock to give enough time for the sync :/
|
||||
(context.getSystemService(Context.POWER_SERVICE) as PowerManager).run {
|
||||
newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "riotx:fdroidSynclock").apply {
|
||||
acquire((10_000).toLong())
|
||||
}
|
||||
}
|
||||
|
||||
val sessionId = intent.getStringExtra(SyncService.EXTRA_SESSION_ID) ?: return
|
||||
// This method is called when the BroadcastReceiver is receiving an Intent broadcast.
|
||||
Timber.d("RestartBroadcastReceiver received intent")
|
||||
VectorSyncService.newIntent(context, sessionId).let {
|
||||
try {
|
||||
ContextCompat.startForegroundService(context, it)
|
||||
} catch (ex: Throwable) {
|
||||
// TODO
|
||||
Timber.e(ex)
|
||||
}
|
||||
}
|
||||
|
||||
scheduleAlarm(context, sessionId, 30_000L)
|
||||
Timber.i("Alarm scheduled to restart service")
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val REQUEST_CODE = 0
|
||||
|
||||
fun scheduleAlarm(context: Context, sessionId: String, delay: Long) {
|
||||
// Reschedule
|
||||
val intent = Intent(context, AlarmSyncBroadcastReceiver::class.java).apply {
|
||||
putExtra(SyncService.EXTRA_SESSION_ID, sessionId)
|
||||
}
|
||||
val pIntent = PendingIntent.getBroadcast(context, REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
val firstMillis = System.currentTimeMillis() + delay
|
||||
val alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, firstMillis, pIntent)
|
||||
} else {
|
||||
alarmMgr.set(AlarmManager.RTC_WAKEUP, firstMillis, pIntent)
|
||||
}
|
||||
}
|
||||
|
||||
fun cancelAlarm(context: Context) {
|
||||
Timber.v("Cancel alarm")
|
||||
val intent = Intent(context, AlarmSyncBroadcastReceiver::class.java)
|
||||
val pIntent = PendingIntent.getBroadcast(context, REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
val alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
alarmMgr.cancel(pIntent)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2018 New Vector Ltd
|
||||
* Copyright 2019 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.fdroid.receiver
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import im.vector.app.core.di.HasVectorInjector
|
||||
import timber.log.Timber
|
||||
|
||||
class OnApplicationUpgradeOrRebootReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
Timber.v("## onReceive() ${intent.action}")
|
||||
val appContext = context.applicationContext
|
||||
if (appContext is HasVectorInjector) {
|
||||
val activeSession = appContext.injector().activeSessionHolder().getSafeActiveSession()
|
||||
if (activeSession != null) {
|
||||
AlarmSyncBroadcastReceiver.scheduleAlarm(context, activeSession.sessionId, 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright 2014 OpenMarket Ltd
|
||||
* Copyright 2018 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.
|
||||
*/
|
||||
@file:Suppress("UNUSED_PARAMETER")
|
||||
|
||||
package im.vector.app.push.fcm
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.pushers.PushersManager
|
||||
import im.vector.app.fdroid.receiver.AlarmSyncBroadcastReceiver
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* This class has an alter ego in the gplay variant.
|
||||
*/
|
||||
object FcmHelper {
|
||||
|
||||
fun isPushSupported(): Boolean = false
|
||||
|
||||
/**
|
||||
* Retrieves the FCM registration token.
|
||||
*
|
||||
* @return the FCM token or null if not received from FCM
|
||||
*/
|
||||
fun getFcmToken(context: Context): String? {
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Store FCM token to the SharedPrefs
|
||||
*
|
||||
* @param context android context
|
||||
* @param token the token to store
|
||||
*/
|
||||
fun storeFcmToken(context: Context, token: String?) {
|
||||
// No op
|
||||
}
|
||||
|
||||
/**
|
||||
* onNewToken may not be called on application upgrade, so ensure my shared pref is set
|
||||
*
|
||||
* @param activity the first launch Activity
|
||||
*/
|
||||
fun ensureFcmTokenIsRetrieved(activity: Activity, pushersManager: PushersManager, registerPusher: Boolean) {
|
||||
// No op
|
||||
}
|
||||
|
||||
fun onEnterForeground(context: Context) {
|
||||
AlarmSyncBroadcastReceiver.cancelAlarm(context)
|
||||
}
|
||||
|
||||
fun onEnterBackground(context: Context, vectorPreferences: VectorPreferences, activeSessionHolder: ActiveSessionHolder) {
|
||||
// We need to use alarm in this mode
|
||||
if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) {
|
||||
val currentSession = activeSessionHolder.getActiveSession()
|
||||
AlarmSyncBroadcastReceiver.scheduleAlarm(context, currentSession.sessionId, 4_000L)
|
||||
Timber.i("Alarm scheduled to restart service")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2018 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.push.fcm
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import im.vector.app.fdroid.features.settings.troubleshoot.TestAutoStartBoot
|
||||
import im.vector.app.fdroid.features.settings.troubleshoot.TestBackgroundRestrictions
|
||||
import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager
|
||||
import im.vector.app.features.settings.troubleshoot.TestAccountSettings
|
||||
import im.vector.app.features.settings.troubleshoot.TestDeviceSettings
|
||||
import im.vector.app.features.settings.troubleshoot.TestPushRulesSettings
|
||||
import im.vector.app.features.settings.troubleshoot.TestSystemSettings
|
||||
import javax.inject.Inject
|
||||
|
||||
class NotificationTroubleshootTestManagerFactory @Inject constructor(private val testSystemSettings: TestSystemSettings,
|
||||
private val testAccountSettings: TestAccountSettings,
|
||||
private val testDeviceSettings: TestDeviceSettings,
|
||||
private val testPushRulesSettings: TestPushRulesSettings,
|
||||
private val testAutoStartBoot: TestAutoStartBoot,
|
||||
private val testBackgroundRestrictions: TestBackgroundRestrictions) {
|
||||
|
||||
fun create(fragment: Fragment): NotificationTroubleshootTestManager {
|
||||
val mgr = NotificationTroubleshootTestManager(fragment)
|
||||
mgr.addTest(testSystemSettings)
|
||||
mgr.addTest(testAccountSettings)
|
||||
mgr.addTest(testDeviceSettings)
|
||||
mgr.addTest(testPushRulesSettings)
|
||||
mgr.addTest(testAutoStartBoot)
|
||||
mgr.addTest(testBackgroundRestrictions)
|
||||
return mgr
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
* Copyright 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.riotx
|
||||
|
||||
import android.content.Context
|
||||
|
||||
// No op
|
||||
fun openOssLicensesMenuActivity(@Suppress("UNUSED_PARAMETER") context: Context) = Unit
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* Copyright 2018 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.riotx.fdroid.features.settings.troubleshoot
|
||||
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.resources.StringProvider
|
||||
import im.vector.riotx.features.settings.VectorPreferences
|
||||
import im.vector.riotx.features.settings.troubleshoot.TroubleshootTest
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Test that the application is started on boot
|
||||
*/
|
||||
class TestAutoStartBoot @Inject constructor(private val vectorPreferences: VectorPreferences,
|
||||
private val stringProvider: StringProvider)
|
||||
: TroubleshootTest(R.string.settings_troubleshoot_test_service_boot_title) {
|
||||
|
||||
override fun perform() {
|
||||
if (vectorPreferences.autoStartOnBoot()) {
|
||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_service_boot_success)
|
||||
status = TestStatus.SUCCESS
|
||||
quickFix = null
|
||||
} else {
|
||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_service_boot_failed)
|
||||
quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_service_boot_quickfix) {
|
||||
override fun doFix() {
|
||||
vectorPreferences.setAutoStartOnBoot(true)
|
||||
manager?.retry()
|
||||
}
|
||||
}
|
||||
status = TestStatus.FAILED
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* Copyright 2018 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.riotx.fdroid.features.settings.troubleshoot
|
||||
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.net.ConnectivityManagerCompat
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.resources.StringProvider
|
||||
import im.vector.riotx.features.settings.troubleshoot.TroubleshootTest
|
||||
import javax.inject.Inject
|
||||
|
||||
class TestBackgroundRestrictions @Inject constructor(private val context: AppCompatActivity,
|
||||
private val stringProvider: StringProvider)
|
||||
: TroubleshootTest(R.string.settings_troubleshoot_test_bg_restricted_title) {
|
||||
|
||||
override fun perform() {
|
||||
(context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).apply {
|
||||
// Checks if the device is on a metered network
|
||||
if (isActiveNetworkMetered) {
|
||||
// Checks user’s Data Saver settings.
|
||||
when (ConnectivityManagerCompat.getRestrictBackgroundStatus(this)) {
|
||||
ConnectivityManagerCompat.RESTRICT_BACKGROUND_STATUS_ENABLED -> {
|
||||
// Background data usage is blocked for this app. Wherever possible,
|
||||
// the app should also use less data in the foreground.
|
||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_bg_restricted_failed,
|
||||
"RESTRICT_BACKGROUND_STATUS_ENABLED")
|
||||
status = TestStatus.FAILED
|
||||
quickFix = null
|
||||
}
|
||||
ConnectivityManagerCompat.RESTRICT_BACKGROUND_STATUS_WHITELISTED -> {
|
||||
// The app is whitelisted. Wherever possible,
|
||||
// the app should use less data in the foreground and background.
|
||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_bg_restricted_success,
|
||||
"RESTRICT_BACKGROUND_STATUS_WHITELISTED")
|
||||
status = TestStatus.SUCCESS
|
||||
quickFix = null
|
||||
}
|
||||
ConnectivityManagerCompat.RESTRICT_BACKGROUND_STATUS_DISABLED -> {
|
||||
// Data Saver is disabled. Since the device is connected to a
|
||||
// metered network, the app should use less data wherever possible.
|
||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_bg_restricted_success,
|
||||
"RESTRICT_BACKGROUND_STATUS_DISABLED")
|
||||
status = TestStatus.SUCCESS
|
||||
quickFix = null
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The device is not on a metered network.
|
||||
// Use data as required to perform syncs, downloads, and updates.
|
||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_bg_restricted_success, "")
|
||||
status = TestStatus.SUCCESS
|
||||
quickFix = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright 2018 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.riotx.fdroid.features.settings.troubleshoot
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.utils.isIgnoringBatteryOptimizations
|
||||
import im.vector.riotx.core.utils.requestDisablingBatteryOptimization
|
||||
import im.vector.riotx.features.settings.troubleshoot.NotificationTroubleshootTestManager
|
||||
import im.vector.riotx.features.settings.troubleshoot.TroubleshootTest
|
||||
|
||||
// Not used anymore
|
||||
class TestBatteryOptimization(val fragment: Fragment) : TroubleshootTest(R.string.settings_troubleshoot_test_battery_title) {
|
||||
|
||||
override fun perform() {
|
||||
val context = fragment.context
|
||||
if (context != null && isIgnoringBatteryOptimizations(context)) {
|
||||
description = fragment.getString(R.string.settings_troubleshoot_test_battery_success)
|
||||
status = TestStatus.SUCCESS
|
||||
quickFix = null
|
||||
} else {
|
||||
description = fragment.getString(R.string.settings_troubleshoot_test_battery_failed)
|
||||
quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_battery_quickfix) {
|
||||
override fun doFix() {
|
||||
fragment.activity?.let {
|
||||
requestDisablingBatteryOptimization(it, fragment, NotificationTroubleshootTestManager.REQ_CODE_FIX)
|
||||
}
|
||||
}
|
||||
}
|
||||
status = TestStatus.FAILED
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Code exclusively used by the FDroid build and not referenced on the main source code
|
||||
*/
|
||||
package im.vector.riotx.fdroid
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 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.riotx.fdroid.receiver
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.PowerManager
|
||||
import androidx.core.content.ContextCompat
|
||||
import im.vector.matrix.android.internal.session.sync.job.SyncService
|
||||
import im.vector.riotx.core.di.HasVectorInjector
|
||||
import im.vector.riotx.core.services.VectorSyncService
|
||||
import timber.log.Timber
|
||||
|
||||
class AlarmSyncBroadcastReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val appContext = context.applicationContext
|
||||
if (appContext is HasVectorInjector) {
|
||||
val activeSession = appContext.injector().activeSessionHolder().getSafeActiveSession()
|
||||
if (activeSession == null) {
|
||||
Timber.v("No active session don't launch sync service.")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Acquire a lock to give enough time for the sync :/
|
||||
(context.getSystemService(Context.POWER_SERVICE) as PowerManager).run {
|
||||
newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "riotx:fdroidSynclock").apply {
|
||||
acquire((10_000).toLong())
|
||||
}
|
||||
}
|
||||
|
||||
val sessionId = intent.getStringExtra(SyncService.EXTRA_SESSION_ID) ?: return
|
||||
// This method is called when the BroadcastReceiver is receiving an Intent broadcast.
|
||||
Timber.d("RestartBroadcastReceiver received intent")
|
||||
VectorSyncService.newIntent(context, sessionId).let {
|
||||
try {
|
||||
ContextCompat.startForegroundService(context, it)
|
||||
} catch (ex: Throwable) {
|
||||
// TODO
|
||||
Timber.e(ex)
|
||||
}
|
||||
}
|
||||
|
||||
scheduleAlarm(context, sessionId, 30_000L)
|
||||
Timber.i("Alarm scheduled to restart service")
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val REQUEST_CODE = 0
|
||||
|
||||
fun scheduleAlarm(context: Context, sessionId: String, delay: Long) {
|
||||
// Reschedule
|
||||
val intent = Intent(context, AlarmSyncBroadcastReceiver::class.java).apply {
|
||||
putExtra(SyncService.EXTRA_SESSION_ID, sessionId)
|
||||
}
|
||||
val pIntent = PendingIntent.getBroadcast(context, REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
val firstMillis = System.currentTimeMillis() + delay
|
||||
val alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, firstMillis, pIntent)
|
||||
} else {
|
||||
alarmMgr.set(AlarmManager.RTC_WAKEUP, firstMillis, pIntent)
|
||||
}
|
||||
}
|
||||
|
||||
fun cancelAlarm(context: Context) {
|
||||
Timber.v("Cancel alarm")
|
||||
val intent = Intent(context, AlarmSyncBroadcastReceiver::class.java)
|
||||
val pIntent = PendingIntent.getBroadcast(context, REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
val alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
alarmMgr.cancel(pIntent)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* Copyright 2018 New Vector Ltd
|
||||
* Copyright 2019 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.riotx.fdroid.receiver
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import im.vector.riotx.core.di.HasVectorInjector
|
||||
import timber.log.Timber
|
||||
|
||||
class OnApplicationUpgradeOrRebootReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
Timber.v("## onReceive() ${intent.action}")
|
||||
val appContext = context.applicationContext
|
||||
if (appContext is HasVectorInjector) {
|
||||
val activeSession = appContext.injector().activeSessionHolder().getSafeActiveSession()
|
||||
if (activeSession != null) {
|
||||
AlarmSyncBroadcastReceiver.scheduleAlarm(context, activeSession.sessionId, 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
* Copyright 2014 OpenMarket Ltd
|
||||
* Copyright 2018 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.
|
||||
*/
|
||||
@file:Suppress("UNUSED_PARAMETER")
|
||||
|
||||
package im.vector.riotx.push.fcm
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import im.vector.riotx.core.di.ActiveSessionHolder
|
||||
import im.vector.riotx.core.pushers.PushersManager
|
||||
import im.vector.riotx.fdroid.receiver.AlarmSyncBroadcastReceiver
|
||||
import im.vector.riotx.features.settings.VectorPreferences
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* This class has an alter ego in the gplay variant.
|
||||
*/
|
||||
object FcmHelper {
|
||||
|
||||
fun isPushSupported(): Boolean = false
|
||||
|
||||
/**
|
||||
* Retrieves the FCM registration token.
|
||||
*
|
||||
* @return the FCM token or null if not received from FCM
|
||||
*/
|
||||
fun getFcmToken(context: Context): String? {
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Store FCM token to the SharedPrefs
|
||||
*
|
||||
* @param context android context
|
||||
* @param token the token to store
|
||||
*/
|
||||
fun storeFcmToken(context: Context, token: String?) {
|
||||
// No op
|
||||
}
|
||||
|
||||
/**
|
||||
* onNewToken may not be called on application upgrade, so ensure my shared pref is set
|
||||
*
|
||||
* @param activity the first launch Activity
|
||||
*/
|
||||
fun ensureFcmTokenIsRetrieved(activity: Activity, pushersManager: PushersManager, registerPusher: Boolean) {
|
||||
// No op
|
||||
}
|
||||
|
||||
fun onEnterForeground(context: Context) {
|
||||
AlarmSyncBroadcastReceiver.cancelAlarm(context)
|
||||
}
|
||||
|
||||
fun onEnterBackground(context: Context, vectorPreferences: VectorPreferences, activeSessionHolder: ActiveSessionHolder) {
|
||||
// We need to use alarm in this mode
|
||||
if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) {
|
||||
val currentSession = activeSessionHolder.getActiveSession()
|
||||
AlarmSyncBroadcastReceiver.scheduleAlarm(context, currentSession.sessionId, 4_000L)
|
||||
Timber.i("Alarm scheduled to restart service")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright 2018 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.riotx.push.fcm
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import im.vector.riotx.fdroid.features.settings.troubleshoot.TestAutoStartBoot
|
||||
import im.vector.riotx.fdroid.features.settings.troubleshoot.TestBackgroundRestrictions
|
||||
import im.vector.riotx.features.settings.troubleshoot.NotificationTroubleshootTestManager
|
||||
import im.vector.riotx.features.settings.troubleshoot.TestAccountSettings
|
||||
import im.vector.riotx.features.settings.troubleshoot.TestPushRulesSettings
|
||||
import im.vector.riotx.features.settings.troubleshoot.TestDeviceSettings
|
||||
import im.vector.riotx.features.settings.troubleshoot.TestSystemSettings
|
||||
import javax.inject.Inject
|
||||
|
||||
class NotificationTroubleshootTestManagerFactory @Inject constructor(private val testSystemSettings: TestSystemSettings,
|
||||
private val testAccountSettings: TestAccountSettings,
|
||||
private val testDeviceSettings: TestDeviceSettings,
|
||||
private val testPushRulesSettings: TestPushRulesSettings,
|
||||
private val testAutoStartBoot: TestAutoStartBoot,
|
||||
private val testBackgroundRestrictions: TestBackgroundRestrictions) {
|
||||
|
||||
fun create(fragment: Fragment): NotificationTroubleshootTestManager {
|
||||
val mgr = NotificationTroubleshootTestManager(fragment)
|
||||
mgr.addTest(testSystemSettings)
|
||||
mgr.addTest(testAccountSettings)
|
||||
mgr.addTest(testDeviceSettings)
|
||||
mgr.addTest(testPushRulesSettings)
|
||||
mgr.addTest(testAutoStartBoot)
|
||||
mgr.addTest(testBackgroundRestrictions)
|
||||
return mgr
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="im.vector.riotx">
|
||||
package="im.vector.app">
|
||||
|
||||
<application>
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="im.vector.riotx">
|
||||
package="im.vector.app">
|
||||
|
||||
<!-- Needed for VOIP call to detect and switch to headset-->
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
|
@ -38,7 +38,7 @@
|
|||
android:required="false" />
|
||||
|
||||
<application
|
||||
android:name=".VectorApplication"
|
||||
android:name="im.vector.app.VectorApplication"
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
|
@ -54,13 +54,13 @@
|
|||
android:value="9.9" />
|
||||
|
||||
<activity
|
||||
android:name=".features.MainActivity"
|
||||
android:name="im.vector.app.features.MainActivity"
|
||||
android:theme="@style/AppTheme.Launcher" />
|
||||
|
||||
<!-- Activity alias for the launcher Activity (must be declared after the Activity it targets) -->
|
||||
<activity-alias
|
||||
android:name=".features.Alias"
|
||||
android:targetActivity=".features.MainActivity">
|
||||
android:targetActivity="im.vector.app.features.MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
|
@ -68,9 +68,9 @@
|
|||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity android:name=".features.home.HomeActivity" />
|
||||
<activity android:name="im.vector.app.features.home.HomeActivity" />
|
||||
<activity
|
||||
android:name=".features.login.LoginActivity"
|
||||
android:name="im.vector.app.features.login.LoginActivity"
|
||||
android:launchMode="singleTask"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Add intent filter to handle redirection URL after SSO login in external browser -->
|
||||
|
@ -84,50 +84,50 @@
|
|||
<data android:host="element" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".features.media.ImageMediaViewerActivity" />
|
||||
<activity android:name="im.vector.app.features.media.ImageMediaViewerActivity" />
|
||||
|
||||
<activity
|
||||
android:name=".features.media.VectorAttachmentViewerActivity"
|
||||
android:name="im.vector.app.features.media.VectorAttachmentViewerActivity"
|
||||
android:theme="@style/AppTheme.Transparent" />
|
||||
|
||||
<activity android:name=".features.media.BigImageViewerActivity" />
|
||||
<activity android:name="im.vector.app.features.media.BigImageViewerActivity" />
|
||||
<activity
|
||||
android:name=".features.rageshake.BugReportActivity"
|
||||
android:name="im.vector.app.features.rageshake.BugReportActivity"
|
||||
android:label="@string/title_activity_bug_report" />
|
||||
<activity
|
||||
android:name=".features.settings.VectorSettingsActivity"
|
||||
android:name="im.vector.app.features.settings.VectorSettingsActivity"
|
||||
android:label="@string/title_activity_settings"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<activity android:name=".features.media.VideoMediaViewerActivity" />
|
||||
<activity android:name="im.vector.app.features.media.VideoMediaViewerActivity" />
|
||||
<activity
|
||||
android:name=".features.crypto.keysbackup.restore.KeysBackupRestoreActivity"
|
||||
android:name="im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivity"
|
||||
android:label="@string/title_activity_keys_backup_setup" />
|
||||
<activity
|
||||
android:name=".features.crypto.keysbackup.setup.KeysBackupSetupActivity"
|
||||
android:name="im.vector.app.features.crypto.keysbackup.setup.KeysBackupSetupActivity"
|
||||
android:label="@string/title_activity_keys_backup_restore" />
|
||||
<activity
|
||||
android:name=".features.crypto.keysbackup.settings.KeysBackupManageActivity"
|
||||
android:name="im.vector.app.features.crypto.keysbackup.settings.KeysBackupManageActivity"
|
||||
android:label="@string/encryption_message_recovery" />
|
||||
|
||||
<activity
|
||||
android:name=".features.reactions.EmojiReactionPickerActivity"
|
||||
android:name="im.vector.app.features.reactions.EmojiReactionPickerActivity"
|
||||
android:label="@string/title_activity_emoji_reaction_picker" />
|
||||
<activity android:name=".features.roomdirectory.createroom.CreateRoomActivity" />
|
||||
<activity android:name=".features.roomdirectory.RoomDirectoryActivity" />
|
||||
<activity android:name=".features.roomdirectory.roompreview.RoomPreviewActivity" />
|
||||
<activity android:name=".features.home.room.filtered.FilteredRoomsActivity" />
|
||||
<activity android:name="im.vector.app.features.roomdirectory.createroom.CreateRoomActivity" />
|
||||
<activity android:name="im.vector.app.features.roomdirectory.RoomDirectoryActivity" />
|
||||
<activity android:name="im.vector.app.features.roomdirectory.roompreview.RoomPreviewActivity" />
|
||||
<activity android:name="im.vector.app.features.home.room.filtered.FilteredRoomsActivity" />
|
||||
<activity
|
||||
android:name=".features.home.room.detail.RoomDetailActivity"
|
||||
android:parentActivityName=".features.home.HomeActivity">
|
||||
android:name="im.vector.app.features.home.room.detail.RoomDetailActivity"
|
||||
android:parentActivityName="im.vector.app.features.home.HomeActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".features.home.HomeActivity" />
|
||||
android:value="im.vector.app.features.home.HomeActivity" />
|
||||
</activity>
|
||||
<activity android:name=".features.debug.DebugMenuActivity" />
|
||||
<activity android:name="im.vector.riotx.features.createdirect.CreateDirectRoomActivity" />
|
||||
<activity android:name="im.vector.riotx.features.invite.InviteUsersToRoomActivity" />
|
||||
<activity android:name=".features.webview.VectorWebViewActivity" />
|
||||
<activity android:name=".features.link.LinkHandlerActivity">
|
||||
<activity android:name="im.vector.app.features.debug.DebugMenuActivity" />
|
||||
<activity android:name="im.vector.app.features.createdirect.CreateDirectRoomActivity" />
|
||||
<activity android:name="im.vector.app.features.invite.InviteUsersToRoomActivity" />
|
||||
<activity android:name="im.vector.app.features.webview.VectorWebViewActivity" />
|
||||
<activity android:name="im.vector.app.features.link.LinkHandlerActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
|
@ -142,11 +142,11 @@
|
|||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".features.share.IncomingShareActivity"
|
||||
android:parentActivityName=".features.home.HomeActivity">
|
||||
android:name="im.vector.app.features.share.IncomingShareActivity"
|
||||
android:parentActivityName="im.vector.app.features.home.HomeActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".features.home.HomeActivity" />
|
||||
android:value="im.vector.app.features.home.HomeActivity" />
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
|
@ -164,13 +164,13 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".features.roomprofile.RoomProfileActivity" />
|
||||
<activity android:name="im.vector.app.features.roomprofile.RoomProfileActivity" />
|
||||
|
||||
<activity android:name=".features.signout.hard.SignedOutActivity" />
|
||||
<activity android:name="im.vector.app.features.signout.hard.SignedOutActivity" />
|
||||
<activity
|
||||
android:name=".features.signout.soft.SoftLogoutActivity"
|
||||
android:name="im.vector.app.features.signout.soft.SoftLogoutActivity"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<activity android:name=".features.permalink.PermalinkHandlerActivity">
|
||||
<activity android:name="im.vector.app.features.permalink.PermalinkHandlerActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
|
@ -184,33 +184,33 @@
|
|||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".features.roommemberprofile.RoomMemberProfileActivity"
|
||||
android:parentActivityName=".features.home.HomeActivity">
|
||||
android:name="im.vector.app.features.roommemberprofile.RoomMemberProfileActivity"
|
||||
android:parentActivityName="im.vector.app.features.home.HomeActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".features.home.HomeActivity" />
|
||||
android:value="im.vector.app.features.home.HomeActivity" />
|
||||
</activity>
|
||||
|
||||
<activity android:name=".features.qrcode.QrCodeScannerActivity" />
|
||||
<activity android:name="im.vector.app.features.qrcode.QrCodeScannerActivity" />
|
||||
|
||||
<activity android:name=".features.crypto.quads.SharedSecureStorageActivity" />
|
||||
<activity android:name="im.vector.app.features.crypto.quads.SharedSecureStorageActivity" />
|
||||
<activity
|
||||
android:name="com.yalantis.ucrop.UCropActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".features.attachments.preview.AttachmentsPreviewActivity"
|
||||
android:name="im.vector.app.features.attachments.preview.AttachmentsPreviewActivity"
|
||||
android:theme="@style/AppTheme.AttachmentsPreview" />
|
||||
<activity android:name=".features.call.VectorCallActivity" />
|
||||
<activity android:name="im.vector.app.features.call.VectorCallActivity" />
|
||||
|
||||
<activity android:name=".features.terms.ReviewTermsActivity" />
|
||||
<activity android:name=".features.widgets.WidgetActivity" />
|
||||
<activity android:name=".features.pin.PinActivity" />
|
||||
<activity android:name="im.vector.app.features.terms.ReviewTermsActivity" />
|
||||
<activity android:name="im.vector.app.features.widgets.WidgetActivity" />
|
||||
<activity android:name="im.vector.app.features.pin.PinActivity" />
|
||||
|
||||
<!-- Services -->
|
||||
|
||||
<service
|
||||
android:name=".core.services.CallService"
|
||||
android:name="im.vector.app.core.services.CallService"
|
||||
android:exported="false">
|
||||
<!-- in order to get headset button events -->
|
||||
<intent-filter>
|
||||
|
@ -219,11 +219,11 @@
|
|||
</service>
|
||||
|
||||
<service
|
||||
android:name=".core.services.VectorSyncService"
|
||||
android:name="im.vector.app.core.services.VectorSyncService"
|
||||
android:exported="false" />
|
||||
|
||||
<service
|
||||
android:name=".features.call.telecom.VectorConnectionService"
|
||||
android:name="im.vector.app.features.call.telecom.VectorConnectionService"
|
||||
android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE">
|
||||
<intent-filter>
|
||||
<action android:name="android.telecom.ConnectionService" />
|
||||
|
@ -233,12 +233,12 @@
|
|||
<!-- Receivers -->
|
||||
|
||||
<receiver
|
||||
android:name=".features.call.service.CallHeadsUpActionReceiver"
|
||||
android:name="im.vector.app.features.call.service.CallHeadsUpActionReceiver"
|
||||
android:exported="false" />
|
||||
|
||||
<!-- Exported false, should only be accessible from this app!! -->
|
||||
<receiver
|
||||
android:name=".features.notifications.NotificationBroadcastReceiver"
|
||||
android:name="im.vector.app.features.notifications.NotificationBroadcastReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2019 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
|
||||
|
||||
import arrow.core.Option
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.app.core.utils.BehaviorDataSource
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class ActiveSessionDataSource @Inject constructor() : BehaviorDataSource<Option<Session>>()
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright 2019 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
|
||||
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.OnLifecycleEvent
|
||||
import arrow.core.Option
|
||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.roomSummaryQueryParams
|
||||
import im.vector.matrix.rx.rx
|
||||
import im.vector.app.features.grouplist.ALL_COMMUNITIES_GROUP_ID
|
||||
import im.vector.app.features.grouplist.SelectedGroupDataSource
|
||||
import im.vector.app.features.home.HomeRoomListDataSource
|
||||
import im.vector.app.features.home.room.list.ChronologicalRoomComparator
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.functions.BiFunction
|
||||
import io.reactivex.rxkotlin.addTo
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* This class handles the global app state. At the moment, it only manages room list.
|
||||
* It requires to be added to ProcessLifecycleOwner.get().lifecycle
|
||||
*/
|
||||
@Singleton
|
||||
class AppStateHandler @Inject constructor(
|
||||
private val sessionDataSource: ActiveSessionDataSource,
|
||||
private val homeRoomListDataSource: HomeRoomListDataSource,
|
||||
private val selectedGroupDataSource: SelectedGroupDataSource,
|
||||
private val chronologicalRoomComparator: ChronologicalRoomComparator) : LifecycleObserver {
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
||||
fun entersForeground() {
|
||||
observeRoomsAndGroup()
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
|
||||
fun entersBackground() {
|
||||
compositeDisposable.clear()
|
||||
}
|
||||
|
||||
private fun observeRoomsAndGroup() {
|
||||
Observable
|
||||
.combineLatest<List<RoomSummary>, Option<GroupSummary>, List<RoomSummary>>(
|
||||
sessionDataSource.observe()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.switchMap {
|
||||
val query = roomSummaryQueryParams {}
|
||||
it.orNull()?.rx()?.liveRoomSummaries(query)
|
||||
?: Observable.just(emptyList())
|
||||
}
|
||||
.throttleLast(300, TimeUnit.MILLISECONDS),
|
||||
selectedGroupDataSource.observe(),
|
||||
BiFunction { rooms, selectedGroupOption ->
|
||||
val selectedGroup = selectedGroupOption.orNull()
|
||||
val filteredRooms = rooms.filter {
|
||||
if (selectedGroup == null || selectedGroup.groupId == ALL_COMMUNITIES_GROUP_ID) {
|
||||
true
|
||||
} else if (it.isDirect) {
|
||||
it.otherMemberIds
|
||||
.intersect(selectedGroup.userIds)
|
||||
.isNotEmpty()
|
||||
} else {
|
||||
selectedGroup.roomIds.contains(it.roomId)
|
||||
}
|
||||
}
|
||||
filteredRooms.sortedWith(chronologicalRoomComparator)
|
||||
}
|
||||
)
|
||||
.subscribe {
|
||||
homeRoomListDataSource.post(it)
|
||||
}
|
||||
.addTo(compositeDisposable)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright 2019 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
|
||||
|
||||
import android.graphics.Typeface
|
||||
import androidx.core.provider.FontsContractCompat
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class EmojiCompatFontProvider @Inject constructor(): FontsContractCompat.FontRequestCallback() {
|
||||
|
||||
var typeface: Typeface? = null
|
||||
set(value) {
|
||||
if (value != field) {
|
||||
field = value
|
||||
listeners.forEach {
|
||||
try {
|
||||
it.compatibilityFontUpdate(value)
|
||||
} catch (t: Throwable) {
|
||||
Timber.e(t)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val listeners = ArrayList<FontProviderListener>()
|
||||
|
||||
override fun onTypefaceRetrieved(typeface: Typeface) {
|
||||
this.typeface = typeface
|
||||
}
|
||||
|
||||
override fun onTypefaceRequestFailed(reason: Int) {
|
||||
Timber.e("Failed to load Emoji Compatible font, reason:$reason")
|
||||
}
|
||||
|
||||
fun addListener(listener: FontProviderListener) {
|
||||
if (listener !in listeners) {
|
||||
listeners.add(listener)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeListener(listener: FontProviderListener) {
|
||||
listeners.remove(listener)
|
||||
}
|
||||
|
||||
interface FontProviderListener {
|
||||
fun compatibilityFontUpdate(typeface: Typeface?)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright 2019 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
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.provider.FontRequest
|
||||
import androidx.emoji.text.EmojiCompat
|
||||
import androidx.emoji.text.FontRequestEmojiCompatConfig
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class EmojiCompatWrapper @Inject constructor(private val context: Context) {
|
||||
|
||||
private var initialized = false
|
||||
|
||||
fun init(fontRequest: FontRequest) {
|
||||
// Use emoji compat for the benefit of emoji spans
|
||||
val config = FontRequestEmojiCompatConfig(context, fontRequest)
|
||||
// we want to replace all emojis with selected font
|
||||
.setReplaceAll(true)
|
||||
// Debug options
|
||||
// .setEmojiSpanIndicatorEnabled(true)
|
||||
// .setEmojiSpanIndicatorColor(Color.GREEN)
|
||||
EmojiCompat.init(config)
|
||||
.registerInitCallback(object : EmojiCompat.InitCallback() {
|
||||
override fun onInitialized() {
|
||||
Timber.v("Emoji compat onInitialized success ")
|
||||
initialized = true
|
||||
}
|
||||
|
||||
override fun onFailed(throwable: Throwable?) {
|
||||
Timber.e(throwable, "Failed to init EmojiCompat")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun safeEmojiSpanify(sequence: CharSequence): CharSequence {
|
||||
if (initialized) {
|
||||
try {
|
||||
return EmojiCompat.get().process(sequence)
|
||||
} catch (throwable: Throwable) {
|
||||
// Defensive coding against error (should not happend as it is initialized)
|
||||
Timber.e(throwable, "Failed to init EmojiCompat")
|
||||
return sequence
|
||||
}
|
||||
} else {
|
||||
return sequence
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* Copyright 2019 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
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import androidx.core.provider.FontRequest
|
||||
import androidx.core.provider.FontsContractCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.OnLifecycleEvent
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import androidx.multidex.MultiDex
|
||||
import com.airbnb.epoxy.EpoxyAsyncUtil
|
||||
import com.airbnb.epoxy.EpoxyController
|
||||
import com.facebook.stetho.Stetho
|
||||
import com.gabrielittner.threetenbp.LazyThreeTen
|
||||
import im.vector.matrix.android.api.Matrix
|
||||
import im.vector.matrix.android.api.MatrixConfiguration
|
||||
import im.vector.matrix.android.api.auth.AuthenticationService
|
||||
import im.vector.matrix.android.api.legacy.LegacySessionImporter
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.di.DaggerVectorComponent
|
||||
import im.vector.app.core.di.HasVectorInjector
|
||||
import im.vector.app.core.di.VectorComponent
|
||||
import im.vector.app.core.extensions.configureAndStart
|
||||
import im.vector.app.core.rx.RxConfig
|
||||
import im.vector.app.features.configuration.VectorConfiguration
|
||||
import im.vector.app.features.disclaimer.doNotShowDisclaimerDialog
|
||||
import im.vector.app.features.lifecycle.VectorActivityLifecycleCallbacks
|
||||
import im.vector.app.features.notifications.NotificationDrawerManager
|
||||
import im.vector.app.features.notifications.NotificationUtils
|
||||
import im.vector.app.features.pin.PinLocker
|
||||
import im.vector.app.features.popup.PopupAlertManager
|
||||
import im.vector.app.features.rageshake.VectorUncaughtExceptionHandler
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import im.vector.app.features.version.VersionProvider
|
||||
import im.vector.app.push.fcm.FcmHelper
|
||||
import timber.log.Timber
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.Executors
|
||||
import javax.inject.Inject
|
||||
|
||||
import androidx.work.Configuration as WorkConfiguration
|
||||
|
||||
class VectorApplication :
|
||||
Application(),
|
||||
HasVectorInjector,
|
||||
MatrixConfiguration.Provider,
|
||||
WorkConfiguration.Provider {
|
||||
|
||||
lateinit var appContext: Context
|
||||
@Inject lateinit var legacySessionImporter: LegacySessionImporter
|
||||
@Inject lateinit var authenticationService: AuthenticationService
|
||||
@Inject lateinit var vectorConfiguration: VectorConfiguration
|
||||
@Inject lateinit var emojiCompatFontProvider: EmojiCompatFontProvider
|
||||
@Inject lateinit var emojiCompatWrapper: EmojiCompatWrapper
|
||||
@Inject lateinit var vectorUncaughtExceptionHandler: VectorUncaughtExceptionHandler
|
||||
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
||||
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
||||
@Inject lateinit var vectorPreferences: VectorPreferences
|
||||
@Inject lateinit var versionProvider: VersionProvider
|
||||
@Inject lateinit var notificationUtils: NotificationUtils
|
||||
@Inject lateinit var appStateHandler: AppStateHandler
|
||||
@Inject lateinit var rxConfig: RxConfig
|
||||
@Inject lateinit var popupAlertManager: PopupAlertManager
|
||||
@Inject lateinit var pinLocker: PinLocker
|
||||
|
||||
lateinit var vectorComponent: VectorComponent
|
||||
|
||||
// font thread handler
|
||||
private var fontThreadHandler: Handler? = null
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
appContext = this
|
||||
vectorComponent = DaggerVectorComponent.factory().create(this)
|
||||
vectorComponent.inject(this)
|
||||
vectorUncaughtExceptionHandler.activate(this)
|
||||
rxConfig.setupRxPlugin()
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Timber.plant(Timber.DebugTree())
|
||||
}
|
||||
Timber.plant(vectorComponent.vectorFileLogger())
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Stetho.initializeWithDefaults(this)
|
||||
}
|
||||
logInfo()
|
||||
LazyThreeTen.init(this)
|
||||
|
||||
EpoxyController.defaultDiffingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
|
||||
EpoxyController.defaultModelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
|
||||
registerActivityLifecycleCallbacks(VectorActivityLifecycleCallbacks(popupAlertManager))
|
||||
val fontRequest = FontRequest(
|
||||
"com.google.android.gms.fonts",
|
||||
"com.google.android.gms",
|
||||
"Noto Color Emoji Compat",
|
||||
R.array.com_google_android_gms_fonts_certs
|
||||
)
|
||||
FontsContractCompat.requestFont(this, fontRequest, emojiCompatFontProvider, getFontThreadHandler())
|
||||
vectorConfiguration.initConfiguration()
|
||||
|
||||
emojiCompatWrapper.init(fontRequest)
|
||||
|
||||
notificationUtils.createNotificationChannels()
|
||||
|
||||
// It can takes time, but do we care?
|
||||
val sessionImported = legacySessionImporter.process()
|
||||
if (!sessionImported) {
|
||||
// Do not display the name change popup
|
||||
doNotShowDisclaimerDialog(this)
|
||||
}
|
||||
|
||||
if (authenticationService.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()) {
|
||||
val lastAuthenticatedSession = authenticationService.getLastAuthenticatedSession()!!
|
||||
activeSessionHolder.setActiveSession(lastAuthenticatedSession)
|
||||
lastAuthenticatedSession.configureAndStart(applicationContext)
|
||||
}
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(object : LifecycleObserver {
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
||||
fun entersForeground() {
|
||||
Timber.i("App entered foreground")
|
||||
FcmHelper.onEnterForeground(appContext)
|
||||
activeSessionHolder.getSafeActiveSession()?.also {
|
||||
it.stopAnyBackgroundSync()
|
||||
}
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
|
||||
fun entersBackground() {
|
||||
Timber.i("App entered background") // call persistInfo
|
||||
notificationDrawerManager.persistInfo()
|
||||
FcmHelper.onEnterBackground(appContext, vectorPreferences, activeSessionHolder)
|
||||
}
|
||||
})
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(appStateHandler)
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(pinLocker)
|
||||
// This should be done as early as possible
|
||||
// initKnownEmojiHashSet(appContext)
|
||||
}
|
||||
|
||||
override fun providesMatrixConfiguration() = MatrixConfiguration(BuildConfig.FLAVOR_DESCRIPTION)
|
||||
|
||||
override fun getWorkManagerConfiguration(): WorkConfiguration {
|
||||
return WorkConfiguration.Builder()
|
||||
.setExecutor(Executors.newCachedThreadPool())
|
||||
.build()
|
||||
}
|
||||
|
||||
override fun injector(): VectorComponent {
|
||||
return vectorComponent
|
||||
}
|
||||
|
||||
private fun logInfo() {
|
||||
val appVersion = versionProvider.getVersion(longFormat = true, useBuildNumber = true)
|
||||
val sdkVersion = Matrix.getSdkVersion()
|
||||
val date = SimpleDateFormat("MM-dd HH:mm:ss.SSSZ", Locale.US).format(Date())
|
||||
|
||||
Timber.v("----------------------------------------------------------------")
|
||||
Timber.v("----------------------------------------------------------------")
|
||||
Timber.v(" Application version: $appVersion")
|
||||
Timber.v(" SDK version: $sdkVersion")
|
||||
Timber.v(" Local time: $date")
|
||||
Timber.v("----------------------------------------------------------------")
|
||||
Timber.v("----------------------------------------------------------------\n\n\n\n")
|
||||
}
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
super.attachBaseContext(base)
|
||||
MultiDex.install(this)
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
vectorConfiguration.onConfigurationChanged()
|
||||
}
|
||||
|
||||
private fun getFontThreadHandler(): Handler {
|
||||
return fontThreadHandler ?: createFontThreadHandler().also {
|
||||
fontThreadHandler = it
|
||||
}
|
||||
}
|
||||
|
||||
private fun createFontThreadHandler(): Handler {
|
||||
val handlerThread = HandlerThread("fonts")
|
||||
handlerThread.start()
|
||||
return Handler(handlerThread.looper)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 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.core.animations
|
||||
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import com.google.android.material.appbar.AppBarLayout.OnOffsetChangedListener
|
||||
import kotlin.math.abs
|
||||
|
||||
abstract class AppBarStateChangeListener : OnOffsetChangedListener {
|
||||
|
||||
enum class State {
|
||||
EXPANDED, COLLAPSED, IDLE
|
||||
}
|
||||
|
||||
var currentState = State.IDLE
|
||||
private set
|
||||
|
||||
override fun onOffsetChanged(appBarLayout: AppBarLayout, i: Int) {
|
||||
currentState = if (i == 0) {
|
||||
if (currentState != State.EXPANDED) {
|
||||
onStateChanged(appBarLayout, State.EXPANDED)
|
||||
}
|
||||
State.EXPANDED
|
||||
} else if (abs(i) >= appBarLayout.totalScrollRange) {
|
||||
if (currentState != State.COLLAPSED) {
|
||||
onStateChanged(appBarLayout, State.COLLAPSED)
|
||||
}
|
||||
State.COLLAPSED
|
||||
} else {
|
||||
if (currentState != State.IDLE) {
|
||||
onStateChanged(appBarLayout, State.IDLE)
|
||||
}
|
||||
State.IDLE
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun onStateChanged(appBarLayout: AppBarLayout, state: State)
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.animations
|
||||
|
||||
const val ANIMATION_DURATION_SHORT = 200L
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 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.core.animations
|
||||
|
||||
import android.view.View
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
|
||||
class MatrixItemAppBarStateChangeListener(private val headerView: View, private val toolbarViews: List<View>) : AppBarStateChangeListener() {
|
||||
|
||||
override fun onStateChanged(appBarLayout: AppBarLayout, state: State) {
|
||||
if (state == State.COLLAPSED) {
|
||||
headerView.visibility = View.INVISIBLE
|
||||
toolbarViews.forEach {
|
||||
it.animate().alpha(1f).duration = 150
|
||||
}
|
||||
} else {
|
||||
headerView.visibility = View.VISIBLE
|
||||
toolbarViews.forEach {
|
||||
it.animate().alpha(0f).duration = 150
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.animations
|
||||
|
||||
import android.animation.Animator
|
||||
|
||||
open class SimpleAnimatorListener : Animator.AnimatorListener {
|
||||
override fun onAnimationRepeat(animation: Animator?) {
|
||||
// No op
|
||||
}
|
||||
|
||||
override fun onAnimationEnd(animation: Animator?) {
|
||||
// No op
|
||||
}
|
||||
|
||||
override fun onAnimationCancel(animation: Animator?) {
|
||||
// No op
|
||||
}
|
||||
|
||||
override fun onAnimationStart(animation: Animator?) {
|
||||
// No op
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.animations
|
||||
|
||||
import androidx.transition.Transition
|
||||
|
||||
open class SimpleTransitionListener : Transition.TransitionListener {
|
||||
override fun onTransitionEnd(transition: Transition) {
|
||||
// No op
|
||||
}
|
||||
|
||||
override fun onTransitionResume(transition: Transition) {
|
||||
// No op
|
||||
}
|
||||
|
||||
override fun onTransitionPause(transition: Transition) {
|
||||
// No op
|
||||
}
|
||||
|
||||
override fun onTransitionCancel(transition: Transition) {
|
||||
// No op
|
||||
}
|
||||
|
||||
override fun onTransitionStart(transition: Transition) {
|
||||
// No op
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.animations
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import androidx.transition.ChangeBounds
|
||||
import androidx.transition.ChangeTransform
|
||||
import androidx.transition.Fade
|
||||
import androidx.transition.TransitionSet
|
||||
|
||||
class VectorFullTransitionSet : TransitionSet {
|
||||
|
||||
constructor() {
|
||||
init()
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||
init()
|
||||
}
|
||||
|
||||
private fun init() {
|
||||
ordering = ORDERING_TOGETHER
|
||||
addTransition(Fade(Fade.OUT))
|
||||
.addTransition(ChangeBounds())
|
||||
.addTransition(ChangeTransform())
|
||||
.addTransition(Fade(Fade.IN))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* Copyright 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.core.animations.behavior
|
||||
|
||||
import android.animation.ArgbEvaluator
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.content.withStyledAttributes
|
||||
|
||||
import im.vector.app.R
|
||||
import kotlin.math.abs
|
||||
|
||||
private const val UNSPECIFIED_INT = Integer.MAX_VALUE
|
||||
private val UNSPECIFIED_FLOAT = Float.MAX_VALUE
|
||||
private const val DEPEND_TYPE_HEIGHT = 0
|
||||
private const val DEPEND_TYPE_WIDTH = 1
|
||||
private const val DEPEND_TYPE_X = 2
|
||||
private const val DEPEND_TYPE_Y = 3
|
||||
|
||||
class PercentViewBehavior<V : View>(context: Context, attrs: AttributeSet) : CoordinatorLayout.Behavior<V>(context, attrs) {
|
||||
|
||||
private var dependType: Int = 0
|
||||
private var dependViewId: Int = 0
|
||||
private var dependTarget: Int = 0
|
||||
private var dependStartX: Int = 0
|
||||
private var dependStartY: Int = 0
|
||||
private var dependStartWidth: Int = 0
|
||||
private var dependStartHeight: Int = 0
|
||||
|
||||
private var startX: Int = 0
|
||||
private var startY: Int = 0
|
||||
private var startWidth: Int = 0
|
||||
private var startHeight: Int = 0
|
||||
private var startBackgroundColor: Int = 0
|
||||
private var startAlpha: Float = 0f
|
||||
private var startRotateX: Float = 0f
|
||||
private var startRotateY: Float = 0f
|
||||
|
||||
private var targetX: Int = 0
|
||||
private var targetY: Int = 0
|
||||
private var targetWidth: Int = 0
|
||||
private var targetHeight: Int = 0
|
||||
private var targetBackgroundColor: Int = 0
|
||||
private var targetAlpha: Float = 0f
|
||||
private var targetRotateX: Float = 0f
|
||||
private var targetRotateY: Float = 0f
|
||||
|
||||
/**
|
||||
* Is the values prepared to be use
|
||||
*/
|
||||
private var isPrepared: Boolean = false
|
||||
|
||||
init {
|
||||
context.withStyledAttributes(attrs, R.styleable.PercentViewBehavior) {
|
||||
dependViewId = getResourceId(R.styleable.PercentViewBehavior_behavior_dependsOn, 0)
|
||||
dependType = getInt(R.styleable.PercentViewBehavior_behavior_dependType, DEPEND_TYPE_WIDTH)
|
||||
dependTarget = getDimensionPixelOffset(R.styleable.PercentViewBehavior_behavior_dependTarget, UNSPECIFIED_INT)
|
||||
targetX = getDimensionPixelOffset(R.styleable.PercentViewBehavior_behavior_targetX, UNSPECIFIED_INT)
|
||||
targetY = getDimensionPixelOffset(R.styleable.PercentViewBehavior_behavior_targetY, UNSPECIFIED_INT)
|
||||
targetWidth = getDimensionPixelOffset(R.styleable.PercentViewBehavior_behavior_targetWidth, UNSPECIFIED_INT)
|
||||
targetHeight = getDimensionPixelOffset(R.styleable.PercentViewBehavior_behavior_targetHeight, UNSPECIFIED_INT)
|
||||
targetBackgroundColor = getColor(R.styleable.PercentViewBehavior_behavior_targetBackgroundColor, UNSPECIFIED_INT)
|
||||
targetAlpha = getFloat(R.styleable.PercentViewBehavior_behavior_targetAlpha, UNSPECIFIED_FLOAT)
|
||||
targetRotateX = getFloat(R.styleable.PercentViewBehavior_behavior_targetRotateX, UNSPECIFIED_FLOAT)
|
||||
targetRotateY = getFloat(R.styleable.PercentViewBehavior_behavior_targetRotateY, UNSPECIFIED_FLOAT)
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepare(parent: CoordinatorLayout, child: View, dependency: View) {
|
||||
dependStartX = dependency.x.toInt()
|
||||
dependStartY = dependency.y.toInt()
|
||||
dependStartWidth = dependency.width
|
||||
dependStartHeight = dependency.height
|
||||
startX = child.x.toInt()
|
||||
startY = child.y.toInt()
|
||||
startWidth = child.width
|
||||
startHeight = child.height
|
||||
startAlpha = child.alpha
|
||||
startRotateX = child.rotationX
|
||||
startRotateY = child.rotationY
|
||||
|
||||
// only set the start background color when the background is color drawable
|
||||
val background = child.background
|
||||
if (background is ColorDrawable) {
|
||||
startBackgroundColor = background.color
|
||||
}
|
||||
|
||||
// if parent fitsSystemWindows is true, add status bar height to target y if specified
|
||||
if (parent.fitsSystemWindows && targetY != UNSPECIFIED_INT) {
|
||||
var result = 0
|
||||
val resources = parent.context.resources
|
||||
val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
|
||||
if (resourceId > 0) {
|
||||
result = resources.getDimensionPixelSize(resourceId)
|
||||
}
|
||||
targetY += result
|
||||
}
|
||||
isPrepared = true
|
||||
}
|
||||
|
||||
override fun layoutDependsOn(parent: CoordinatorLayout, child: V, dependency: View): Boolean {
|
||||
return dependency.id == dependViewId
|
||||
}
|
||||
|
||||
override fun onDependentViewChanged(parent: CoordinatorLayout, child: V, dependency: View): Boolean {
|
||||
// first time, prepare values before continue
|
||||
if (!isPrepared) {
|
||||
prepare(parent, child, dependency)
|
||||
}
|
||||
updateView(child, dependency)
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onLayoutChild(parent: CoordinatorLayout, child: V, layoutDirection: Int): Boolean {
|
||||
val bool = super.onLayoutChild(parent, child, layoutDirection)
|
||||
if (isPrepared) {
|
||||
updateView(child, parent.getDependencies(child)[0])
|
||||
}
|
||||
return bool
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the child view from the dependency states
|
||||
*
|
||||
* @param child child view
|
||||
* @param dependency dependency view
|
||||
*/
|
||||
private fun updateView(child: V, dependency: View) {
|
||||
var percent = 0f
|
||||
var start = 0f
|
||||
var current = 0f
|
||||
var end = UNSPECIFIED_INT.toFloat()
|
||||
when (dependType) {
|
||||
DEPEND_TYPE_WIDTH -> {
|
||||
start = dependStartWidth.toFloat()
|
||||
current = dependency.width.toFloat()
|
||||
end = dependTarget.toFloat()
|
||||
}
|
||||
DEPEND_TYPE_HEIGHT -> {
|
||||
start = dependStartHeight.toFloat()
|
||||
current = dependency.height.toFloat()
|
||||
end = dependTarget.toFloat()
|
||||
}
|
||||
DEPEND_TYPE_X -> {
|
||||
start = dependStartX.toFloat()
|
||||
current = dependency.x
|
||||
end = dependTarget.toFloat()
|
||||
}
|
||||
DEPEND_TYPE_Y -> {
|
||||
start = dependStartY.toFloat()
|
||||
current = dependency.y
|
||||
end = dependTarget.toFloat()
|
||||
}
|
||||
}
|
||||
|
||||
// need to define target value according to the depend type, if not then skip
|
||||
if (end != UNSPECIFIED_INT.toFloat()) {
|
||||
percent = abs(current - start) / abs(end - start)
|
||||
}
|
||||
updateViewWithPercent(child, if (percent > 1f) 1f else percent)
|
||||
}
|
||||
|
||||
private fun updateViewWithPercent(child: View, percent: Float) {
|
||||
var newX = if (targetX == UNSPECIFIED_INT) 0f else (targetX - startX) * percent
|
||||
var newY = if (targetY == UNSPECIFIED_INT) 0f else (targetY - startY) * percent
|
||||
|
||||
// set scale
|
||||
if (targetWidth != UNSPECIFIED_INT) {
|
||||
val newWidth = startWidth + (targetWidth - startWidth) * percent
|
||||
child.scaleX = newWidth / startWidth
|
||||
newX -= (startWidth - newWidth) / 2
|
||||
}
|
||||
if (targetHeight != UNSPECIFIED_INT) {
|
||||
val newHeight = startHeight + (targetHeight - startHeight) * percent
|
||||
child.scaleY = newHeight / startHeight
|
||||
newY -= (startHeight - newHeight) / 2
|
||||
}
|
||||
|
||||
// set new position
|
||||
child.translationX = newX
|
||||
child.translationY = newY
|
||||
|
||||
// set alpha
|
||||
if (targetAlpha != UNSPECIFIED_FLOAT) {
|
||||
child.alpha = startAlpha + (targetAlpha - startAlpha) * percent
|
||||
}
|
||||
|
||||
// set background color
|
||||
if (targetBackgroundColor != UNSPECIFIED_INT && startBackgroundColor != 0) {
|
||||
val evaluator = ArgbEvaluator()
|
||||
val color = evaluator.evaluate(percent, startBackgroundColor, targetBackgroundColor) as Int
|
||||
child.setBackgroundColor(color)
|
||||
}
|
||||
|
||||
// set rotation
|
||||
if (targetRotateX != UNSPECIFIED_FLOAT) {
|
||||
child.rotationX = startRotateX + (targetRotateX - startRotateX) * percent
|
||||
}
|
||||
if (targetRotateY != UNSPECIFIED_FLOAT) {
|
||||
child.rotationY = startRotateY + (targetRotateY - startRotateY) * percent
|
||||
}
|
||||
|
||||
child.requestLayout()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* 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.core.contacts
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.provider.ContactsContract
|
||||
import androidx.annotation.WorkerThread
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
class ContactsDataSource @Inject constructor(
|
||||
private val context: Context
|
||||
) {
|
||||
|
||||
/**
|
||||
* Will return a list of contact from the contacts book of the device, with at least one email or phone.
|
||||
* If both param are false, you will get en empty list.
|
||||
* Note: The return list does not contain any matrixId.
|
||||
*/
|
||||
@WorkerThread
|
||||
fun getContacts(
|
||||
withEmails: Boolean,
|
||||
withMsisdn: Boolean
|
||||
): List<MappedContact> {
|
||||
val map = mutableMapOf<Long, MappedContactBuilder>()
|
||||
val contentResolver = context.contentResolver
|
||||
|
||||
measureTimeMillis {
|
||||
contentResolver.query(
|
||||
ContactsContract.Contacts.CONTENT_URI,
|
||||
arrayOf(
|
||||
ContactsContract.Contacts._ID,
|
||||
ContactsContract.Data.DISPLAY_NAME,
|
||||
ContactsContract.Data.PHOTO_URI
|
||||
),
|
||||
null,
|
||||
null,
|
||||
// Sort by Display name
|
||||
ContactsContract.Data.DISPLAY_NAME
|
||||
)
|
||||
?.use { cursor ->
|
||||
if (cursor.count > 0) {
|
||||
while (cursor.moveToNext()) {
|
||||
val id = cursor.getLong(ContactsContract.Contacts._ID) ?: continue
|
||||
val displayName = cursor.getString(ContactsContract.Contacts.DISPLAY_NAME) ?: continue
|
||||
|
||||
val mappedContactBuilder = MappedContactBuilder(
|
||||
id = id,
|
||||
displayName = displayName
|
||||
)
|
||||
|
||||
cursor.getString(ContactsContract.Data.PHOTO_URI)
|
||||
?.let { Uri.parse(it) }
|
||||
?.let { mappedContactBuilder.photoURI = it }
|
||||
|
||||
map[id] = mappedContactBuilder
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the phone numbers
|
||||
if (withMsisdn) {
|
||||
contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
|
||||
arrayOf(
|
||||
ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
|
||||
ContactsContract.CommonDataKinds.Phone.NUMBER
|
||||
),
|
||||
null,
|
||||
null,
|
||||
null)
|
||||
?.use { innerCursor ->
|
||||
while (innerCursor.moveToNext()) {
|
||||
val mappedContactBuilder = innerCursor.getLong(ContactsContract.CommonDataKinds.Phone.CONTACT_ID)
|
||||
?.let { map[it] }
|
||||
?: continue
|
||||
innerCursor.getString(ContactsContract.CommonDataKinds.Phone.NUMBER)
|
||||
?.let {
|
||||
mappedContactBuilder.msisdns.add(
|
||||
MappedMsisdn(
|
||||
phoneNumber = it,
|
||||
matrixId = null
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get Emails
|
||||
if (withEmails) {
|
||||
contentResolver.query(
|
||||
ContactsContract.CommonDataKinds.Email.CONTENT_URI,
|
||||
arrayOf(
|
||||
ContactsContract.CommonDataKinds.Email.CONTACT_ID,
|
||||
ContactsContract.CommonDataKinds.Email.DATA
|
||||
),
|
||||
null,
|
||||
null,
|
||||
null)
|
||||
?.use { innerCursor ->
|
||||
while (innerCursor.moveToNext()) {
|
||||
// This would allow you get several email addresses
|
||||
// if the email addresses were stored in an array
|
||||
val mappedContactBuilder = innerCursor.getLong(ContactsContract.CommonDataKinds.Email.CONTACT_ID)
|
||||
?.let { map[it] }
|
||||
?: continue
|
||||
innerCursor.getString(ContactsContract.CommonDataKinds.Email.DATA)
|
||||
?.let {
|
||||
mappedContactBuilder.emails.add(
|
||||
MappedEmail(
|
||||
email = it,
|
||||
matrixId = null
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.also { Timber.d("Took ${it}ms to fetch ${map.size} contact(s)") }
|
||||
|
||||
return map
|
||||
.values
|
||||
.filter { it.emails.isNotEmpty() || it.msisdns.isNotEmpty() }
|
||||
.map { it.build() }
|
||||
}
|
||||
|
||||
private fun Cursor.getString(column: String): String? {
|
||||
return getColumnIndex(column)
|
||||
.takeIf { it != -1 }
|
||||
?.let { getString(it) }
|
||||
}
|
||||
|
||||
private fun Cursor.getLong(column: String): Long? {
|
||||
return getColumnIndex(column)
|
||||
.takeIf { it != -1 }
|
||||
?.let { getLong(it) }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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.core.contacts
|
||||
|
||||
import android.net.Uri
|
||||
|
||||
class MappedContactBuilder(
|
||||
val id: Long,
|
||||
val displayName: String
|
||||
) {
|
||||
var photoURI: Uri? = null
|
||||
val msisdns = mutableListOf<MappedMsisdn>()
|
||||
val emails = mutableListOf<MappedEmail>()
|
||||
|
||||
fun build(): MappedContact {
|
||||
return MappedContact(
|
||||
id = id,
|
||||
displayName = displayName,
|
||||
photoURI = photoURI,
|
||||
msisdns = msisdns,
|
||||
emails = emails
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class MappedContact(
|
||||
val id: Long,
|
||||
val displayName: String,
|
||||
val photoURI: Uri? = null,
|
||||
val msisdns: List<MappedMsisdn> = emptyList(),
|
||||
val emails: List<MappedEmail> = emptyList()
|
||||
)
|
||||
|
||||
data class MappedEmail(
|
||||
val email: String,
|
||||
val matrixId: String?
|
||||
)
|
||||
|
||||
data class MappedMsisdn(
|
||||
val phoneNumber: String,
|
||||
val matrixId: String?
|
||||
)
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.date
|
||||
|
||||
import android.content.Context
|
||||
import android.text.format.DateUtils
|
||||
import im.vector.app.core.resources.LocaleProvider
|
||||
import org.threeten.bp.LocalDateTime
|
||||
import org.threeten.bp.format.DateTimeFormatter
|
||||
import javax.inject.Inject
|
||||
|
||||
class VectorDateFormatter @Inject constructor(private val context: Context,
|
||||
private val localeProvider: LocaleProvider) {
|
||||
|
||||
private val messageHourFormatter by lazy {
|
||||
DateTimeFormatter.ofPattern("H:mm", localeProvider.current())
|
||||
}
|
||||
private val messageDayFormatter by lazy {
|
||||
DateTimeFormatter.ofPattern("EEE d MMM", localeProvider.current())
|
||||
}
|
||||
|
||||
fun formatMessageHour(localDateTime: LocalDateTime): String {
|
||||
return messageHourFormatter.format(localDateTime)
|
||||
}
|
||||
|
||||
fun formatMessageDay(localDateTime: LocalDateTime): String {
|
||||
return messageDayFormatter.format(localDateTime)
|
||||
}
|
||||
|
||||
fun formatRelativeDateTime(time: Long?): String {
|
||||
if (time == null) {
|
||||
return ""
|
||||
}
|
||||
return DateUtils.getRelativeDateTimeString(
|
||||
context,
|
||||
time,
|
||||
DateUtils.DAY_IN_MILLIS,
|
||||
2 * DateUtils.DAY_IN_MILLIS,
|
||||
DateUtils.FORMAT_SHOW_WEEKDAY or DateUtils.FORMAT_SHOW_TIME
|
||||
).toString()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.di
|
||||
|
||||
import arrow.core.Option
|
||||
import im.vector.app.ActiveSessionDataSource
|
||||
import im.vector.app.features.call.WebRtcPeerConnectionManager
|
||||
import im.vector.app.features.crypto.keysrequest.KeyRequestHandler
|
||||
import im.vector.app.features.crypto.verification.IncomingVerificationRequestHandler
|
||||
import im.vector.app.features.notifications.PushRuleTriggerListener
|
||||
import im.vector.app.features.session.SessionListener
|
||||
import im.vector.matrix.android.api.auth.AuthenticationService
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class ActiveSessionHolder @Inject constructor(private val authenticationService: AuthenticationService,
|
||||
private val sessionObservableStore: ActiveSessionDataSource,
|
||||
private val keyRequestHandler: KeyRequestHandler,
|
||||
private val incomingVerificationRequestHandler: IncomingVerificationRequestHandler,
|
||||
private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager,
|
||||
private val pushRuleTriggerListener: PushRuleTriggerListener,
|
||||
private val sessionListener: SessionListener,
|
||||
private val imageManager: ImageManager
|
||||
) {
|
||||
|
||||
private var activeSession: AtomicReference<Session?> = AtomicReference()
|
||||
|
||||
fun setActiveSession(session: Session) {
|
||||
Timber.w("setActiveSession of ${session.myUserId}")
|
||||
activeSession.set(session)
|
||||
sessionObservableStore.post(Option.just(session))
|
||||
|
||||
keyRequestHandler.start(session)
|
||||
incomingVerificationRequestHandler.start(session)
|
||||
session.addListener(sessionListener)
|
||||
pushRuleTriggerListener.startWithSession(session)
|
||||
session.callSignalingService().addCallListener(webRtcPeerConnectionManager)
|
||||
imageManager.onSessionStarted(session)
|
||||
}
|
||||
|
||||
fun clearActiveSession() {
|
||||
// Do some cleanup first
|
||||
getSafeActiveSession()?.let {
|
||||
Timber.w("clearActiveSession of ${it.myUserId}")
|
||||
it.callSignalingService().removeCallListener(webRtcPeerConnectionManager)
|
||||
it.removeListener(sessionListener)
|
||||
}
|
||||
|
||||
activeSession.set(null)
|
||||
sessionObservableStore.post(Option.empty())
|
||||
|
||||
keyRequestHandler.stop()
|
||||
incomingVerificationRequestHandler.stop()
|
||||
pushRuleTriggerListener.stop()
|
||||
}
|
||||
|
||||
fun hasActiveSession(): Boolean {
|
||||
return activeSession.get() != null
|
||||
}
|
||||
|
||||
fun getSafeActiveSession(): Session? {
|
||||
return activeSession.get()
|
||||
}
|
||||
|
||||
fun getActiveSession(): Session {
|
||||
return activeSession.get()
|
||||
?: throw IllegalStateException("You should authenticate before using this")
|
||||
}
|
||||
|
||||
// TODO: Stop sync ?
|
||||
// fun switchToSession(sessionParams: SessionParams) {
|
||||
// val newActiveSession = authenticationService.getSession(sessionParams)
|
||||
// activeSession.set(newActiveSession)
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.di
|
||||
|
||||
import com.squareup.inject.assisted.dagger2.AssistedModule
|
||||
import dagger.Module
|
||||
|
||||
@AssistedModule
|
||||
@Module(includes = [AssistedInject_AssistedInjectModule::class])
|
||||
interface AssistedInjectModule
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.di
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import dagger.MapKey
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@MapKey
|
||||
annotation class FragmentKey(val value: KClass<out Fragment>)
|
|
@ -0,0 +1,549 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.di
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentFactory
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.multibindings.IntoMap
|
||||
import im.vector.app.features.attachments.preview.AttachmentsPreviewFragment
|
||||
import im.vector.app.features.contactsbook.ContactsBookFragment
|
||||
import im.vector.app.features.crypto.keysbackup.settings.KeysBackupSettingsFragment
|
||||
import im.vector.app.features.crypto.quads.SharedSecuredStorageKeyFragment
|
||||
import im.vector.app.features.crypto.quads.SharedSecuredStoragePassphraseFragment
|
||||
import im.vector.app.features.crypto.recover.BootstrapAccountPasswordFragment
|
||||
import im.vector.app.features.crypto.recover.BootstrapConclusionFragment
|
||||
import im.vector.app.features.crypto.recover.BootstrapConfirmPassphraseFragment
|
||||
import im.vector.app.features.crypto.recover.BootstrapEnterPassphraseFragment
|
||||
import im.vector.app.features.crypto.recover.BootstrapMigrateBackupFragment
|
||||
import im.vector.app.features.crypto.recover.BootstrapSaveRecoveryKeyFragment
|
||||
import im.vector.app.features.crypto.recover.BootstrapSetupRecoveryKeyFragment
|
||||
import im.vector.app.features.crypto.recover.BootstrapWaitingFragment
|
||||
import im.vector.app.features.crypto.verification.cancel.VerificationCancelFragment
|
||||
import im.vector.app.features.crypto.verification.cancel.VerificationNotMeFragment
|
||||
import im.vector.app.features.crypto.verification.choose.VerificationChooseMethodFragment
|
||||
import im.vector.app.features.crypto.verification.conclusion.VerificationConclusionFragment
|
||||
import im.vector.app.features.crypto.verification.emoji.VerificationEmojiCodeFragment
|
||||
import im.vector.app.features.crypto.verification.qrconfirmation.VerificationQRWaitingFragment
|
||||
import im.vector.app.features.crypto.verification.qrconfirmation.VerificationQrScannedByOtherFragment
|
||||
import im.vector.app.features.crypto.verification.request.VerificationRequestFragment
|
||||
import im.vector.app.features.discovery.DiscoverySettingsFragment
|
||||
import im.vector.app.features.discovery.change.SetIdentityServerFragment
|
||||
import im.vector.app.features.grouplist.GroupListFragment
|
||||
import im.vector.app.features.home.HomeDetailFragment
|
||||
import im.vector.app.features.home.HomeDrawerFragment
|
||||
import im.vector.app.features.home.LoadingFragment
|
||||
import im.vector.app.features.home.room.breadcrumbs.BreadcrumbsFragment
|
||||
import im.vector.app.features.home.room.detail.RoomDetailFragment
|
||||
import im.vector.app.features.home.room.list.RoomListFragment
|
||||
import im.vector.app.features.login.LoginCaptchaFragment
|
||||
import im.vector.app.features.login.LoginFragment
|
||||
import im.vector.app.features.login.LoginGenericTextInputFormFragment
|
||||
import im.vector.app.features.login.LoginResetPasswordFragment
|
||||
import im.vector.app.features.login.LoginResetPasswordMailConfirmationFragment
|
||||
import im.vector.app.features.login.LoginResetPasswordSuccessFragment
|
||||
import im.vector.app.features.login.LoginServerSelectionFragment
|
||||
import im.vector.app.features.login.LoginServerUrlFormFragment
|
||||
import im.vector.app.features.login.LoginSignUpSignInSelectionFragment
|
||||
import im.vector.app.features.login.LoginSignUpSignInSsoFragment
|
||||
import im.vector.app.features.login.LoginSplashFragment
|
||||
import im.vector.app.features.login.LoginWaitForEmailFragment
|
||||
import im.vector.app.features.login.LoginWebFragment
|
||||
import im.vector.app.features.login.terms.LoginTermsFragment
|
||||
import im.vector.app.features.pin.PinFragment
|
||||
import im.vector.app.features.qrcode.QrCodeScannerFragment
|
||||
import im.vector.app.features.reactions.EmojiChooserFragment
|
||||
import im.vector.app.features.reactions.EmojiSearchResultFragment
|
||||
import im.vector.app.features.roomdirectory.PublicRoomsFragment
|
||||
import im.vector.app.features.roomdirectory.createroom.CreateRoomFragment
|
||||
import im.vector.app.features.roomdirectory.picker.RoomDirectoryPickerFragment
|
||||
import im.vector.app.features.roomdirectory.roompreview.RoomPreviewNoPreviewFragment
|
||||
import im.vector.app.features.roommemberprofile.RoomMemberProfileFragment
|
||||
import im.vector.app.features.roommemberprofile.devices.DeviceListFragment
|
||||
import im.vector.app.features.roommemberprofile.devices.DeviceTrustInfoActionFragment
|
||||
import im.vector.app.features.roomprofile.RoomProfileFragment
|
||||
import im.vector.app.features.roomprofile.banned.RoomBannedMemberListFragment
|
||||
import im.vector.app.features.roomprofile.members.RoomMemberListFragment
|
||||
import im.vector.app.features.roomprofile.settings.RoomSettingsFragment
|
||||
import im.vector.app.features.roomprofile.uploads.RoomUploadsFragment
|
||||
import im.vector.app.features.roomprofile.uploads.files.RoomUploadsFilesFragment
|
||||
import im.vector.app.features.roomprofile.uploads.media.RoomUploadsMediaFragment
|
||||
import im.vector.app.features.settings.VectorSettingsAdvancedNotificationPreferenceFragment
|
||||
import im.vector.app.features.settings.VectorSettingsHelpAboutFragment
|
||||
import im.vector.app.features.settings.VectorSettingsLabsFragment
|
||||
import im.vector.app.features.settings.VectorSettingsNotificationPreferenceFragment
|
||||
import im.vector.app.features.settings.VectorSettingsNotificationsTroubleshootFragment
|
||||
import im.vector.app.features.settings.VectorSettingsPreferencesFragment
|
||||
import im.vector.app.features.settings.VectorSettingsSecurityPrivacyFragment
|
||||
import im.vector.app.features.settings.account.deactivation.DeactivateAccountFragment
|
||||
import im.vector.app.features.settings.crosssigning.CrossSigningSettingsFragment
|
||||
import im.vector.app.features.settings.devices.VectorSettingsDevicesFragment
|
||||
import im.vector.app.features.settings.devtools.AccountDataFragment
|
||||
import im.vector.app.features.settings.devtools.GossipingEventsPaperTrailFragment
|
||||
import im.vector.app.features.settings.devtools.IncomingKeyRequestListFragment
|
||||
import im.vector.app.features.settings.devtools.KeyRequestsFragment
|
||||
import im.vector.app.features.settings.devtools.OutgoingKeyRequestListFragment
|
||||
import im.vector.app.features.settings.ignored.VectorSettingsIgnoredUsersFragment
|
||||
import im.vector.app.features.settings.locale.LocalePickerFragment
|
||||
import im.vector.app.features.settings.push.PushGatewaysFragment
|
||||
import im.vector.app.features.share.IncomingShareFragment
|
||||
import im.vector.app.features.signout.soft.SoftLogoutFragment
|
||||
import im.vector.app.features.terms.ReviewTermsFragment
|
||||
import im.vector.app.features.userdirectory.KnownUsersFragment
|
||||
import im.vector.app.features.userdirectory.UserDirectoryFragment
|
||||
import im.vector.app.features.widgets.WidgetFragment
|
||||
|
||||
@Module
|
||||
interface FragmentModule {
|
||||
/**
|
||||
* Fragments with @IntoMap will be injected by this factory
|
||||
*/
|
||||
@Binds
|
||||
fun bindFragmentFactory(factory: VectorFragmentFactory): FragmentFactory
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(RoomListFragment::class)
|
||||
fun bindRoomListFragment(fragment: RoomListFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(LocalePickerFragment::class)
|
||||
fun bindLocalePickerFragment(fragment: LocalePickerFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(GroupListFragment::class)
|
||||
fun bindGroupListFragment(fragment: GroupListFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(RoomDetailFragment::class)
|
||||
fun bindRoomDetailFragment(fragment: RoomDetailFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(RoomDirectoryPickerFragment::class)
|
||||
fun bindRoomDirectoryPickerFragment(fragment: RoomDirectoryPickerFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(CreateRoomFragment::class)
|
||||
fun bindCreateRoomFragment(fragment: CreateRoomFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(RoomPreviewNoPreviewFragment::class)
|
||||
fun bindRoomPreviewNoPreviewFragment(fragment: RoomPreviewNoPreviewFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(KeysBackupSettingsFragment::class)
|
||||
fun bindKeysBackupSettingsFragment(fragment: KeysBackupSettingsFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(LoadingFragment::class)
|
||||
fun bindLoadingFragment(fragment: LoadingFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(HomeDrawerFragment::class)
|
||||
fun bindHomeDrawerFragment(fragment: HomeDrawerFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(HomeDetailFragment::class)
|
||||
fun bindHomeDetailFragment(fragment: HomeDetailFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(EmojiSearchResultFragment::class)
|
||||
fun bindEmojiSearchResultFragment(fragment: EmojiSearchResultFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(LoginFragment::class)
|
||||
fun bindLoginFragment(fragment: LoginFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(LoginCaptchaFragment::class)
|
||||
fun bindLoginCaptchaFragment(fragment: LoginCaptchaFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(LoginTermsFragment::class)
|
||||
fun bindLoginTermsFragment(fragment: LoginTermsFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(LoginServerUrlFormFragment::class)
|
||||
fun bindLoginServerUrlFormFragment(fragment: LoginServerUrlFormFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(LoginResetPasswordMailConfirmationFragment::class)
|
||||
fun bindLoginResetPasswordMailConfirmationFragment(fragment: LoginResetPasswordMailConfirmationFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(LoginResetPasswordFragment::class)
|
||||
fun bindLoginResetPasswordFragment(fragment: LoginResetPasswordFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(LoginResetPasswordSuccessFragment::class)
|
||||
fun bindLoginResetPasswordSuccessFragment(fragment: LoginResetPasswordSuccessFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(LoginServerSelectionFragment::class)
|
||||
fun bindLoginServerSelectionFragment(fragment: LoginServerSelectionFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(LoginSignUpSignInSelectionFragment::class)
|
||||
fun bindLoginSignUpSignInSelectionFragment(fragment: LoginSignUpSignInSelectionFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(LoginSignUpSignInSsoFragment::class)
|
||||
fun bindLoginSignUpSignInSsoFragment(fragment: LoginSignUpSignInSsoFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(LoginSplashFragment::class)
|
||||
fun bindLoginSplashFragment(fragment: LoginSplashFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(LoginWebFragment::class)
|
||||
fun bindLoginWebFragment(fragment: LoginWebFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(LoginGenericTextInputFormFragment::class)
|
||||
fun bindLoginGenericTextInputFormFragment(fragment: LoginGenericTextInputFormFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(LoginWaitForEmailFragment::class)
|
||||
fun bindLoginWaitForEmailFragment(fragment: LoginWaitForEmailFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(UserDirectoryFragment::class)
|
||||
fun bindUserDirectoryFragment(fragment: UserDirectoryFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(KnownUsersFragment::class)
|
||||
fun bindKnownUsersFragment(fragment: KnownUsersFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(PushGatewaysFragment::class)
|
||||
fun bindPushGatewaysFragment(fragment: PushGatewaysFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(VectorSettingsNotificationsTroubleshootFragment::class)
|
||||
fun bindVectorSettingsNotificationsTroubleshootFragment(fragment: VectorSettingsNotificationsTroubleshootFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(VectorSettingsAdvancedNotificationPreferenceFragment::class)
|
||||
fun bindVectorSettingsAdvancedNotificationPreferenceFragment(fragment: VectorSettingsAdvancedNotificationPreferenceFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(VectorSettingsNotificationPreferenceFragment::class)
|
||||
fun bindVectorSettingsNotificationPreferenceFragment(fragment: VectorSettingsNotificationPreferenceFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(VectorSettingsLabsFragment::class)
|
||||
fun bindVectorSettingsLabsFragment(fragment: VectorSettingsLabsFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(VectorSettingsPreferencesFragment::class)
|
||||
fun bindVectorSettingsPreferencesFragment(fragment: VectorSettingsPreferencesFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(VectorSettingsSecurityPrivacyFragment::class)
|
||||
fun bindVectorSettingsSecurityPrivacyFragment(fragment: VectorSettingsSecurityPrivacyFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(VectorSettingsHelpAboutFragment::class)
|
||||
fun bindVectorSettingsHelpAboutFragment(fragment: VectorSettingsHelpAboutFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(VectorSettingsIgnoredUsersFragment::class)
|
||||
fun bindVectorSettingsIgnoredUsersFragment(fragment: VectorSettingsIgnoredUsersFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(VectorSettingsDevicesFragment::class)
|
||||
fun bindVectorSettingsDevicesFragment(fragment: VectorSettingsDevicesFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(PublicRoomsFragment::class)
|
||||
fun bindPublicRoomsFragment(fragment: PublicRoomsFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(RoomProfileFragment::class)
|
||||
fun bindRoomProfileFragment(fragment: RoomProfileFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(RoomMemberListFragment::class)
|
||||
fun bindRoomMemberListFragment(fragment: RoomMemberListFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(RoomUploadsFragment::class)
|
||||
fun bindRoomUploadsFragment(fragment: RoomUploadsFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(RoomUploadsMediaFragment::class)
|
||||
fun bindRoomUploadsMediaFragment(fragment: RoomUploadsMediaFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(RoomUploadsFilesFragment::class)
|
||||
fun bindRoomUploadsFilesFragment(fragment: RoomUploadsFilesFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(RoomSettingsFragment::class)
|
||||
fun bindRoomSettingsFragment(fragment: RoomSettingsFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(RoomMemberProfileFragment::class)
|
||||
fun bindRoomMemberProfileFragment(fragment: RoomMemberProfileFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(BreadcrumbsFragment::class)
|
||||
fun bindBreadcrumbsFragment(fragment: BreadcrumbsFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(EmojiChooserFragment::class)
|
||||
fun bindEmojiChooserFragment(fragment: EmojiChooserFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(SoftLogoutFragment::class)
|
||||
fun bindSoftLogoutFragment(fragment: SoftLogoutFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(VerificationRequestFragment::class)
|
||||
fun bindVerificationRequestFragment(fragment: VerificationRequestFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(VerificationChooseMethodFragment::class)
|
||||
fun bindVerificationChooseMethodFragment(fragment: VerificationChooseMethodFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(VerificationEmojiCodeFragment::class)
|
||||
fun bindVerificationEmojiCodeFragment(fragment: VerificationEmojiCodeFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(VerificationQrScannedByOtherFragment::class)
|
||||
fun bindVerificationQrScannedByOtherFragment(fragment: VerificationQrScannedByOtherFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(VerificationQRWaitingFragment::class)
|
||||
fun bindVerificationQRWaitingFragment(fragment: VerificationQRWaitingFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(VerificationConclusionFragment::class)
|
||||
fun bindVerificationConclusionFragment(fragment: VerificationConclusionFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(VerificationCancelFragment::class)
|
||||
fun bindVerificationCancelFragment(fragment: VerificationCancelFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(VerificationNotMeFragment::class)
|
||||
fun bindVerificationNotMeFragment(fragment: VerificationNotMeFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(QrCodeScannerFragment::class)
|
||||
fun bindQrCodeScannerFragment(fragment: QrCodeScannerFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(DeviceListFragment::class)
|
||||
fun bindDeviceListFragment(fragment: DeviceListFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(DeviceTrustInfoActionFragment::class)
|
||||
fun bindDeviceTrustInfoActionFragment(fragment: DeviceTrustInfoActionFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(CrossSigningSettingsFragment::class)
|
||||
fun bindCrossSigningSettingsFragment(fragment: CrossSigningSettingsFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(AttachmentsPreviewFragment::class)
|
||||
fun bindAttachmentsPreviewFragment(fragment: AttachmentsPreviewFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(IncomingShareFragment::class)
|
||||
fun bindIncomingShareFragment(fragment: IncomingShareFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(AccountDataFragment::class)
|
||||
fun bindAccountDataFragment(fragment: AccountDataFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(OutgoingKeyRequestListFragment::class)
|
||||
fun bindOutgoingKeyRequestListFragment(fragment: OutgoingKeyRequestListFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(IncomingKeyRequestListFragment::class)
|
||||
fun bindIncomingKeyRequestListFragment(fragment: IncomingKeyRequestListFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(KeyRequestsFragment::class)
|
||||
fun bindKeyRequestsFragment(fragment: KeyRequestsFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(GossipingEventsPaperTrailFragment::class)
|
||||
fun bindGossipingEventsPaperTrailFragment(fragment: GossipingEventsPaperTrailFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(BootstrapEnterPassphraseFragment::class)
|
||||
fun bindBootstrapEnterPassphraseFragment(fragment: BootstrapEnterPassphraseFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(BootstrapConfirmPassphraseFragment::class)
|
||||
fun bindBootstrapConfirmPassphraseFragment(fragment: BootstrapConfirmPassphraseFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(BootstrapWaitingFragment::class)
|
||||
fun bindBootstrapWaitingFragment(fragment: BootstrapWaitingFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(BootstrapSetupRecoveryKeyFragment::class)
|
||||
fun bindBootstrapSetupRecoveryKeyFragment(fragment: BootstrapSetupRecoveryKeyFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(BootstrapSaveRecoveryKeyFragment::class)
|
||||
fun bindBootstrapSaveRecoveryKeyFragment(fragment: BootstrapSaveRecoveryKeyFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(BootstrapConclusionFragment::class)
|
||||
fun bindBootstrapConclusionFragment(fragment: BootstrapConclusionFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(BootstrapAccountPasswordFragment::class)
|
||||
fun bindBootstrapAccountPasswordFragment(fragment: BootstrapAccountPasswordFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(BootstrapMigrateBackupFragment::class)
|
||||
fun bindBootstrapMigrateBackupFragment(fragment: BootstrapMigrateBackupFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(DeactivateAccountFragment::class)
|
||||
fun bindDeactivateAccountFragment(fragment: DeactivateAccountFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(SharedSecuredStoragePassphraseFragment::class)
|
||||
fun bindSharedSecuredStoragePassphraseFragment(fragment: SharedSecuredStoragePassphraseFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(SharedSecuredStorageKeyFragment::class)
|
||||
fun bindSharedSecuredStorageKeyFragment(fragment: SharedSecuredStorageKeyFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(SetIdentityServerFragment::class)
|
||||
fun bindSetIdentityServerFragment(fragment: SetIdentityServerFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(DiscoverySettingsFragment::class)
|
||||
fun bindDiscoverySettingsFragment(fragment: DiscoverySettingsFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(ReviewTermsFragment::class)
|
||||
fun bindReviewTermsFragment(fragment: ReviewTermsFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(WidgetFragment::class)
|
||||
fun bindWidgetFragment(fragment: WidgetFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(ContactsBookFragment::class)
|
||||
fun bindPhoneBookFragment(fragment: ContactsBookFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(PinFragment::class)
|
||||
fun bindPinFragment(fragment: PinFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(RoomBannedMemberListFragment::class)
|
||||
fun bindRoomBannedMemberListFragment(fragment: RoomBannedMemberListFragment): Fragment
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.di
|
||||
|
||||
interface HasScreenInjector {
|
||||
|
||||
fun injector(): ScreenComponent
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.di
|
||||
|
||||
interface HasVectorInjector {
|
||||
|
||||
fun injector(): VectorComponent
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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.core.di
|
||||
|
||||
import android.content.Context
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.model.GlideUrl
|
||||
import com.github.piasy.biv.BigImageViewer
|
||||
import com.github.piasy.biv.loader.glide.GlideImageLoader
|
||||
import im.vector.app.ActiveSessionDataSource
|
||||
import im.vector.app.core.glide.FactoryUrl
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import java.io.InputStream
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* This class is used to configure the library we use for images
|
||||
*/
|
||||
class ImageManager @Inject constructor(
|
||||
private val context: Context,
|
||||
private val activeSessionDataSource: ActiveSessionDataSource
|
||||
) {
|
||||
|
||||
fun onSessionStarted(session: Session) {
|
||||
// Do this call first
|
||||
BigImageViewer.initialize(GlideImageLoader.with(context, session.getOkHttpClient()))
|
||||
|
||||
val glide = Glide.get(context)
|
||||
|
||||
// And this one. FIXME But are losing what BigImageViewer has done to add a Progress listener
|
||||
glide.registry.replace(GlideUrl::class.java, InputStream::class.java, FactoryUrl(activeSessionDataSource))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.di
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.FragmentFactory
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import dagger.BindsInstance
|
||||
import dagger.Component
|
||||
import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
|
||||
import im.vector.app.core.error.ErrorFormatter
|
||||
import im.vector.app.core.preference.UserAvatarPreference
|
||||
import im.vector.app.features.MainActivity
|
||||
import im.vector.app.features.call.CallControlsBottomSheet
|
||||
import im.vector.app.features.call.VectorCallActivity
|
||||
import im.vector.app.features.createdirect.CreateDirectRoomActivity
|
||||
import im.vector.app.features.crypto.keysbackup.settings.KeysBackupManageActivity
|
||||
import im.vector.app.features.crypto.quads.SharedSecureStorageActivity
|
||||
import im.vector.app.features.crypto.recover.BootstrapBottomSheet
|
||||
import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
||||
import im.vector.app.features.debug.DebugMenuActivity
|
||||
import im.vector.app.features.home.HomeActivity
|
||||
import im.vector.app.features.home.HomeModule
|
||||
import im.vector.app.features.home.room.detail.RoomDetailActivity
|
||||
import im.vector.app.features.home.room.detail.readreceipts.DisplayReadReceiptsBottomSheet
|
||||
import im.vector.app.features.home.room.detail.timeline.action.MessageActionsBottomSheet
|
||||
import im.vector.app.features.home.room.detail.timeline.edithistory.ViewEditHistoryBottomSheet
|
||||
import im.vector.app.features.home.room.detail.timeline.reactions.ViewReactionsBottomSheet
|
||||
import im.vector.app.features.home.room.detail.widget.RoomWidgetsBottomSheet
|
||||
import im.vector.app.features.home.room.filtered.FilteredRoomsActivity
|
||||
import im.vector.app.features.home.room.list.RoomListModule
|
||||
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
|
||||
import im.vector.app.features.invite.InviteUsersToRoomActivity
|
||||
import im.vector.app.features.invite.VectorInviteView
|
||||
import im.vector.app.features.link.LinkHandlerActivity
|
||||
import im.vector.app.features.login.LoginActivity
|
||||
import im.vector.app.features.media.BigImageViewerActivity
|
||||
import im.vector.app.features.media.ImageMediaViewerActivity
|
||||
import im.vector.app.features.media.VectorAttachmentViewerActivity
|
||||
import im.vector.app.features.media.VideoMediaViewerActivity
|
||||
import im.vector.app.features.navigation.Navigator
|
||||
import im.vector.app.features.permalink.PermalinkHandlerActivity
|
||||
import im.vector.app.features.pin.PinLocker
|
||||
import im.vector.app.features.qrcode.QrCodeScannerActivity
|
||||
import im.vector.app.features.rageshake.BugReportActivity
|
||||
import im.vector.app.features.rageshake.BugReporter
|
||||
import im.vector.app.features.rageshake.RageShake
|
||||
import im.vector.app.features.reactions.EmojiReactionPickerActivity
|
||||
import im.vector.app.features.reactions.widget.ReactionButton
|
||||
import im.vector.app.features.roomdirectory.RoomDirectoryActivity
|
||||
import im.vector.app.features.roomdirectory.createroom.CreateRoomActivity
|
||||
import im.vector.app.features.roommemberprofile.RoomMemberProfileActivity
|
||||
import im.vector.app.features.roommemberprofile.devices.DeviceListBottomSheet
|
||||
import im.vector.app.features.roomprofile.RoomProfileActivity
|
||||
import im.vector.app.features.settings.VectorSettingsActivity
|
||||
import im.vector.app.features.settings.devices.DeviceVerificationInfoBottomSheet
|
||||
import im.vector.app.features.share.IncomingShareActivity
|
||||
import im.vector.app.features.signout.soft.SoftLogoutActivity
|
||||
import im.vector.app.features.terms.ReviewTermsActivity
|
||||
import im.vector.app.features.ui.UiStateRepository
|
||||
import im.vector.app.features.widgets.WidgetActivity
|
||||
import im.vector.app.features.widgets.permissions.RoomWidgetPermissionBottomSheet
|
||||
import im.vector.app.features.workers.signout.SignOutBottomSheetDialogFragment
|
||||
|
||||
@Component(
|
||||
dependencies = [
|
||||
VectorComponent::class
|
||||
],
|
||||
modules = [
|
||||
AssistedInjectModule::class,
|
||||
ViewModelModule::class,
|
||||
FragmentModule::class,
|
||||
HomeModule::class,
|
||||
RoomListModule::class,
|
||||
ScreenModule::class
|
||||
]
|
||||
)
|
||||
@ScreenScope
|
||||
interface ScreenComponent {
|
||||
|
||||
/* ==========================================================================================
|
||||
* Shortcut to VectorComponent elements
|
||||
* ========================================================================================== */
|
||||
|
||||
fun activeSessionHolder(): ActiveSessionHolder
|
||||
fun fragmentFactory(): FragmentFactory
|
||||
fun viewModelFactory(): ViewModelProvider.Factory
|
||||
fun bugReporter(): BugReporter
|
||||
fun rageShake(): RageShake
|
||||
fun navigator(): Navigator
|
||||
fun pinLocker(): PinLocker
|
||||
fun errorFormatter(): ErrorFormatter
|
||||
fun uiStateRepository(): UiStateRepository
|
||||
fun unrecognizedCertificateDialog(): UnrecognizedCertificateDialog
|
||||
|
||||
/* ==========================================================================================
|
||||
* Activities
|
||||
* ========================================================================================== */
|
||||
|
||||
fun inject(activity: HomeActivity)
|
||||
fun inject(activity: RoomDetailActivity)
|
||||
fun inject(activity: RoomProfileActivity)
|
||||
fun inject(activity: RoomMemberProfileActivity)
|
||||
fun inject(activity: VectorSettingsActivity)
|
||||
fun inject(activity: KeysBackupManageActivity)
|
||||
fun inject(activity: EmojiReactionPickerActivity)
|
||||
fun inject(activity: LoginActivity)
|
||||
fun inject(activity: LinkHandlerActivity)
|
||||
fun inject(activity: MainActivity)
|
||||
fun inject(activity: RoomDirectoryActivity)
|
||||
fun inject(activity: BugReportActivity)
|
||||
fun inject(activity: ImageMediaViewerActivity)
|
||||
fun inject(activity: FilteredRoomsActivity)
|
||||
fun inject(activity: CreateRoomActivity)
|
||||
fun inject(activity: VideoMediaViewerActivity)
|
||||
fun inject(activity: CreateDirectRoomActivity)
|
||||
fun inject(activity: IncomingShareActivity)
|
||||
fun inject(activity: SoftLogoutActivity)
|
||||
fun inject(activity: PermalinkHandlerActivity)
|
||||
fun inject(activity: QrCodeScannerActivity)
|
||||
fun inject(activity: DebugMenuActivity)
|
||||
fun inject(activity: SharedSecureStorageActivity)
|
||||
fun inject(activity: BigImageViewerActivity)
|
||||
fun inject(activity: InviteUsersToRoomActivity)
|
||||
fun inject(activity: ReviewTermsActivity)
|
||||
fun inject(activity: WidgetActivity)
|
||||
fun inject(activity: VectorCallActivity)
|
||||
fun inject(activity: VectorAttachmentViewerActivity)
|
||||
|
||||
/* ==========================================================================================
|
||||
* BottomSheets
|
||||
* ========================================================================================== */
|
||||
|
||||
fun inject(bottomSheet: MessageActionsBottomSheet)
|
||||
fun inject(bottomSheet: ViewReactionsBottomSheet)
|
||||
fun inject(bottomSheet: ViewEditHistoryBottomSheet)
|
||||
fun inject(bottomSheet: DisplayReadReceiptsBottomSheet)
|
||||
fun inject(bottomSheet: RoomListQuickActionsBottomSheet)
|
||||
fun inject(bottomSheet: VerificationBottomSheet)
|
||||
fun inject(bottomSheet: DeviceVerificationInfoBottomSheet)
|
||||
fun inject(bottomSheet: DeviceListBottomSheet)
|
||||
fun inject(bottomSheet: BootstrapBottomSheet)
|
||||
fun inject(bottomSheet: RoomWidgetPermissionBottomSheet)
|
||||
fun inject(bottomSheet: RoomWidgetsBottomSheet)
|
||||
fun inject(bottomSheet: CallControlsBottomSheet)
|
||||
fun inject(bottomSheet: SignOutBottomSheetDialogFragment)
|
||||
|
||||
/* ==========================================================================================
|
||||
* Others
|
||||
* ========================================================================================== */
|
||||
|
||||
fun inject(view: VectorInviteView)
|
||||
fun inject(preference: UserAvatarPreference)
|
||||
fun inject(button: ReactionButton)
|
||||
|
||||
/* ==========================================================================================
|
||||
* Factory
|
||||
* ========================================================================================== */
|
||||
|
||||
@Component.Factory
|
||||
interface Factory {
|
||||
fun create(vectorComponent: VectorComponent,
|
||||
@BindsInstance context: AppCompatActivity
|
||||
): ScreenComponent
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.di
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import im.vector.app.core.glide.GlideApp
|
||||
|
||||
@Module
|
||||
object ScreenModule {
|
||||
|
||||
@Provides
|
||||
@JvmStatic
|
||||
fun providesGlideRequests(context: AppCompatActivity) = GlideApp.with(context)
|
||||
|
||||
@Provides
|
||||
@JvmStatic
|
||||
@ScreenScope
|
||||
fun providesSharedViewPool() = RecyclerView.RecycledViewPool()
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.di
|
||||
|
||||
import javax.inject.Scope
|
||||
|
||||
@Scope
|
||||
@MustBeDocumented
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class ScreenScope
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.di
|
||||
|
||||
/*
|
||||
@Module(includes = [AssistedInject_VectorAssistedModule::class])
|
||||
@AssistedModule
|
||||
class VectorAssistedModule*/
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.di
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import dagger.BindsInstance
|
||||
import dagger.Component
|
||||
import im.vector.app.ActiveSessionDataSource
|
||||
import im.vector.app.EmojiCompatFontProvider
|
||||
import im.vector.app.EmojiCompatWrapper
|
||||
import im.vector.app.VectorApplication
|
||||
import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
|
||||
import im.vector.app.core.error.ErrorFormatter
|
||||
import im.vector.app.core.pushers.PushersManager
|
||||
import im.vector.app.core.utils.AssetReader
|
||||
import im.vector.app.core.utils.DimensionConverter
|
||||
import im.vector.app.features.call.WebRtcPeerConnectionManager
|
||||
import im.vector.app.features.configuration.VectorConfiguration
|
||||
import im.vector.app.features.crypto.keysrequest.KeyRequestHandler
|
||||
import im.vector.app.features.crypto.verification.IncomingVerificationRequestHandler
|
||||
import im.vector.app.features.grouplist.SelectedGroupDataSource
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.HomeRoomListDataSource
|
||||
import im.vector.app.features.html.EventHtmlRenderer
|
||||
import im.vector.app.features.html.VectorHtmlCompressor
|
||||
import im.vector.app.features.login.ReAuthHelper
|
||||
import im.vector.app.features.navigation.Navigator
|
||||
import im.vector.app.features.notifications.NotifiableEventResolver
|
||||
import im.vector.app.features.notifications.NotificationBroadcastReceiver
|
||||
import im.vector.app.features.notifications.NotificationDrawerManager
|
||||
import im.vector.app.features.notifications.NotificationUtils
|
||||
import im.vector.app.features.notifications.PushRuleTriggerListener
|
||||
import im.vector.app.features.pin.PinCodeStore
|
||||
import im.vector.app.features.pin.PinLocker
|
||||
import im.vector.app.features.popup.PopupAlertManager
|
||||
import im.vector.app.features.rageshake.BugReporter
|
||||
import im.vector.app.features.rageshake.VectorFileLogger
|
||||
import im.vector.app.features.rageshake.VectorUncaughtExceptionHandler
|
||||
import im.vector.app.features.reactions.data.EmojiDataSource
|
||||
import im.vector.app.features.session.SessionListener
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import im.vector.app.features.ui.UiStateRepository
|
||||
import im.vector.matrix.android.api.Matrix
|
||||
import im.vector.matrix.android.api.auth.AuthenticationService
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Component(modules = [VectorModule::class])
|
||||
@Singleton
|
||||
interface VectorComponent {
|
||||
|
||||
fun inject(notificationBroadcastReceiver: NotificationBroadcastReceiver)
|
||||
|
||||
fun inject(vectorApplication: VectorApplication)
|
||||
|
||||
fun matrix(): Matrix
|
||||
|
||||
fun sessionListener(): SessionListener
|
||||
|
||||
fun currentSession(): Session
|
||||
|
||||
fun notificationUtils(): NotificationUtils
|
||||
|
||||
fun notificationDrawerManager(): NotificationDrawerManager
|
||||
|
||||
fun appContext(): Context
|
||||
|
||||
fun resources(): Resources
|
||||
|
||||
fun assetReader(): AssetReader
|
||||
|
||||
fun dimensionConverter(): DimensionConverter
|
||||
|
||||
fun vectorConfiguration(): VectorConfiguration
|
||||
|
||||
fun avatarRenderer(): AvatarRenderer
|
||||
|
||||
fun activeSessionHolder(): ActiveSessionHolder
|
||||
|
||||
fun unrecognizedCertificateDialog(): UnrecognizedCertificateDialog
|
||||
|
||||
fun emojiCompatFontProvider(): EmojiCompatFontProvider
|
||||
|
||||
fun emojiCompatWrapper(): EmojiCompatWrapper
|
||||
|
||||
fun eventHtmlRenderer(): EventHtmlRenderer
|
||||
|
||||
fun vectorHtmlCompressor(): VectorHtmlCompressor
|
||||
|
||||
fun navigator(): Navigator
|
||||
|
||||
fun errorFormatter(): ErrorFormatter
|
||||
|
||||
fun homeRoomListObservableStore(): HomeRoomListDataSource
|
||||
|
||||
fun selectedGroupStore(): SelectedGroupDataSource
|
||||
|
||||
fun activeSessionObservableStore(): ActiveSessionDataSource
|
||||
|
||||
fun incomingVerificationRequestHandler(): IncomingVerificationRequestHandler
|
||||
|
||||
fun incomingKeyRequestHandler(): KeyRequestHandler
|
||||
|
||||
fun authenticationService(): AuthenticationService
|
||||
|
||||
fun bugReporter(): BugReporter
|
||||
|
||||
fun vectorUncaughtExceptionHandler(): VectorUncaughtExceptionHandler
|
||||
|
||||
fun pushRuleTriggerListener(): PushRuleTriggerListener
|
||||
|
||||
fun pusherManager(): PushersManager
|
||||
|
||||
fun notifiableEventResolver(): NotifiableEventResolver
|
||||
|
||||
fun vectorPreferences(): VectorPreferences
|
||||
|
||||
fun vectorFileLogger(): VectorFileLogger
|
||||
|
||||
fun uiStateRepository(): UiStateRepository
|
||||
|
||||
fun pinCodeStore(): PinCodeStore
|
||||
|
||||
fun emojiDataSource(): EmojiDataSource
|
||||
|
||||
fun alertManager(): PopupAlertManager
|
||||
|
||||
fun reAuthHelper(): ReAuthHelper
|
||||
|
||||
fun pinLocker(): PinLocker
|
||||
|
||||
fun webRtcPeerConnectionManager(): WebRtcPeerConnectionManager
|
||||
|
||||
@Component.Factory
|
||||
interface Factory {
|
||||
fun create(@BindsInstance context: Context): VectorComponent
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.di
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentFactory
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
|
||||
/**
|
||||
* FragmentFactory which uses Dagger to create the instances.
|
||||
*/
|
||||
class VectorFragmentFactory @Inject constructor(
|
||||
private val creators: @JvmSuppressWildcards Map<Class<out Fragment>, Provider<Fragment>>
|
||||
) : FragmentFactory() {
|
||||
|
||||
override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
|
||||
val fragmentClass = loadFragmentClass(classLoader, className)
|
||||
val creator: Provider<out Fragment>? = creators[fragmentClass]
|
||||
return if (creator == null) {
|
||||
Timber.v("Unknown model class: $className, fallback to default instance")
|
||||
super.instantiate(classLoader, className)
|
||||
} else {
|
||||
creator.get()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.di
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Context.MODE_PRIVATE
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.Resources
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import im.vector.app.core.error.DefaultErrorFormatter
|
||||
import im.vector.app.core.error.ErrorFormatter
|
||||
import im.vector.app.features.navigation.DefaultNavigator
|
||||
import im.vector.app.features.navigation.Navigator
|
||||
import im.vector.app.features.pin.PinCodeStore
|
||||
import im.vector.app.features.pin.SharedPrefPinCodeStore
|
||||
import im.vector.app.features.ui.SharedPreferencesUiStateRepository
|
||||
import im.vector.app.features.ui.UiStateRepository
|
||||
import im.vector.matrix.android.api.Matrix
|
||||
import im.vector.matrix.android.api.auth.AuthenticationService
|
||||
import im.vector.matrix.android.api.legacy.LegacySessionImporter
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
|
||||
@Module
|
||||
abstract class VectorModule {
|
||||
|
||||
@Module
|
||||
companion object {
|
||||
|
||||
@Provides
|
||||
@JvmStatic
|
||||
fun providesResources(context: Context): Resources {
|
||||
return context.resources
|
||||
}
|
||||
|
||||
@Provides
|
||||
@JvmStatic
|
||||
fun providesSharedPreferences(context: Context): SharedPreferences {
|
||||
return context.getSharedPreferences("im.vector.riot", MODE_PRIVATE)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@JvmStatic
|
||||
fun providesMatrix(context: Context): Matrix {
|
||||
return Matrix.getInstance(context)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@JvmStatic
|
||||
fun providesCurrentSession(activeSessionHolder: ActiveSessionHolder): Session {
|
||||
// TODO: handle session injection better
|
||||
return activeSessionHolder.getActiveSession()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@JvmStatic
|
||||
fun providesLegacySessionImporter(matrix: Matrix): LegacySessionImporter {
|
||||
return matrix.legacySessionImporter()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@JvmStatic
|
||||
fun providesAuthenticationService(matrix: Matrix): AuthenticationService {
|
||||
return matrix.authenticationService()
|
||||
}
|
||||
}
|
||||
|
||||
@Binds
|
||||
abstract fun bindNavigator(navigator: DefaultNavigator): Navigator
|
||||
|
||||
@Binds
|
||||
abstract fun bindErrorFormatter(formatter: DefaultErrorFormatter): ErrorFormatter
|
||||
|
||||
@Binds
|
||||
abstract fun bindUiStateRepository(repository: SharedPreferencesUiStateRepository): UiStateRepository
|
||||
|
||||
@Binds
|
||||
abstract fun bindPinCodeStore(store: SharedPrefPinCodeStore): PinCodeStore
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.di
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
|
||||
/**
|
||||
* ViewModelFactory which uses Dagger to create the instances.
|
||||
*/
|
||||
class VectorViewModelFactory @Inject constructor(
|
||||
private val creators: @JvmSuppressWildcards Map<Class<out ViewModel>, Provider<ViewModel>>
|
||||
) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
var creator: Provider<out ViewModel>? = creators[modelClass]
|
||||
if (creator == null) {
|
||||
for ((key, value) in creators) {
|
||||
if (modelClass.isAssignableFrom(key)) {
|
||||
creator = value
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (creator == null) {
|
||||
throw IllegalArgumentException("Unknown model class: $modelClass")
|
||||
}
|
||||
try {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return creator.get() as T
|
||||
} catch (e: Exception) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.di
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import dagger.MapKey
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@MapKey
|
||||
annotation class ViewModelKey(val value: KClass<out ViewModel>)
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.di
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.multibindings.IntoMap
|
||||
import im.vector.app.core.platform.ConfigurationViewModel
|
||||
import im.vector.app.features.call.SharedActiveCallViewModel
|
||||
import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreFromKeyViewModel
|
||||
import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreFromPassphraseViewModel
|
||||
import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreSharedViewModel
|
||||
import im.vector.app.features.crypto.keysbackup.setup.KeysBackupSetupSharedViewModel
|
||||
import im.vector.app.features.discovery.DiscoverySharedViewModel
|
||||
import im.vector.app.features.home.HomeSharedActionViewModel
|
||||
import im.vector.app.features.home.room.detail.RoomDetailSharedActionViewModel
|
||||
import im.vector.app.features.home.room.detail.timeline.action.MessageSharedActionViewModel
|
||||
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
|
||||
import im.vector.app.features.reactions.EmojiChooserViewModel
|
||||
import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel
|
||||
import im.vector.app.features.roomprofile.RoomProfileSharedActionViewModel
|
||||
import im.vector.app.features.userdirectory.UserDirectorySharedActionViewModel
|
||||
|
||||
@Module
|
||||
interface ViewModelModule {
|
||||
|
||||
/**
|
||||
* ViewModels with @IntoMap will be injected by this factory
|
||||
*/
|
||||
@Binds
|
||||
fun bindViewModelFactory(factory: VectorViewModelFactory): ViewModelProvider.Factory
|
||||
|
||||
/**
|
||||
* Below are bindings for the androidx view models (which extend ViewModel). Will be converted to MvRx ViewModel in the future.
|
||||
*/
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(EmojiChooserViewModel::class)
|
||||
fun bindEmojiChooserViewModel(viewModel: EmojiChooserViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(KeysBackupRestoreFromKeyViewModel::class)
|
||||
fun bindKeysBackupRestoreFromKeyViewModel(viewModel: KeysBackupRestoreFromKeyViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(KeysBackupRestoreSharedViewModel::class)
|
||||
fun bindKeysBackupRestoreSharedViewModel(viewModel: KeysBackupRestoreSharedViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(KeysBackupRestoreFromPassphraseViewModel::class)
|
||||
fun bindKeysBackupRestoreFromPassphraseViewModel(viewModel: KeysBackupRestoreFromPassphraseViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(KeysBackupSetupSharedViewModel::class)
|
||||
fun bindKeysBackupSetupSharedViewModel(viewModel: KeysBackupSetupSharedViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(ConfigurationViewModel::class)
|
||||
fun bindConfigurationViewModel(viewModel: ConfigurationViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(SharedActiveCallViewModel::class)
|
||||
fun bindSharedActiveCallViewModel(viewModel: SharedActiveCallViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(UserDirectorySharedActionViewModel::class)
|
||||
fun bindUserDirectorySharedActionViewModel(viewModel: UserDirectorySharedActionViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(HomeSharedActionViewModel::class)
|
||||
fun bindHomeSharedActionViewModel(viewModel: HomeSharedActionViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(MessageSharedActionViewModel::class)
|
||||
fun bindMessageSharedActionViewModel(viewModel: MessageSharedActionViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(RoomListQuickActionsSharedActionViewModel::class)
|
||||
fun bindRoomListQuickActionsSharedActionViewModel(viewModel: RoomListQuickActionsSharedActionViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(RoomDirectorySharedActionViewModel::class)
|
||||
fun bindRoomDirectorySharedActionViewModel(viewModel: RoomDirectorySharedActionViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(RoomDetailSharedActionViewModel::class)
|
||||
fun bindRoomDetailSharedActionViewModel(viewModel: RoomDetailSharedActionViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(RoomProfileSharedActionViewModel::class)
|
||||
fun bindRoomProfileSharedActionViewModel(viewModel: RoomProfileSharedActionViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(DiscoverySharedViewModel::class)
|
||||
fun bindDiscoverySharedViewModel(viewModel: DiscoverySharedViewModel): ViewModel
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.core.dialogs
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isVisible
|
||||
import im.vector.app.R
|
||||
import kotlinx.android.synthetic.main.dialog_confirmation_with_reason.view.*
|
||||
|
||||
object ConfirmationDialogBuilder {
|
||||
|
||||
fun show(activity: Activity,
|
||||
askForReason: Boolean,
|
||||
@StringRes titleRes: Int,
|
||||
@StringRes confirmationRes: Int,
|
||||
@StringRes positiveRes: Int,
|
||||
@StringRes reasonHintRes: Int,
|
||||
confirmation: (String?) -> Unit) {
|
||||
val layout = activity.layoutInflater.inflate(R.layout.dialog_confirmation_with_reason, null)
|
||||
layout.dialogConfirmationText.setText(confirmationRes)
|
||||
|
||||
layout.dialogReasonCheck.isVisible = askForReason
|
||||
layout.dialogReasonTextInputLayout.isVisible = askForReason
|
||||
|
||||
layout.dialogReasonCheck.setOnCheckedChangeListener { _, isChecked ->
|
||||
layout.dialogReasonTextInputLayout.isEnabled = isChecked
|
||||
}
|
||||
if (askForReason && reasonHintRes != 0) {
|
||||
layout.dialogReasonInput.setHint(reasonHintRes)
|
||||
}
|
||||
|
||||
AlertDialog.Builder(activity)
|
||||
.setTitle(titleRes)
|
||||
.setView(layout)
|
||||
.setPositiveButton(positiveRes) { _, _ ->
|
||||
val reason = layout.dialogReasonInput.text.toString()
|
||||
.takeIf { askForReason }
|
||||
?.takeIf { layout.dialogReasonCheck.isChecked }
|
||||
?.takeIf { it.isNotBlank() }
|
||||
confirmation(reason)
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.dialogs
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import im.vector.app.core.platform.Restorable
|
||||
import timber.log.Timber
|
||||
|
||||
private const val KEY_DIALOG_IS_DISPLAYED = "DialogLocker.KEY_DIALOG_IS_DISPLAYED"
|
||||
|
||||
/**
|
||||
* Class to avoid displaying twice the same dialog
|
||||
*/
|
||||
class DialogLocker(savedInstanceState: Bundle?) : Restorable {
|
||||
|
||||
private var isDialogDisplayed = savedInstanceState?.getBoolean(KEY_DIALOG_IS_DISPLAYED, false) == true
|
||||
|
||||
private fun unlock() {
|
||||
isDialogDisplayed = false
|
||||
}
|
||||
|
||||
private fun lock() {
|
||||
isDialogDisplayed = true
|
||||
}
|
||||
|
||||
fun displayDialog(builder: () -> AlertDialog.Builder): AlertDialog? {
|
||||
return if (isDialogDisplayed) {
|
||||
Timber.w("Filtered dialog request")
|
||||
null
|
||||
} else {
|
||||
builder
|
||||
.invoke()
|
||||
.create()
|
||||
.apply {
|
||||
setOnShowListener { lock() }
|
||||
setOnCancelListener { unlock() }
|
||||
setOnDismissListener { unlock() }
|
||||
show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
outState.putBoolean(KEY_DIALOG_IS_DISPLAYED, isDialogDisplayed)
|
||||
}
|
||||
|
||||
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
|
||||
isDialogDisplayed = savedInstanceState?.getBoolean(KEY_DIALOG_IS_DISPLAYED, false) == true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.dialogs
|
||||
|
||||
import android.app.Activity
|
||||
import android.text.Editable
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.showPassword
|
||||
import im.vector.app.core.platform.SimpleTextWatcher
|
||||
|
||||
class ExportKeysDialog {
|
||||
|
||||
private var passwordVisible = false
|
||||
|
||||
fun show(activity: Activity, exportKeyDialogListener: ExportKeyDialogListener) {
|
||||
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_export_e2e_keys, null)
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
.setTitle(R.string.encryption_export_room_keys)
|
||||
.setView(dialogLayout)
|
||||
|
||||
val passPhrase1EditText = dialogLayout.findViewById<TextInputEditText>(R.id.exportDialogEt)
|
||||
val passPhrase2EditText = dialogLayout.findViewById<TextInputEditText>(R.id.exportDialogEtConfirm)
|
||||
val passPhrase2Til = dialogLayout.findViewById<TextInputLayout>(R.id.exportDialogTilConfirm)
|
||||
val exportButton = dialogLayout.findViewById<Button>(R.id.exportDialogSubmit)
|
||||
val textWatcher = object : SimpleTextWatcher() {
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
when {
|
||||
passPhrase1EditText.text.isNullOrEmpty() -> {
|
||||
exportButton.isEnabled = false
|
||||
passPhrase2Til.error = null
|
||||
}
|
||||
passPhrase1EditText.text.toString() == passPhrase2EditText.text.toString() -> {
|
||||
exportButton.isEnabled = true
|
||||
passPhrase2Til.error = null
|
||||
}
|
||||
else -> {
|
||||
exportButton.isEnabled = false
|
||||
passPhrase2Til.error = activity.getString(R.string.passphrase_passphrase_does_not_match)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
passPhrase1EditText.addTextChangedListener(textWatcher)
|
||||
passPhrase2EditText.addTextChangedListener(textWatcher)
|
||||
|
||||
val showPassword = dialogLayout.findViewById<ImageView>(R.id.exportDialogShowPassword)
|
||||
showPassword.setOnClickListener {
|
||||
passwordVisible = !passwordVisible
|
||||
passPhrase1EditText.showPassword(passwordVisible)
|
||||
passPhrase2EditText.showPassword(passwordVisible)
|
||||
showPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
}
|
||||
|
||||
val exportDialog = builder.show()
|
||||
|
||||
exportButton.setOnClickListener {
|
||||
exportKeyDialogListener.onPassphrase(passPhrase1EditText.text.toString())
|
||||
|
||||
exportDialog.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
interface ExportKeyDialogListener {
|
||||
fun onPassphrase(passphrase: String)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.dialogs
|
||||
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import im.vector.app.R
|
||||
|
||||
fun AlertDialog.withColoredButton(whichButton: Int, @ColorRes color: Int = R.color.vector_error_color): AlertDialog {
|
||||
getButton(whichButton)?.setTextColor(ContextCompat.getColor(context, color))
|
||||
return this
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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.core.dialogs
|
||||
|
||||
import android.app.Activity
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import im.vector.app.R
|
||||
import im.vector.matrix.android.api.extensions.getFingerprintHumanReadable
|
||||
import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo
|
||||
|
||||
object ManuallyVerifyDialog {
|
||||
|
||||
fun show(activity: Activity, cryptoDeviceInfo: CryptoDeviceInfo, onVerified: (() -> Unit)) {
|
||||
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_device_verify, null)
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
.setTitle(R.string.cross_signing_verify_by_text)
|
||||
.setView(dialogLayout)
|
||||
.setPositiveButton(R.string.encryption_information_verify) { _, _ ->
|
||||
onVerified()
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
|
||||
dialogLayout.findViewById<TextView>(R.id.encrypted_device_info_device_name)?.let {
|
||||
it.text = cryptoDeviceInfo.displayName()
|
||||
}
|
||||
|
||||
dialogLayout.findViewById<TextView>(R.id.encrypted_device_info_device_id)?.let {
|
||||
it.text = cryptoDeviceInfo.deviceId
|
||||
}
|
||||
|
||||
dialogLayout.findViewById<TextView>(R.id.encrypted_device_info_device_key)?.let {
|
||||
it.text = cryptoDeviceInfo.getFingerprintHumanReadable()
|
||||
}
|
||||
|
||||
builder.show()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright 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.core.dialogs
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.DialogInterface
|
||||
import android.text.Editable
|
||||
import android.view.KeyEvent
|
||||
import android.widget.ImageView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.hideKeyboard
|
||||
import im.vector.app.core.extensions.showPassword
|
||||
import im.vector.app.core.platform.SimpleTextWatcher
|
||||
|
||||
class PromptPasswordDialog {
|
||||
|
||||
private var passwordVisible = false
|
||||
|
||||
fun show(activity: Activity, listener: (String) -> Unit) {
|
||||
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_prompt_password, null)
|
||||
|
||||
val passwordTil = dialogLayout.findViewById<TextInputLayout>(R.id.promptPasswordTil)
|
||||
val passwordEditText = dialogLayout.findViewById<TextInputEditText>(R.id.promptPassword)
|
||||
val textWatcher = object : SimpleTextWatcher() {
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
passwordTil.error = null
|
||||
}
|
||||
}
|
||||
passwordEditText.addTextChangedListener(textWatcher)
|
||||
|
||||
val showPassword = dialogLayout.findViewById<ImageView>(R.id.promptPasswordPasswordReveal)
|
||||
showPassword.setOnClickListener {
|
||||
passwordVisible = !passwordVisible
|
||||
passwordEditText.showPassword(passwordVisible)
|
||||
showPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed else R.drawable.ic_eye)
|
||||
}
|
||||
|
||||
AlertDialog.Builder(activity)
|
||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||
.setTitle(R.string.devices_delete_dialog_title)
|
||||
.setView(dialogLayout)
|
||||
.setPositiveButton(R.string.auth_submit, null)
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.setOnKeyListener(DialogInterface.OnKeyListener { dialog, keyCode, event ->
|
||||
if (event.action == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
dialog.cancel()
|
||||
return@OnKeyListener true
|
||||
}
|
||||
false
|
||||
})
|
||||
.setOnDismissListener {
|
||||
dialogLayout.hideKeyboard()
|
||||
}
|
||||
.create()
|
||||
.apply {
|
||||
setOnShowListener {
|
||||
getButton(AlertDialog.BUTTON_POSITIVE)
|
||||
.setOnClickListener {
|
||||
if (passwordEditText.text.toString().isEmpty()) {
|
||||
passwordTil.error = activity.getString(R.string.error_empty_field_your_password)
|
||||
} else {
|
||||
listener.invoke(passwordEditText.text.toString())
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* 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.core.dialogs
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.matrix.android.internal.network.ssl.Fingerprint
|
||||
import timber.log.Timber
|
||||
import java.util.HashMap
|
||||
import java.util.HashSet
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* This class displays the unknown certificate dialog
|
||||
*/
|
||||
class UnrecognizedCertificateDialog @Inject constructor(
|
||||
private val activeSessionHolder: ActiveSessionHolder,
|
||||
private val stringProvider: StringProvider
|
||||
) {
|
||||
private val ignoredFingerprints: MutableMap<String, MutableSet<Fingerprint>> = HashMap()
|
||||
private val openDialogIds: MutableSet<String> = HashSet()
|
||||
|
||||
/**
|
||||
* Display a certificate dialog box, asking the user about an unknown certificate
|
||||
* To use when user is currently logged in
|
||||
*
|
||||
* @param unrecognizedFingerprint the fingerprint for the unknown certificate
|
||||
* @param callback callback to fire when the user makes a decision
|
||||
*/
|
||||
fun show(activity: Activity,
|
||||
unrecognizedFingerprint: Fingerprint,
|
||||
callback: Callback) {
|
||||
val userId = activeSessionHolder.getSafeActiveSession()?.myUserId
|
||||
val hsConfig = activeSessionHolder.getSafeActiveSession()?.sessionParams?.homeServerConnectionConfig ?: return
|
||||
|
||||
internalShow(activity, unrecognizedFingerprint, true, callback, userId, hsConfig.homeServerUri.toString(), hsConfig.allowedFingerprints.isNotEmpty())
|
||||
}
|
||||
|
||||
/**
|
||||
* To use during login flow
|
||||
*/
|
||||
fun show(activity: Activity,
|
||||
unrecognizedFingerprint: Fingerprint,
|
||||
homeServerUrl: String,
|
||||
callback: Callback) {
|
||||
internalShow(activity, unrecognizedFingerprint, false, callback, null, homeServerUrl, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a certificate dialog box, asking the user about an unknown certificate
|
||||
*
|
||||
* @param unrecognizedFingerprint the fingerprint for the unknown certificate
|
||||
* @param existing the current session already exist, so it mean that something has changed server side
|
||||
* @param callback callback to fire when the user makes a decision
|
||||
*/
|
||||
private fun internalShow(activity: Activity,
|
||||
unrecognizedFingerprint: Fingerprint,
|
||||
existing: Boolean,
|
||||
callback: Callback,
|
||||
userId: String?,
|
||||
homeServerUrl: String,
|
||||
homeServerConnectionConfigHasFingerprints: Boolean) {
|
||||
val dialogId = userId ?: homeServerUrl + unrecognizedFingerprint.displayableHexRepr
|
||||
|
||||
if (openDialogIds.contains(dialogId)) {
|
||||
Timber.i("Not opening dialog $dialogId as one is already open.")
|
||||
return
|
||||
}
|
||||
|
||||
if (userId != null) {
|
||||
val f: Set<Fingerprint>? = ignoredFingerprints[userId]
|
||||
if (f != null && f.contains(unrecognizedFingerprint)) {
|
||||
callback.onIgnore()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
val inflater = activity.layoutInflater
|
||||
val layout: View = inflater.inflate(R.layout.dialog_ssl_fingerprint, null)
|
||||
val sslFingerprintTitle = layout.findViewById<TextView>(R.id.ssl_fingerprint_title)
|
||||
sslFingerprintTitle.text = stringProvider.getString(R.string.ssl_fingerprint_hash, unrecognizedFingerprint.hashType.toString())
|
||||
val sslFingerprint = layout.findViewById<TextView>(R.id.ssl_fingerprint)
|
||||
sslFingerprint.text = unrecognizedFingerprint.displayableHexRepr
|
||||
val sslUserId = layout.findViewById<TextView>(R.id.ssl_user_id)
|
||||
if (userId != null) {
|
||||
sslUserId.text = stringProvider.getString(R.string.generic_label_and_value,
|
||||
stringProvider.getString(R.string.username),
|
||||
userId)
|
||||
} else {
|
||||
sslUserId.text = stringProvider.getString(R.string.generic_label_and_value,
|
||||
stringProvider.getString(R.string.hs_url),
|
||||
homeServerUrl)
|
||||
}
|
||||
val sslExpl = layout.findViewById<TextView>(R.id.ssl_explanation)
|
||||
if (existing) {
|
||||
if (homeServerConnectionConfigHasFingerprints) {
|
||||
sslExpl.text = stringProvider.getString(R.string.ssl_expected_existing_expl)
|
||||
} else {
|
||||
sslExpl.text = stringProvider.getString(R.string.ssl_unexpected_existing_expl)
|
||||
}
|
||||
} else {
|
||||
sslExpl.text = stringProvider.getString(R.string.ssl_cert_new_account_expl)
|
||||
}
|
||||
builder.setView(layout)
|
||||
builder.setTitle(R.string.ssl_could_not_verify)
|
||||
builder.setPositiveButton(R.string.ssl_trust) { _, _ ->
|
||||
callback.onAccept()
|
||||
}
|
||||
if (existing) {
|
||||
builder.setNegativeButton(R.string.ssl_remain_offline) { _, _ ->
|
||||
if (userId != null) {
|
||||
var f = ignoredFingerprints[userId]
|
||||
if (f == null) {
|
||||
f = HashSet()
|
||||
ignoredFingerprints[userId] = f
|
||||
}
|
||||
f.add(unrecognizedFingerprint)
|
||||
}
|
||||
callback.onIgnore()
|
||||
}
|
||||
builder.setNeutralButton(R.string.ssl_logout_account) { _, _ -> callback.onReject() }
|
||||
} else {
|
||||
builder.setNegativeButton(R.string.cancel) { _, _ -> callback.onReject() }
|
||||
}
|
||||
|
||||
builder.setOnDismissListener {
|
||||
Timber.d("Dismissed!")
|
||||
openDialogIds.remove(dialogId)
|
||||
}
|
||||
|
||||
builder.show()
|
||||
openDialogIds.add(dialogId)
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
/**
|
||||
* The certificate was explicitly accepted
|
||||
*/
|
||||
fun onAccept()
|
||||
|
||||
/**
|
||||
* The warning was ignored by the user
|
||||
*/
|
||||
fun onIgnore()
|
||||
|
||||
/**
|
||||
* The unknown certificate was explicitly rejected
|
||||
*/
|
||||
fun onReject()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.epoxy
|
||||
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
|
||||
/**
|
||||
* Default background color is for the bottom sheets (R.attr.vctr_list_bottom_sheet_divider_color).
|
||||
* To use in fragment, set color using R.attr.riotx_list_divider_color
|
||||
*/
|
||||
@EpoxyModelClass(layout = R.layout.item_divider)
|
||||
abstract class DividerItem : VectorEpoxyModel<DividerItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute var color: Int = -1
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
if (color != -1) {
|
||||
holder.view.setBackgroundColor(color)
|
||||
}
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder()
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.epoxy
|
||||
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_empty)
|
||||
abstract class EmptyItem : VectorEpoxyModel<EmptyItem.Holder>() {
|
||||
class Holder : VectorEpoxyHolder()
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.epoxy
|
||||
|
||||
import android.widget.Button
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_error_retry)
|
||||
abstract class ErrorWithRetryItem : VectorEpoxyModel<ErrorWithRetryItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
var text: String? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var listener: (() -> Unit)? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.textView.text = text
|
||||
holder.buttonView.isVisible = listener != null
|
||||
holder.buttonView.setOnClickListener { listener?.invoke() }
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val textView by bind<TextView>(R.id.itemErrorRetryText)
|
||||
val buttonView by bind<Button>(R.id.itemErrorRetryButton)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.epoxy
|
||||
|
||||
import android.widget.TextView
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_help_footer)
|
||||
abstract class HelpFooterItem : VectorEpoxyModel<HelpFooterItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
var text: String? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.textView.text = text
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val textView by bind<TextView>(R.id.itemHelpText)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.epoxy
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import im.vector.app.core.platform.DefaultListUpdateCallback
|
||||
import im.vector.app.core.platform.Restorable
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
private const val LAYOUT_MANAGER_STATE = "LAYOUT_MANAGER_STATE"
|
||||
|
||||
class LayoutManagerStateRestorer(layoutManager: RecyclerView.LayoutManager) : Restorable, DefaultListUpdateCallback {
|
||||
|
||||
private var layoutManager: RecyclerView.LayoutManager? = null
|
||||
private var layoutManagerState = AtomicReference<Parcelable?>()
|
||||
|
||||
init {
|
||||
this.layoutManager = layoutManager
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
layoutManager = null
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
val layoutManagerState = layoutManager?.onSaveInstanceState()
|
||||
outState.putParcelable(LAYOUT_MANAGER_STATE, layoutManagerState)
|
||||
}
|
||||
|
||||
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
|
||||
val parcelable = savedInstanceState?.getParcelable<Parcelable>(LAYOUT_MANAGER_STATE)
|
||||
layoutManagerState.set(parcelable)
|
||||
}
|
||||
|
||||
override fun onInserted(position: Int, count: Int) {
|
||||
layoutManagerState.getAndSet(null)?.also {
|
||||
layoutManager?.onRestoreInstanceState(it)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 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.core.epoxy
|
||||
|
||||
import android.view.View
|
||||
|
||||
/**
|
||||
* Generally we do not care about the View parameter in [View.OnClickListener.onClick()], so create facility to remove it.
|
||||
*/
|
||||
typealias ClickListener = () -> Unit
|
||||
|
||||
fun View.onClick(listener: ClickListener?) {
|
||||
setOnClickListener { listener?.invoke() }
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.epoxy
|
||||
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.setTextOrHide
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_loading)
|
||||
abstract class LoadingItem : VectorEpoxyModel<LoadingItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute var loadingText: String? = null
|
||||
@EpoxyAttribute var showLoader: Boolean = true
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.progressBar.isVisible = showLoader
|
||||
holder.textView.setTextOrHide(loadingText)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val textView by bind<TextView>(R.id.loadingText)
|
||||
val progressBar by bind<ProgressBar>(R.id.loadingProgress)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.epoxy
|
||||
|
||||
import android.widget.TextView
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_no_result)
|
||||
abstract class NoResultItem : VectorEpoxyModel<NoResultItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
var text: String? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.textView.text = text
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val textView by bind<TextView>(R.id.itemNoResultText)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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.core.epoxy
|
||||
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.app.R
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_loading_square)
|
||||
abstract class SquareLoadingItem : VectorEpoxyModel<SquareLoadingItem.Holder>() {
|
||||
|
||||
class Holder : VectorEpoxyHolder()
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.epoxy
|
||||
|
||||
import android.view.View
|
||||
import com.airbnb.epoxy.EpoxyHolder
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
/**
|
||||
* A pattern for easier view binding with an [EpoxyHolder]
|
||||
*
|
||||
* See [SampleKotlinModelWithHolder] for a usage example.
|
||||
*/
|
||||
abstract class VectorEpoxyHolder : EpoxyHolder() {
|
||||
lateinit var view: View
|
||||
|
||||
override fun bindView(itemView: View) {
|
||||
view = itemView
|
||||
}
|
||||
|
||||
protected fun <V : View> bind(id: Int): ReadOnlyProperty<VectorEpoxyHolder, V> =
|
||||
Lazy { holder: VectorEpoxyHolder, prop ->
|
||||
holder.view.findViewById(id) as V?
|
||||
?: throw IllegalStateException("View ID $id for '${prop.name}' not found.")
|
||||
}
|
||||
|
||||
/**
|
||||
* Taken from Kotterknife.
|
||||
* https://github.com/JakeWharton/kotterknife
|
||||
*/
|
||||
private class Lazy<V>(
|
||||
private val initializer: (VectorEpoxyHolder, KProperty<*>) -> V
|
||||
) : ReadOnlyProperty<VectorEpoxyHolder, V> {
|
||||
private object EMPTY
|
||||
|
||||
private var value: Any? = EMPTY
|
||||
|
||||
override fun getValue(thisRef: VectorEpoxyHolder, property: KProperty<*>): V {
|
||||
if (value == EMPTY) {
|
||||
value = initializer(thisRef, property)
|
||||
}
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return value as V
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright 2019 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.core.epoxy
|
||||
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LifecycleRegistry
|
||||
import com.airbnb.epoxy.EpoxyModelWithHolder
|
||||
import com.airbnb.epoxy.VisibilityState
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.cancelChildren
|
||||
|
||||
/**
|
||||
* EpoxyModelWithHolder which can listen to visibility state change
|
||||
*/
|
||||
abstract class VectorEpoxyModel<H : VectorEpoxyHolder> : EpoxyModelWithHolder<H>(), LifecycleOwner {
|
||||
|
||||
protected val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
|
||||
private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(this)
|
||||
|
||||
override fun getLifecycle() = lifecycleRegistry
|
||||
|
||||
private var onModelVisibilityStateChangedListener: OnVisibilityStateChangedListener? = null
|
||||
|
||||
@CallSuper
|
||||
override fun bind(holder: H) {
|
||||
super.bind(holder)
|
||||
lifecycleRegistry.currentState = Lifecycle.State.STARTED
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
override fun unbind(holder: H) {
|
||||
lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
|
||||
coroutineScope.coroutineContext.cancelChildren()
|
||||
super.unbind(holder)
|
||||
}
|
||||
|
||||
override fun onVisibilityStateChanged(visibilityState: Int, view: H) {
|
||||
onModelVisibilityStateChangedListener?.onVisibilityStateChanged(visibilityState)
|
||||
super.onVisibilityStateChanged(visibilityState, view)
|
||||
}
|
||||
|
||||
fun setOnVisibilityStateChanged(listener: OnVisibilityStateChangedListener): VectorEpoxyModel<H> {
|
||||
this.onModelVisibilityStateChangedListener = listener
|
||||
return this
|
||||
}
|
||||
|
||||
interface OnVisibilityStateChangedListener {
|
||||
fun onVisibilityStateChanged(@VisibilityState.Visibility visibilityState: Int)
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue