Skip to content

Commit 75361d0

Browse files
committed
Merge branch 'release/1.1.9'
2 parents fd8aab7 + 9bd0273 commit 75361d0

File tree

18 files changed

+359
-94
lines changed

18 files changed

+359
-94
lines changed

commons/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
apply plugin: 'com.android.library'
22
apply plugin: 'kotlin-android'
33

4-
version = "0.8.2"
4+
version = "0.8.3"
55

66
android {
77
compileSdkVersion 29

commons/src/main/java/fr/geonature/commons/data/AppSync.kt

+14
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ import java.util.Date
1616
data class AppSync(
1717
var packageId: String,
1818
var lastSync: Date? = null,
19+
var lastSyncEssential: Date? = null,
1920
var inputsToSynchronize: Int = 0
2021
) : Parcelable {
2122

2223
private constructor(source: Parcel) : this(
2324
source.readString()!!,
2425
source.readSerializable() as Date,
26+
source.readSerializable() as Date,
2527
source.readInt()
2628
)
2729

@@ -36,6 +38,7 @@ data class AppSync(
3638
dest?.also {
3739
it.writeString(packageId)
3840
it.writeSerializable(lastSync)
41+
it.writeSerializable(lastSyncEssential)
3942
it.writeInt(inputsToSynchronize)
4043
}
4144
}
@@ -47,6 +50,7 @@ data class AppSync(
4750
const val TABLE_NAME = "app_sync"
4851
const val COLUMN_ID = "package_id"
4952
const val COLUMN_LAST_SYNC = "last_sync"
53+
const val COLUMN_LAST_SYNC_ESSENTIAL = "last_sync_essential"
5054
const val COLUMN_INPUTS_TO_SYNCHRONIZE = "inputs_to_synchronize"
5155

5256
/**
@@ -62,6 +66,10 @@ data class AppSync(
6266
COLUMN_LAST_SYNC,
6367
tableAlias
6468
),
69+
column(
70+
COLUMN_LAST_SYNC_ESSENTIAL,
71+
tableAlias
72+
),
6573
column(
6674
COLUMN_INPUTS_TO_SYNCHRONIZE,
6775
tableAlias
@@ -113,6 +121,12 @@ data class AppSync(
113121
tableAlias
114122
)
115123
),
124+
cursor.get(
125+
getColumnAlias(
126+
COLUMN_LAST_SYNC_ESSENTIAL,
127+
tableAlias
128+
)
129+
),
116130
requireNotNull(
117131
cursor.get(
118132
getColumnAlias(

commons/src/test/java/fr/geonature/commons/data/AppSyncTest.kt

+33-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import org.mockito.Mockito.`when`
1212
import org.mockito.Mockito.mock
1313
import org.robolectric.RobolectricTestRunner
1414
import java.time.Instant
15+
import java.time.temporal.ChronoUnit
1516
import java.util.Date
1617

1718
/**
@@ -29,11 +30,27 @@ class AppSyncTest {
2930
assertEquals(
3031
AppSync(
3132
"fr.geonature.sync",
33+
Date.from(
34+
now
35+
.toInstant()
36+
.minus(
37+
1,
38+
ChronoUnit.HOURS
39+
)
40+
),
3241
now,
3342
3
3443
),
3544
AppSync(
3645
"fr.geonature.sync",
46+
Date.from(
47+
now
48+
.toInstant()
49+
.minus(
50+
1,
51+
ChronoUnit.HOURS
52+
)
53+
),
3754
now,
3855
3
3956
)
@@ -51,8 +68,9 @@ class AppSyncTest {
5168
}
5269

5370
`when`(cursor.getString(0)).thenReturn("fr.geonature.sync")
54-
`when`(cursor.getLong(1)).thenReturn(1477642500000)
55-
`when`(cursor.getInt(2)).thenReturn(3)
71+
`when`(cursor.getLong(1)).thenReturn(1477638900000)
72+
`when`(cursor.getLong(2)).thenReturn(1477642500000)
73+
`when`(cursor.getInt(3)).thenReturn(3)
5674

5775
// when getting AppSync instance from Cursor
5876
val appSync = AppSync.fromCursor(cursor)
@@ -62,6 +80,7 @@ class AppSyncTest {
6280
assertEquals(
6381
AppSync(
6482
"fr.geonature.sync",
83+
Date.from(Instant.parse("2016-10-28T07:15:00Z")),
6584
Date.from(Instant.parse("2016-10-28T08:15:00Z")),
6685
3
6786
),
@@ -74,6 +93,14 @@ class AppSyncTest {
7493
// given AppSync
7594
val appSync = AppSync(
7695
"fr.geonature.sync",
96+
Date.from(
97+
Instant
98+
.now()
99+
.minus(
100+
1,
101+
ChronoUnit.HOURS
102+
)
103+
),
77104
Date.from(Instant.now()),
78105
3
79106
)
@@ -107,6 +134,10 @@ class AppSyncTest {
107134
"${AppSync.TABLE_NAME}.\"${AppSync.COLUMN_LAST_SYNC}\"",
108135
"${AppSync.TABLE_NAME}_${AppSync.COLUMN_LAST_SYNC}"
109136
),
137+
Pair(
138+
"${AppSync.TABLE_NAME}.\"${AppSync.COLUMN_LAST_SYNC_ESSENTIAL}\"",
139+
"${AppSync.TABLE_NAME}_${AppSync.COLUMN_LAST_SYNC_ESSENTIAL}"
140+
),
110141
Pair(
111142
"${AppSync.TABLE_NAME}.\"${AppSync.COLUMN_INPUTS_TO_SYNCHRONIZE}\"",
112143
"${AppSync.TABLE_NAME}_${AppSync.COLUMN_INPUTS_TO_SYNCHRONIZE}"

commons/version.properties

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
#Sun Mar 28 16:42:31 CEST 2021
2-
VERSION_CODE=2820
1+
#Sun May 23 16:23:47 CEST 2021
2+
VERSION_CODE=2855

sync/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ apply plugin: 'com.android.application'
22
apply plugin: 'kotlin-android'
33
apply plugin: "kotlin-kapt"
44

5-
version = "1.1.8"
5+
version = "1.1.9"
66

77
android {
88
compileSdkVersion 29

sync/src/main/java/fr/geonature/sync/MainApplication.kt

+19
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import androidx.work.PeriodicWorkRequestBuilder
1010
import androidx.work.WorkManager
1111
import fr.geonature.mountpoint.util.MountPointUtils.getExternalStorage
1212
import fr.geonature.mountpoint.util.MountPointUtils.getInternalStorage
13+
import fr.geonature.sync.sync.worker.CheckAuthLoginWorker
1314
import fr.geonature.sync.sync.worker.CheckInputsToSynchronizeWorker
1415
import java.util.concurrent.TimeUnit
1516

@@ -36,9 +37,27 @@ class MainApplication : Application() {
3637
configureCheckInputsToSynchronizeChannel(notificationManager)
3738
configureSynchronizeDataChannel(notificationManager)
3839

40+
checkAuthLogin()
3941
checkInputsToSynchronize()
4042
}
4143

44+
private fun checkAuthLogin() {
45+
val workManager: WorkManager = WorkManager.getInstance(this)
46+
47+
val request = PeriodicWorkRequestBuilder<CheckAuthLoginWorker>(
48+
1,
49+
TimeUnit.HOURS
50+
)
51+
.addTag(CheckAuthLoginWorker.CHECK_AUTH_LOGIN_WORKER_TAG)
52+
.build()
53+
54+
workManager.enqueueUniquePeriodicWork(
55+
CheckAuthLoginWorker.CHECK_AUTH_LOGIN_WORKER,
56+
ExistingPeriodicWorkPolicy.REPLACE,
57+
request
58+
)
59+
}
60+
4261
private fun checkInputsToSynchronize() {
4362
val workManager: WorkManager = WorkManager.getInstance(this)
4463

sync/src/main/java/fr/geonature/sync/auth/AuthLoginViewModel.kt

+21-16
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ class AuthLoginViewModel(application: Application) : AndroidViewModel(applicatio
3030

3131
private val authManager: AuthManager = AuthManager.getInstance(application)
3232
private val geoNatureAPIClient: GeoNatureAPIClient? = GeoNatureAPIClient.instance(application)
33-
private val connectivityManager =
34-
application.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
33+
private val connectivityManager = application.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
3534

3635
private val _loginFormState = MutableLiveData<LoginFormState>()
3736
val loginFormState: LiveData<LoginFormState> = _loginFormState
@@ -52,6 +51,16 @@ class AuthLoginViewModel(application: Application) : AndroidViewModel(applicatio
5251
}
5352
}
5453

54+
fun checkAuthLogin(): LiveData<AuthLogin?> {
55+
val authLoginLiveData = MutableLiveData<AuthLogin?>()
56+
57+
viewModelScope.launch {
58+
authLoginLiveData.postValue(authManager.getAuthLogin())
59+
}
60+
61+
return authLoginLiveData
62+
}
63+
5564
fun login(
5665
username: String,
5766
password: String,
@@ -95,13 +104,13 @@ class AuthLoginViewModel(application: Application) : AndroidViewModel(applicatio
95104
return@launch
96105
}
97106

98-
authManager.setAuthLogin(authLogin)
107+
authManager
108+
.setAuthLogin(authLogin)
99109
.also {
100110
_loginResult.value = LoginResult(success = authLogin)
101111
}
102112
} catch (e: Exception) {
103-
_loginResult.value =
104-
LoginResult(error = if (connectivityManager.allNetworks.isEmpty()) R.string.snackbar_network_lost else R.string.login_failed)
113+
_loginResult.value = LoginResult(error = if (connectivityManager.allNetworks.isEmpty()) R.string.snackbar_network_lost else R.string.login_failed)
105114
}
106115
}
107116
}
@@ -111,14 +120,12 @@ class AuthLoginViewModel(application: Application) : AndroidViewModel(applicatio
111120
password: String
112121
) {
113122
if (!isUserNameValid(username)) {
114-
_loginFormState.value =
115-
LoginFormState(usernameError = R.string.login_form_username_invalid)
123+
_loginFormState.value = LoginFormState(usernameError = R.string.login_form_username_invalid)
116124
return
117125
}
118126

119127
if (!isPasswordValid(password)) {
120-
_loginFormState.value =
121-
LoginFormState(passwordError = R.string.login_form_password_invalid)
128+
_loginFormState.value = LoginFormState(passwordError = R.string.login_form_password_invalid)
122129
return
123130
}
124131

@@ -153,7 +160,8 @@ class AuthLoginViewModel(application: Application) : AndroidViewModel(applicatio
153160
val type = object : TypeToken<AuthLoginError>() {}.type
154161

155162
return Gson().fromJson(
156-
response.errorBody()!!
163+
response
164+
.errorBody()!!
157165
.charStream(),
158166
type
159167
)
@@ -165,10 +173,8 @@ class AuthLoginViewModel(application: Application) : AndroidViewModel(applicatio
165173
* @author [S. Grimault](mailto:[email protected])
166174
*/
167175
data class LoginFormState(
168-
@StringRes
169-
val usernameError: Int? = null,
170-
@StringRes
171-
val passwordError: Int? = null,
176+
@StringRes val usernameError: Int? = null,
177+
@StringRes val passwordError: Int? = null,
172178
val isValid: Boolean = false
173179
)
174180

@@ -179,8 +185,7 @@ class AuthLoginViewModel(application: Application) : AndroidViewModel(applicatio
179185
*/
180186
data class LoginResult(
181187
val success: AuthLogin? = null,
182-
@StringRes
183-
val error: Int? = null
188+
@StringRes val error: Int? = null
184189
) {
185190

186191
fun hasError(): Boolean {

sync/src/main/java/fr/geonature/sync/data/dao/AppSyncDao.kt

+36-15
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,20 @@ import java.util.Date
1919
*/
2020
class AppSyncDao(private val context: Context) {
2121

22-
private val sharedPreferences: SharedPreferences =
23-
PreferenceManager.getDefaultSharedPreferences(context)
22+
private val sharedPreferences: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
2423

2524
fun findByPackageId(packageId: String?): Cursor {
26-
val cursor = MatrixCursor(AppSync.defaultProjection().map { it.second }.toTypedArray())
25+
val cursor = MatrixCursor(AppSync
26+
.defaultProjection()
27+
.map { it.second }
28+
.toTypedArray())
2729

2830
if (packageId.isNullOrBlank()) return cursor
2931

3032
val values = arrayOf(
3133
packageId,
3234
dateToTimestamp(getLastSynchronizedDate()),
35+
dateToTimestamp(getLastEssentialSynchronizedDate()),
3336
countInputsToSynchronize(packageId)
3437
)
3538

@@ -38,35 +41,53 @@ class AppSyncDao(private val context: Context) {
3841
return cursor
3942
}
4043

41-
fun updateLastSynchronizedDate(): Date {
44+
fun updateLastSynchronizedDate(complete: Boolean = true): Date {
4245
val now = Date()
4346

44-
this.sharedPreferences.edit()
47+
this.sharedPreferences
48+
.edit()
4549
.putLong(
46-
"sync.${AppSync.COLUMN_LAST_SYNC}",
47-
dateToTimestamp(now) ?: -1L
50+
buildLastSynchronizedDatePreferenceKey(complete),
51+
dateToTimestamp(now)
52+
?: -1L
4853
)
4954
.apply()
5055

5156
return now
5257
}
5358

5459
fun getLastSynchronizedDate(): Date? {
55-
return this.sharedPreferences.getLong(
56-
"sync.${AppSync.COLUMN_LAST_SYNC}",
57-
-1L
58-
)
60+
return this.sharedPreferences
61+
.getLong(
62+
buildLastSynchronizedDatePreferenceKey(),
63+
-1L
64+
)
65+
.takeUnless { it == -1L }
66+
.run { fromTimestamp(this) }
67+
}
68+
69+
fun getLastEssentialSynchronizedDate(): Date? {
70+
return this.sharedPreferences
71+
.getLong(
72+
buildLastSynchronizedDatePreferenceKey(false),
73+
-1L
74+
)
5975
.takeUnless { it == -1L }
6076
.run { fromTimestamp(this) }
6177
}
6278

6379
private fun countInputsToSynchronize(packageId: String): Number {
64-
return FileUtils.getInputsFolder(
65-
context,
66-
packageId
67-
)
80+
return FileUtils
81+
.getInputsFolder(
82+
context,
83+
packageId
84+
)
6885
.walkTopDown()
6986
.filter { it.isFile && it.extension == "json" && it.canRead() }
7087
.count()
7188
}
89+
90+
private fun buildLastSynchronizedDatePreferenceKey(complete: Boolean = true): String {
91+
return "sync.${if (complete) AppSync.COLUMN_LAST_SYNC else AppSync.COLUMN_LAST_SYNC_ESSENTIAL}"
92+
}
7293
}

0 commit comments

Comments
 (0)