1
0
mirror of https://github.com/wulkanowy/wulkanowy.git synced 2024-11-22 20:36:24 -06:00

Add force sync feature in settings (#643)

This commit is contained in:
Dominik Korsa 2020-04-05 16:46:49 +02:00 committed by GitHub
parent 3612326628
commit 6a0ce3a58d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 128 additions and 10 deletions

View File

@ -154,6 +154,8 @@ dependencies {
implementation "androidx.work:work-rxjava2:$work_manager"
implementation "androidx.work:work-gcm:$work_manager"
implementation 'com.github.PaulinaSadowska:RxWorkManagerObservers:1.0.0'
implementation "androidx.room:room-runtime:$room"
implementation "androidx.room:room-rxjava2:$room"
implementation "androidx.room:room-ktx:$room"

View File

@ -5,18 +5,24 @@ import android.os.Build.VERSION_CODES.O
import androidx.core.app.NotificationManagerCompat
import androidx.work.BackoffPolicy.EXPONENTIAL
import androidx.work.Constraints
import androidx.work.Data
import androidx.work.ExistingPeriodicWorkPolicy.KEEP
import androidx.work.ExistingPeriodicWorkPolicy.REPLACE
import androidx.work.ExistingWorkPolicy
import androidx.work.NetworkType.CONNECTED
import androidx.work.NetworkType.UNMETERED
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkInfo
import androidx.work.WorkManager
import com.paulinasadowska.rxworkmanagerobservers.extensions.getWorkInfoByIdObservable
import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.db.SharedPrefProvider.Companion.APP_VERSION_CODE_KEY
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.services.sync.channels.Channel
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.isHolidays
import io.reactivex.Observable
import org.threeten.bp.LocalDate.now
import timber.log.Timber
import java.util.concurrent.TimeUnit.MINUTES
@ -42,13 +48,13 @@ class SyncManager @Inject constructor(
}
if (sharedPrefProvider.getLong(APP_VERSION_CODE_KEY, -1L) != appInfo.versionCode.toLong()) {
startSyncWorker(true)
startPeriodicSyncWorker(true)
sharedPrefProvider.putLong(APP_VERSION_CODE_KEY, appInfo.versionCode.toLong(), true)
}
Timber.i("SyncManager was initialized")
}
fun startSyncWorker(restart: Boolean = false) {
fun startPeriodicSyncWorker(restart: Boolean = false) {
if (preferencesRepository.isServiceEnabled && !now().isHolidays) {
workManager.enqueueUniquePeriodicWork(SyncWorker::class.java.simpleName, if (restart) REPLACE else KEEP,
PeriodicWorkRequestBuilder<SyncWorker>(preferencesRepository.servicesInterval, MINUTES)
@ -61,6 +67,19 @@ class SyncManager @Inject constructor(
}
}
fun startOneTimeSyncWorker(): Observable<WorkInfo> {
val work = OneTimeWorkRequestBuilder<SyncWorker>()
.setInputData(
Data.Builder()
.putBoolean("one_time", true)
.build()
)
.build()
workManager.enqueueUniqueWork("${SyncWorker::class.java.simpleName}_one_time", ExistingWorkPolicy.REPLACE, work)
return workManager.getWorkInfoByIdObservable(work.id)
}
fun stopSyncWorker() {
workManager.cancelUniqueWork(SyncWorker::class.java.simpleName)
}

View File

@ -1,10 +1,12 @@
package io.github.wulkanowy.services.sync
import android.content.Context
import android.os.Build.VERSION_CODES.LOLLIPOP
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationCompat.BigTextStyle
import androidx.core.app.NotificationCompat.PRIORITY_DEFAULT
import androidx.core.app.NotificationManagerCompat
import androidx.work.Data
import androidx.work.ListenableWorker
import androidx.work.RxWorker
import androidx.work.WorkerParameters
@ -17,6 +19,7 @@ import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.sdk.exception.FeatureDisabledException
import io.github.wulkanowy.services.sync.channels.DebugChannel
import io.github.wulkanowy.services.sync.works.Work
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.getCompatColor
import io.reactivex.Completable
import io.reactivex.Single
@ -30,7 +33,8 @@ class SyncWorker @AssistedInject constructor(
private val semesterRepository: SemesterRepository,
private val works: Set<@JvmSuppressWildcards Work>,
private val preferencesRepository: PreferencesRepository,
private val notificationManager: NotificationManagerCompat
private val notificationManager: NotificationManagerCompat,
private val appInfo: AppInfo
) : RxWorker(appContext, workerParameters) {
override fun createWork(): Single<Result> {
@ -52,8 +56,15 @@ class SyncWorker @AssistedInject constructor(
.toSingleDefault(Result.success())
.onErrorReturn {
Timber.e(it, "There was an error during synchronization")
if (it is FeatureDisabledException) Result.success()
else Result.retry()
when {
it is FeatureDisabledException -> Result.success()
inputData.getBoolean("one_time", false) -> {
Result.failure(Data.Builder()
.putString("error", it.toString())
.build())
}
else -> Result.retry()
}
}
.doOnSuccess {
if (preferencesRepository.isDebugNotificationEnable) notify(it)
@ -64,7 +75,7 @@ class SyncWorker @AssistedInject constructor(
private fun notify(result: Result) {
notificationManager.notify(Random.nextInt(Int.MAX_VALUE), NotificationCompat.Builder(applicationContext, DebugChannel.CHANNEL_ID)
.setContentTitle("Debug notification")
.setSmallIcon(R.drawable.ic_more_settings)
.setSmallIcon(R.drawable.ic_stat_push)
.setAutoCancel(true)
.setColor(applicationContext.getCompatColor(R.color.colorPrimary))
.setStyle(BigTextStyle().bigText("${SyncWorker::class.java.simpleName} result: $result"))

View File

@ -33,7 +33,7 @@ class MainPresenter @Inject constructor(
Timber.i("Main view was initialized with $startMenuIndex menu index and $startMenuMoreIndex more index")
}
syncManager.startSyncWorker()
syncManager.startPeriodicSyncWorker()
analytics.logEvent("app_open", "destination" to initMenu?.name)
}

View File

@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.modules.settings
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import com.yariksoffice.lingver.Lingver
@ -33,11 +34,24 @@ class SettingsFragment : PreferenceFragmentCompat(),
override val titleStringId get() = R.string.settings_title
override val syncSuccessString get() = getString(R.string.pref_services_message_sync_success)
override val syncFailedString get() = getString(R.string.pref_services_message_sync_failed)
override fun onAttach(context: Context) {
AndroidSupportInjection.inject(this)
super.onAttach(context)
}
override fun initView() {
findPreference<Preference>(getString(R.string.pref_key_services_force_sync))?.run {
onPreferenceClickListener = Preference.OnPreferenceClickListener {
presenter.onSyncNowClicked()
true
}
}
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
presenter.onAttachView(this)
@ -61,12 +75,19 @@ class SettingsFragment : PreferenceFragmentCompat(),
}
override fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean) {
findPreference<Preference>(serviceEnablesKey)?.apply {
findPreference<Preference>(serviceEnablesKey)?.run {
summary = if (isHolidays) getString(R.string.pref_services_suspended) else ""
isEnabled = !isHolidays
}
}
override fun setSyncInProgress(inProgress: Boolean) {
findPreference<Preference>(getString(R.string.pref_key_services_force_sync))?.run {
isEnabled = !inProgress
summary = if (inProgress) getString(R.string.pref_services_sync_in_progress) else ""
}
}
override fun showError(text: String, error: Throwable) {
(activity as? BaseActivity<*>)?.showError(text, error)
}
@ -87,6 +108,15 @@ class SettingsFragment : PreferenceFragmentCompat(),
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
}
override fun showForceSyncDialog() {
AlertDialog.Builder(requireContext())
.setTitle(R.string.pref_services_dialog_force_sync_title)
.setMessage(R.string.pref_services_dialog_force_sync_summary)
.setPositiveButton(android.R.string.ok) { _, _ -> presenter.onForceSyncDialogSubmit() }
.setNegativeButton(android.R.string.cancel) { _, _ -> }
.show()
}
override fun onResume() {
super.onResume()
preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.ui.modules.settings
import androidx.work.WorkInfo
import com.chuckerteam.chucker.api.ChuckerCollector
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.data.repositories.student.StudentRepository
@ -29,6 +30,7 @@ class SettingsPresenter @Inject constructor(
super.onAttachView(view)
Timber.i("Settings view was initialized")
view.setServicesSuspended(preferencesRepository.serviceEnableKey, now().isHolidays)
view.initView()
}
fun onSharedPreferenceChanged(key: String) {
@ -36,8 +38,8 @@ class SettingsPresenter @Inject constructor(
with(preferencesRepository) {
when (key) {
serviceEnableKey -> with(syncManager) { if (isServiceEnabled) startSyncWorker() else stopSyncWorker() }
servicesIntervalKey, servicesOnlyWifiKey -> syncManager.startSyncWorker(true)
serviceEnableKey -> with(syncManager) { if (isServiceEnabled) startPeriodicSyncWorker() else stopSyncWorker() }
servicesIntervalKey, servicesOnlyWifiKey -> syncManager.startPeriodicSyncWorker(true)
isDebugNotificationEnableKey -> chuckerCollector.showNotification = isDebugNotificationEnable
appThemeKey -> view?.recreateView()
appLanguageKey -> view?.run {
@ -49,4 +51,25 @@ class SettingsPresenter @Inject constructor(
}
analytics.logEvent("setting_changed", "name" to key)
}
fun onSyncNowClicked() {
view?.showForceSyncDialog()
}
fun onForceSyncDialogSubmit() {
view?.run {
Timber.i("Setting sync now started")
analytics.logEvent("sync_now_started")
disposable.add(syncManager.startOneTimeSyncWorker()
.doOnSubscribe { setSyncInProgress(true) }
.doFinally { setSyncInProgress(false) }
.subscribe({ workInfo ->
if (workInfo.state == WorkInfo.State.SUCCEEDED) showMessage(syncSuccessString)
else if (workInfo.state == WorkInfo.State.FAILED) showError(syncFailedString, Throwable(workInfo.outputData.getString("error")))
}, {
Timber.e("Sync now failed")
})
)
}
}
}

View File

@ -4,9 +4,19 @@ import io.github.wulkanowy.ui.base.BaseView
interface SettingsView : BaseView {
val syncSuccessString: String
val syncFailedString: String
fun initView()
fun recreateView()
fun updateLanguage(langCode: String)
fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean)
fun setSyncInProgress(inProgress: Boolean)
fun showForceSyncDialog()
}

View File

@ -375,6 +375,15 @@
<string name="pref_services_suspended">Zawieszona na wakacjach</string>
<string name="pref_services_interval">Interwał aktualizacji</string>
<string name="pref_services_wifi">Tylko WiFi</string>
<string name="pref_services_force_sync">Synchronizuj teraz</string>
<string name="pref_services_message_sync_success">Zsynchronizowano!</string>
<string name="pref_services_message_sync_failed">Synchronizacja nie powiodła się</string>
<string name="pref_services_sync_in_progress">Synchronizacja w trakcie</string>
<string name="pref_services_dialog_force_sync_title">Synchronizacja</string>
<string name="pref_services_dialog_force_sync_summary">
Ręczna synchronizacja nie odświeża widoków w aplikacji.
\nAby zobaczyć zsynchronizowane informacje uruchom ponownie aplikację po zsynchronizowaniu.
</string>
<string name="pref_other_header">Inne</string>
<string name="pref_other_grade_modifier_plus">Wartość plusa</string>

View File

@ -11,6 +11,7 @@
<string name="pref_key_services_enable">services_enable</string>
<string name="pref_key_services_interval">services_interval</string>
<string name="pref_key_services_wifi_only">services_disable_wifi_only</string>
<string name="pref_key_services_force_sync">services_force_sync</string>
<string name="pref_key_notifications_enable">notifications_enable</string>
<string name="pref_key_notification_debug">notification_debug</string>
<string name="pref_key_grade_modifier_plus">grade_modifier_plus</string>

View File

@ -360,6 +360,15 @@
<string name="pref_services_suspended">Suspended on holidays</string>
<string name="pref_services_interval">Updates interval</string>
<string name="pref_services_wifi">Wi-Fi only</string>
<string name="pref_services_force_sync">Sync now</string>
<string name="pref_services_message_sync_success">Synced!</string>
<string name="pref_services_message_sync_failed">Sync failed</string>
<string name="pref_services_sync_in_progress">Sync in progress</string>
<string name="pref_services_dialog_force_sync_title">Synchronization</string>
<string name="pref_services_dialog_force_sync_summary">
Manual sync doesn\'t refresh app views.
\nTo see the synced data relaunch the app after syncing.
</string>
<string name="pref_other_header">Other</string>
<string name="pref_other_grade_modifier_plus">Value of the plus</string>

View File

@ -77,6 +77,10 @@
app:iconSpaceReserved="false"
app:key="@string/pref_key_services_wifi_only"
app:title="@string/pref_services_wifi" />
<Preference
app:iconSpaceReserved="false"
app:title="@string/pref_services_force_sync"
app:key="@string/pref_key_services_force_sync" />
</PreferenceCategory>
<PreferenceCategory
app:iconSpaceReserved="false"