@@ -2,32 +2,32 @@ package com.lcl.lclmeasurementtool
2
2
3
3
import android.content.Context
4
4
import android.util.Log
5
+ import androidx.compose.runtime.MutableState
6
+ import androidx.compose.ui.graphics.Color
5
7
import androidx.lifecycle.ViewModel
6
8
import androidx.lifecycle.viewModelScope
7
9
import com.google.protobuf.ByteString
8
10
import com.jsoniter.JsonIterator
9
11
import com.jsoniter.spi.JsonException
10
12
import com.kongzue.dialogx.dialogs.TipDialog
11
- import com.kongzue.dialogx.dialogs.WaitDialog
12
13
import com.lcl.lclmeasurementtool.Utils.ECDSA
13
14
import com.lcl.lclmeasurementtool.Utils.Hex
14
15
import com.lcl.lclmeasurementtool.Utils.SecurityUtils
15
- import com.lcl.lclmeasurementtool.features.iperf.runIperf
16
+ import com.lcl.lclmeasurementtool.constants.NetworkConstants
17
+ import com.lcl.lclmeasurementtool.features.iperf.IperfRunner
18
+ import com.lcl.lclmeasurementtool.features.iperf.IperfStatus
19
+ import com.lcl.lclmeasurementtool.features.ping.Ping
20
+ import com.lcl.lclmeasurementtool.features.ping.PingError
21
+ import com.lcl.lclmeasurementtool.features.ping.PingErrorCase
22
+ import com.lcl.lclmeasurementtool.features.ping.PingResult
16
23
import com.lcl.lclmeasurementtool.model.datamodel.QRCodeKeysModel
17
24
import com.lcl.lclmeasurementtool.model.datamodel.RegistrationModel
18
25
import com.lcl.lclmeasurementtool.model.datamodel.UserData
19
26
import com.lcl.lclmeasurementtool.model.repository.NetworkApiRepository
20
27
import com.lcl.lclmeasurementtool.model.repository.UserDataRepository
21
28
import dagger.hilt.android.lifecycle.HiltViewModel
22
- import dagger.hilt.android.qualifiers.ApplicationContext
23
- import kotlinx.coroutines.Dispatchers
24
- import kotlinx.coroutines.async
25
- import kotlinx.coroutines.flow.SharingStarted
26
- import kotlinx.coroutines.flow.StateFlow
27
- import kotlinx.coroutines.flow.map
28
- import kotlinx.coroutines.flow.stateIn
29
- import kotlinx.coroutines.launch
30
- import kotlinx.coroutines.withContext
29
+ import kotlinx.coroutines.*
30
+ import kotlinx.coroutines.flow.*
31
31
import java.io.ByteArrayOutputStream
32
32
import java.security.SecureRandom
33
33
import java.security.interfaces.ECPrivateKey
@@ -37,8 +37,14 @@ import javax.inject.Inject
37
37
@HiltViewModel
38
38
class MainActivityViewModel @Inject constructor(
39
39
private val userDataRepository : UserDataRepository ,
40
- private val networkApi : NetworkApiRepository ,
40
+ private val networkApi : NetworkApiRepository
41
41
) : ViewModel() {
42
+
43
+ companion object {
44
+ const val TAG = " MainActivityViewModel"
45
+ }
46
+
47
+ // UI
42
48
val uiState: StateFlow <MainActivityUiState > = userDataRepository.userData.map {
43
49
if (it.loggedIn) MainActivityUiState .Success (it) else MainActivityUiState .Login
44
50
}.stateIn(
@@ -47,6 +53,7 @@ class MainActivityViewModel @Inject constructor(
47
53
started = SharingStarted .WhileSubscribed (5_000 )
48
54
)
49
55
56
+ // Authentication
50
57
fun login (hPKR : ByteString , skT : ByteString ) = viewModelScope.launch {
51
58
userDataRepository.setKeys(hPKR, skT)
52
59
}
@@ -71,7 +78,7 @@ class MainActivityViewModel @Inject constructor(
71
78
)
72
79
} catch (e: JsonException ) {
73
80
// TipDialog.show("The QR Code is invalid. Please rescan the code or contact the administrator at [email protected] .", WaitDialog.TYPE.ERROR)
74
- Log .d(
" MainViewModel " ,
" The QR Code is invalid. Please rescan the code or contact the administrator at [email protected] ." )
81
+ Log .d(
TAG ,
" The QR Code is invalid. Please rescan the code or contact the administrator at [email protected] ." )
75
82
// val reasons =
76
83
// AnalyticsUtils.formatProperties(e.message, Arrays.toString(e.stackTrace))
77
84
// Analytics.trackEvent(AnalyticsUtils.QR_CODE_PARSING_FAILED, reasons)
@@ -179,9 +186,82 @@ class MainActivityViewModel @Inject constructor(
179
186
180
187
return LoginStatus .ScanSuccess (sigmaTHex, pkAHex, skTHex)
181
188
}
189
+
190
+
191
+ // Network Testing
192
+ var uploadResult: ConnectivityTestResult .Result ? = null
193
+ var downloadResult: ConnectivityTestResult .Result ? = null
194
+ private var _pingResult = MutableStateFlow (PingResultState ())
195
+ val pingResult: StateFlow <PingResultState > = _pingResult .asStateFlow()
196
+ private val _isTestActive = MutableStateFlow (false )
197
+ val isTestActive = _isTestActive .asStateFlow()
198
+
199
+ fun doPing () = viewModelScope.launch {
200
+ try {
201
+ Ping .cancellableStart(address = NetworkConstants .PING_TEST_ADDRESS , timeout = 1000 )
202
+ .onStart {
203
+ Log .d(TAG , " isActive = true" )
204
+ _isTestActive .value = true
205
+ }
206
+ .onCompletion {
207
+ Log .d(TAG , " isActive = false" )
208
+ _pingResult .value = PingResultState .Error (PingError (PingErrorCase .CANCELLED , it?.message))
209
+ _isTestActive .value = false
210
+ }
211
+ .collect {
212
+ ensureActive()
213
+ Log .d(TAG , " Test is still active" )
214
+ when (it.error.code) {
215
+ PingErrorCase .OK -> _pingResult .value = PingResultState .Success (it)
216
+ else -> _pingResult .value = PingResultState .Error (it.error)
217
+ }
218
+ }
219
+ } catch (e: IllegalArgumentException ) {
220
+ _pingResult .value = PingResultState .Error (PingError (PingErrorCase .OTHER , e.message))
221
+ Log .e(TAG , " Ping Config error" )
222
+ }
223
+ }
224
+
225
+ fun getUploadResult (context : Context ) = viewModelScope.launch {
226
+ IperfRunner ().getTestResult(IperfRunner .iperfUploadConfig, context.cacheDir).collect { result ->
227
+ uploadResult = when (result.status) {
228
+ IperfStatus .RUNNING -> {
229
+ ConnectivityTestResult .Result (result.bandWidth, Color .LightGray )
230
+ }
231
+ IperfStatus .FINISHED -> {
232
+ ConnectivityTestResult .Result (result.bandWidth, Color .Black )
233
+ }
234
+ IperfStatus .ERROR -> TODO ()
235
+ }
236
+ }
237
+ }
238
+
239
+
240
+ fun getDownloadResult (context : Context ) = viewModelScope.launch {
241
+ IperfRunner ().getTestResult(IperfRunner .iperfDownloadConfig, context.cacheDir).collect { result ->
242
+ downloadResult = when (result.status) {
243
+ IperfStatus .RUNNING -> {
244
+ ConnectivityTestResult .Result (result.bandWidth, Color .LightGray )
245
+ }
246
+ IperfStatus .FINISHED -> {
247
+ ConnectivityTestResult .Result (result.bandWidth, Color .Black )
248
+ }
249
+ IperfStatus .ERROR -> TODO ()
250
+ }
251
+ }
252
+ }
182
253
}
183
254
184
255
sealed interface MainActivityUiState {
185
256
object Login : MainActivityUiState
186
257
data class Success (val userData : UserData ) : MainActivityUiState
258
+ }
259
+
260
+ sealed interface ConnectivityTestResult {
261
+ data class Result (val result : String , val color : Color ): ConnectivityTestResult
262
+ }
263
+
264
+ open class PingResultState {
265
+ data class Success (val result : PingResult ): PingResultState()
266
+ data class Error (val error : PingError ): PingResultState()
187
267
}
0 commit comments