|
26 | 26 | import androidx.appcompat.widget.SearchView; |
27 | 27 | import androidx.core.splashscreen.SplashScreen; |
28 | 28 | import androidx.recyclerview.widget.RecyclerView; |
| 29 | +import androidx.work.Data; |
| 30 | +import androidx.work.WorkInfo; |
| 31 | +import androidx.work.WorkManager; |
29 | 32 |
|
30 | 33 | import com.google.android.material.dialog.MaterialAlertDialogBuilder; |
31 | 34 | import com.google.android.material.floatingactionbutton.FloatingActionButton; |
| 35 | +import com.google.android.material.snackbar.Snackbar; |
32 | 36 | import com.google.android.material.tabs.TabLayout; |
33 | 37 |
|
34 | 38 | import java.io.UnsupportedEncodingException; |
35 | 39 | import java.util.ArrayList; |
36 | 40 | import java.util.Arrays; |
37 | 41 | import java.util.Collections; |
38 | 42 | import java.util.List; |
| 43 | +import java.util.Objects; |
| 44 | +import java.util.concurrent.ExecutionException; |
39 | 45 | import java.util.concurrent.atomic.AtomicInteger; |
40 | 46 |
|
41 | 47 | import protect.card_locker.databinding.ContentMainBinding; |
42 | 48 | import protect.card_locker.databinding.MainActivityBinding; |
43 | 49 | import protect.card_locker.databinding.SortingOptionBinding; |
| 50 | +import protect.card_locker.importexport.DataFormat; |
| 51 | +import protect.card_locker.importexport.ImportExportWorker; |
44 | 52 | import protect.card_locker.preferences.SettingsActivity; |
45 | 53 |
|
46 | 54 | public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCardCursorAdapter.CardAdapterListener { |
@@ -71,6 +79,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard |
71 | 79 |
|
72 | 80 | private ActivityResultLauncher<Intent> mBarcodeScannerLauncher; |
73 | 81 | private ActivityResultLauncher<Intent> mSettingsLauncher; |
| 82 | + private ActivityResultLauncher<Intent> mImportExportLauncher; |
74 | 83 |
|
75 | 84 | private ActionMode.Callback mCurrentActionModeCallback = new ActionMode.Callback() { |
76 | 85 | @Override |
@@ -304,6 +313,69 @@ public void onClick(DialogInterface dialog, int whichButton) { |
304 | 313 | } |
305 | 314 | }); |
306 | 315 |
|
| 316 | + mImportExportLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> { |
| 317 | + // User didn't ask for import or export |
| 318 | + if (result.getResultCode() != RESULT_OK) { |
| 319 | + return; |
| 320 | + } |
| 321 | + |
| 322 | + // Watch for active imports/exports |
| 323 | + new Thread(() -> { |
| 324 | + WorkManager workManager = WorkManager.getInstance(MainActivity.this); |
| 325 | + |
| 326 | + Snackbar importRunning = Snackbar.make(binding.getRoot(), R.string.importing, Snackbar.LENGTH_INDEFINITE); |
| 327 | + |
| 328 | + while (true) { |
| 329 | + try { |
| 330 | + List<WorkInfo> activeImports = workManager.getWorkInfosForUniqueWork(ImportExportWorker.ACTION_IMPORT).get(); |
| 331 | + |
| 332 | + // We should only have one import running at a time, so it should be safe to always grab the latest |
| 333 | + WorkInfo activeImport = activeImports.get(activeImports.size() - 1); |
| 334 | + WorkInfo.State importState = activeImport.getState(); |
| 335 | + |
| 336 | + if (importState == WorkInfo.State.RUNNING || importState == WorkInfo.State.ENQUEUED || importState == WorkInfo.State.BLOCKED) { |
| 337 | + importRunning.show(); |
| 338 | + } else if (importState == WorkInfo.State.SUCCEEDED) { |
| 339 | + importRunning.dismiss(); |
| 340 | + runOnUiThread(() -> { |
| 341 | + Toast.makeText(getApplicationContext(), getString(R.string.importSuccessful), Toast.LENGTH_LONG).show(); |
| 342 | + updateLoyaltyCardList(true); |
| 343 | + }); |
| 344 | + |
| 345 | + break; |
| 346 | + } else { |
| 347 | + importRunning.dismiss(); |
| 348 | + |
| 349 | + Data outputData = activeImport.getOutputData(); |
| 350 | + |
| 351 | + // FIXME: This dialog will asynchronously be accepted or declined and we don't know the status of it so we can't show the import state |
| 352 | + // We want to get back into this function |
| 353 | + // A cheap fix would be to keep looping but if the user dismissed the dialog that could mean we're looping forever... |
| 354 | + if (Objects.equals(outputData.getString(ImportExportWorker.OUTPUT_ERROR_REASON), ImportExportWorker.ERROR_PASSWORD_REQUIRED)) { |
| 355 | + runOnUiThread(() -> ImportExportActivity.retryWithPassword( |
| 356 | + MainActivity.this, |
| 357 | + DataFormat.valueOf(outputData.getString(ImportExportWorker.INPUT_FORMAT)), |
| 358 | + Uri.parse(outputData.getString(ImportExportWorker.INPUT_URI)) |
| 359 | + )); |
| 360 | + } else { |
| 361 | + runOnUiThread(() -> { |
| 362 | + Toast.makeText(getApplicationContext(), getString(R.string.importFailed), Toast.LENGTH_LONG).show(); |
| 363 | + Toast.makeText(getApplicationContext(), activeImport.getOutputData().getString(ImportExportWorker.OUTPUT_ERROR_REASON), Toast.LENGTH_LONG).show(); |
| 364 | + Toast.makeText(getApplicationContext(), activeImport.getOutputData().getString(ImportExportWorker.OUTPUT_ERROR_DETAILS), Toast.LENGTH_LONG).show(); |
| 365 | + }); |
| 366 | + } |
| 367 | + |
| 368 | + break; |
| 369 | + } |
| 370 | + } catch (ExecutionException e) { |
| 371 | + throw new RuntimeException(e); |
| 372 | + } catch (InterruptedException e) { |
| 373 | + throw new RuntimeException(e); |
| 374 | + } |
| 375 | + } |
| 376 | + }).start(); |
| 377 | + }); |
| 378 | + |
307 | 379 | getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) { |
308 | 380 | @Override |
309 | 381 | public void handleOnBackPressed() { |
@@ -641,7 +713,7 @@ public boolean onOptionsItemSelected(MenuItem inputItem) { |
641 | 713 |
|
642 | 714 | if (id == R.id.action_import_export) { |
643 | 715 | Intent i = new Intent(getApplicationContext(), ImportExportActivity.class); |
644 | | - startActivity(i); |
| 716 | + mImportExportLauncher.launch(i); |
645 | 717 | return true; |
646 | 718 | } |
647 | 719 |
|
|
0 commit comments