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