diff --git a/app/src/main/java/org/dhis2/usescases/settings/SyncManagerFragment.java b/app/src/main/java/org/dhis2/usescases/settings/SyncManagerFragment.java index 131ba3fe59d..9070907938b 100644 --- a/app/src/main/java/org/dhis2/usescases/settings/SyncManagerFragment.java +++ b/app/src/main/java/org/dhis2/usescases/settings/SyncManagerFragment.java @@ -35,6 +35,7 @@ import android.view.inputmethod.EditorInfo; import android.widget.AdapterView; import android.widget.ArrayAdapter; +import android.widget.Toast; import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; @@ -66,6 +67,7 @@ import org.dhis2.usescases.general.FragmentGlobalAbstract; import org.dhis2.usescases.settings.models.DataSettingsViewModel; import org.dhis2.usescases.settings.models.ErrorViewModel; +import org.dhis2.usescases.settings.models.ExportDbModel; import org.dhis2.usescases.settings.models.MetadataSettingsViewModel; import org.dhis2.usescases.settings.models.ReservedValueSettingsViewModel; import org.dhis2.usescases.settings.models.SMSSettingsViewModel; @@ -138,32 +140,62 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, binding.smsSettings.setVisibility(ContextExtensionsKt.showSMS(context) ? View.VISIBLE : View.GONE); binding.setVersionName(BuildConfig.VERSION_NAME); FormFileProvider.INSTANCE.init(requireContext()); + presenter.getExportedDb().observe(getViewLifecycleOwner(), fileData -> { - new FileHandler().copyAndOpen(fileData.getFile(), fileLiveData -> { - fileLiveData.observe(getViewLifecycleOwner(), file -> { - Uri contentUri = FileProvider.getUriForFile(requireContext(), - FormFileProvider.fileProviderAuthority, - fileData.getFile()); - Intent intentShare = new Intent(Intent.ACTION_SEND) - .setDataAndType(contentUri, requireContext().getContentResolver().getType(contentUri)) - .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - .putExtra(Intent.EXTRA_STREAM, contentUri); - Intent chooser = Intent.createChooser(intentShare, getString(R.string.open_with)); - try { - startActivity(chooser); - } catch (Exception e) { - Timber.e(e); - } - }); - return null; + if (fileData.getShare()) { + shareDB(fileData); + } else { + downloadDB(fileData); + } + + }); + + ExportOptionKt.setExportOption( + binding.exportShare, + () -> { + presenter.onExportAndDownloadDB(); + return null; + }, + () -> { + presenter.onExportAndShareDB(); + return null; + }, + ()-> presenter.getExporting() + ); + return binding.getRoot(); + } + + private void shareDB(ExportDbModel fileData) { + new FileHandler().copyAndOpen(fileData.getFile(), fileLiveData -> { + fileLiveData.observe(getViewLifecycleOwner(), file -> { + Uri contentUri = FileProvider.getUriForFile(requireContext(), + FormFileProvider.fileProviderAuthority, + fileData.getFile()); + Intent intentShare = new Intent(Intent.ACTION_SEND) + .setDataAndType(contentUri, requireContext().getContentResolver().getType(contentUri)) + .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + .putExtra(Intent.EXTRA_STREAM, contentUri); + Intent chooser = Intent.createChooser(intentShare, getString(R.string.open_with)); + try { + startActivity(chooser); + } catch (Exception e) { + Timber.e(e); + }finally { + presenter.onExportEnd(); + } }); + return null; }); + } - ExportOptionKt.setExportOption(binding.exportShare, () -> { - presenter.onExportAndShareDB(); + private void downloadDB(ExportDbModel fileData) { + new FileHandler().copyAndOpen(fileData.getFile(), fileLiveData -> { + fileLiveData.observe(getViewLifecycleOwner(), file -> { + Toast.makeText(requireContext(), R.string.downloaded_confirm, Toast.LENGTH_SHORT).show(); + presenter.onExportEnd(); + }); return null; }); - return binding.getRoot(); } @Override diff --git a/app/src/main/java/org/dhis2/usescases/settings/SyncManagerPresenter.kt b/app/src/main/java/org/dhis2/usescases/settings/SyncManagerPresenter.kt index 55ead0823a2..74e6f5876e0 100644 --- a/app/src/main/java/org/dhis2/usescases/settings/SyncManagerPresenter.kt +++ b/app/src/main/java/org/dhis2/usescases/settings/SyncManagerPresenter.kt @@ -90,6 +90,9 @@ class SyncManagerPresenter internal constructor( private val _exportedDb = MutableLiveData() val exportedDb: LiveData = _exportedDb + private val _exporting = MutableLiveData(false) + val exporting: LiveData = _exporting + init { checkData = PublishProcessor.create() compositeDisposable = CompositeDisposable() @@ -473,12 +476,26 @@ class SyncManagerPresenter internal constructor( } fun onExportAndShareDB() { + exportDB(download = true, share = false) + } + + fun onExportAndDownloadDB() { + exportDB(download = false, share = true) + } + + private fun exportDB(download: Boolean, share: Boolean) { + _exporting.value = true try { val db = d2.maintenanceModule().databaseImportExport() .exportLoggedUserDatabase() - _exportedDb.value = ExportDbModel(file = db) + _exportedDb.value = ExportDbModel(file = db, share = share, download = download) } catch (e: Exception) { view.displayMessage(resourceManager.parseD2Error(e)) + onExportEnd() } } + + fun onExportEnd() { + _exporting.value = false + } } diff --git a/app/src/main/java/org/dhis2/usescases/settings/models/ExportDbModel.kt b/app/src/main/java/org/dhis2/usescases/settings/models/ExportDbModel.kt index dfd92512f35..dfd049e0f4d 100644 --- a/app/src/main/java/org/dhis2/usescases/settings/models/ExportDbModel.kt +++ b/app/src/main/java/org/dhis2/usescases/settings/models/ExportDbModel.kt @@ -6,4 +6,6 @@ import java.util.UUID data class ExportDbModel( val id: UUID = UUID.randomUUID(), val file: File, + val share: Boolean, + val download: Boolean, ) diff --git a/app/src/main/java/org/dhis2/usescases/settings/ui/ExportOption.kt b/app/src/main/java/org/dhis2/usescases/settings/ui/ExportOption.kt index 1cab8e48f87..82e97826f66 100644 --- a/app/src/main/java/org/dhis2/usescases/settings/ui/ExportOption.kt +++ b/app/src/main/java/org/dhis2/usescases/settings/ui/ExportOption.kt @@ -1,56 +1,128 @@ package org.dhis2.usescases.settings.ui +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.togetherWith import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Share import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.res.stringResource +import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.lifecycle.LiveData import com.google.accompanist.themeadapter.material3.Mdc3Theme import org.dhis2.R import org.hisp.dhis.mobile.ui.designsystem.component.Button import org.hisp.dhis.mobile.ui.designsystem.component.ButtonStyle +import org.hisp.dhis.mobile.ui.designsystem.component.ProgressIndicator +import org.hisp.dhis.mobile.ui.designsystem.component.ProgressIndicatorType @Composable fun ExportOption( - onClick: () -> Unit, + onDownload: () -> Unit, + onShare: () -> Unit, + displayProgress: Boolean, ) { - Row( - modifier = Modifier - .fillMaxWidth() - .height(72.dp), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center, - ) { - Button( - onClick = onClick, - style = ButtonStyle.TEXT, - text = stringResource(id = R.string.share), - icon = { - Icon( - imageVector = Icons.Filled.Share, - contentDescription = "Share", - tint = MaterialTheme.colors.primary, + AnimatedContent( + targetState = displayProgress, + transitionSpec = { + fadeIn( + animationSpec = tween(3000), + ) togetherWith fadeOut(animationSpec = tween(3000)) + }, + label = "import content", + ) { targetState -> + + Row( + modifier = Modifier + .fillMaxWidth() + .height(72.dp) + .padding( + start = if (displayProgress) 16.dp else 72.dp, + top = 16.dp, + end = 16.dp, + bottom = 16.dp, + ), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = if (displayProgress) Arrangement.Center else spacedBy(16.dp), + ) { + if (targetState.not()) { + Button( + modifier = Modifier.weight(1f), + onClick = onDownload, + style = ButtonStyle.TEXT, + text = stringResource(id = R.string.download), + icon = { + Icon( + imageVector = ImageVector.vectorResource(R.drawable.ic_file_download), + contentDescription = "Download", + tint = MaterialTheme.colors.primary, + ) + }, + ) + + Button( + modifier = Modifier.weight(1f), + onClick = onShare, + style = ButtonStyle.TEXT, + text = stringResource(id = R.string.share), + icon = { + Icon( + imageVector = Icons.Filled.Share, + contentDescription = "Share", + tint = MaterialTheme.colors.primary, + ) + }, ) - }, - ) + } else { + ProgressIndicator(type = ProgressIndicatorType.CIRCULAR) + } + } + } +} + +@Preview +@Composable +fun PreviewExportOption() { + Mdc3Theme { + ExportOption(onDownload = { }, onShare = { }, false) + } +} + +@Preview +@Composable +fun PreviewExportOptionProgress() { + Mdc3Theme { + ExportOption(onDownload = { }, onShare = { }, true) } } fun ComposeView.setExportOption( - onClick: () -> Unit, + onDownload: () -> Unit, + onShare: () -> Unit, + displayProgressProvider: () -> LiveData, ) { setContent { + val displayProgress by displayProgressProvider().observeAsState(false) Mdc3Theme { - ExportOption(onClick) + ExportOption(onShare, onDownload, displayProgress) } } }