Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
TheLastProject committed May 21, 2024
1 parent 4b1d1f4 commit cd5ef26
Show file tree
Hide file tree
Showing 11 changed files with 490 additions and 355 deletions.
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ dependencies {
implementation("androidx.preference:preference:1.2.1")
implementation("com.google.android.material:material:1.12.0")
implementation("com.github.yalantis:ucrop:2.2.9")
implementation("androidx.work:work-runtime:2.9.0")
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4")

// Splash Screen
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
<uses-sdk tools:overrideLibrary="com.google.zxing.client.android" />

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="23" />

<uses-feature
Expand Down Expand Up @@ -188,5 +190,6 @@
<action android:name="android.service.controls.ControlsProviderService" />
</intent-filter>
</service>
<service android:name=".importexport.ImportExportWorker"/>
</application>
</manifest>
235 changes: 91 additions & 144 deletions app/src/main/java/protect/card_locker/ImportExportActivity.java

Large diffs are not rendered by default.

143 changes: 0 additions & 143 deletions app/src/main/java/protect/card_locker/ImportExportTask.java

This file was deleted.

74 changes: 73 additions & 1 deletion app/src/main/java/protect/card_locker/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,29 @@
import androidx.appcompat.widget.SearchView;
import androidx.core.splashscreen.SplashScreen;
import androidx.recyclerview.widget.RecyclerView;
import androidx.work.Data;
import androidx.work.WorkInfo;
import androidx.work.WorkManager;

import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.tabs.TabLayout;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicInteger;

import protect.card_locker.databinding.ContentMainBinding;
import protect.card_locker.databinding.MainActivityBinding;
import protect.card_locker.databinding.SortingOptionBinding;
import protect.card_locker.importexport.DataFormat;
import protect.card_locker.importexport.ImportExportWorker;
import protect.card_locker.preferences.SettingsActivity;

public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCardCursorAdapter.CardAdapterListener {
Expand Down Expand Up @@ -71,6 +79,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard

private ActivityResultLauncher<Intent> mBarcodeScannerLauncher;
private ActivityResultLauncher<Intent> mSettingsLauncher;
private ActivityResultLauncher<Intent> mImportExportLauncher;

private ActionMode.Callback mCurrentActionModeCallback = new ActionMode.Callback() {
@Override
Expand Down Expand Up @@ -304,6 +313,69 @@ public void onClick(DialogInterface dialog, int whichButton) {
}
});

mImportExportLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
// User didn't ask for import or export
if (result.getResultCode() != RESULT_OK) {
return;
}

// Watch for active imports/exports
new Thread(() -> {
WorkManager workManager = WorkManager.getInstance(MainActivity.this);

Snackbar importRunning = Snackbar.make(binding.getRoot(), R.string.importing, Snackbar.LENGTH_INDEFINITE);

while (true) {
try {
List<WorkInfo> activeImports = workManager.getWorkInfosForUniqueWork(ImportExportWorker.ACTION_IMPORT).get();

// We should only have one import running at a time, so it should be safe to always grab the latest
WorkInfo activeImport = activeImports.get(activeImports.size() - 1);
WorkInfo.State importState = activeImport.getState();

if (importState == WorkInfo.State.RUNNING || importState == WorkInfo.State.ENQUEUED || importState == WorkInfo.State.BLOCKED) {
importRunning.show();
} else if (importState == WorkInfo.State.SUCCEEDED) {
importRunning.dismiss();
runOnUiThread(() -> {
Toast.makeText(getApplicationContext(), getString(R.string.importSuccessful), Toast.LENGTH_LONG).show();
updateLoyaltyCardList(true);
});

break;
} else {
importRunning.dismiss();

Data outputData = activeImport.getOutputData();

// 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
// We want to get back into this function
// A cheap fix would be to keep looping but if the user dismissed the dialog that could mean we're looping forever...
if (Objects.equals(outputData.getString(ImportExportWorker.OUTPUT_ERROR_REASON), ImportExportWorker.ERROR_PASSWORD_REQUIRED)) {
runOnUiThread(() -> ImportExportActivity.retryWithPassword(
MainActivity.this,
DataFormat.valueOf(outputData.getString(ImportExportWorker.INPUT_FORMAT)),
Uri.parse(outputData.getString(ImportExportWorker.INPUT_URI))
));
} else {
runOnUiThread(() -> {
Toast.makeText(getApplicationContext(), getString(R.string.importFailed), Toast.LENGTH_LONG).show();
Toast.makeText(getApplicationContext(), activeImport.getOutputData().getString(ImportExportWorker.OUTPUT_ERROR_REASON), Toast.LENGTH_LONG).show();
Toast.makeText(getApplicationContext(), activeImport.getOutputData().getString(ImportExportWorker.OUTPUT_ERROR_DETAILS), Toast.LENGTH_LONG).show();
});
}

break;
}
} catch (ExecutionException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}).start();
});

getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
Expand Down Expand Up @@ -641,7 +713,7 @@ public boolean onOptionsItemSelected(MenuItem inputItem) {

if (id == R.id.action_import_export) {
Intent i = new Intent(getApplicationContext(), ImportExportActivity.class);
startActivity(i);
mImportExportLauncher.launch(i);
return true;
}

Expand Down
63 changes: 63 additions & 0 deletions app/src/main/java/protect/card_locker/NotificationHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package protect.card_locker;

import static android.content.Context.NOTIFICATION_SERVICE;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class NotificationHelper {

// Do not change these IDs!
public static final String CHANNEL_IMPORT = "import";

public static final String CHANNEL_EXPORT = "export";

public static final int IMPORT_ID = 100;
public static final int IMPORT_PROGRESS_ID = 101;
public static final int EXPORT_ID = 103;
public static final int EXPORT_PROGRESS_ID = 104;


public static Notification.Builder createNotificationBuilder(@NonNull Context context, @NonNull String channel, @NonNull int icon, @NonNull String title, @Nullable String message) {
Notification.Builder notificationBuilder = new Notification.Builder(context)
.setSmallIcon(icon)
.setTicker(title)
.setContentTitle(title);

if (message != null) {
notificationBuilder.setContentText(message);
}

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
NotificationChannel notificationChannel = new NotificationChannel(channel, getChannelName(channel), NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(notificationChannel);

notificationBuilder.setChannelId(channel);
}

return notificationBuilder;
}

public static void sendNotification(@NonNull Context context, @NonNull int notificationId, @NonNull Notification notification) {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);

notificationManager.notify(notificationId, notification);
}

private static String getChannelName(@NonNull String channel) {
switch(channel) {
case CHANNEL_IMPORT:
return "Import";
case CHANNEL_EXPORT:
return "Export";
default:
throw new IllegalArgumentException("Unknown notification channel");
}
}
}
Loading

0 comments on commit cd5ef26

Please sign in to comment.