update last sync time

This commit is contained in:
moon 2026-06-16 23:22:59 +06:30
parent a286a8258c
commit b9be038d68
5 changed files with 58 additions and 7 deletions

View File

@ -61,6 +61,7 @@ import androidx.compose.material3.rememberDrawerState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
@ -441,7 +442,8 @@ fun DashboardScreen2(
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
SummaryCard( SummaryCard(
onClickLastSync onClickLastSync = onClickLastSync,
lastSyncTime = dashboardUiState.lastSyncTime
) )
} }
//pager section //pager section
@ -511,10 +513,29 @@ private fun AdvertisingArea() {
} }
} }
private fun formatRelativeTime(timestamp: Long?, now: Long): String {
if (timestamp == null) return "Never"
val diff = now - timestamp
return when {
diff < 60_000L -> "Just now"
diff < 3_600_000L -> "${diff / 60_000L} mins ago"
diff < 86_400_000L -> "${diff / 3_600_000L} hours ago"
else -> "${diff / 86_400_000L} days ago"
}
}
@Composable @Composable
private fun SummaryCard( private fun SummaryCard(
onClickLastSync: () -> Unit onClickLastSync: () -> Unit,
lastSyncTime: Long?
) { ) {
var now by remember { mutableLongStateOf(System.currentTimeMillis()) }
LaunchedEffect(Unit) {
while (true) {
delay(30_000)
now = System.currentTimeMillis()
}
}
var isRotating by remember { mutableStateOf(false) } var isRotating by remember { mutableStateOf(false) }
val rotation by animateFloatAsState( val rotation by animateFloatAsState(
targetValue = if (isRotating) 360f else 0f, targetValue = if (isRotating) 360f else 0f,
@ -596,7 +617,7 @@ private fun SummaryCard(
Spacer(Modifier.height(6.dp)) Spacer(Modifier.height(6.dp))
Text( Text(
text = "5 mins ago", text = formatRelativeTime(lastSyncTime, now),
fontSize = 18.sp, fontSize = 18.sp,
color = Color.LegacyRed, color = Color.LegacyRed,
fontWeight = FontWeight.SemiBold fontWeight = FontWeight.SemiBold

View File

@ -11,5 +11,6 @@ data class TrnxRecord(
) )
data class DashboardUiState( data class DashboardUiState(
val recentTransactions: List<TrnxRecord> = emptyList() val recentTransactions: List<TrnxRecord> = emptyList(),
val lastSyncTime: Long? = null
) )

View File

@ -1,11 +1,13 @@
package com.mob.utsmyanmar.ui.dashboard package com.mob.utsmyanmar.ui.dashboard
import android.content.Context
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asFlow import androidx.lifecycle.asFlow
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.utsmyanmar.baselib.repo.Repository import com.utsmyanmar.baselib.repo.Repository
import com.utsmyanmar.paylibs.model.PayDetail import com.utsmyanmar.paylibs.model.PayDetail
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
@ -15,7 +17,8 @@ import javax.inject.Inject
@HiltViewModel @HiltViewModel
class DashboardViewModel @Inject constructor( class DashboardViewModel @Inject constructor(
private val repository: Repository private val repository: Repository,
@ApplicationContext private val context: Context
) : ViewModel() { ) : ViewModel() {
private val _uiState = MutableStateFlow(DashboardUiState()) private val _uiState = MutableStateFlow(DashboardUiState())
@ -31,6 +34,14 @@ class DashboardViewModel @Inject constructor(
} }
} }
} }
refreshLastSyncTime()
}
fun refreshLastSyncTime() {
val time = context.getSharedPreferences("mobpos_prefs", Context.MODE_PRIVATE)
.getLong("last_sync_time", 0L)
.takeIf { it > 0L }
_uiState.update { it.copy(lastSyncTime = time) }
} }
} }

View File

@ -110,6 +110,11 @@ fun AppNavGraph(
val deviceInfo by deviceInfoViewModel.uiState.collectAsStateWithLifecycle() val deviceInfo by deviceInfoViewModel.uiState.collectAsStateWithLifecycle()
val tmsSetupViewModel: TmsSetupViewModel = hiltViewModel() val tmsSetupViewModel: TmsSetupViewModel = hiltViewModel()
androidx.compose.runtime.LaunchedEffect(Unit) { deviceInfoViewModel.loadDeviceInfo() } androidx.compose.runtime.LaunchedEffect(Unit) { deviceInfoViewModel.loadDeviceInfo() }
androidx.compose.runtime.LaunchedEffect(tmsSetupViewModel) {
tmsSetupViewModel.onSyncCompleted.collect {
dashboardViewModel.refreshLastSyncTime()
}
}
DashboardScreen2( DashboardScreen2(
dashboardUiState = dashboardUiState, dashboardUiState = dashboardUiState,
deviceInfo = deviceInfo, deviceInfo = deviceInfo,

View File

@ -1,6 +1,7 @@
package com.mob.utsmyanmar.ui.tms_setup package com.mob.utsmyanmar.ui.tms_setup
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.mob.utsmyanmar.model.sirius.SiriusResponse import com.mob.utsmyanmar.model.sirius.SiriusResponse
@ -14,6 +15,7 @@ import com.utsmyanmar.baselib.network.model.sirius.SiriusRequest
import com.utsmyanmar.baselib.repo.Repository import com.utsmyanmar.baselib.repo.Repository
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
@ -42,7 +44,8 @@ data class TmsSetupUiState(
@HiltViewModel @HiltViewModel
class TmsSetupViewModel @Inject constructor( class TmsSetupViewModel @Inject constructor(
private val repository: Repository, private val repository: Repository,
private val emvParamOperation: EmvParamOperation private val emvParamOperation: EmvParamOperation,
@ApplicationContext private val context: Context
) : ViewModel() { ) : ViewModel() {
private val _uiState = MutableStateFlow(TmsSetupUiState()) private val _uiState = MutableStateFlow(TmsSetupUiState())
@ -54,6 +57,9 @@ class TmsSetupViewModel @Inject constructor(
private val _navigateToDisable = MutableSharedFlow<String>() private val _navigateToDisable = MutableSharedFlow<String>()
val navigateToDisable: SharedFlow<String> = _navigateToDisable.asSharedFlow() val navigateToDisable: SharedFlow<String> = _navigateToDisable.asSharedFlow()
private val _onSyncCompleted = MutableSharedFlow<Unit>()
val onSyncCompleted: SharedFlow<Unit> = _onSyncCompleted.asSharedFlow()
private val disposables = CompositeDisposable() private val disposables = CompositeDisposable()
private val tmsSetups = TMSSetupsImpl() private val tmsSetups = TMSSetupsImpl()
@ -132,8 +138,15 @@ class TmsSetupViewModel @Inject constructor(
val validity = TMSUtil.getInstance().checkParams() val validity = TMSUtil.getInstance().checkParams()
if (validity.status == ValidityStatus.SUCCESS) { if (validity.status == ValidityStatus.SUCCESS) {
context.getSharedPreferences("mobpos_prefs", Context.MODE_PRIVATE)
.edit()
.putLong("last_sync_time", System.currentTimeMillis())
.apply()
_uiState.update { it.copy(isLoading = false, statusText = "Ready.") } _uiState.update { it.copy(isLoading = false, statusText = "Ready.") }
viewModelScope.launch { _navigateToDashboard.emit(Unit) } viewModelScope.launch {
_onSyncCompleted.emit(Unit)
_navigateToDashboard.emit(Unit)
}
} else { } else {
_uiState.update { _uiState.update {
it.copy( it.copy(