adding clock abstraction for avoiding directly using the System.currentTimeMillis

This commit is contained in:
Adam Brown 2021-11-24 15:53:59 +00:00
parent 8fa264589a
commit 5d1812008d
4 changed files with 46 additions and 4 deletions

View file

@ -29,6 +29,8 @@ import dagger.hilt.components.SingletonComponent
import im.vector.app.core.dispatchers.CoroutineDispatchers import im.vector.app.core.dispatchers.CoroutineDispatchers
import im.vector.app.core.error.DefaultErrorFormatter import im.vector.app.core.error.DefaultErrorFormatter
import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.time.Clock
import im.vector.app.core.time.DefaultClock
import im.vector.app.features.invite.AutoAcceptInvites import im.vector.app.features.invite.AutoAcceptInvites
import im.vector.app.features.invite.CompileTimeAutoAcceptInvites import im.vector.app.features.invite.CompileTimeAutoAcceptInvites
import im.vector.app.features.navigation.DefaultNavigator import im.vector.app.features.navigation.DefaultNavigator
@ -66,6 +68,9 @@ abstract class VectorBindModule {
@Binds @Binds
abstract fun bindAutoAcceptInvites(autoAcceptInvites: CompileTimeAutoAcceptInvites): AutoAcceptInvites abstract fun bindAutoAcceptInvites(autoAcceptInvites: CompileTimeAutoAcceptInvites): AutoAcceptInvites
@Binds
abstract fun bindDefaultClock(clock: DefaultClock): Clock
} }
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)

View file

@ -0,0 +1,29 @@
/*
* Copyright (c) 2021 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.core.time
import javax.inject.Inject
interface Clock {
fun epochMillis(): Long
}
class DefaultClock @Inject constructor() : Clock {
override fun epochMillis(): Long {
return System.currentTimeMillis()
}
}

View file

@ -87,6 +87,7 @@ import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.platform.lifecycleAwareLazy import im.vector.app.core.platform.lifecycleAwareLazy
import im.vector.app.core.platform.showOptimizedSnackbar import im.vector.app.core.platform.showOptimizedSnackbar
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.ui.views.CurrentCallsView import im.vector.app.core.ui.views.CurrentCallsView
import im.vector.app.core.ui.views.CurrentCallsViewPresenter import im.vector.app.core.ui.views.CurrentCallsViewPresenter
import im.vector.app.core.ui.views.FailedMessagesWarningView import im.vector.app.core.ui.views.FailedMessagesWarningView
@ -250,7 +251,8 @@ class RoomDetailFragment @Inject constructor(
private val roomDetailPendingActionStore: RoomDetailPendingActionStore, private val roomDetailPendingActionStore: RoomDetailPendingActionStore,
private val pillsPostProcessorFactory: PillsPostProcessor.Factory, private val pillsPostProcessorFactory: PillsPostProcessor.Factory,
private val callManager: WebRtcCallManager, private val callManager: WebRtcCallManager,
private val voiceMessagePlaybackTracker: VoiceMessagePlaybackTracker private val voiceMessagePlaybackTracker: VoiceMessagePlaybackTracker,
private val clock: Clock
) : ) :
VectorBaseFragment<FragmentRoomDetailBinding>(), VectorBaseFragment<FragmentRoomDetailBinding>(),
TimelineEventController.Callback, TimelineEventController.Callback,
@ -699,7 +701,7 @@ class RoomDetailFragment @Inject constructor(
if (checkPermissions(PERMISSIONS_FOR_VOICE_MESSAGE, requireActivity(), permissionVoiceMessageLauncher)) { if (checkPermissions(PERMISSIONS_FOR_VOICE_MESSAGE, requireActivity(), permissionVoiceMessageLauncher)) {
messageComposerViewModel.handle(MessageComposerAction.StartRecordingVoiceMessage) messageComposerViewModel.handle(MessageComposerAction.StartRecordingVoiceMessage)
vibrate(requireContext()) vibrate(requireContext())
updateRecordingUiState(RecordingUiState.Started(System.currentTimeMillis())) updateRecordingUiState(RecordingUiState.Started(clock.epochMillis()))
} }
} }
@ -714,7 +716,7 @@ class RoomDetailFragment @Inject constructor(
override fun onVoiceRecordingLocked() { override fun onVoiceRecordingLocked() {
val startedState = withState(messageComposerViewModel) { it.voiceRecordingUiState as? RecordingUiState.Started } val startedState = withState(messageComposerViewModel) { it.voiceRecordingUiState as? RecordingUiState.Started }
val startTime = startedState?.recordingStartTimestamp ?: System.currentTimeMillis() val startTime = startedState?.recordingStartTimestamp ?: clock.epochMillis()
updateRecordingUiState(RecordingUiState.Locked(startTime)) updateRecordingUiState(RecordingUiState.Locked(startTime))
} }

View file

@ -20,19 +20,23 @@ import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import dagger.hilt.android.AndroidEntryPoint
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.extensions.exhaustive import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.hardware.vibrate import im.vector.app.core.hardware.vibrate
import im.vector.app.core.time.Clock
import im.vector.app.core.utils.CountUpTimer import im.vector.app.core.utils.CountUpTimer
import im.vector.app.core.utils.DimensionConverter import im.vector.app.core.utils.DimensionConverter
import im.vector.app.databinding.ViewVoiceMessageRecorderBinding import im.vector.app.databinding.ViewVoiceMessageRecorderBinding
import im.vector.app.features.home.room.detail.timeline.helper.VoiceMessagePlaybackTracker import im.vector.app.features.home.room.detail.timeline.helper.VoiceMessagePlaybackTracker
import javax.inject.Inject
import kotlin.math.floor import kotlin.math.floor
/** /**
* Encapsulates the voice message recording view and animations. * Encapsulates the voice message recording view and animations.
*/ */
@AndroidEntryPoint
class VoiceMessageRecorderView @JvmOverloads constructor( class VoiceMessageRecorderView @JvmOverloads constructor(
context: Context, context: Context,
attrs: AttributeSet? = null, attrs: AttributeSet? = null,
@ -51,6 +55,8 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
fun onRecordingWaveformClicked() fun onRecordingWaveformClicked()
} }
@Inject lateinit var clock: Clock
// We need to define views as lateinit var to be able to check if initialized for the bug fix on api 21 and 22. // We need to define views as lateinit var to be able to check if initialized for the bug fix on api 21 and 22.
@Suppress("UNNECESSARY_LATEINIT") @Suppress("UNNECESSARY_LATEINIT")
private lateinit var voiceMessageViews: VoiceMessageViews private lateinit var voiceMessageViews: VoiceMessageViews
@ -163,7 +169,7 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
} }
private fun startRecordingTicker(startFromLocked: Boolean, startAt: Long) { private fun startRecordingTicker(startFromLocked: Boolean, startAt: Long) {
val startMs = ((System.currentTimeMillis() - startAt)).coerceAtLeast(0) val startMs = ((clock.epochMillis() - startAt)).coerceAtLeast(0)
recordingTicker?.stop() recordingTicker?.stop()
recordingTicker = CountUpTimer().apply { recordingTicker = CountUpTimer().apply {
tickListener = object : CountUpTimer.TickListener { tickListener = object : CountUpTimer.TickListener {