mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 02:15:35 +03:00
Use Clock interface app side
This commit is contained in:
parent
45526c0e3a
commit
40d3203297
45 changed files with 320 additions and 174 deletions
|
@ -43,6 +43,7 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
|
||||||
|
import im.vector.app.core.time.DefaultClock
|
||||||
import im.vector.app.espresso.tools.waitUntilViewVisible
|
import im.vector.app.espresso.tools.waitUntilViewVisible
|
||||||
import org.hamcrest.Matcher
|
import org.hamcrest.Matcher
|
||||||
import org.hamcrest.Matchers
|
import org.hamcrest.Matchers
|
||||||
|
@ -52,6 +53,7 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.PrivateKeysInfo
|
||||||
import org.matrix.android.sdk.api.session.sync.SyncState
|
import org.matrix.android.sdk.api.session.sync.SyncState
|
||||||
import org.matrix.android.sdk.api.util.Optional
|
import org.matrix.android.sdk.api.util.Optional
|
||||||
import java.util.concurrent.TimeoutException
|
import java.util.concurrent.TimeoutException
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
object EspressoHelper {
|
object EspressoHelper {
|
||||||
fun getCurrentActivity(): Activity? {
|
fun getCurrentActivity(): Activity? {
|
||||||
|
@ -89,6 +91,8 @@ fun getString(@StringRes id: Int): String {
|
||||||
|
|
||||||
fun waitForView(viewMatcher: Matcher<View>, timeout: Long = 10_000, waitForDisplayed: Boolean = true): ViewAction {
|
fun waitForView(viewMatcher: Matcher<View>, timeout: Long = 10_000, waitForDisplayed: Boolean = true): ViewAction {
|
||||||
return object : ViewAction {
|
return object : ViewAction {
|
||||||
|
private val clock = DefaultClock()
|
||||||
|
|
||||||
override fun getConstraints(): Matcher<View> {
|
override fun getConstraints(): Matcher<View> {
|
||||||
return Matchers.any(View::class.java)
|
return Matchers.any(View::class.java)
|
||||||
}
|
}
|
||||||
|
@ -102,14 +106,14 @@ fun waitForView(viewMatcher: Matcher<View>, timeout: Long = 10_000, waitForDispl
|
||||||
override fun perform(uiController: UiController, view: View) {
|
override fun perform(uiController: UiController, view: View) {
|
||||||
println("*** waitForView 1 $view")
|
println("*** waitForView 1 $view")
|
||||||
uiController.loopMainThreadUntilIdle()
|
uiController.loopMainThreadUntilIdle()
|
||||||
val startTime = System.currentTimeMillis()
|
val startTime = clock.epochMillis()
|
||||||
val endTime = startTime + timeout
|
val endTime = startTime + timeout
|
||||||
val visibleMatcher = isDisplayed()
|
val visibleMatcher = isDisplayed()
|
||||||
|
|
||||||
uiController.loopMainThreadForAtLeast(100)
|
uiController.loopMainThreadForAtLeast(100)
|
||||||
|
|
||||||
do {
|
do {
|
||||||
println("*** waitForView loop $view end:$endTime current:${System.currentTimeMillis()}")
|
println("*** waitForView loop $view end:$endTime current:${clock.epochMillis()}")
|
||||||
val viewVisible = TreeIterables.breadthFirstViewTraversal(view)
|
val viewVisible = TreeIterables.breadthFirstViewTraversal(view)
|
||||||
.any { viewMatcher.matches(it) && visibleMatcher.matches(it) }
|
.any { viewMatcher.matches(it) && visibleMatcher.matches(it) }
|
||||||
|
|
||||||
|
@ -118,7 +122,7 @@ fun waitForView(viewMatcher: Matcher<View>, timeout: Long = 10_000, waitForDispl
|
||||||
println("*** waitForView loop loopMainThreadForAtLeast...")
|
println("*** waitForView loop loopMainThreadForAtLeast...")
|
||||||
uiController.loopMainThreadForAtLeast(50)
|
uiController.loopMainThreadForAtLeast(50)
|
||||||
println("*** waitForView loop ...loopMainThreadForAtLeast")
|
println("*** waitForView loop ...loopMainThreadForAtLeast")
|
||||||
} while (System.currentTimeMillis() < endTime)
|
} while (clock.epochMillis() < endTime)
|
||||||
|
|
||||||
println("*** waitForView timeout $view")
|
println("*** waitForView timeout $view")
|
||||||
// Timeout happens.
|
// Timeout happens.
|
||||||
|
@ -168,7 +172,7 @@ fun activityIdlingResource(activityClass: Class<*>): IdlingResource {
|
||||||
val res = object : IdlingResource, ActivityLifecycleCallback {
|
val res = object : IdlingResource, ActivityLifecycleCallback {
|
||||||
private var callback: IdlingResource.ResourceCallback? = null
|
private var callback: IdlingResource.ResourceCallback? = null
|
||||||
private var resumedActivity: Activity? = null
|
private var resumedActivity: Activity? = null
|
||||||
private val uniqTS = System.currentTimeMillis()
|
private val uniqTS = Random.nextLong()
|
||||||
|
|
||||||
override fun getName() = "activityIdlingResource_${activityClass.name}_$uniqTS"
|
override fun getName() = "activityIdlingResource_${activityClass.name}_$uniqTS"
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.hamcrest.CoreMatchers.not
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
@LargeTest
|
@LargeTest
|
||||||
|
@ -44,7 +45,7 @@ class RegistrationTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun simpleRegister() {
|
fun simpleRegister() {
|
||||||
val userId: String = "UiAutoTest_${System.currentTimeMillis()}"
|
val userId: String = "UiAutoTest_${Random.nextLong()}"
|
||||||
val password: String = "password"
|
val password: String = "password"
|
||||||
val homeServerUrl: String = "http://10.0.2.2:8080"
|
val homeServerUrl: String = "http://10.0.2.2:8080"
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
@LargeTest
|
@LargeTest
|
||||||
|
@ -61,7 +62,7 @@ class SecurityBootstrapTest : VerificationTestBase() {
|
||||||
@Before
|
@Before
|
||||||
fun createSessionWithCrossSigning() {
|
fun createSessionWithCrossSigning() {
|
||||||
val matrix = getMatrixInstance()
|
val matrix = getMatrixInstance()
|
||||||
val userName = "foobar_${System.currentTimeMillis()}"
|
val userName = "foobar_${Random.nextLong()}"
|
||||||
existingSession = createAccountAndSync(matrix, userName, password, true)
|
existingSession = createAccountAndSync(matrix, userName, password, true)
|
||||||
stubAllExternalIntents()
|
stubAllExternalIntents()
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransa
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState
|
||||||
import kotlin.coroutines.Continuation
|
import kotlin.coroutines.Continuation
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
@LargeTest
|
@LargeTest
|
||||||
|
@ -66,7 +67,7 @@ class VerifySessionInteractiveTest : VerificationTestBase() {
|
||||||
@Before
|
@Before
|
||||||
fun createSessionWithCrossSigning() {
|
fun createSessionWithCrossSigning() {
|
||||||
val matrix = getMatrixInstance()
|
val matrix = getMatrixInstance()
|
||||||
val userName = "foobar_${System.currentTimeMillis()}"
|
val userName = "foobar_${Random.nextLong()}"
|
||||||
existingSession = createAccountAndSync(matrix, userName, password, true)
|
existingSession = createAccountAndSync(matrix, userName, password, true)
|
||||||
doSync<Unit> {
|
doSync<Unit> {
|
||||||
existingSession!!.cryptoService().crossSigningService()
|
existingSession!!.cryptoService().crossSigningService()
|
||||||
|
|
|
@ -53,6 +53,7 @@ import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import kotlin.coroutines.Continuation
|
import kotlin.coroutines.Continuation
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
@LargeTest
|
@LargeTest
|
||||||
|
@ -68,7 +69,7 @@ class VerifySessionPassphraseTest : VerificationTestBase() {
|
||||||
fun createSessionWithCrossSigningAnd4S() {
|
fun createSessionWithCrossSigningAnd4S() {
|
||||||
val context = InstrumentationRegistry.getInstrumentation().targetContext
|
val context = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
val matrix = getMatrixInstance()
|
val matrix = getMatrixInstance()
|
||||||
val userName = "foobar_${System.currentTimeMillis()}"
|
val userName = "foobar_${Random.nextLong()}"
|
||||||
existingSession = createAccountAndSync(matrix, userName, password, true)
|
existingSession = createAccountAndSync(matrix, userName, password, true)
|
||||||
doSync<Unit> {
|
doSync<Unit> {
|
||||||
existingSession!!.cryptoService().crossSigningService()
|
existingSession!!.cryptoService().crossSigningService()
|
||||||
|
|
|
@ -24,6 +24,7 @@ import android.os.Build
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
|
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
|
||||||
|
import im.vector.app.core.time.DefaultClock
|
||||||
import org.junit.rules.TestWatcher
|
import org.junit.rules.TestWatcher
|
||||||
import org.junit.runner.Description
|
import org.junit.runner.Description
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
@ -54,7 +55,7 @@ private fun storeFailureScreenshot(bitmap: Bitmap, screenshotName: String) {
|
||||||
|
|
||||||
val contentValues = ContentValues().apply {
|
val contentValues = ContentValues().apply {
|
||||||
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
|
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
|
||||||
put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())
|
put(MediaStore.Images.Media.DATE_TAKEN, DefaultClock().epochMillis())
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
useMediaStoreScreenshotStorage(
|
useMediaStoreScreenshotStorage(
|
||||||
|
|
|
@ -29,6 +29,7 @@ import im.vector.app.R
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||||
import im.vector.app.core.utils.checkPermissions
|
import im.vector.app.core.utils.checkPermissions
|
||||||
import im.vector.app.core.utils.registerForPermissionsResult
|
import im.vector.app.core.utils.registerForPermissionsResult
|
||||||
|
@ -59,6 +60,8 @@ class DebugMenuActivity : VectorBaseActivity<ActivityDebugMenuBinding>() {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var activeSessionHolder: ActiveSessionHolder
|
lateinit var activeSessionHolder: ActiveSessionHolder
|
||||||
|
@Inject
|
||||||
|
lateinit var clock: Clock
|
||||||
|
|
||||||
private lateinit var buffer: ByteArray
|
private lateinit var buffer: ByteArray
|
||||||
|
|
||||||
|
@ -165,7 +168,7 @@ class DebugMenuActivity : VectorBaseActivity<ActivityDebugMenuBinding>() {
|
||||||
}
|
}
|
||||||
|
|
||||||
val builder = NotificationCompat.Builder(this, "CHAN")
|
val builder = NotificationCompat.Builder(this, "CHAN")
|
||||||
.setWhen(System.currentTimeMillis())
|
.setWhen(clock.epochMillis())
|
||||||
.setContentTitle("Title")
|
.setContentTitle("Title")
|
||||||
.setContentText("Content")
|
.setContentText("Content")
|
||||||
// No effect because it's a group summary notif
|
// No effect because it's a group summary notif
|
||||||
|
@ -180,16 +183,16 @@ class DebugMenuActivity : VectorBaseActivity<ActivityDebugMenuBinding>() {
|
||||||
.setName("User name")
|
.setName("User name")
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.addMessage("Message 1 - 1", System.currentTimeMillis(), Person.Builder().setName("user 1-1").build())
|
.addMessage("Message 1 - 1", clock.epochMillis(), Person.Builder().setName("user 1-1").build())
|
||||||
.addMessage("Message 1 - 2", System.currentTimeMillis(), Person.Builder().setName("user 1-2").build())
|
.addMessage("Message 1 - 2", clock.epochMillis(), Person.Builder().setName("user 1-2").build())
|
||||||
|
|
||||||
val messagingStyle2 = NotificationCompat.MessagingStyle(
|
val messagingStyle2 = NotificationCompat.MessagingStyle(
|
||||||
Person.Builder()
|
Person.Builder()
|
||||||
.setName("User name 2")
|
.setName("User name 2")
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.addMessage("Message 2 - 1", System.currentTimeMillis(), Person.Builder().setName("user 1-1").build())
|
.addMessage("Message 2 - 1", clock.epochMillis(), Person.Builder().setName("user 1-1").build())
|
||||||
.addMessage("Message 2 - 2", System.currentTimeMillis(), Person.Builder().setName("user 1-2").build())
|
.addMessage("Message 2 - 2", clock.epochMillis(), Person.Builder().setName("user 1-2").build())
|
||||||
|
|
||||||
notificationManager.notify(10, builder.build())
|
notificationManager.notify(10, builder.build())
|
||||||
|
|
||||||
|
@ -197,7 +200,7 @@ class DebugMenuActivity : VectorBaseActivity<ActivityDebugMenuBinding>() {
|
||||||
11,
|
11,
|
||||||
NotificationCompat.Builder(this, "CHAN")
|
NotificationCompat.Builder(this, "CHAN")
|
||||||
.setChannelId("CHAN")
|
.setChannelId("CHAN")
|
||||||
.setWhen(System.currentTimeMillis())
|
.setWhen(clock.epochMillis())
|
||||||
.setContentTitle("Title 1")
|
.setContentTitle("Title 1")
|
||||||
.setContentText("Content 1")
|
.setContentText("Content 1")
|
||||||
// For shortcut on long press on launcher icon
|
// For shortcut on long press on launcher icon
|
||||||
|
@ -211,7 +214,7 @@ class DebugMenuActivity : VectorBaseActivity<ActivityDebugMenuBinding>() {
|
||||||
notificationManager.notify(
|
notificationManager.notify(
|
||||||
12,
|
12,
|
||||||
NotificationCompat.Builder(this, "CHAN2")
|
NotificationCompat.Builder(this, "CHAN2")
|
||||||
.setWhen(System.currentTimeMillis())
|
.setWhen(clock.epochMillis())
|
||||||
.setContentTitle("Title 2")
|
.setContentTitle("Title 2")
|
||||||
.setContentText("Content 2")
|
.setContentText("Content 2")
|
||||||
.setStyle(messagingStyle2)
|
.setStyle(messagingStyle2)
|
||||||
|
|
|
@ -74,7 +74,7 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() {
|
||||||
intent,
|
intent,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
val firstMillis = System.currentTimeMillis() + delayInSeconds * 1000L
|
val firstMillis = clock.epochMillis() + delayInSeconds * 1000L
|
||||||
val alarmMgr = context.getSystemService<AlarmManager>()!!
|
val alarmMgr = context.getSystemService<AlarmManager>()!!
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, firstMillis, pIntent)
|
alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, firstMillis, pIntent)
|
||||||
|
|
|
@ -22,15 +22,19 @@ import android.text.format.DateUtils
|
||||||
import im.vector.app.core.resources.DateProvider
|
import im.vector.app.core.resources.DateProvider
|
||||||
import im.vector.app.core.resources.LocaleProvider
|
import im.vector.app.core.resources.LocaleProvider
|
||||||
import im.vector.app.core.resources.toTimestamp
|
import im.vector.app.core.resources.toTimestamp
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import org.threeten.bp.LocalDateTime
|
import org.threeten.bp.LocalDateTime
|
||||||
import org.threeten.bp.Period
|
import org.threeten.bp.Period
|
||||||
import org.threeten.bp.format.DateTimeFormatter
|
import org.threeten.bp.format.DateTimeFormatter
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
class VectorDateFormatter @Inject constructor(private val context: Context,
|
class VectorDateFormatter @Inject constructor(
|
||||||
private val localeProvider: LocaleProvider,
|
private val context: Context,
|
||||||
private val dateFormatterProviders: DateFormatterProviders) {
|
private val localeProvider: LocaleProvider,
|
||||||
|
private val dateFormatterProviders: DateFormatterProviders,
|
||||||
|
private val clock: Clock,
|
||||||
|
) {
|
||||||
|
|
||||||
private val hourFormatter by lazy {
|
private val hourFormatter by lazy {
|
||||||
if (DateFormat.is24HourFormat(context)) {
|
if (DateFormat.is24HourFormat(context)) {
|
||||||
|
@ -158,8 +162,9 @@ class VectorDateFormatter @Inject constructor(private val context: Context,
|
||||||
private fun getRelativeDay(ts: Long): String {
|
private fun getRelativeDay(ts: Long): String {
|
||||||
return DateUtils.getRelativeTimeSpanString(
|
return DateUtils.getRelativeTimeSpanString(
|
||||||
ts,
|
ts,
|
||||||
System.currentTimeMillis(),
|
clock.epochMillis(),
|
||||||
DateUtils.DAY_IN_MILLIS,
|
DateUtils.DAY_IN_MILLIS,
|
||||||
DateUtils.FORMAT_SHOW_WEEKDAY).toString()
|
DateUtils.FORMAT_SHOW_WEEKDAY
|
||||||
|
).toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import im.vector.app.core.dialogs.GalleryOrCameraDialogHelper.Listener
|
||||||
import im.vector.app.core.extensions.insertBeforeLast
|
import im.vector.app.core.extensions.insertBeforeLast
|
||||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||||
import im.vector.app.core.resources.ColorProvider
|
import im.vector.app.core.resources.ColorProvider
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||||
import im.vector.app.core.utils.checkPermissions
|
import im.vector.app.core.utils.checkPermissions
|
||||||
import im.vector.app.core.utils.onPermissionDeniedDialog
|
import im.vector.app.core.utils.onPermissionDeniedDialog
|
||||||
|
@ -45,7 +46,8 @@ import java.io.File
|
||||||
class GalleryOrCameraDialogHelper(
|
class GalleryOrCameraDialogHelper(
|
||||||
// must implement GalleryOrCameraDialogHelper.Listener
|
// must implement GalleryOrCameraDialogHelper.Listener
|
||||||
private val fragment: Fragment,
|
private val fragment: Fragment,
|
||||||
private val colorProvider: ColorProvider
|
private val colorProvider: ColorProvider,
|
||||||
|
private val clock: Clock,
|
||||||
) {
|
) {
|
||||||
interface Listener {
|
interface Listener {
|
||||||
fun onImageReady(uri: Uri?)
|
fun onImageReady(uri: Uri?)
|
||||||
|
@ -91,7 +93,7 @@ class GalleryOrCameraDialogHelper(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startUCrop(image: MultiPickerImageType) {
|
private fun startUCrop(image: MultiPickerImageType) {
|
||||||
val destinationFile = File(activity.cacheDir, image.displayName.insertBeforeLast("_e_${System.currentTimeMillis()}"))
|
val destinationFile = File(activity.cacheDir, image.displayName.insertBeforeLast("_e_${clock.epochMillis()}"))
|
||||||
val uri = image.contentUri
|
val uri = image.contentUri
|
||||||
createUCropWithDefaultSettings(colorProvider, uri, destinationFile.toUri(), fragment.getString(R.string.rotate_and_crop_screen_title))
|
createUCropWithDefaultSettings(colorProvider, uri, destinationFile.toUri(), fragment.getString(R.string.rotate_and_crop_screen_title))
|
||||||
.withAspectRatio(1f, 1f)
|
.withAspectRatio(1f, 1f)
|
||||||
|
|
|
@ -33,6 +33,8 @@ import androidx.work.WorkerParameters
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.platform.PendingIntentCompat
|
import im.vector.app.core.platform.PendingIntentCompat
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
|
import im.vector.app.core.time.DefaultClock
|
||||||
import im.vector.app.features.notifications.NotificationUtils
|
import im.vector.app.features.notifications.NotificationUtils
|
||||||
import im.vector.app.features.settings.BackgroundSyncMode
|
import im.vector.app.features.settings.BackgroundSyncMode
|
||||||
import org.matrix.android.sdk.api.Matrix
|
import org.matrix.android.sdk.api.Matrix
|
||||||
|
@ -77,6 +79,7 @@ class VectorSyncService : SyncService() {
|
||||||
|
|
||||||
@Inject lateinit var notificationUtils: NotificationUtils
|
@Inject lateinit var notificationUtils: NotificationUtils
|
||||||
@Inject lateinit var matrix: Matrix
|
@Inject lateinit var matrix: Matrix
|
||||||
|
@Inject lateinit var clock: Clock
|
||||||
|
|
||||||
override fun provideMatrix() = matrix
|
override fun provideMatrix() = matrix
|
||||||
|
|
||||||
|
@ -102,7 +105,8 @@ class VectorSyncService : SyncService() {
|
||||||
syncTimeoutSeconds = syncTimeoutSeconds,
|
syncTimeoutSeconds = syncTimeoutSeconds,
|
||||||
syncDelaySeconds = syncDelaySeconds,
|
syncDelaySeconds = syncDelaySeconds,
|
||||||
isPeriodic = true,
|
isPeriodic = true,
|
||||||
isNetworkBack = false
|
isNetworkBack = false,
|
||||||
|
now = clock.epochMillis()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,9 +118,10 @@ class VectorSyncService : SyncService() {
|
||||||
val rescheduleSyncWorkRequest: WorkRequest =
|
val rescheduleSyncWorkRequest: WorkRequest =
|
||||||
OneTimeWorkRequestBuilder<RestartWhenNetworkOn>()
|
OneTimeWorkRequestBuilder<RestartWhenNetworkOn>()
|
||||||
.setInputData(RestartWhenNetworkOn.createInputData(sessionId, syncTimeoutSeconds, syncDelaySeconds, isPeriodic))
|
.setInputData(RestartWhenNetworkOn.createInputData(sessionId, syncTimeoutSeconds, syncDelaySeconds, isPeriodic))
|
||||||
.setConstraints(Constraints.Builder()
|
.setConstraints(
|
||||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
Constraints.Builder()
|
||||||
.build()
|
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||||
|
.build()
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
@ -137,20 +142,27 @@ class VectorSyncService : SyncService() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// I do not move or rename this class, since I'm not sure about the side effect regarding the WorkManager
|
// I do not move or rename this class, since I'm not sure about the side effect regarding the WorkManager
|
||||||
class RestartWhenNetworkOn(appContext: Context, workerParams: WorkerParameters) :
|
class RestartWhenNetworkOn(
|
||||||
Worker(appContext, workerParams) {
|
appContext: Context,
|
||||||
|
workerParams: WorkerParameters
|
||||||
|
) : Worker(appContext, workerParams) {
|
||||||
|
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
Timber.d("## Sync: RestartWhenNetworkOn.doWork()")
|
Timber.d("## Sync: RestartWhenNetworkOn.doWork()")
|
||||||
val sessionId = inputData.getString(KEY_SESSION_ID) ?: return Result.failure()
|
val sessionId = inputData.getString(KEY_SESSION_ID) ?: return Result.failure()
|
||||||
val syncTimeoutSeconds = inputData.getInt(KEY_SYNC_TIMEOUT_SECONDS, BackgroundSyncMode.DEFAULT_SYNC_TIMEOUT_SECONDS)
|
val syncTimeoutSeconds = inputData.getInt(KEY_SYNC_TIMEOUT_SECONDS, BackgroundSyncMode.DEFAULT_SYNC_TIMEOUT_SECONDS)
|
||||||
val syncDelaySeconds = inputData.getInt(KEY_SYNC_DELAY_SECONDS, BackgroundSyncMode.DEFAULT_SYNC_DELAY_SECONDS)
|
val syncDelaySeconds = inputData.getInt(KEY_SYNC_DELAY_SECONDS, BackgroundSyncMode.DEFAULT_SYNC_DELAY_SECONDS)
|
||||||
val isPeriodic = inputData.getBoolean(KEY_IS_PERIODIC, false)
|
val isPeriodic = inputData.getBoolean(KEY_IS_PERIODIC, false)
|
||||||
|
|
||||||
|
// Not sure how to inject a Clock here
|
||||||
|
val clock = DefaultClock()
|
||||||
applicationContext.rescheduleSyncService(
|
applicationContext.rescheduleSyncService(
|
||||||
sessionId = sessionId,
|
sessionId = sessionId,
|
||||||
syncTimeoutSeconds = syncTimeoutSeconds,
|
syncTimeoutSeconds = syncTimeoutSeconds,
|
||||||
syncDelaySeconds = syncDelaySeconds,
|
syncDelaySeconds = syncDelaySeconds,
|
||||||
isPeriodic = isPeriodic,
|
isPeriodic = isPeriodic,
|
||||||
isNetworkBack = true
|
isNetworkBack = true,
|
||||||
|
now = clock.epochMillis()
|
||||||
)
|
)
|
||||||
// Indicate whether the work finished successfully with the Result
|
// Indicate whether the work finished successfully with the Result
|
||||||
return Result.success()
|
return Result.success()
|
||||||
|
@ -182,7 +194,8 @@ private fun Context.rescheduleSyncService(sessionId: String,
|
||||||
syncTimeoutSeconds: Int,
|
syncTimeoutSeconds: Int,
|
||||||
syncDelaySeconds: Int,
|
syncDelaySeconds: Int,
|
||||||
isPeriodic: Boolean,
|
isPeriodic: Boolean,
|
||||||
isNetworkBack: Boolean) {
|
isNetworkBack: Boolean,
|
||||||
|
now: Long) {
|
||||||
Timber.d("## Sync: rescheduleSyncService")
|
Timber.d("## Sync: rescheduleSyncService")
|
||||||
val intent = if (isPeriodic) {
|
val intent = if (isPeriodic) {
|
||||||
VectorSyncService.newPeriodicIntent(
|
VectorSyncService.newPeriodicIntent(
|
||||||
|
@ -208,7 +221,7 @@ private fun Context.rescheduleSyncService(sessionId: String,
|
||||||
} else {
|
} else {
|
||||||
PendingIntent.getService(this, 0, intent, PendingIntentCompat.FLAG_IMMUTABLE)
|
PendingIntent.getService(this, 0, intent, PendingIntentCompat.FLAG_IMMUTABLE)
|
||||||
}
|
}
|
||||||
val firstMillis = System.currentTimeMillis() + syncDelaySeconds * 1000L
|
val firstMillis = now + syncDelaySeconds * 1000L
|
||||||
val alarmMgr = getSystemService<AlarmManager>()!!
|
val alarmMgr = getSystemService<AlarmManager>()!!
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent)
|
alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, firstMillis, pendingIntent)
|
||||||
|
|
|
@ -147,8 +147,11 @@ fun openFileSelection(activity: Activity,
|
||||||
* Send an email to address with optional subject and message
|
* Send an email to address with optional subject and message
|
||||||
*/
|
*/
|
||||||
fun sendMailTo(address: String, subject: String? = null, message: String? = null, activity: Activity) {
|
fun sendMailTo(address: String, subject: String? = null, message: String? = null, activity: Activity) {
|
||||||
val intent = Intent(Intent.ACTION_SENDTO, Uri.fromParts(
|
val intent = Intent(
|
||||||
"mailto", address, null))
|
Intent.ACTION_SENDTO, Uri.fromParts(
|
||||||
|
"mailto", address, null
|
||||||
|
)
|
||||||
|
)
|
||||||
intent.putExtra(Intent.EXTRA_SUBJECT, subject)
|
intent.putExtra(Intent.EXTRA_SUBJECT, subject)
|
||||||
intent.putExtra(Intent.EXTRA_TEXT, message)
|
intent.putExtra(Intent.EXTRA_TEXT, message)
|
||||||
|
|
||||||
|
@ -248,7 +251,12 @@ private fun appendTimeToFilename(name: String): String {
|
||||||
return """${filename}_$dateExtension.$fileExtension"""
|
return """${filename}_$dateExtension.$fileExtension"""
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun saveMedia(context: Context, file: File, title: String, mediaMimeType: String?, notificationUtils: NotificationUtils) {
|
suspend fun saveMedia(context: Context,
|
||||||
|
file: File,
|
||||||
|
title: String,
|
||||||
|
mediaMimeType: String?,
|
||||||
|
notificationUtils: NotificationUtils,
|
||||||
|
now: Long) {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
val filename = appendTimeToFilename(title)
|
val filename = appendTimeToFilename(title)
|
||||||
|
@ -257,8 +265,8 @@ suspend fun saveMedia(context: Context, file: File, title: String, mediaMimeType
|
||||||
put(MediaStore.Images.Media.TITLE, filename)
|
put(MediaStore.Images.Media.TITLE, filename)
|
||||||
put(MediaStore.Images.Media.DISPLAY_NAME, filename)
|
put(MediaStore.Images.Media.DISPLAY_NAME, filename)
|
||||||
put(MediaStore.Images.Media.MIME_TYPE, mediaMimeType)
|
put(MediaStore.Images.Media.MIME_TYPE, mediaMimeType)
|
||||||
put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis())
|
put(MediaStore.Images.Media.DATE_ADDED, now)
|
||||||
put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())
|
put(MediaStore.Images.Media.DATE_TAKEN, now)
|
||||||
}
|
}
|
||||||
val externalContentUri = when {
|
val externalContentUri = when {
|
||||||
mediaMimeType?.isMimeTypeImage() == true -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
|
mediaMimeType?.isMimeTypeImage() == true -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
|
||||||
|
@ -289,7 +297,7 @@ suspend fun saveMedia(context: Context, file: File, title: String, mediaMimeType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
saveMediaLegacy(context, mediaMimeType, title, file)
|
saveMediaLegacy(context, mediaMimeType, title, file, now)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -298,7 +306,8 @@ suspend fun saveMedia(context: Context, file: File, title: String, mediaMimeType
|
||||||
private fun saveMediaLegacy(context: Context,
|
private fun saveMediaLegacy(context: Context,
|
||||||
mediaMimeType: String?,
|
mediaMimeType: String?,
|
||||||
title: String,
|
title: String,
|
||||||
file: File) {
|
file: File,
|
||||||
|
now: Long) {
|
||||||
val state = Environment.getExternalStorageState()
|
val state = Environment.getExternalStorageState()
|
||||||
if (Environment.MEDIA_MOUNTED != state) {
|
if (Environment.MEDIA_MOUNTED != state) {
|
||||||
context.toast(context.getString(R.string.error_saving_media_file))
|
context.toast(context.getString(R.string.error_saving_media_file))
|
||||||
|
@ -319,7 +328,7 @@ private fun saveMediaLegacy(context: Context,
|
||||||
} else {
|
} else {
|
||||||
title
|
title
|
||||||
}
|
}
|
||||||
val savedFile = saveFileIntoLegacy(file, downloadDir, outputFilename)
|
val savedFile = saveFileIntoLegacy(file, downloadDir, outputFilename, now)
|
||||||
if (savedFile != null) {
|
if (savedFile != null) {
|
||||||
val downloadManager = context.getSystemService<DownloadManager>()
|
val downloadManager = context.getSystemService<DownloadManager>()
|
||||||
downloadManager?.addCompletedDownload(
|
downloadManager?.addCompletedDownload(
|
||||||
|
@ -329,7 +338,8 @@ private fun saveMediaLegacy(context: Context,
|
||||||
mediaMimeType ?: MimeTypes.OctetStream,
|
mediaMimeType ?: MimeTypes.OctetStream,
|
||||||
savedFile.absolutePath,
|
savedFile.absolutePath,
|
||||||
savedFile.length(),
|
savedFile.length(),
|
||||||
true)
|
true
|
||||||
|
)
|
||||||
addToGallery(savedFile, mediaMimeType, context)
|
addToGallery(savedFile, mediaMimeType, context)
|
||||||
}
|
}
|
||||||
} catch (error: Throwable) {
|
} catch (error: Throwable) {
|
||||||
|
@ -411,7 +421,7 @@ fun selectTxtFileToWrite(
|
||||||
* @return the created file
|
* @return the created file
|
||||||
*/
|
*/
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
fun saveFileIntoLegacy(sourceFile: File, dstDirPath: File, outputFilename: String?): File? {
|
fun saveFileIntoLegacy(sourceFile: File, dstDirPath: File, outputFilename: String?, now: Long): File? {
|
||||||
// defines another name for the external media
|
// defines another name for the external media
|
||||||
var dstFileName: String
|
var dstFileName: String
|
||||||
|
|
||||||
|
@ -423,7 +433,7 @@ fun saveFileIntoLegacy(sourceFile: File, dstDirPath: File, outputFilename: Strin
|
||||||
if (dotPos > 0) {
|
if (dotPos > 0) {
|
||||||
fileExt = sourceFile.name.substring(dotPos)
|
fileExt = sourceFile.name.substring(dotPos)
|
||||||
}
|
}
|
||||||
dstFileName = "vector_" + System.currentTimeMillis() + fileExt
|
dstFileName = "vector_$now$fileExt"
|
||||||
} else {
|
} else {
|
||||||
dstFileName = outputFilename
|
dstFileName = outputFilename
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ import im.vector.app.core.extensions.insertBeforeLast
|
||||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.resources.ColorProvider
|
import im.vector.app.core.resources.ColorProvider
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.core.utils.OnSnapPositionChangeListener
|
import im.vector.app.core.utils.OnSnapPositionChangeListener
|
||||||
import im.vector.app.core.utils.SnapOnScrollListener
|
import im.vector.app.core.utils.SnapOnScrollListener
|
||||||
import im.vector.app.core.utils.attachSnapHelperWithListener
|
import im.vector.app.core.utils.attachSnapHelperWithListener
|
||||||
|
@ -64,7 +65,8 @@ data class AttachmentsPreviewArgs(
|
||||||
class AttachmentsPreviewFragment @Inject constructor(
|
class AttachmentsPreviewFragment @Inject constructor(
|
||||||
private val attachmentMiniaturePreviewController: AttachmentMiniaturePreviewController,
|
private val attachmentMiniaturePreviewController: AttachmentMiniaturePreviewController,
|
||||||
private val attachmentBigPreviewController: AttachmentBigPreviewController,
|
private val attachmentBigPreviewController: AttachmentBigPreviewController,
|
||||||
private val colorProvider: ColorProvider
|
private val colorProvider: ColorProvider,
|
||||||
|
private val clock: Clock,
|
||||||
) : VectorBaseFragment<FragmentAttachmentsPreviewBinding>(), AttachmentMiniaturePreviewController.Callback {
|
) : VectorBaseFragment<FragmentAttachmentsPreviewBinding>(), AttachmentMiniaturePreviewController.Callback {
|
||||||
|
|
||||||
private val fragmentArgs: AttachmentsPreviewArgs by args()
|
private val fragmentArgs: AttachmentsPreviewArgs by args()
|
||||||
|
@ -192,7 +194,7 @@ class AttachmentsPreviewFragment @Inject constructor(
|
||||||
|
|
||||||
private fun handleEditAction() = withState(viewModel) {
|
private fun handleEditAction() = withState(viewModel) {
|
||||||
val currentAttachment = it.attachments.getOrNull(it.currentAttachmentIndex) ?: return@withState
|
val currentAttachment = it.attachments.getOrNull(it.currentAttachmentIndex) ?: return@withState
|
||||||
val destinationFile = File(requireContext().cacheDir, currentAttachment.name.insertBeforeLast("_edited_image_${System.currentTimeMillis()}"))
|
val destinationFile = File(requireContext().cacheDir, currentAttachment.name.insertBeforeLast("_edited_image_${clock.epochMillis()}"))
|
||||||
val uri = currentAttachment.queryUri
|
val uri = currentAttachment.queryUri
|
||||||
createUCropWithDefaultSettings(colorProvider, uri, destinationFile.toUri(), currentAttachment.name)
|
createUCropWithDefaultSettings(colorProvider, uri, destinationFile.toUri(), currentAttachment.name)
|
||||||
.getIntent(requireContext())
|
.getIntent(requireContext())
|
||||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.app.features.call.conference
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.network.await
|
import im.vector.app.core.network.await
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.core.utils.ensureProtocol
|
import im.vector.app.core.utils.ensureProtocol
|
||||||
import im.vector.app.core.utils.toBase32String
|
import im.vector.app.core.utils.toBase32String
|
||||||
import im.vector.app.features.call.conference.jwt.JitsiJWTFactory
|
import im.vector.app.features.call.conference.jwt.JitsiJWTFactory
|
||||||
|
@ -46,7 +47,9 @@ class JitsiService @Inject constructor(
|
||||||
private val rawService: RawService,
|
private val rawService: RawService,
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
private val themeProvider: ThemeProvider,
|
private val themeProvider: ThemeProvider,
|
||||||
private val jitsiJWTFactory: JitsiJWTFactory) {
|
private val jitsiJWTFactory: JitsiJWTFactory,
|
||||||
|
private val clock: Clock,
|
||||||
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val JITSI_OPEN_ID_TOKEN_JWT_AUTH = "openidtoken-jwt"
|
const val JITSI_OPEN_ID_TOKEN_JWT_AUTH = "openidtoken-jwt"
|
||||||
|
@ -60,7 +63,7 @@ class JitsiService @Inject constructor(
|
||||||
|
|
||||||
suspend fun createJitsiWidget(roomId: String, withVideo: Boolean): Widget {
|
suspend fun createJitsiWidget(roomId: String, withVideo: Boolean): Widget {
|
||||||
// Build data for a jitsi widget
|
// Build data for a jitsi widget
|
||||||
val widgetId: String = WidgetType.Jitsi.preferred + "_" + session.myUserId + "_" + System.currentTimeMillis()
|
val widgetId: String = WidgetType.Jitsi.preferred + "_" + session.myUserId + "_" + clock.epochMillis()
|
||||||
val preferredJitsiDomain = tryOrNull {
|
val preferredJitsiDomain = tryOrNull {
|
||||||
rawService.getElementWellknown(session.sessionParams)
|
rawService.getElementWellknown(session.sessionParams)
|
||||||
?.jitsiServer
|
?.jitsiServer
|
||||||
|
|
|
@ -21,6 +21,7 @@ import android.os.Binder
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.core.services.VectorService
|
import im.vector.app.core.services.VectorService
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.features.notifications.NotificationUtils
|
import im.vector.app.features.notifications.NotificationUtils
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -28,6 +29,7 @@ import javax.inject.Inject
|
||||||
class ScreenCaptureService : VectorService() {
|
class ScreenCaptureService : VectorService() {
|
||||||
|
|
||||||
@Inject lateinit var notificationUtils: NotificationUtils
|
@Inject lateinit var notificationUtils: NotificationUtils
|
||||||
|
@Inject lateinit var clock: Clock
|
||||||
private val binder = LocalBinder()
|
private val binder = LocalBinder()
|
||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
@ -37,7 +39,7 @@ class ScreenCaptureService : VectorService() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showStickyNotification() {
|
private fun showStickyNotification() {
|
||||||
val notificationId = System.currentTimeMillis().toInt()
|
val notificationId = clock.epochMillis().toInt()
|
||||||
val notification = notificationUtils.buildScreenSharingNotification()
|
val notification = notificationUtils.buildScreenSharingNotification()
|
||||||
startForeground(notificationId, notification)
|
startForeground(notificationId, notification)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import androidx.lifecycle.ViewModel
|
||||||
import com.nulabinc.zxcvbn.Strength
|
import com.nulabinc.zxcvbn.Strength
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.platform.WaitingViewData
|
import im.vector.app.core.platform.WaitingViewData
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.core.utils.LiveEvent
|
import im.vector.app.core.utils.LiveEvent
|
||||||
import org.matrix.android.sdk.api.MatrixCallback
|
import org.matrix.android.sdk.api.MatrixCallback
|
||||||
import org.matrix.android.sdk.api.listeners.ProgressListener
|
import org.matrix.android.sdk.api.listeners.ProgressListener
|
||||||
|
@ -37,7 +38,9 @@ import javax.inject.Inject
|
||||||
/**
|
/**
|
||||||
* The shared view model between all fragments.
|
* The shared view model between all fragments.
|
||||||
*/
|
*/
|
||||||
class KeysBackupSetupSharedViewModel @Inject constructor() : ViewModel() {
|
class KeysBackupSetupSharedViewModel @Inject constructor(
|
||||||
|
private val clock: Clock,
|
||||||
|
) : ViewModel() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val NAVIGATE_TO_STEP_2 = "NAVIGATE_TO_STEP_2"
|
const val NAVIGATE_TO_STEP_2 = "NAVIGATE_TO_STEP_2"
|
||||||
|
@ -85,7 +88,7 @@ class KeysBackupSetupSharedViewModel @Inject constructor() : ViewModel() {
|
||||||
|
|
||||||
fun prepareRecoveryKey(context: Context, withPassphrase: String?) {
|
fun prepareRecoveryKey(context: Context, withPassphrase: String?) {
|
||||||
// Update requestId
|
// Update requestId
|
||||||
currentRequestId.value = System.currentTimeMillis()
|
currentRequestId.value = clock.epochMillis()
|
||||||
isCreatingBackupVersion.value = true
|
isCreatingBackupVersion.value = true
|
||||||
|
|
||||||
recoveryKey.value = null
|
recoveryKey.value = null
|
||||||
|
@ -101,9 +104,11 @@ class KeysBackupSetupSharedViewModel @Inject constructor() : ViewModel() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
loadingStatus.value = WaitingViewData(context.getString(R.string.keys_backup_setup_step3_generating_key_status),
|
loadingStatus.value = WaitingViewData(
|
||||||
|
context.getString(R.string.keys_backup_setup_step3_generating_key_status),
|
||||||
progress,
|
progress,
|
||||||
total)
|
total
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
object : MatrixCallback<MegolmBackupCreationInfo> {
|
object : MatrixCallback<MegolmBackupCreationInfo> {
|
||||||
|
|
|
@ -18,6 +18,7 @@ package im.vector.app.features.crypto.verification
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.features.displayname.getBestName
|
import im.vector.app.features.displayname.getBestName
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
import im.vector.app.features.home.room.detail.RoomDetailActivity
|
import im.vector.app.features.home.room.detail.RoomDetailActivity
|
||||||
|
@ -42,7 +43,9 @@ import javax.inject.Singleton
|
||||||
class IncomingVerificationRequestHandler @Inject constructor(
|
class IncomingVerificationRequestHandler @Inject constructor(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private var avatarRenderer: Provider<AvatarRenderer>,
|
private var avatarRenderer: Provider<AvatarRenderer>,
|
||||||
private val popupAlertManager: PopupAlertManager) : VerificationService.Listener {
|
private val popupAlertManager: PopupAlertManager,
|
||||||
|
private val clock: Clock,
|
||||||
|
) : VerificationService.Listener {
|
||||||
|
|
||||||
private var session: Session? = null
|
private var session: Session? = null
|
||||||
|
|
||||||
|
@ -104,7 +107,7 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
// 10mn expiration
|
// 10mn expiration
|
||||||
expirationTimestamp = System.currentTimeMillis() + (10 * 60 * 1000L)
|
expirationTimestamp = clock.epochMillis() + (10 * 60 * 1000L)
|
||||||
}
|
}
|
||||||
popupAlertManager.postVectorAlert(alert)
|
popupAlertManager.postVectorAlert(alert)
|
||||||
}
|
}
|
||||||
|
@ -168,7 +171,7 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
||||||
}
|
}
|
||||||
colorAttribute = R.attr.vctr_notice_secondary
|
colorAttribute = R.attr.vctr_notice_secondary
|
||||||
// 5mn expiration
|
// 5mn expiration
|
||||||
expirationTimestamp = System.currentTimeMillis() + (5 * 60 * 1000L)
|
expirationTimestamp = clock.epochMillis() + (5 * 60 * 1000L)
|
||||||
}
|
}
|
||||||
popupAlertManager.postVectorAlert(alert)
|
popupAlertManager.postVectorAlert(alert)
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||||
import im.vector.app.core.platform.EmptyViewEvents
|
import im.vector.app.core.platform.EmptyViewEvents
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
import im.vector.app.core.platform.VectorViewModelAction
|
import im.vector.app.core.platform.VectorViewModelAction
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
@ -56,10 +57,12 @@ data class DeviceDetectionInfo(
|
||||||
val currentSessionTrust: Boolean
|
val currentSessionTrust: Boolean
|
||||||
)
|
)
|
||||||
|
|
||||||
class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted initialState: UnknownDevicesState,
|
class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(
|
||||||
session: Session,
|
@Assisted initialState: UnknownDevicesState,
|
||||||
private val vectorPreferences: VectorPreferences) :
|
session: Session,
|
||||||
VectorViewModel<UnknownDevicesState, UnknownDeviceDetectorSharedViewModel.Action, EmptyViewEvents>(initialState) {
|
private val vectorPreferences: VectorPreferences,
|
||||||
|
clock: Clock,
|
||||||
|
) : VectorViewModel<UnknownDevicesState, UnknownDeviceDetectorSharedViewModel.Action, EmptyViewEvents>(initialState) {
|
||||||
|
|
||||||
sealed class Action : VectorViewModelAction {
|
sealed class Action : VectorViewModelAction {
|
||||||
data class IgnoreDevice(val deviceIds: List<String>) : Action()
|
data class IgnoreDevice(val deviceIds: List<String>) : Action()
|
||||||
|
@ -75,11 +78,10 @@ class UnknownDeviceDetectorSharedViewModel @AssistedInject constructor(@Assisted
|
||||||
private val ignoredDeviceList = ArrayList<String>()
|
private val ignoredDeviceList = ArrayList<String>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|
||||||
val currentSessionTs = session.cryptoService().getCryptoDeviceInfo(session.myUserId)
|
val currentSessionTs = session.cryptoService().getCryptoDeviceInfo(session.myUserId)
|
||||||
.firstOrNull { it.deviceId == session.sessionParams.deviceId }
|
.firstOrNull { it.deviceId == session.sessionParams.deviceId }
|
||||||
?.firstTimeSeenLocalTs
|
?.firstTimeSeenLocalTs
|
||||||
?: System.currentTimeMillis()
|
?: clock.epochMillis()
|
||||||
Timber.v("## Detector - Current Session first time seen $currentSessionTs")
|
Timber.v("## Detector - Current Session first time seen $currentSessionTs")
|
||||||
|
|
||||||
ignoredDeviceList.addAll(
|
ignoredDeviceList.addAll(
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package im.vector.app.features.home.room.detail
|
package im.vector.app.features.home.room.detail
|
||||||
|
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
||||||
|
@ -45,7 +46,9 @@ fun ChatEffect.toMessageType(): String {
|
||||||
* precisely an event decrypted with a few delay won't trigger an effect; it's acceptable)
|
* precisely an event decrypted with a few delay won't trigger an effect; it's acceptable)
|
||||||
* Events that are more that 10s old won't trigger effects
|
* Events that are more that 10s old won't trigger effects
|
||||||
*/
|
*/
|
||||||
class ChatEffectManager @Inject constructor() {
|
class ChatEffectManager @Inject constructor(
|
||||||
|
private val clock: Clock,
|
||||||
|
) {
|
||||||
|
|
||||||
interface Delegate {
|
interface Delegate {
|
||||||
fun stopEffects()
|
fun stopEffects()
|
||||||
|
@ -61,7 +64,7 @@ class ChatEffectManager @Inject constructor() {
|
||||||
|
|
||||||
fun checkForEffect(event: TimelineEvent) {
|
fun checkForEffect(event: TimelineEvent) {
|
||||||
val age = event.root.ageLocalTs ?: 0
|
val age = event.root.ageLocalTs ?: 0
|
||||||
val now = System.currentTimeMillis()
|
val now = clock.epochMillis()
|
||||||
// messages older than 10s should not trigger any effect
|
// messages older than 10s should not trigger any effect
|
||||||
if ((now - age) >= 10_000) return
|
if ((now - age) >= 10_000) return
|
||||||
val content = event.root.getClearContent()?.toModel<MessageContent>() ?: return
|
val content = event.root.getClearContent()?.toModel<MessageContent>() ?: return
|
||||||
|
|
|
@ -33,14 +33,18 @@ import com.airbnb.epoxy.EpoxyModel
|
||||||
import com.airbnb.epoxy.EpoxyTouchHelperCallback
|
import com.airbnb.epoxy.EpoxyTouchHelperCallback
|
||||||
import com.airbnb.epoxy.EpoxyViewHolder
|
import com.airbnb.epoxy.EpoxyViewHolder
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
class RoomMessageTouchHelperCallback(private val context: Context,
|
class RoomMessageTouchHelperCallback(
|
||||||
@DrawableRes actionIcon: Int,
|
private val context: Context,
|
||||||
private val handler: QuickReplayHandler) : EpoxyTouchHelperCallback() {
|
@DrawableRes actionIcon: Int,
|
||||||
|
private val handler: QuickReplayHandler,
|
||||||
|
private val clock: Clock,
|
||||||
|
) : EpoxyTouchHelperCallback() {
|
||||||
|
|
||||||
interface QuickReplayHandler {
|
interface QuickReplayHandler {
|
||||||
fun performQuickReplyOnHolder(model: EpoxyModel<*>)
|
fun performQuickReplyOnHolder(model: EpoxyModel<*>)
|
||||||
|
@ -141,7 +145,7 @@ class RoomMessageTouchHelperCallback(private val context: Context,
|
||||||
private fun drawReplyButton(canvas: Canvas, itemView: View) {
|
private fun drawReplyButton(canvas: Canvas, itemView: View) {
|
||||||
// Timber.v("drawReplyButton")
|
// Timber.v("drawReplyButton")
|
||||||
val translationX = abs(itemView.translationX)
|
val translationX = abs(itemView.translationX)
|
||||||
val newTime = System.currentTimeMillis()
|
val newTime = clock.epochMillis()
|
||||||
val dt = min(17, newTime - lastReplyButtonAnimationTime)
|
val dt = min(17, newTime - lastReplyButtonAnimationTime)
|
||||||
lastReplyButtonAnimationTime = newTime
|
lastReplyButtonAnimationTime = newTime
|
||||||
val showing = translationX >= minShowDistance
|
val showing = translationX >= minShowDistance
|
||||||
|
|
|
@ -296,7 +296,7 @@ class TimelineFragment @Inject constructor(
|
||||||
private const val ircPattern = " (IRC)"
|
private const val ircPattern = " (IRC)"
|
||||||
}
|
}
|
||||||
|
|
||||||
private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider)
|
private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider, clock)
|
||||||
|
|
||||||
private val timelineArgs: TimelineArgs by args()
|
private val timelineArgs: TimelineArgs by args()
|
||||||
private val glideRequests by lazy {
|
private val glideRequests by lazy {
|
||||||
|
@ -1443,7 +1443,7 @@ class TimelineFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val swipeCallback = RoomMessageTouchHelperCallback(requireContext(), R.drawable.ic_reply, quickReplyHandler)
|
val swipeCallback = RoomMessageTouchHelperCallback(requireContext(), R.drawable.ic_reply, quickReplyHandler, clock)
|
||||||
val touchHelper = ItemTouchHelper(swipeCallback)
|
val touchHelper = ItemTouchHelper(swipeCallback)
|
||||||
touchHelper.attachToRecyclerView(views.timelineRecyclerView)
|
touchHelper.attachToRecyclerView(views.timelineRecyclerView)
|
||||||
}
|
}
|
||||||
|
@ -2186,7 +2186,8 @@ class TimelineFragment @Inject constructor(
|
||||||
file = it,
|
file = it,
|
||||||
title = action.messageContent.body,
|
title = action.messageContent.body,
|
||||||
mediaMimeType = action.messageContent.mimeType ?: getMimeTypeFromUri(requireContext(), it.toUri()),
|
mediaMimeType = action.messageContent.mimeType ?: getMimeTypeFromUri(requireContext(), it.toUri()),
|
||||||
notificationUtils = notificationUtils
|
notificationUtils = notificationUtils,
|
||||||
|
now = clock.epochMillis()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.onFailure {
|
.onFailure {
|
||||||
|
|
|
@ -21,6 +21,7 @@ import im.vector.app.features.home.room.detail.arguments.TimelineArgs
|
||||||
import im.vector.app.features.home.room.detail.composer.voice.VoiceMessageRecorderView
|
import im.vector.app.features.home.room.detail.composer.voice.VoiceMessageRecorderView
|
||||||
import org.matrix.android.sdk.api.extensions.orFalse
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes the current send mode:
|
* Describes the current send mode:
|
||||||
|
@ -35,7 +36,7 @@ sealed interface SendMode {
|
||||||
val text: String,
|
val text: String,
|
||||||
val fromSharing: Boolean,
|
val fromSharing: Boolean,
|
||||||
// This is necessary for forcing refresh on selectSubscribe
|
// This is necessary for forcing refresh on selectSubscribe
|
||||||
private val ts: Long = System.currentTimeMillis()
|
private val ts: Int = Random.nextInt()
|
||||||
) : SendMode
|
) : SendMode
|
||||||
|
|
||||||
data class Quote(val timelineEvent: TimelineEvent, val text: String) : SendMode
|
data class Quote(val timelineEvent: TimelineEvent, val text: String) : SendMode
|
||||||
|
@ -83,7 +84,8 @@ data class MessageComposerViewState(
|
||||||
constructor(args: TimelineArgs) : this(
|
constructor(args: TimelineArgs) : this(
|
||||||
roomId = args.roomId,
|
roomId = args.roomId,
|
||||||
startsThread = args.threadTimelineArgs?.startsThread.orFalse(),
|
startsThread = args.threadTimelineArgs?.startsThread.orFalse(),
|
||||||
rootThreadEventId = args.threadTimelineArgs?.rootThreadEventId)
|
rootThreadEventId = args.threadTimelineArgs?.rootThreadEventId
|
||||||
|
)
|
||||||
|
|
||||||
fun isInThreadTimeline(): Boolean = rootThreadEventId != null
|
fun isInThreadTimeline(): Boolean = rootThreadEventId != null
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import im.vector.app.core.epoxy.loadingItem
|
||||||
import im.vector.app.core.epoxy.noResultItem
|
import im.vector.app.core.epoxy.noResultItem
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.core.resources.UserPreferencesProvider
|
import im.vector.app.core.resources.UserPreferencesProvider
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.core.ui.list.GenericHeaderItem_
|
import im.vector.app.core.ui.list.GenericHeaderItem_
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
import im.vector.app.features.home.room.detail.timeline.format.DisplayableEventFormatter
|
import im.vector.app.features.home.room.detail.timeline.format.DisplayableEventFormatter
|
||||||
|
@ -47,7 +48,8 @@ class SearchResultController @Inject constructor(
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
private val dateFormatter: VectorDateFormatter,
|
private val dateFormatter: VectorDateFormatter,
|
||||||
private val displayableEventFormatter: DisplayableEventFormatter,
|
private val displayableEventFormatter: DisplayableEventFormatter,
|
||||||
private val userPreferencesProvider: UserPreferencesProvider
|
private val userPreferencesProvider: UserPreferencesProvider,
|
||||||
|
private val clock: Clock,
|
||||||
) : TypedEpoxyController<SearchViewState>() {
|
) : TypedEpoxyController<SearchViewState>() {
|
||||||
|
|
||||||
var listener: Listener? = null
|
var listener: Listener? = null
|
||||||
|
@ -109,7 +111,7 @@ class SearchResultController @Inject constructor(
|
||||||
val spannable = setHighLightedText(text, data.highlights) ?: return@forEach
|
val spannable = setHighLightedText(text, data.highlights) ?: return@forEach
|
||||||
|
|
||||||
val eventDate = Calendar.getInstance().apply {
|
val eventDate = Calendar.getInstance().apply {
|
||||||
timeInMillis = eventAndSender.event.originServerTs ?: System.currentTimeMillis()
|
timeInMillis = eventAndSender.event.originServerTs ?: clock.epochMillis()
|
||||||
}
|
}
|
||||||
if (lastDate?.get(Calendar.DAY_OF_YEAR) != eventDate.get(Calendar.DAY_OF_YEAR)) {
|
if (lastDate?.get(Calendar.DAY_OF_YEAR) != eventDate.get(Calendar.DAY_OF_YEAR)) {
|
||||||
GenericHeaderItem_()
|
GenericHeaderItem_()
|
||||||
|
@ -125,7 +127,8 @@ class SearchResultController @Inject constructor(
|
||||||
.formattedDate(dateFormatter.format(event.originServerTs, DateFormatKind.MESSAGE_SIMPLE))
|
.formattedDate(dateFormatter.format(event.originServerTs, DateFormatKind.MESSAGE_SIMPLE))
|
||||||
.spannable(spannable.toEpoxyCharSequence())
|
.spannable(spannable.toEpoxyCharSequence())
|
||||||
.sender(eventAndSender.sender
|
.sender(eventAndSender.sender
|
||||||
?: eventAndSender.event.senderId?.let { session.roomService().getRoomMember(it, data.roomId) }?.toMatrixItem())
|
?: eventAndSender.event.senderId?.let { session.roomService().getRoomMember(it, data.roomId) }?.toMatrixItem()
|
||||||
|
)
|
||||||
.threadDetails(event.threadDetails)
|
.threadDetails(event.threadDetails)
|
||||||
.threadSummaryFormatted(displayableEventFormatter.formatThreadSummary(event.threadDetails?.threadSummaryLatestEvent).toString())
|
.threadSummaryFormatted(displayableEventFormatter.formatThreadSummary(event.threadDetails?.threadSummaryLatestEvent).toString())
|
||||||
.areThreadMessagesEnabled(userPreferencesProvider.areThreadMessagesEnabled())
|
.areThreadMessagesEnabled(userPreferencesProvider.areThreadMessagesEnabled())
|
||||||
|
|
|
@ -31,6 +31,7 @@ import im.vector.app.core.epoxy.LoadingItem_
|
||||||
import im.vector.app.core.extensions.localDateTime
|
import im.vector.app.core.extensions.localDateTime
|
||||||
import im.vector.app.core.extensions.nextOrNull
|
import im.vector.app.core.extensions.nextOrNull
|
||||||
import im.vector.app.core.extensions.prevOrNull
|
import im.vector.app.core.extensions.prevOrNull
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.features.home.room.detail.JitsiState
|
import im.vector.app.features.home.room.detail.JitsiState
|
||||||
import im.vector.app.features.home.room.detail.RoomDetailAction
|
import im.vector.app.features.home.room.detail.RoomDetailAction
|
||||||
import im.vector.app.features.home.room.detail.RoomDetailViewState
|
import im.vector.app.features.home.room.detail.RoomDetailViewState
|
||||||
|
@ -78,19 +79,21 @@ import javax.inject.Inject
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
class TimelineEventController @Inject constructor(private val dateFormatter: VectorDateFormatter,
|
class TimelineEventController @Inject constructor(
|
||||||
private val vectorPreferences: VectorPreferences,
|
private val dateFormatter: VectorDateFormatter,
|
||||||
private val contentUploadStateTrackerBinder: ContentUploadStateTrackerBinder,
|
private val vectorPreferences: VectorPreferences,
|
||||||
private val contentDownloadStateTrackerBinder: ContentDownloadStateTrackerBinder,
|
private val contentUploadStateTrackerBinder: ContentUploadStateTrackerBinder,
|
||||||
private val timelineItemFactory: TimelineItemFactory,
|
private val contentDownloadStateTrackerBinder: ContentDownloadStateTrackerBinder,
|
||||||
private val timelineMediaSizeProvider: TimelineMediaSizeProvider,
|
private val timelineItemFactory: TimelineItemFactory,
|
||||||
private val mergedHeaderItemFactory: MergedHeaderItemFactory,
|
private val timelineMediaSizeProvider: TimelineMediaSizeProvider,
|
||||||
private val session: Session,
|
private val mergedHeaderItemFactory: MergedHeaderItemFactory,
|
||||||
@TimelineEventControllerHandler
|
private val session: Session,
|
||||||
private val backgroundHandler: Handler,
|
@TimelineEventControllerHandler
|
||||||
private val timelineEventVisibilityHelper: TimelineEventVisibilityHelper,
|
private val backgroundHandler: Handler,
|
||||||
private val readReceiptsItemFactory: ReadReceiptsItemFactory,
|
private val timelineEventVisibilityHelper: TimelineEventVisibilityHelper,
|
||||||
private val reactionListFactory: ReactionsSummaryFactory
|
private val readReceiptsItemFactory: ReadReceiptsItemFactory,
|
||||||
|
private val reactionListFactory: ReactionsSummaryFactory,
|
||||||
|
private val clock: Clock,
|
||||||
) : EpoxyController(backgroundHandler, backgroundHandler), Timeline.Listener, EpoxyController.Interceptor {
|
) : EpoxyController(backgroundHandler, backgroundHandler), Timeline.Listener, EpoxyController.Interceptor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -209,8 +212,10 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
|
||||||
override fun onChanged(position: Int, count: Int, payload: Any?) {
|
override fun onChanged(position: Int, count: Int, payload: Any?) {
|
||||||
synchronized(modelCache) {
|
synchronized(modelCache) {
|
||||||
assertUpdateCallbacksAllowed()
|
assertUpdateCallbacksAllowed()
|
||||||
Timber.v("listUpdateCallback.onChanged(position: $position, count: $count). " +
|
Timber.v(
|
||||||
"\ncurrentSnapshot has size of ${currentSnapshot.size} items")
|
"listUpdateCallback.onChanged(position: $position, count: $count). " +
|
||||||
|
"\ncurrentSnapshot has size of ${currentSnapshot.size} items"
|
||||||
|
)
|
||||||
(position until position + count).forEach {
|
(position until position + count).forEach {
|
||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
modelCache[it] = null
|
modelCache[it] = null
|
||||||
|
@ -238,8 +243,10 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
|
||||||
override fun onMoved(fromPosition: Int, toPosition: Int) {
|
override fun onMoved(fromPosition: Int, toPosition: Int) {
|
||||||
synchronized(modelCache) {
|
synchronized(modelCache) {
|
||||||
assertUpdateCallbacksAllowed()
|
assertUpdateCallbacksAllowed()
|
||||||
Timber.v("listUpdateCallback.onMoved(fromPosition: $fromPosition, toPosition: $toPosition). " +
|
Timber.v(
|
||||||
"\ncurrentSnapshot has size of ${currentSnapshot.size} items")
|
"listUpdateCallback.onMoved(fromPosition: $fromPosition, toPosition: $toPosition). " +
|
||||||
|
"\ncurrentSnapshot has size of ${currentSnapshot.size} items"
|
||||||
|
)
|
||||||
val model = modelCache.removeAt(fromPosition)
|
val model = modelCache.removeAt(fromPosition)
|
||||||
modelCache.add(toPosition, model)
|
modelCache.add(toPosition, model)
|
||||||
requestModelBuild()
|
requestModelBuild()
|
||||||
|
@ -249,8 +256,10 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
|
||||||
override fun onInserted(position: Int, count: Int) {
|
override fun onInserted(position: Int, count: Int) {
|
||||||
synchronized(modelCache) {
|
synchronized(modelCache) {
|
||||||
assertUpdateCallbacksAllowed()
|
assertUpdateCallbacksAllowed()
|
||||||
Timber.v("listUpdateCallback.onInserted(position: $position, count: $count). " +
|
Timber.v(
|
||||||
"\ncurrentSnapshot has size of ${currentSnapshot.size} items")
|
"listUpdateCallback.onInserted(position: $position, count: $count). " +
|
||||||
|
"\ncurrentSnapshot has size of ${currentSnapshot.size} items"
|
||||||
|
)
|
||||||
repeat(count) {
|
repeat(count) {
|
||||||
modelCache.add(position, null)
|
modelCache.add(position, null)
|
||||||
}
|
}
|
||||||
|
@ -261,8 +270,10 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
|
||||||
override fun onRemoved(position: Int, count: Int) {
|
override fun onRemoved(position: Int, count: Int) {
|
||||||
synchronized(modelCache) {
|
synchronized(modelCache) {
|
||||||
assertUpdateCallbacksAllowed()
|
assertUpdateCallbacksAllowed()
|
||||||
Timber.v("listUpdateCallback.onRemoved(position: $position, count: $count). " +
|
Timber.v(
|
||||||
"\ncurrentSnapshot has size of ${currentSnapshot.size} items")
|
"listUpdateCallback.onRemoved(position: $position, count: $count). " +
|
||||||
|
"\ncurrentSnapshot has size of ${currentSnapshot.size} items"
|
||||||
|
)
|
||||||
repeat(count) {
|
repeat(count) {
|
||||||
modelCache.removeAt(position)
|
modelCache.removeAt(position)
|
||||||
}
|
}
|
||||||
|
@ -314,7 +325,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
|
||||||
if (partialState.roomSummary?.membership != Membership.JOIN) {
|
if (partialState.roomSummary?.membership != Membership.JOIN) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val timestamp = System.currentTimeMillis()
|
val timestamp = clock.epochMillis()
|
||||||
|
|
||||||
val showingForwardLoader = LoadingItem_()
|
val showingForwardLoader = LoadingItem_()
|
||||||
.id("forward_loading_item_$timestamp")
|
.id("forward_loading_item_$timestamp")
|
||||||
|
@ -406,14 +417,16 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
|
||||||
timelineEvent = it,
|
timelineEvent = it,
|
||||||
highlightedEventId = partialState.highlightedEventId,
|
highlightedEventId = partialState.highlightedEventId,
|
||||||
isFromThreadTimeline = partialState.isFromThreadTimeline(),
|
isFromThreadTimeline = partialState.isFromThreadTimeline(),
|
||||||
rootThreadEventId = partialState.rootThreadEventId)
|
rootThreadEventId = partialState.rootThreadEventId
|
||||||
|
)
|
||||||
}
|
}
|
||||||
val nextDisplayableEvent = currentSnapshot.subList(position + 1, currentSnapshot.size).firstOrNull {
|
val nextDisplayableEvent = currentSnapshot.subList(position + 1, currentSnapshot.size).firstOrNull {
|
||||||
timelineEventVisibilityHelper.shouldShowEvent(
|
timelineEventVisibilityHelper.shouldShowEvent(
|
||||||
timelineEvent = it,
|
timelineEvent = it,
|
||||||
highlightedEventId = partialState.highlightedEventId,
|
highlightedEventId = partialState.highlightedEventId,
|
||||||
isFromThreadTimeline = partialState.isFromThreadTimeline(),
|
isFromThreadTimeline = partialState.isFromThreadTimeline(),
|
||||||
rootThreadEventId = partialState.rootThreadEventId)
|
rootThreadEventId = partialState.rootThreadEventId
|
||||||
|
)
|
||||||
}
|
}
|
||||||
val timelineEventsGroup = timelineEventsGroups.getOrNull(event)
|
val timelineEventsGroup = timelineEventsGroups.getOrNull(event)
|
||||||
val params = TimelineItemFactoryParams(
|
val params = TimelineItemFactoryParams(
|
||||||
|
@ -466,7 +479,8 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
|
||||||
position: Int,
|
position: Int,
|
||||||
receiptsByEvents: Map<String, List<ReadReceipt>>): CacheItemData {
|
receiptsByEvents: Map<String, List<ReadReceipt>>): CacheItemData {
|
||||||
val wantsDateSeparator = wantsDateSeparator(event, nextEvent)
|
val wantsDateSeparator = wantsDateSeparator(event, nextEvent)
|
||||||
val mergedHeaderModel = mergedHeaderItemFactory.create(event,
|
val mergedHeaderModel = mergedHeaderItemFactory.create(
|
||||||
|
event,
|
||||||
nextEvent = nextEvent,
|
nextEvent = nextEvent,
|
||||||
partialState = partialState,
|
partialState = partialState,
|
||||||
items = this@TimelineEventController.currentSnapshot,
|
items = this@TimelineEventController.currentSnapshot,
|
||||||
|
@ -537,7 +551,8 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
|
||||||
timelineEvent = event,
|
timelineEvent = event,
|
||||||
highlightedEventId = partialState.highlightedEventId,
|
highlightedEventId = partialState.highlightedEventId,
|
||||||
isFromThreadTimeline = partialState.isFromThreadTimeline(),
|
isFromThreadTimeline = partialState.isFromThreadTimeline(),
|
||||||
rootThreadEventId = partialState.rootThreadEventId)) {
|
rootThreadEventId = partialState.rootThreadEventId
|
||||||
|
)) {
|
||||||
lastShownEventId = event.eventId
|
lastShownEventId = event.eventId
|
||||||
}
|
}
|
||||||
if (lastShownEventId == null) {
|
if (lastShownEventId == null) {
|
||||||
|
|
|
@ -26,6 +26,7 @@ import im.vector.app.core.date.DateFormatKind
|
||||||
import im.vector.app.core.date.VectorDateFormatter
|
import im.vector.app.core.date.VectorDateFormatter
|
||||||
import im.vector.app.core.resources.ColorProvider
|
import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.core.ui.list.genericFooterItem
|
import im.vector.app.core.ui.list.genericFooterItem
|
||||||
import im.vector.app.core.ui.list.genericHeaderItem
|
import im.vector.app.core.ui.list.genericHeaderItem
|
||||||
import im.vector.app.core.ui.list.genericItem
|
import im.vector.app.core.ui.list.genericItem
|
||||||
|
@ -49,7 +50,8 @@ class ViewEditHistoryEpoxyController @Inject constructor(
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
private val colorProvider: ColorProvider,
|
private val colorProvider: ColorProvider,
|
||||||
private val eventHtmlRenderer: EventHtmlRenderer,
|
private val eventHtmlRenderer: EventHtmlRenderer,
|
||||||
private val dateFormatter: VectorDateFormatter
|
private val dateFormatter: VectorDateFormatter,
|
||||||
|
private val clock: Clock,
|
||||||
) : TypedEpoxyController<ViewEditHistoryViewState>() {
|
) : TypedEpoxyController<ViewEditHistoryViewState>() {
|
||||||
|
|
||||||
override fun buildModels(state: ViewEditHistoryViewState) {
|
override fun buildModels(state: ViewEditHistoryViewState) {
|
||||||
|
@ -86,7 +88,7 @@ class ViewEditHistoryEpoxyController @Inject constructor(
|
||||||
|
|
||||||
val evDate = Calendar.getInstance().apply {
|
val evDate = Calendar.getInstance().apply {
|
||||||
timeInMillis = timelineEvent.originServerTs
|
timeInMillis = timelineEvent.originServerTs
|
||||||
?: System.currentTimeMillis()
|
?: clock.epochMillis()
|
||||||
}
|
}
|
||||||
if (lastDate?.get(Calendar.DAY_OF_YEAR) != evDate.get(Calendar.DAY_OF_YEAR)) {
|
if (lastDate?.get(Calendar.DAY_OF_YEAR) != evDate.get(Calendar.DAY_OF_YEAR)) {
|
||||||
// need to display header with day
|
// need to display header with day
|
||||||
|
|
|
@ -25,6 +25,7 @@ import im.vector.app.features.home.room.detail.timeline.item.DaySeparatorItem
|
||||||
import im.vector.app.features.home.room.detail.timeline.item.ItemWithEvents
|
import im.vector.app.features.home.room.detail.timeline.item.ItemWithEvents
|
||||||
import im.vector.app.features.home.room.detail.timeline.item.TimelineReadMarkerItem_
|
import im.vector.app.features.home.room.detail.timeline.item.TimelineReadMarkerItem_
|
||||||
import org.matrix.android.sdk.api.session.room.timeline.Timeline
|
import org.matrix.android.sdk.api.session.room.timeline.Timeline
|
||||||
|
import kotlin.random.Random
|
||||||
import kotlin.reflect.KMutableProperty0
|
import kotlin.reflect.KMutableProperty0
|
||||||
|
|
||||||
private const val DEFAULT_PREFETCH_THRESHOLD = 30
|
private const val DEFAULT_PREFETCH_THRESHOLD = 30
|
||||||
|
@ -104,7 +105,7 @@ class TimelineControllerInterceptorHelper(private val positionOfReadMarker: KMut
|
||||||
.coerceAtLeast(0)
|
.coerceAtLeast(0)
|
||||||
|
|
||||||
val loadingItem = LoadingItem_()
|
val loadingItem = LoadingItem_()
|
||||||
.id("prefetch_backward_loading${System.currentTimeMillis()}")
|
.id("prefetch_backward_loading${Random.nextLong()}")
|
||||||
.showLoader(false)
|
.showLoader(false)
|
||||||
.setVisibilityStateChangedListener(Timeline.Direction.BACKWARDS, callback)
|
.setVisibilityStateChangedListener(Timeline.Direction.BACKWARDS, callback)
|
||||||
|
|
||||||
|
@ -120,7 +121,7 @@ class TimelineControllerInterceptorHelper(private val positionOfReadMarker: KMut
|
||||||
.coerceAtLeast(0)
|
.coerceAtLeast(0)
|
||||||
|
|
||||||
val loadingItem = LoadingItem_()
|
val loadingItem = LoadingItem_()
|
||||||
.id("prefetch_forward_loading${System.currentTimeMillis()}")
|
.id("prefetch_forward_loading${Random.nextLong()}")
|
||||||
.showLoader(false)
|
.showLoader(false)
|
||||||
.setVisibilityStateChangedListener(Timeline.Direction.FORWARDS, callback)
|
.setVisibilityStateChangedListener(Timeline.Direction.FORWARDS, callback)
|
||||||
add(indexOfPrefetchForward, loadingItem)
|
add(indexOfPrefetchForward, loadingItem)
|
||||||
|
|
|
@ -31,6 +31,7 @@ import im.vector.app.core.date.VectorDateFormatter
|
||||||
import im.vector.app.core.dialogs.GalleryOrCameraDialogHelper
|
import im.vector.app.core.dialogs.GalleryOrCameraDialogHelper
|
||||||
import im.vector.app.core.intent.getFilenameFromUri
|
import im.vector.app.core.intent.getFilenameFromUri
|
||||||
import im.vector.app.core.resources.ColorProvider
|
import im.vector.app.core.resources.ColorProvider
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.databinding.DialogBaseEditTextBinding
|
import im.vector.app.databinding.DialogBaseEditTextBinding
|
||||||
import im.vector.app.databinding.FragmentLoginAccountCreatedBinding
|
import im.vector.app.databinding.FragmentLoginAccountCreatedBinding
|
||||||
import im.vector.app.features.displayname.getBestName
|
import im.vector.app.features.displayname.getBestName
|
||||||
|
@ -52,13 +53,14 @@ class AccountCreatedFragment @Inject constructor(
|
||||||
private val avatarRenderer: AvatarRenderer,
|
private val avatarRenderer: AvatarRenderer,
|
||||||
private val dateFormatter: VectorDateFormatter,
|
private val dateFormatter: VectorDateFormatter,
|
||||||
private val matrixItemColorProvider: MatrixItemColorProvider,
|
private val matrixItemColorProvider: MatrixItemColorProvider,
|
||||||
|
private val clock: Clock,
|
||||||
colorProvider: ColorProvider
|
colorProvider: ColorProvider
|
||||||
) : AbstractLoginFragment2<FragmentLoginAccountCreatedBinding>(),
|
) : AbstractLoginFragment2<FragmentLoginAccountCreatedBinding>(),
|
||||||
GalleryOrCameraDialogHelper.Listener {
|
GalleryOrCameraDialogHelper.Listener {
|
||||||
|
|
||||||
private val viewModel: AccountCreatedViewModel by fragmentViewModel()
|
private val viewModel: AccountCreatedViewModel by fragmentViewModel()
|
||||||
|
|
||||||
private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider)
|
private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider, clock)
|
||||||
|
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginAccountCreatedBinding {
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLoginAccountCreatedBinding {
|
||||||
return FragmentLoginAccountCreatedBinding.inflate(inflater, container, false)
|
return FragmentLoginAccountCreatedBinding.inflate(inflater, container, false)
|
||||||
|
@ -73,7 +75,7 @@ class AccountCreatedFragment @Inject constructor(
|
||||||
|
|
||||||
viewModel.onEach { invalidateState(it) }
|
viewModel.onEach { invalidateState(it) }
|
||||||
|
|
||||||
views.loginAccountCreatedTime.text = dateFormatter.format(System.currentTimeMillis(), DateFormatKind.MESSAGE_SIMPLE)
|
views.loginAccountCreatedTime.text = dateFormatter.format(clock.epochMillis(), DateFormatKind.MESSAGE_SIMPLE)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeViewEvents() {
|
private fun observeViewEvents() {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import android.content.Context
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import im.vector.app.core.intent.getMimeTypeFromUri
|
import im.vector.app.core.intent.getMimeTypeFromUri
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.core.utils.saveMedia
|
import im.vector.app.core.utils.saveMedia
|
||||||
import im.vector.app.features.notifications.NotificationUtils
|
import im.vector.app.features.notifications.NotificationUtils
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
@ -30,7 +31,8 @@ import javax.inject.Inject
|
||||||
class DownloadMediaUseCase @Inject constructor(
|
class DownloadMediaUseCase @Inject constructor(
|
||||||
@ApplicationContext private val appContext: Context,
|
@ApplicationContext private val appContext: Context,
|
||||||
private val session: Session,
|
private val session: Session,
|
||||||
private val notificationUtils: NotificationUtils
|
private val notificationUtils: NotificationUtils,
|
||||||
|
private val clock: Clock,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun execute(input: File): Result<Unit> = withContext(session.coroutineDispatchers.io) {
|
suspend fun execute(input: File): Result<Unit> = withContext(session.coroutineDispatchers.io) {
|
||||||
|
@ -40,7 +42,8 @@ class DownloadMediaUseCase @Inject constructor(
|
||||||
file = input,
|
file = input,
|
||||||
title = input.name,
|
title = input.name,
|
||||||
mediaMimeType = getMimeTypeFromUri(appContext, input.toUri()),
|
mediaMimeType = getMimeTypeFromUri(appContext, input.toUri()),
|
||||||
notificationUtils = notificationUtils
|
notificationUtils = notificationUtils,
|
||||||
|
now = clock.epochMillis()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import im.vector.app.BuildConfig
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.takeAs
|
import im.vector.app.core.extensions.takeAs
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.features.displayname.getBestName
|
import im.vector.app.features.displayname.getBestName
|
||||||
import im.vector.app.features.home.room.detail.timeline.format.DisplayableEventFormatter
|
import im.vector.app.features.home.room.detail.timeline.format.DisplayableEventFormatter
|
||||||
import im.vector.app.features.home.room.detail.timeline.format.NoticeEventFormatter
|
import im.vector.app.features.home.room.detail.timeline.format.NoticeEventFormatter
|
||||||
|
@ -58,7 +59,8 @@ import javax.inject.Inject
|
||||||
class NotifiableEventResolver @Inject constructor(
|
class NotifiableEventResolver @Inject constructor(
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
private val noticeEventFormatter: NoticeEventFormatter,
|
private val noticeEventFormatter: NoticeEventFormatter,
|
||||||
private val displayableEventFormatter: DisplayableEventFormatter
|
private val displayableEventFormatter: DisplayableEventFormatter,
|
||||||
|
private val clock: Clock,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// private val eventDisplay = RiotEventDisplay(context)
|
// private val eventDisplay = RiotEventDisplay(context)
|
||||||
|
@ -86,7 +88,7 @@ class NotifiableEventResolver @Inject constructor(
|
||||||
eventId = event.eventId!!,
|
eventId = event.eventId!!,
|
||||||
editedEventId = timelineEvent.getEditedEventId(),
|
editedEventId = timelineEvent.getEditedEventId(),
|
||||||
noisy = false, // will be updated
|
noisy = false, // will be updated
|
||||||
timestamp = event.originServerTs ?: System.currentTimeMillis(),
|
timestamp = event.originServerTs ?: clock.epochMillis(),
|
||||||
description = bodyPreview,
|
description = bodyPreview,
|
||||||
title = stringProvider.getString(R.string.notification_unknown_new_event),
|
title = stringProvider.getString(R.string.notification_unknown_new_event),
|
||||||
soundName = null,
|
soundName = null,
|
||||||
|
@ -178,15 +180,19 @@ class NotifiableEventResolver @Inject constructor(
|
||||||
roomName = roomName,
|
roomName = roomName,
|
||||||
roomIsDirect = room.roomSummary()?.isDirect ?: false,
|
roomIsDirect = room.roomSummary()?.isDirect ?: false,
|
||||||
roomAvatarPath = session.contentUrlResolver()
|
roomAvatarPath = session.contentUrlResolver()
|
||||||
.resolveThumbnail(room.roomSummary()?.avatarUrl,
|
.resolveThumbnail(
|
||||||
|
room.roomSummary()?.avatarUrl,
|
||||||
250,
|
250,
|
||||||
250,
|
250,
|
||||||
ContentUrlResolver.ThumbnailMethod.SCALE),
|
ContentUrlResolver.ThumbnailMethod.SCALE
|
||||||
|
),
|
||||||
senderAvatarPath = session.contentUrlResolver()
|
senderAvatarPath = session.contentUrlResolver()
|
||||||
.resolveThumbnail(event.senderInfo.avatarUrl,
|
.resolveThumbnail(
|
||||||
|
event.senderInfo.avatarUrl,
|
||||||
250,
|
250,
|
||||||
250,
|
250,
|
||||||
ContentUrlResolver.ThumbnailMethod.SCALE),
|
ContentUrlResolver.ThumbnailMethod.SCALE
|
||||||
|
),
|
||||||
matrixID = session.myUserId,
|
matrixID = session.myUserId,
|
||||||
soundName = null
|
soundName = null
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,6 +23,7 @@ import androidx.core.app.RemoteInput
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.features.analytics.AnalyticsTracker
|
import im.vector.app.features.analytics.AnalyticsTracker
|
||||||
import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom
|
import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom
|
||||||
import im.vector.app.features.session.coroutineScope
|
import im.vector.app.features.session.coroutineScope
|
||||||
|
@ -45,6 +46,7 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
|
||||||
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
||||||
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
||||||
@Inject lateinit var analyticsTracker: AnalyticsTracker
|
@Inject lateinit var analyticsTracker: AnalyticsTracker
|
||||||
|
@Inject lateinit var clock: Clock
|
||||||
|
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
if (intent == null || context == null) return
|
if (intent == null || context == null) return
|
||||||
|
@ -137,7 +139,7 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
|
||||||
eventId = UUID.randomUUID().toString(),
|
eventId = UUID.randomUUID().toString(),
|
||||||
editedEventId = null,
|
editedEventId = null,
|
||||||
noisy = false,
|
noisy = false,
|
||||||
timestamp = System.currentTimeMillis(),
|
timestamp = clock.epochMillis(),
|
||||||
senderName = session.roomService().getRoomMember(session.myUserId, room.roomId)?.displayName
|
senderName = session.roomService().getRoomMember(session.myUserId, room.roomId)?.displayName
|
||||||
?: context?.getString(R.string.notification_sender_me),
|
?: context?.getString(R.string.notification_sender_me),
|
||||||
senderId = session.myUserId,
|
senderId = session.myUserId,
|
||||||
|
@ -188,7 +190,7 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
|
||||||
val notifiableMessageEvent = NotifiableMessageEvent(
|
val notifiableMessageEvent = NotifiableMessageEvent(
|
||||||
event.eventId,
|
event.eventId,
|
||||||
false,
|
false,
|
||||||
System.currentTimeMillis(),
|
clock.epochMillis(),
|
||||||
session.myUser?.displayname
|
session.myUser?.displayname
|
||||||
?: context?.getString(R.string.notification_sender_me),
|
?: context?.getString(R.string.notification_sender_me),
|
||||||
session.myUserId,
|
session.myUserId,
|
||||||
|
|
|
@ -51,6 +51,7 @@ import im.vector.app.core.extensions.createIgnoredUri
|
||||||
import im.vector.app.core.platform.PendingIntentCompat
|
import im.vector.app.core.platform.PendingIntentCompat
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.core.services.CallService
|
import im.vector.app.core.services.CallService
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.core.utils.startNotificationChannelSettingsIntent
|
import im.vector.app.core.utils.startNotificationChannelSettingsIntent
|
||||||
import im.vector.app.features.call.VectorCallActivity
|
import im.vector.app.features.call.VectorCallActivity
|
||||||
import im.vector.app.features.call.service.CallHeadsUpActionReceiver
|
import im.vector.app.features.call.service.CallHeadsUpActionReceiver
|
||||||
|
@ -72,9 +73,12 @@ import kotlin.random.Random
|
||||||
* Note: Cannot inject ColorProvider in the constructor, because it requires an Activity
|
* Note: Cannot inject ColorProvider in the constructor, because it requires an Activity
|
||||||
*/
|
*/
|
||||||
@Singleton
|
@Singleton
|
||||||
class NotificationUtils @Inject constructor(private val context: Context,
|
class NotificationUtils @Inject constructor(
|
||||||
private val stringProvider: StringProvider,
|
private val context: Context,
|
||||||
private val vectorPreferences: VectorPreferences) {
|
private val stringProvider: StringProvider,
|
||||||
|
private val vectorPreferences: VectorPreferences,
|
||||||
|
private val clock: Clock,
|
||||||
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
|
@ -323,7 +327,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
||||||
}
|
}
|
||||||
val contentPendingIntent = PendingIntent.getActivity(
|
val contentPendingIntent = PendingIntent.getActivity(
|
||||||
context,
|
context,
|
||||||
System.currentTimeMillis().toInt(),
|
clock.epochMillis().toInt(),
|
||||||
contentIntent,
|
contentIntent,
|
||||||
PendingIntentCompat.FLAG_IMMUTABLE
|
PendingIntentCompat.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
|
@ -337,7 +341,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
||||||
mode = VectorCallActivity.INCOMING_ACCEPT
|
mode = VectorCallActivity.INCOMING_ACCEPT
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE)
|
.getPendingIntent(clock.epochMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE)
|
||||||
|
|
||||||
val rejectCallPendingIntent = buildRejectCallPendingIntent(call.callId)
|
val rejectCallPendingIntent = buildRejectCallPendingIntent(call.callId)
|
||||||
|
|
||||||
|
@ -392,7 +396,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
||||||
}
|
}
|
||||||
val contentPendingIntent = PendingIntent.getActivity(
|
val contentPendingIntent = PendingIntent.getActivity(
|
||||||
context,
|
context,
|
||||||
System.currentTimeMillis().toInt(),
|
clock.epochMillis().toInt(),
|
||||||
contentIntent,
|
contentIntent,
|
||||||
PendingIntentCompat.FLAG_IMMUTABLE
|
PendingIntentCompat.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
|
@ -453,7 +457,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
||||||
val contentPendingIntent = TaskStackBuilder.create(context)
|
val contentPendingIntent = TaskStackBuilder.create(context)
|
||||||
.addNextIntentWithParentStack(HomeActivity.newIntent(context))
|
.addNextIntentWithParentStack(HomeActivity.newIntent(context))
|
||||||
.addNextIntent(VectorCallActivity.newIntent(context, call, null))
|
.addNextIntent(VectorCallActivity.newIntent(context, call, null))
|
||||||
.getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE)
|
.getPendingIntent(clock.epochMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE)
|
||||||
|
|
||||||
builder.setContentIntent(contentPendingIntent)
|
builder.setContentIntent(contentPendingIntent)
|
||||||
|
|
||||||
|
@ -467,7 +471,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
||||||
}
|
}
|
||||||
return PendingIntent.getBroadcast(
|
return PendingIntent.getBroadcast(
|
||||||
context,
|
context,
|
||||||
System.currentTimeMillis().toInt(),
|
clock.epochMillis().toInt(),
|
||||||
rejectCallActionReceiver,
|
rejectCallActionReceiver,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
|
@ -515,7 +519,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
||||||
val contentPendingIntent = TaskStackBuilder.create(context)
|
val contentPendingIntent = TaskStackBuilder.create(context)
|
||||||
.addNextIntentWithParentStack(HomeActivity.newIntent(context))
|
.addNextIntentWithParentStack(HomeActivity.newIntent(context))
|
||||||
.addNextIntent(RoomDetailActivity.newIntent(context, TimelineArgs(callInformation.nativeRoomId)))
|
.addNextIntent(RoomDetailActivity.newIntent(context, TimelineArgs(callInformation.nativeRoomId)))
|
||||||
.getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE)
|
.getPendingIntent(clock.epochMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE)
|
||||||
|
|
||||||
builder.setContentIntent(contentPendingIntent)
|
builder.setContentIntent(contentPendingIntent)
|
||||||
return builder.build()
|
return builder.build()
|
||||||
|
@ -562,7 +566,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
||||||
}
|
}
|
||||||
PendingIntent.getActivity(
|
PendingIntent.getActivity(
|
||||||
context,
|
context,
|
||||||
System.currentTimeMillis().toInt(),
|
clock.epochMillis().toInt(),
|
||||||
intent,
|
intent,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
||||||
).let {
|
).let {
|
||||||
|
@ -636,7 +640,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
||||||
markRoomReadIntent.putExtra(NotificationBroadcastReceiver.KEY_ROOM_ID, roomInfo.roomId)
|
markRoomReadIntent.putExtra(NotificationBroadcastReceiver.KEY_ROOM_ID, roomInfo.roomId)
|
||||||
val markRoomReadPendingIntent = PendingIntent.getBroadcast(
|
val markRoomReadPendingIntent = PendingIntent.getBroadcast(
|
||||||
context,
|
context,
|
||||||
System.currentTimeMillis().toInt(),
|
clock.epochMillis().toInt(),
|
||||||
markRoomReadIntent,
|
markRoomReadIntent,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
|
@ -677,7 +681,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
||||||
intent.action = DISMISS_ROOM_NOTIF_ACTION
|
intent.action = DISMISS_ROOM_NOTIF_ACTION
|
||||||
val pendingIntent = PendingIntent.getBroadcast(
|
val pendingIntent = PendingIntent.getBroadcast(
|
||||||
context.applicationContext,
|
context.applicationContext,
|
||||||
System.currentTimeMillis().toInt(),
|
clock.epochMillis().toInt(),
|
||||||
intent,
|
intent,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
|
@ -712,7 +716,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
||||||
rejectIntent.putExtra(NotificationBroadcastReceiver.KEY_ROOM_ID, roomId)
|
rejectIntent.putExtra(NotificationBroadcastReceiver.KEY_ROOM_ID, roomId)
|
||||||
val rejectIntentPendingIntent = PendingIntent.getBroadcast(
|
val rejectIntentPendingIntent = PendingIntent.getBroadcast(
|
||||||
context,
|
context,
|
||||||
System.currentTimeMillis().toInt(),
|
clock.epochMillis().toInt(),
|
||||||
rejectIntent,
|
rejectIntent,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
|
@ -730,7 +734,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
||||||
joinIntent.putExtra(NotificationBroadcastReceiver.KEY_ROOM_ID, roomId)
|
joinIntent.putExtra(NotificationBroadcastReceiver.KEY_ROOM_ID, roomId)
|
||||||
val joinIntentPendingIntent = PendingIntent.getBroadcast(
|
val joinIntentPendingIntent = PendingIntent.getBroadcast(
|
||||||
context,
|
context,
|
||||||
System.currentTimeMillis().toInt(),
|
clock.epochMillis().toInt(),
|
||||||
joinIntent,
|
joinIntent,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
|
@ -811,7 +815,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
||||||
.addNextIntentWithParentStack(HomeActivity.newIntent(context))
|
.addNextIntentWithParentStack(HomeActivity.newIntent(context))
|
||||||
.addNextIntent(roomIntentTap)
|
.addNextIntent(roomIntentTap)
|
||||||
.getPendingIntent(
|
.getPendingIntent(
|
||||||
System.currentTimeMillis().toInt(),
|
clock.epochMillis().toInt(),
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -844,7 +848,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
|
||||||
intent.putExtra(NotificationBroadcastReceiver.KEY_ROOM_ID, roomId)
|
intent.putExtra(NotificationBroadcastReceiver.KEY_ROOM_ID, roomId)
|
||||||
return PendingIntent.getBroadcast(
|
return PendingIntent.getBroadcast(
|
||||||
context,
|
context,
|
||||||
System.currentTimeMillis().toInt(),
|
clock.epochMillis().toInt(),
|
||||||
intent,
|
intent,
|
||||||
// PendingIntents attached to actions with remote inputs must be mutable
|
// PendingIntents attached to actions with remote inputs must be mutable
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_MUTABLE
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_MUTABLE
|
||||||
|
|
|
@ -29,6 +29,7 @@ import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.dialogs.GalleryOrCameraDialogHelper
|
import im.vector.app.core.dialogs.GalleryOrCameraDialogHelper
|
||||||
import im.vector.app.core.extensions.singletonEntryPoint
|
import im.vector.app.core.extensions.singletonEntryPoint
|
||||||
import im.vector.app.core.resources.ColorProvider
|
import im.vector.app.core.resources.ColorProvider
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.databinding.FragmentFtueProfilePictureBinding
|
import im.vector.app.databinding.FragmentFtueProfilePictureBinding
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
import im.vector.app.features.onboarding.OnboardingAction
|
import im.vector.app.features.onboarding.OnboardingAction
|
||||||
|
@ -39,10 +40,11 @@ import javax.inject.Inject
|
||||||
|
|
||||||
class FtueAuthChooseProfilePictureFragment @Inject constructor(
|
class FtueAuthChooseProfilePictureFragment @Inject constructor(
|
||||||
private val activeSessionHolder: ActiveSessionHolder,
|
private val activeSessionHolder: ActiveSessionHolder,
|
||||||
colorProvider: ColorProvider
|
colorProvider: ColorProvider,
|
||||||
|
clock: Clock,
|
||||||
) : AbstractFtueAuthFragment<FragmentFtueProfilePictureBinding>(), GalleryOrCameraDialogHelper.Listener {
|
) : AbstractFtueAuthFragment<FragmentFtueProfilePictureBinding>(), GalleryOrCameraDialogHelper.Listener {
|
||||||
|
|
||||||
private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider)
|
private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider, clock)
|
||||||
private val avatarRenderer: AvatarRenderer by lazy { requireContext().singletonEntryPoint().avatarRenderer() }
|
private val avatarRenderer: AvatarRenderer by lazy { requireContext().singletonEntryPoint().avatarRenderer() }
|
||||||
|
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtueProfilePictureBinding {
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtueProfilePictureBinding {
|
||||||
|
|
|
@ -24,6 +24,7 @@ import android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
|
||||||
import com.tapadoo.alerter.Alerter
|
import com.tapadoo.alerter.Alerter
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.core.utils.isAnimationDisabled
|
import im.vector.app.core.utils.isAnimationDisabled
|
||||||
import im.vector.app.features.analytics.ui.consent.AnalyticsOptInActivity
|
import im.vector.app.features.analytics.ui.consent.AnalyticsOptInActivity
|
||||||
import im.vector.app.features.pin.PinActivity
|
import im.vector.app.features.pin.PinActivity
|
||||||
|
@ -41,7 +42,9 @@ import javax.inject.Singleton
|
||||||
* will be back in the queue in first position.
|
* will be back in the queue in first position.
|
||||||
*/
|
*/
|
||||||
@Singleton
|
@Singleton
|
||||||
class PopupAlertManager @Inject constructor() {
|
class PopupAlertManager @Inject constructor(
|
||||||
|
private val clock: Clock,
|
||||||
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val INCOMING_CALL_PRIORITY = Int.MAX_VALUE
|
const val INCOMING_CALL_PRIORITY = Int.MAX_VALUE
|
||||||
|
@ -116,7 +119,7 @@ class PopupAlertManager @Inject constructor() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (currentAlerter != null) {
|
if (currentAlerter != null) {
|
||||||
if (currentAlerter!!.expirationTimestamp != null && System.currentTimeMillis() > currentAlerter!!.expirationTimestamp!!) {
|
if (currentAlerter!!.expirationTimestamp != null && clock.epochMillis() > currentAlerter!!.expirationTimestamp!!) {
|
||||||
// this alert has expired, remove it
|
// this alert has expired, remove it
|
||||||
// perform dismiss
|
// perform dismiss
|
||||||
try {
|
try {
|
||||||
|
@ -162,7 +165,7 @@ class PopupAlertManager @Inject constructor() {
|
||||||
currentAlerter = next
|
currentAlerter = next
|
||||||
next?.let {
|
next?.let {
|
||||||
if (!shouldBeDisplayedIn(next, currentActivity)) return
|
if (!shouldBeDisplayedIn(next, currentActivity)) return
|
||||||
val currentTime = System.currentTimeMillis()
|
val currentTime = clock.epochMillis()
|
||||||
if (next.expirationTimestamp != null && currentTime > next.expirationTimestamp!!) {
|
if (next.expirationTimestamp != null && currentTime > next.expirationTimestamp!!) {
|
||||||
// skip
|
// skip
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -37,6 +37,7 @@ import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.OnBackPressed
|
import im.vector.app.core.platform.OnBackPressed
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.resources.ColorProvider
|
import im.vector.app.core.resources.ColorProvider
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.databinding.FragmentCreateRoomBinding
|
import im.vector.app.databinding.FragmentCreateRoomBinding
|
||||||
import im.vector.app.features.navigation.Navigator
|
import im.vector.app.features.navigation.Navigator
|
||||||
import im.vector.app.features.roomdirectory.RoomDirectorySharedAction
|
import im.vector.app.features.roomdirectory.RoomDirectorySharedAction
|
||||||
|
@ -62,7 +63,8 @@ data class CreateRoomArgs(
|
||||||
class CreateRoomFragment @Inject constructor(
|
class CreateRoomFragment @Inject constructor(
|
||||||
private val createRoomController: CreateRoomController,
|
private val createRoomController: CreateRoomController,
|
||||||
private val createSpaceController: CreateSubSpaceController,
|
private val createSpaceController: CreateSubSpaceController,
|
||||||
colorProvider: ColorProvider
|
colorProvider: ColorProvider,
|
||||||
|
clock: Clock,
|
||||||
) : VectorBaseFragment<FragmentCreateRoomBinding>(),
|
) : VectorBaseFragment<FragmentCreateRoomBinding>(),
|
||||||
CreateRoomController.Listener,
|
CreateRoomController.Listener,
|
||||||
GalleryOrCameraDialogHelper.Listener,
|
GalleryOrCameraDialogHelper.Listener,
|
||||||
|
@ -74,7 +76,7 @@ class CreateRoomFragment @Inject constructor(
|
||||||
|
|
||||||
private lateinit var roomJoinRuleSharedActionViewModel: RoomJoinRuleSharedActionViewModel
|
private lateinit var roomJoinRuleSharedActionViewModel: RoomJoinRuleSharedActionViewModel
|
||||||
|
|
||||||
private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider)
|
private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider, clock)
|
||||||
|
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentCreateRoomBinding {
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentCreateRoomBinding {
|
||||||
return FragmentCreateRoomBinding.inflate(inflater, container, false)
|
return FragmentCreateRoomBinding.inflate(inflater, container, false)
|
||||||
|
@ -166,7 +168,8 @@ class CreateRoomFragment @Inject constructor(
|
||||||
} else {
|
} else {
|
||||||
listOf(RoomJoinRules.INVITE, RoomJoinRules.PUBLIC)
|
listOf(RoomJoinRules.INVITE, RoomJoinRules.PUBLIC)
|
||||||
}
|
}
|
||||||
RoomJoinRuleBottomSheet.newInstance(state.roomJoinRules,
|
RoomJoinRuleBottomSheet.newInstance(
|
||||||
|
state.roomJoinRules,
|
||||||
allowed.map { it.toOption(false) },
|
allowed.map { it.toOption(false) },
|
||||||
state.isSubSpace,
|
state.isSubSpace,
|
||||||
state.parentSpaceSummary?.displayName
|
state.parentSpaceSummary?.displayName
|
||||||
|
|
|
@ -37,6 +37,7 @@ import im.vector.app.core.intent.getFilenameFromUri
|
||||||
import im.vector.app.core.platform.OnBackPressed
|
import im.vector.app.core.platform.OnBackPressed
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.resources.ColorProvider
|
import im.vector.app.core.resources.ColorProvider
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.core.utils.toast
|
import im.vector.app.core.utils.toast
|
||||||
import im.vector.app.databinding.FragmentRoomSettingGenericBinding
|
import im.vector.app.databinding.FragmentRoomSettingGenericBinding
|
||||||
import im.vector.app.features.analytics.plan.MobileScreen
|
import im.vector.app.features.analytics.plan.MobileScreen
|
||||||
|
@ -57,7 +58,8 @@ import javax.inject.Inject
|
||||||
class RoomSettingsFragment @Inject constructor(
|
class RoomSettingsFragment @Inject constructor(
|
||||||
private val controller: RoomSettingsController,
|
private val controller: RoomSettingsController,
|
||||||
colorProvider: ColorProvider,
|
colorProvider: ColorProvider,
|
||||||
private val avatarRenderer: AvatarRenderer
|
private val avatarRenderer: AvatarRenderer,
|
||||||
|
clock: Clock,
|
||||||
) :
|
) :
|
||||||
VectorBaseFragment<FragmentRoomSettingGenericBinding>(),
|
VectorBaseFragment<FragmentRoomSettingGenericBinding>(),
|
||||||
RoomSettingsController.Callback,
|
RoomSettingsController.Callback,
|
||||||
|
@ -70,7 +72,7 @@ class RoomSettingsFragment @Inject constructor(
|
||||||
private lateinit var roomJoinRuleSharedActionViewModel: RoomJoinRuleSharedActionViewModel
|
private lateinit var roomJoinRuleSharedActionViewModel: RoomJoinRuleSharedActionViewModel
|
||||||
|
|
||||||
private val roomProfileArgs: RoomProfileArgs by args()
|
private val roomProfileArgs: RoomProfileArgs by args()
|
||||||
private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider)
|
private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider, clock)
|
||||||
|
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomSettingGenericBinding {
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomSettingGenericBinding {
|
||||||
return FragmentRoomSettingGenericBinding.inflate(inflater, container, false)
|
return FragmentRoomSettingGenericBinding.inflate(inflater, container, false)
|
||||||
|
@ -198,7 +200,8 @@ class RoomSettingsFragment @Inject constructor(
|
||||||
RoomSettingsAction.SetAvatarAction(
|
RoomSettingsAction.SetAvatarAction(
|
||||||
RoomSettingsViewState.AvatarAction.UpdateAvatar(
|
RoomSettingsViewState.AvatarAction.UpdateAvatar(
|
||||||
newAvatarUri = uri,
|
newAvatarUri = uri,
|
||||||
newAvatarFileName = getFilenameFromUri(requireContext(), uri) ?: UUID.randomUUID().toString())
|
newAvatarFileName = getFilenameFromUri(requireContext(), uri) ?: UUID.randomUUID().toString()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import com.google.android.material.tabs.TabLayoutMediator
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.intent.getMimeTypeFromUri
|
import im.vector.app.core.intent.getMimeTypeFromUri
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.core.utils.saveMedia
|
import im.vector.app.core.utils.saveMedia
|
||||||
import im.vector.app.core.utils.shareMedia
|
import im.vector.app.core.utils.shareMedia
|
||||||
import im.vector.app.databinding.FragmentRoomUploadsBinding
|
import im.vector.app.databinding.FragmentRoomUploadsBinding
|
||||||
|
@ -43,7 +44,8 @@ import javax.inject.Inject
|
||||||
|
|
||||||
class RoomUploadsFragment @Inject constructor(
|
class RoomUploadsFragment @Inject constructor(
|
||||||
private val avatarRenderer: AvatarRenderer,
|
private val avatarRenderer: AvatarRenderer,
|
||||||
private val notificationUtils: NotificationUtils
|
private val notificationUtils: NotificationUtils,
|
||||||
|
private val clock: Clock,
|
||||||
) : VectorBaseFragment<FragmentRoomUploadsBinding>() {
|
) : VectorBaseFragment<FragmentRoomUploadsBinding>() {
|
||||||
|
|
||||||
private val roomProfileArgs: RoomProfileArgs by args()
|
private val roomProfileArgs: RoomProfileArgs by args()
|
||||||
|
@ -88,7 +90,8 @@ class RoomUploadsFragment @Inject constructor(
|
||||||
file = it.file,
|
file = it.file,
|
||||||
title = it.title,
|
title = it.title,
|
||||||
mediaMimeType = getMimeTypeFromUri(requireContext(), it.file.toUri()),
|
mediaMimeType = getMimeTypeFromUri(requireContext(), it.file.toUri()),
|
||||||
notificationUtils = notificationUtils
|
notificationUtils = notificationUtils,
|
||||||
|
now = clock.epochMillis()
|
||||||
)
|
)
|
||||||
}.onFailure { failure ->
|
}.onFailure { failure ->
|
||||||
if (!isAdded) return@onFailure
|
if (!isAdded) return@onFailure
|
||||||
|
|
|
@ -26,6 +26,7 @@ import com.squareup.seismic.ShakeDetector
|
||||||
import im.vector.app.BuildConfig
|
import im.vector.app.BuildConfig
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.di.DefaultSharedPreferences
|
import im.vector.app.core.di.DefaultSharedPreferences
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.features.disclaimer.SHARED_PREF_KEY
|
import im.vector.app.features.disclaimer.SHARED_PREF_KEY
|
||||||
import im.vector.app.features.homeserver.ServerUrlsRepository
|
import im.vector.app.features.homeserver.ServerUrlsRepository
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
|
@ -33,7 +34,10 @@ import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class VectorPreferences @Inject constructor(private val context: Context) {
|
class VectorPreferences @Inject constructor(
|
||||||
|
private val context: Context,
|
||||||
|
private val clock: Clock,
|
||||||
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val SETTINGS_HELP_PREFERENCE_KEY = "SETTINGS_HELP_PREFERENCE_KEY"
|
const val SETTINGS_HELP_PREFERENCE_KEY = "SETTINGS_HELP_PREFERENCE_KEY"
|
||||||
|
@ -664,9 +668,9 @@ class VectorPreferences @Inject constructor(private val context: Context) {
|
||||||
*/
|
*/
|
||||||
fun getMinMediasLastAccessTime(): Long {
|
fun getMinMediasLastAccessTime(): Long {
|
||||||
return when (getSelectedMediasSavingPeriod()) {
|
return when (getSelectedMediasSavingPeriod()) {
|
||||||
MEDIA_SAVING_3_DAYS -> System.currentTimeMillis() / 1000 - 3 * 24 * 60 * 60
|
MEDIA_SAVING_3_DAYS -> clock.epochMillis() / 1000 - 3 * 24 * 60 * 60
|
||||||
MEDIA_SAVING_1_WEEK -> System.currentTimeMillis() / 1000 - 7 * 24 * 60 * 60
|
MEDIA_SAVING_1_WEEK -> clock.epochMillis() / 1000 - 7 * 24 * 60 * 60
|
||||||
MEDIA_SAVING_1_MONTH -> System.currentTimeMillis() / 1000 - 30 * 24 * 60 * 60
|
MEDIA_SAVING_1_MONTH -> clock.epochMillis() / 1000 - 30 * 24 * 60 * 60
|
||||||
MEDIA_SAVING_FOREVER -> 0
|
MEDIA_SAVING_FOREVER -> 0
|
||||||
else -> 0
|
else -> 0
|
||||||
}
|
}
|
||||||
|
@ -872,8 +876,10 @@ class VectorPreferences @Inject constructor(private val context: Context) {
|
||||||
* @return true if user should always appear offline
|
* @return true if user should always appear offline
|
||||||
*/
|
*/
|
||||||
fun userAlwaysAppearsOffline(): Boolean {
|
fun userAlwaysAppearsOffline(): Boolean {
|
||||||
return defaultPrefs.getBoolean(SETTINGS_PRESENCE_USER_ALWAYS_APPEARS_OFFLINE,
|
return defaultPrefs.getBoolean(
|
||||||
getDefault(R.bool.settings_presence_user_always_appears_offline_default))
|
SETTINGS_PRESENCE_USER_ALWAYS_APPEARS_OFFLINE,
|
||||||
|
getDefault(R.bool.settings_presence_user_always_appears_offline_default)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1005,9 +1011,11 @@ class VectorPreferences @Inject constructor(private val context: Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun prefSpacesShowAllRoomInHome(): Boolean {
|
fun prefSpacesShowAllRoomInHome(): Boolean {
|
||||||
return defaultPrefs.getBoolean(SETTINGS_PREF_SPACE_SHOW_ALL_ROOM_IN_HOME,
|
return defaultPrefs.getBoolean(
|
||||||
|
SETTINGS_PREF_SPACE_SHOW_ALL_ROOM_IN_HOME,
|
||||||
// migration of old property
|
// migration of old property
|
||||||
!labsSpacesOnlyOrphansInHome())
|
!labsSpacesOnlyOrphansInHome()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -45,6 +45,7 @@ import im.vector.app.core.preference.UserAvatarPreference
|
||||||
import im.vector.app.core.preference.VectorPreference
|
import im.vector.app.core.preference.VectorPreference
|
||||||
import im.vector.app.core.preference.VectorSwitchPreference
|
import im.vector.app.core.preference.VectorSwitchPreference
|
||||||
import im.vector.app.core.resources.ColorProvider
|
import im.vector.app.core.resources.ColorProvider
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.core.utils.TextUtils
|
import im.vector.app.core.utils.TextUtils
|
||||||
import im.vector.app.core.utils.getSizeOfFiles
|
import im.vector.app.core.utils.getSizeOfFiles
|
||||||
import im.vector.app.core.utils.toast
|
import im.vector.app.core.utils.toast
|
||||||
|
@ -74,7 +75,8 @@ import java.util.UUID
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class VectorSettingsGeneralFragment @Inject constructor(
|
class VectorSettingsGeneralFragment @Inject constructor(
|
||||||
colorProvider: ColorProvider
|
colorProvider: ColorProvider,
|
||||||
|
clock: Clock,
|
||||||
) :
|
) :
|
||||||
VectorSettingsBaseFragment(),
|
VectorSettingsBaseFragment(),
|
||||||
GalleryOrCameraDialogHelper.Listener {
|
GalleryOrCameraDialogHelper.Listener {
|
||||||
|
@ -82,7 +84,7 @@ class VectorSettingsGeneralFragment @Inject constructor(
|
||||||
override var titleRes = R.string.settings_general_title
|
override var titleRes = R.string.settings_general_title
|
||||||
override val preferenceXmlRes = R.xml.vector_settings_general
|
override val preferenceXmlRes = R.xml.vector_settings_general
|
||||||
|
|
||||||
private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider)
|
private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider, clock)
|
||||||
|
|
||||||
private val mUserSettingsCategory by lazy {
|
private val mUserSettingsCategory by lazy {
|
||||||
findPreference<PreferenceCategory>(VectorPreferences.SETTINGS_USER_SETTINGS_PREFERENCE_KEY)!!
|
findPreference<PreferenceCategory>(VectorPreferences.SETTINGS_USER_SETTINGS_PREFERENCE_KEY)!!
|
||||||
|
|
|
@ -36,12 +36,15 @@ import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.registerStartForActivityResult
|
import im.vector.app.core.extensions.registerStartForActivityResult
|
||||||
import im.vector.app.core.extensions.safeOpenOutputStream
|
import im.vector.app.core.extensions.safeOpenOutputStream
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.core.utils.selectTxtFileToWrite
|
import im.vector.app.core.utils.selectTxtFileToWrite
|
||||||
import im.vector.app.databinding.FragmentDevtoolKeyrequestsBinding
|
import im.vector.app.databinding.FragmentDevtoolKeyrequestsBinding
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class KeyRequestsFragment @Inject constructor() : VectorBaseFragment<FragmentDevtoolKeyrequestsBinding>() {
|
class KeyRequestsFragment @Inject constructor(
|
||||||
|
private val clock: Clock,
|
||||||
|
) : VectorBaseFragment<FragmentDevtoolKeyrequestsBinding>() {
|
||||||
|
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentDevtoolKeyrequestsBinding {
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentDevtoolKeyrequestsBinding {
|
||||||
return FragmentDevtoolKeyrequestsBinding.inflate(inflater, container, false)
|
return FragmentDevtoolKeyrequestsBinding.inflate(inflater, container, false)
|
||||||
|
@ -126,7 +129,7 @@ class KeyRequestsFragment @Inject constructor() : VectorBaseFragment<FragmentDev
|
||||||
selectTxtFileToWrite(
|
selectTxtFileToWrite(
|
||||||
activity = requireActivity(),
|
activity = requireActivity(),
|
||||||
activityResultLauncher = epxortAuditForActivityResult,
|
activityResultLauncher = epxortAuditForActivityResult,
|
||||||
defaultFileName = "audit-export_${System.currentTimeMillis()}.txt",
|
defaultFileName = "audit-export_${clock.epochMillis()}.txt",
|
||||||
chooserHint = "Export Audit"
|
chooserHint = "Export Audit"
|
||||||
)
|
)
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -28,12 +28,14 @@ import im.vector.app.core.extensions.hideKeyboard
|
||||||
import im.vector.app.core.platform.OnBackPressed
|
import im.vector.app.core.platform.OnBackPressed
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.resources.ColorProvider
|
import im.vector.app.core.resources.ColorProvider
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.databinding.FragmentSpaceCreateGenericEpoxyFormBinding
|
import im.vector.app.databinding.FragmentSpaceCreateGenericEpoxyFormBinding
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class CreateSpaceDetailsFragment @Inject constructor(
|
class CreateSpaceDetailsFragment @Inject constructor(
|
||||||
private val epoxyController: SpaceDetailEpoxyController,
|
private val epoxyController: SpaceDetailEpoxyController,
|
||||||
colorProvider: ColorProvider
|
colorProvider: ColorProvider,
|
||||||
|
clock: Clock,
|
||||||
) : VectorBaseFragment<FragmentSpaceCreateGenericEpoxyFormBinding>(), SpaceDetailEpoxyController.Listener,
|
) : VectorBaseFragment<FragmentSpaceCreateGenericEpoxyFormBinding>(), SpaceDetailEpoxyController.Listener,
|
||||||
GalleryOrCameraDialogHelper.Listener, OnBackPressed {
|
GalleryOrCameraDialogHelper.Listener, OnBackPressed {
|
||||||
|
|
||||||
|
@ -42,7 +44,7 @@ class CreateSpaceDetailsFragment @Inject constructor(
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) =
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) =
|
||||||
FragmentSpaceCreateGenericEpoxyFormBinding.inflate(layoutInflater, container, false)
|
FragmentSpaceCreateGenericEpoxyFormBinding.inflate(layoutInflater, container, false)
|
||||||
|
|
||||||
private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider)
|
private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider, clock)
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
|
@ -38,7 +38,7 @@ import im.vector.app.core.intent.getFilenameFromUri
|
||||||
import im.vector.app.core.platform.OnBackPressed
|
import im.vector.app.core.platform.OnBackPressed
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.resources.ColorProvider
|
import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.resources.DrawableProvider
|
import im.vector.app.core.time.Clock
|
||||||
import im.vector.app.core.utils.toast
|
import im.vector.app.core.utils.toast
|
||||||
import im.vector.app.databinding.FragmentRoomSettingGenericBinding
|
import im.vector.app.databinding.FragmentRoomSettingGenericBinding
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
|
@ -60,9 +60,9 @@ import javax.inject.Inject
|
||||||
|
|
||||||
class SpaceSettingsFragment @Inject constructor(
|
class SpaceSettingsFragment @Inject constructor(
|
||||||
private val epoxyController: SpaceSettingsController,
|
private val epoxyController: SpaceSettingsController,
|
||||||
private val colorProvider: ColorProvider,
|
colorProvider: ColorProvider,
|
||||||
|
clock: Clock,
|
||||||
private val avatarRenderer: AvatarRenderer,
|
private val avatarRenderer: AvatarRenderer,
|
||||||
private val drawableProvider: DrawableProvider
|
|
||||||
) : VectorBaseFragment<FragmentRoomSettingGenericBinding>(),
|
) : VectorBaseFragment<FragmentRoomSettingGenericBinding>(),
|
||||||
SpaceSettingsController.Callback,
|
SpaceSettingsController.Callback,
|
||||||
GalleryOrCameraDialogHelper.Listener,
|
GalleryOrCameraDialogHelper.Listener,
|
||||||
|
@ -73,7 +73,7 @@ class SpaceSettingsFragment @Inject constructor(
|
||||||
|
|
||||||
private lateinit var roomJoinRuleSharedActionViewModel: RoomJoinRuleSharedActionViewModel
|
private lateinit var roomJoinRuleSharedActionViewModel: RoomJoinRuleSharedActionViewModel
|
||||||
|
|
||||||
private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider)
|
private val galleryOrCameraDialogHelper = GalleryOrCameraDialogHelper(this, colorProvider, clock)
|
||||||
|
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) = FragmentRoomSettingGenericBinding.inflate(inflater)
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) = FragmentRoomSettingGenericBinding.inflate(inflater)
|
||||||
|
|
||||||
|
@ -236,7 +236,8 @@ class SpaceSettingsFragment @Inject constructor(
|
||||||
RoomSettingsAction.SetAvatarAction(
|
RoomSettingsAction.SetAvatarAction(
|
||||||
RoomSettingsViewState.AvatarAction.UpdateAvatar(
|
RoomSettingsViewState.AvatarAction.UpdateAvatar(
|
||||||
newAvatarUri = uri,
|
newAvatarUri = uri,
|
||||||
newAvatarFileName = getFilenameFromUri(requireContext(), uri) ?: UUID.randomUUID().toString())
|
newAvatarFileName = getFilenameFromUri(requireContext(), uri) ?: UUID.randomUUID().toString()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ import org.matrix.android.sdk.api.session.identity.IdentityServiceListener
|
||||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||||
import org.matrix.android.sdk.api.session.user.model.User
|
import org.matrix.android.sdk.api.session.user.model.User
|
||||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
data class ThreePidUser(
|
data class ThreePidUser(
|
||||||
val email: String,
|
val email: String,
|
||||||
|
@ -142,7 +143,7 @@ class UserListViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun retryUserSearch(state: UserListViewState) {
|
private fun retryUserSearch(state: UserListViewState) {
|
||||||
identityServerUsersSearch.tryEmit(UserSearch(state.searchTerm, cacheBuster = System.currentTimeMillis()))
|
identityServerUsersSearch.tryEmit(UserSearch(state.searchTerm, cacheBuster = Random.nextLong()))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSearchUsers(searchTerm: String) {
|
private fun handleSearchUsers(searchTerm: String) {
|
||||||
|
|
|
@ -20,11 +20,13 @@ import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import com.arthenica.ffmpegkit.FFmpegKit
|
import com.arthenica.ffmpegkit.FFmpegKit
|
||||||
import com.arthenica.ffmpegkit.ReturnCode
|
import com.arthenica.ffmpegkit.ReturnCode
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class VoicePlayerHelper @Inject constructor(
|
class VoicePlayerHelper @Inject constructor(
|
||||||
|
private val clock: Clock,
|
||||||
context: Context
|
context: Context
|
||||||
) {
|
) {
|
||||||
private val outputDirectory: File by lazy {
|
private val outputDirectory: File by lazy {
|
||||||
|
@ -46,9 +48,9 @@ class VoicePlayerHelper @Inject constructor(
|
||||||
if (targetFile.exists()) {
|
if (targetFile.exists()) {
|
||||||
targetFile.delete()
|
targetFile.delete()
|
||||||
}
|
}
|
||||||
val start = System.currentTimeMillis()
|
val start = clock.epochMillis()
|
||||||
val session = FFmpegKit.execute("-i \"${file.path}\" -c:a aac \"${targetFile.path}\"")
|
val session = FFmpegKit.execute("-i \"${file.path}\" -c:a aac \"${targetFile.path}\"")
|
||||||
val duration = System.currentTimeMillis() - start
|
val duration = clock.epochMillis() - start
|
||||||
Timber.d("Convert to mp4 in $duration ms. Size in bytes from ${file.length()} to ${targetFile.length()}")
|
Timber.d("Convert to mp4 in $duration ms. Size in bytes from ${file.length()} to ${targetFile.length()}")
|
||||||
return when {
|
return when {
|
||||||
ReturnCode.isSuccess(session.returnCode) -> {
|
ReturnCode.isSuccess(session.returnCode) -> {
|
||||||
|
|
|
@ -23,10 +23,14 @@ import com.arthenica.ffmpegkit.FFmpegKitConfig
|
||||||
import com.arthenica.ffmpegkit.Level
|
import com.arthenica.ffmpegkit.Level
|
||||||
import com.arthenica.ffmpegkit.ReturnCode
|
import com.arthenica.ffmpegkit.ReturnCode
|
||||||
import im.vector.app.BuildConfig
|
import im.vector.app.BuildConfig
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class VoiceRecorderL(context: Context) : AbstractVoiceRecorder(context, "mp4") {
|
class VoiceRecorderL(
|
||||||
|
context: Context,
|
||||||
|
private val clock: Clock,
|
||||||
|
) : AbstractVoiceRecorder(context, "mp4") {
|
||||||
override fun setOutputFormat(mediaRecorder: MediaRecorder) {
|
override fun setOutputFormat(mediaRecorder: MediaRecorder) {
|
||||||
// Use AAC/MP4 format here
|
// Use AAC/MP4 format here
|
||||||
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
|
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
|
||||||
|
@ -43,9 +47,9 @@ class VoiceRecorderL(context: Context) : AbstractVoiceRecorder(context, "mp4") {
|
||||||
if (targetFile.exists()) {
|
if (targetFile.exists()) {
|
||||||
targetFile.delete()
|
targetFile.delete()
|
||||||
}
|
}
|
||||||
val start = System.currentTimeMillis()
|
val start = clock.epochMillis()
|
||||||
val session = FFmpegKit.execute("-i \"${recordedFile.path}\" -c:a libvorbis \"${targetFile.path}\"")
|
val session = FFmpegKit.execute("-i \"${recordedFile.path}\" -c:a libvorbis \"${targetFile.path}\"")
|
||||||
val duration = System.currentTimeMillis() - start
|
val duration = clock.epochMillis() - start
|
||||||
Timber.d("Convert to ogg in $duration ms. Size in bytes from ${recordedFile.length()} to ${targetFile.length()}")
|
Timber.d("Convert to ogg in $duration ms. Size in bytes from ${recordedFile.length()} to ${targetFile.length()}")
|
||||||
return when {
|
return when {
|
||||||
ReturnCode.isSuccess(session.returnCode) -> {
|
ReturnCode.isSuccess(session.returnCode) -> {
|
||||||
|
|
|
@ -18,16 +18,18 @@ package im.vector.app.features.voice
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import im.vector.app.core.time.Clock
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class VoiceRecorderProvider @Inject constructor(
|
class VoiceRecorderProvider @Inject constructor(
|
||||||
private val context: Context
|
private val context: Context,
|
||||||
|
private val clock: Clock,
|
||||||
) {
|
) {
|
||||||
fun provideVoiceRecorder(): VoiceRecorder {
|
fun provideVoiceRecorder(): VoiceRecorder {
|
||||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
VoiceRecorderQ(context)
|
VoiceRecorderQ(context)
|
||||||
} else {
|
} else {
|
||||||
VoiceRecorderL(context)
|
VoiceRecorderL(context, clock)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue