Unified Import Source configuration, added concurrency prevention and combined UI
This commit is contained in:
@@ -10,6 +10,7 @@ import android.view.View;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.core.graphics.Insets;
|
import androidx.core.graphics.Insets;
|
||||||
import androidx.core.view.ViewCompat;
|
import androidx.core.view.ViewCompat;
|
||||||
@@ -33,7 +34,7 @@ import com.majinnaibu.monstercards.importers.GitRepoImporterService;
|
|||||||
import com.majinnaibu.monstercards.importers.Open5eApiWrapper;
|
import com.majinnaibu.monstercards.importers.Open5eApiWrapper;
|
||||||
import com.majinnaibu.monstercards.init.AppCenterInitializer;
|
import com.majinnaibu.monstercards.init.AppCenterInitializer;
|
||||||
import com.majinnaibu.monstercards.models.BinderExport;
|
import com.majinnaibu.monstercards.models.BinderExport;
|
||||||
import com.majinnaibu.monstercards.models.GitRepositorySource;
|
import com.majinnaibu.monstercards.models.ImportSource;
|
||||||
import com.majinnaibu.monstercards.models.Monster;
|
import com.majinnaibu.monstercards.models.Monster;
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
import com.majinnaibu.monstercards.utils.Logger;
|
||||||
import com.majinnaibu.monstercards.utils.SnackbarHelper;
|
import com.majinnaibu.monstercards.utils.SnackbarHelper;
|
||||||
@@ -53,10 +54,12 @@ import io.reactivex.rxjava3.core.Single;
|
|||||||
import io.reactivex.rxjava3.disposables.Disposable;
|
import io.reactivex.rxjava3.disposables.Disposable;
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private Disposable mOpen5eImportDisposable;
|
private Disposable mImportDisposable;
|
||||||
private Disposable mGitImportDisposable;
|
private ImportSource mCurrentImportSource;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||||
@@ -212,34 +215,44 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void importAllFromOpen5e() {
|
public void startImportFromSource(ImportSource source) {
|
||||||
if (mOpen5eImportDisposable != null && !mOpen5eImportDisposable.isDisposed()) {
|
if (mImportDisposable != null && !mImportDisposable.isDisposed()) {
|
||||||
ToastHelper.showShort(this, "Open5e import already running");
|
new AlertDialog.Builder(this)
|
||||||
|
.setTitle(R.string.dialog_import_already_running_title)
|
||||||
|
.setMessage(getString(R.string.dialog_import_already_running_message, mCurrentImportSource != null ? mCurrentImportSource.projectName : ""))
|
||||||
|
.setPositiveButton(R.string.action_cancel_current, (dialog, which) -> {
|
||||||
|
mImportDisposable.dispose();
|
||||||
|
executeImportFromSource(source);
|
||||||
|
})
|
||||||
|
.setNegativeButton(R.string.dialog_cancel, null)
|
||||||
|
.show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
executeImportFromSource(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeImportFromSource(ImportSource source) {
|
||||||
|
mCurrentImportSource = source;
|
||||||
View rootView = findViewById(android.R.id.content);
|
View rootView = findViewById(android.R.id.content);
|
||||||
Snackbar snackbar = SnackbarHelper.makeIndefinite(rootView, R.string.snackbar_importing_open5e);
|
Snackbar snackbar = SnackbarHelper.makeIndefinite(rootView, getString(R.string.snackbar_importing_source, source.projectName));
|
||||||
snackbar.setAction(R.string.action_cancel, v -> {
|
snackbar.setAction(R.string.action_cancel, v -> {
|
||||||
if (mOpen5eImportDisposable != null && !mOpen5eImportDisposable.isDisposed()) {
|
if (mImportDisposable != null && !mImportDisposable.isDisposed()) {
|
||||||
mOpen5eImportDisposable.dispose();
|
mImportDisposable.dispose();
|
||||||
SnackbarHelper.showLong(rootView, R.string.snackbar_open5e_import_cancelled);
|
SnackbarHelper.showLong(rootView, getString(R.string.snackbar_import_source_cancelled, source.projectName));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
snackbar.show();
|
snackbar.show();
|
||||||
|
|
||||||
mOpen5eImportDisposable = Single.fromCallable(() -> {
|
Callable<Integer> importTask;
|
||||||
|
if (source.importType == ImportSource.ImportType.OPEN5E_API) {
|
||||||
|
importTask = () -> {
|
||||||
int totalImported = 0;
|
int totalImported = 0;
|
||||||
String nextUrl = null;
|
String nextUrl = null;
|
||||||
do {
|
do {
|
||||||
if (mOpen5eImportDisposable != null && mOpen5eImportDisposable.isDisposed()) {
|
if (mImportDisposable != null && mImportDisposable.isDisposed()) break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
Open5eApiWrapper.Open5ePageResult page = Open5eApiWrapper.fetchPage(nextUrl);
|
Open5eApiWrapper.Open5ePageResult page = Open5eApiWrapper.fetchPage(nextUrl);
|
||||||
for (Monster monster : page.monsters) {
|
for (Monster monster : page.monsters) {
|
||||||
if (mOpen5eImportDisposable != null && mOpen5eImportDisposable.isDisposed()) {
|
if (mImportDisposable != null && mImportDisposable.isDisposed()) break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
((MonsterCardsApplication) getApplication()).getMonsterRepository()
|
((MonsterCardsApplication) getApplication()).getMonsterRepository()
|
||||||
.saveMonster(monster)
|
.saveMonster(monster)
|
||||||
@@ -253,41 +266,21 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
nextUrl = page.nextUrl;
|
nextUrl = page.nextUrl;
|
||||||
} while (nextUrl != null && !nextUrl.isEmpty());
|
} while (nextUrl != null && !nextUrl.isEmpty());
|
||||||
return totalImported;
|
return totalImported;
|
||||||
})
|
};
|
||||||
.subscribeOn(Schedulers.io())
|
} else {
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
importTask = () -> GitRepoImporterService.importFromGitRepository(getApplicationContext(), source, () -> mImportDisposable != null && mImportDisposable.isDisposed());
|
||||||
.subscribe(result -> {
|
|
||||||
snackbar.dismiss();
|
|
||||||
SnackbarHelper.showLong(rootView, R.string.snackbar_open5e_import_complete);
|
|
||||||
}, throwable -> {
|
|
||||||
snackbar.dismiss();
|
|
||||||
Logger.logError("Failed to import all Open5e monsters", throwable);
|
|
||||||
SnackbarHelper.showLong(rootView, R.string.snackbar_open5e_import_failed);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void importFromGitRepository(@NonNull GitRepositorySource source) {
|
mImportDisposable = Single.fromCallable(importTask)
|
||||||
if (mGitImportDisposable != null && !mGitImportDisposable.isDisposed()) {
|
|
||||||
ToastHelper.showShort(this, "A GitHub import is already running.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
View rootView = findViewById(android.R.id.content);
|
|
||||||
Snackbar snackbar = SnackbarHelper.makeIndefinite(rootView, R.string.snackbar_importing_github);
|
|
||||||
snackbar.show();
|
|
||||||
|
|
||||||
mGitImportDisposable = Single.fromCallable(() ->
|
|
||||||
GitRepoImporterService.importFromGitRepository(getApplicationContext(), source)
|
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(resultCount -> {
|
.subscribe(resultCount -> {
|
||||||
snackbar.dismiss();
|
snackbar.dismiss();
|
||||||
SnackbarHelper.showLong(rootView, getString(R.string.snackbar_github_import_complete, resultCount, source.projectName));
|
SnackbarHelper.showLong(rootView, getString(R.string.snackbar_import_source_complete, resultCount, source.projectName));
|
||||||
}, throwable -> {
|
}, throwable -> {
|
||||||
snackbar.dismiss();
|
snackbar.dismiss();
|
||||||
Logger.logError("Failed to import from GitHub repository: " + source.projectName, throwable);
|
Logger.logError("Failed to import from source: " + source.projectName, throwable);
|
||||||
SnackbarHelper.showLong(rootView, R.string.snackbar_github_import_failed);
|
SnackbarHelper.showLong(rootView, getString(R.string.snackbar_import_source_failed, source.projectName));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,11 +457,8 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
if (mOpen5eImportDisposable != null && !mOpen5eImportDisposable.isDisposed()) {
|
if (mImportDisposable != null && !mImportDisposable.isDisposed()) {
|
||||||
mOpen5eImportDisposable.dispose();
|
mImportDisposable.dispose();
|
||||||
}
|
|
||||||
if (mGitImportDisposable != null && !mGitImportDisposable.isDisposed()) {
|
|
||||||
mGitImportDisposable.dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.data;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.models.GitRepositorySource;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class GitRepositoryConfig {
|
|
||||||
public static final List<GitRepositorySource> SOURCES = new ArrayList<>();
|
|
||||||
|
|
||||||
static {
|
|
||||||
SOURCES.add(new GitRepositorySource(
|
|
||||||
"pf2e_foundry",
|
|
||||||
"Pathfinder 2e Foundry VTT",
|
|
||||||
"foundryvtt",
|
|
||||||
"https://github.com/foundryvtt/pf2e",
|
|
||||||
"https://github.com/foundryvtt/pf2e/archive/refs/heads/master.zip",
|
|
||||||
"com.majinnaibu.monstercards.importers.Pf2eImporter",
|
|
||||||
".json"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.majinnaibu.monstercards.data;
|
||||||
|
|
||||||
|
import com.majinnaibu.monstercards.models.ImportSource;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ImportConfig {
|
||||||
|
public static final List<ImportSource> SOURCES = new ArrayList<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
SOURCES.add(new ImportSource(
|
||||||
|
"open5e",
|
||||||
|
"Open5e.com System Reference Document",
|
||||||
|
"Open5e",
|
||||||
|
"https://open5e.com",
|
||||||
|
ImportSource.ImportType.OPEN5E_API,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
));
|
||||||
|
|
||||||
|
SOURCES.add(new ImportSource(
|
||||||
|
"pf2e_foundry",
|
||||||
|
"Pathfinder 2e Foundry VTT",
|
||||||
|
"foundryvtt",
|
||||||
|
"https://github.com/foundryvtt/pf2e",
|
||||||
|
ImportSource.ImportType.GIT_ARCHIVE,
|
||||||
|
"https://github.com/foundryvtt/pf2e/archive/refs/heads/master.zip",
|
||||||
|
"com.majinnaibu.monstercards.importers.Pf2eImporter",
|
||||||
|
".json"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ import androidx.annotation.NonNull;
|
|||||||
|
|
||||||
import com.majinnaibu.monstercards.MonsterCardsApplication;
|
import com.majinnaibu.monstercards.MonsterCardsApplication;
|
||||||
import com.majinnaibu.monstercards.data.MonsterRepository;
|
import com.majinnaibu.monstercards.data.MonsterRepository;
|
||||||
import com.majinnaibu.monstercards.models.GitRepositorySource;
|
import com.majinnaibu.monstercards.models.ImportSource;
|
||||||
import com.majinnaibu.monstercards.models.Monster;
|
import com.majinnaibu.monstercards.models.Monster;
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
import com.majinnaibu.monstercards.utils.Logger;
|
||||||
|
|
||||||
@@ -24,23 +24,28 @@ import java.net.URL;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
|
||||||
public class GitRepoImporterService {
|
public class GitRepoImporterService {
|
||||||
|
|
||||||
public static int importFromGitRepository(Context context, GitRepositorySource source) throws Exception {
|
public static int importFromGitRepository(Context context, ImportSource source, BooleanSupplier isCancelled) throws Exception {
|
||||||
int totalImported = 0;
|
int totalImported = 0;
|
||||||
|
|
||||||
File tempZip = File.createTempFile("repo_download", ".zip", context.getCacheDir());
|
File tempZip = File.createTempFile("repo_download", ".zip", context.getCacheDir());
|
||||||
File extractDir = new File(context.getCacheDir(), "repo_extracted_" + System.currentTimeMillis());
|
File extractDir = new File(context.getCacheDir(), "repo_extracted_" + System.currentTimeMillis());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
downloadZip(source.downloadUrl, tempZip);
|
downloadZip(source.downloadUrl, tempZip, isCancelled);
|
||||||
|
|
||||||
|
if (isCancelled.getAsBoolean()) return 0;
|
||||||
|
|
||||||
if (!extractDir.exists()) {
|
if (!extractDir.exists()) {
|
||||||
extractDir.mkdirs();
|
extractDir.mkdirs();
|
||||||
}
|
}
|
||||||
|
|
||||||
unzipAndFilter(tempZip, extractDir, source.fileExtension);
|
unzipAndFilter(tempZip, extractDir, source.fileExtension, isCancelled);
|
||||||
|
|
||||||
|
if (isCancelled.getAsBoolean()) return 0;
|
||||||
|
|
||||||
// Instantiate Importer dynamically
|
// Instantiate Importer dynamically
|
||||||
Class<?> clazz = Class.forName(source.importerClassName);
|
Class<?> clazz = Class.forName(source.importerClassName);
|
||||||
@@ -50,7 +55,7 @@ public class GitRepoImporterService {
|
|||||||
MonsterRepository repository = ((MonsterCardsApplication) context.getApplicationContext()).getMonsterRepository();
|
MonsterRepository repository = ((MonsterCardsApplication) context.getApplicationContext()).getMonsterRepository();
|
||||||
|
|
||||||
// Process files
|
// Process files
|
||||||
totalImported = processDirectory(extractDir, importer, repository);
|
totalImported = processDirectory(extractDir, importer, repository, isCancelled);
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
deleteFileOrDir(tempZip);
|
deleteFileOrDir(tempZip);
|
||||||
@@ -60,7 +65,7 @@ public class GitRepoImporterService {
|
|||||||
return totalImported;
|
return totalImported;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void downloadZip(String urlStr, File dest) throws IOException {
|
private static void downloadZip(String urlStr, File dest, BooleanSupplier isCancelled) throws IOException {
|
||||||
URL url = new URL(urlStr);
|
URL url = new URL(urlStr);
|
||||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||||
conn.setRequestMethod("GET");
|
conn.setRequestMethod("GET");
|
||||||
@@ -86,27 +91,29 @@ public class GitRepoImporterService {
|
|||||||
byte[] buffer = new byte[8192];
|
byte[] buffer = new byte[8192];
|
||||||
int count;
|
int count;
|
||||||
while ((count = in.read(buffer)) != -1) {
|
while ((count = in.read(buffer)) != -1) {
|
||||||
|
if (isCancelled.getAsBoolean()) break;
|
||||||
out.write(buffer, 0, count);
|
out.write(buffer, 0, count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void unzipAndFilter(File zipFile, File extractDir, String filterExtension) throws IOException {
|
private static void unzipAndFilter(File zipFile, File extractDir, String filterExtension, BooleanSupplier isCancelled) throws IOException {
|
||||||
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) {
|
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) {
|
||||||
ZipEntry entry;
|
ZipEntry entry;
|
||||||
while ((entry = zis.getNextEntry()) != null) {
|
while ((entry = zis.getNextEntry()) != null) {
|
||||||
|
if (isCancelled.getAsBoolean()) break;
|
||||||
if (!entry.isDirectory()) {
|
if (!entry.isDirectory()) {
|
||||||
String name = entry.getName();
|
String name = entry.getName();
|
||||||
if (filterExtension == null || name.endsWith(filterExtension)) {
|
if (filterExtension == null || name.endsWith(filterExtension)) {
|
||||||
File outFile = new File(extractDir, new File(name).getName());
|
File outFile = new File(extractDir, new File(name).getName());
|
||||||
if (outFile.exists()) {
|
if (outFile.exists()) {
|
||||||
// in case there are multiple files with same name in different folders
|
|
||||||
outFile = new File(extractDir, System.currentTimeMillis() + "_" + new File(name).getName());
|
outFile = new File(extractDir, System.currentTimeMillis() + "_" + new File(name).getName());
|
||||||
}
|
}
|
||||||
try (FileOutputStream fos = new FileOutputStream(outFile)) {
|
try (FileOutputStream fos = new FileOutputStream(outFile)) {
|
||||||
byte[] buffer = new byte[8192];
|
byte[] buffer = new byte[8192];
|
||||||
int count;
|
int count;
|
||||||
while ((count = zis.read(buffer)) != -1) {
|
while ((count = zis.read(buffer)) != -1) {
|
||||||
|
if (isCancelled.getAsBoolean()) break;
|
||||||
fos.write(buffer, 0, count);
|
fos.write(buffer, 0, count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,12 +124,13 @@ public class GitRepoImporterService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int processDirectory(File dir, EntityImporter<Monster> importer, MonsterRepository repository) {
|
private static int processDirectory(File dir, EntityImporter<Monster> importer, MonsterRepository repository, BooleanSupplier isCancelled) {
|
||||||
int importedCount = 0;
|
int importedCount = 0;
|
||||||
File[] files = dir.listFiles();
|
File[] files = dir.listFiles();
|
||||||
if (files == null) return 0;
|
if (files == null) return 0;
|
||||||
|
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
|
if (isCancelled.getAsBoolean()) break;
|
||||||
if (file.isFile()) {
|
if (file.isFile()) {
|
||||||
String content = readFileContent(file);
|
String content = readFileContent(file);
|
||||||
if (content != null && importer.canImport(content)) {
|
if (content != null && importer.canImport(content)) {
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.models;
|
|
||||||
|
|
||||||
public class GitRepositorySource {
|
|
||||||
public String id;
|
|
||||||
public String projectName;
|
|
||||||
public String creatorGithubName;
|
|
||||||
public String creatorPageLink;
|
|
||||||
public String downloadUrl;
|
|
||||||
public String importerClassName;
|
|
||||||
public String fileExtension;
|
|
||||||
|
|
||||||
public GitRepositorySource(String id, String projectName, String creatorGithubName, String creatorPageLink, String downloadUrl, String importerClassName, String fileExtension) {
|
|
||||||
this.id = id;
|
|
||||||
this.projectName = projectName;
|
|
||||||
this.creatorGithubName = creatorGithubName;
|
|
||||||
this.creatorPageLink = creatorPageLink;
|
|
||||||
this.downloadUrl = downloadUrl;
|
|
||||||
this.importerClassName = importerClassName;
|
|
||||||
this.fileExtension = fileExtension;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.majinnaibu.monstercards.models;
|
||||||
|
|
||||||
|
public class ImportSource {
|
||||||
|
public enum ImportType {
|
||||||
|
GIT_ARCHIVE,
|
||||||
|
OPEN5E_API
|
||||||
|
}
|
||||||
|
|
||||||
|
public String id;
|
||||||
|
public String projectName;
|
||||||
|
public String creatorName;
|
||||||
|
public String creatorPageLink;
|
||||||
|
public ImportType importType;
|
||||||
|
|
||||||
|
// Optional attributes specific to Git archive
|
||||||
|
public String downloadUrl;
|
||||||
|
public String importerClassName;
|
||||||
|
public String fileExtension;
|
||||||
|
|
||||||
|
public ImportSource(String id, String projectName, String creatorName, String creatorPageLink, ImportType importType, String downloadUrl, String importerClassName, String fileExtension) {
|
||||||
|
this.id = id;
|
||||||
|
this.projectName = projectName;
|
||||||
|
this.creatorName = creatorName;
|
||||||
|
this.creatorPageLink = creatorPageLink;
|
||||||
|
this.importType = importType;
|
||||||
|
this.downloadUrl = downloadUrl;
|
||||||
|
this.importerClassName = importerClassName;
|
||||||
|
this.fileExtension = fileExtension;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,8 +36,8 @@ import com.majinnaibu.monstercards.utils.Logger;
|
|||||||
import com.majinnaibu.monstercards.utils.SnackbarHelper;
|
import com.majinnaibu.monstercards.utils.SnackbarHelper;
|
||||||
import com.majinnaibu.monstercards.utils.ToastHelper;
|
import com.majinnaibu.monstercards.utils.ToastHelper;
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.data.GitRepositoryConfig;
|
import com.majinnaibu.monstercards.data.ImportConfig;
|
||||||
import com.majinnaibu.monstercards.models.GitRepositorySource;
|
import com.majinnaibu.monstercards.models.ImportSource;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -159,24 +159,17 @@ public class MCFragment extends Fragment {
|
|||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
});
|
});
|
||||||
|
|
||||||
view.findViewById(R.id.button_import_open5e).setOnClickListener(v -> {
|
view.findViewById(R.id.button_import_source).setOnClickListener(v -> {
|
||||||
if (getActivity() instanceof MainActivity) {
|
|
||||||
((MainActivity) getActivity()).importAllFromOpen5e();
|
|
||||||
}
|
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
});
|
showSourcePicker();
|
||||||
|
|
||||||
view.findViewById(R.id.button_import_github).setOnClickListener(v -> {
|
|
||||||
dialog.dismiss();
|
|
||||||
showGithubRepoPicker();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
dialog.show();
|
dialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showGithubRepoPicker() {
|
private void showSourcePicker() {
|
||||||
Context context = requireContext();
|
Context context = requireContext();
|
||||||
List<GitRepositorySource> sources = GitRepositoryConfig.SOURCES;
|
List<ImportSource> sources = ImportConfig.SOURCES;
|
||||||
if (sources.isEmpty()) {
|
if (sources.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -187,11 +180,11 @@ public class MCFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
new AlertDialog.Builder(context)
|
new AlertDialog.Builder(context)
|
||||||
.setTitle(R.string.dialog_select_github_repo)
|
.setTitle(R.string.dialog_select_import_source)
|
||||||
.setItems(repoNames, (d, which) -> {
|
.setItems(repoNames, (d, which) -> {
|
||||||
GitRepositorySource selected = sources.get(which);
|
ImportSource selected = sources.get(which);
|
||||||
if (getActivity() instanceof MainActivity) {
|
if (getActivity() instanceof MainActivity) {
|
||||||
((MainActivity) getActivity()).importFromGitRepository(selected);
|
((MainActivity) getActivity()).startImportFromSource(selected);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.setNegativeButton(R.string.dialog_cancel, null)
|
.setNegativeButton(R.string.dialog_cancel, null)
|
||||||
|
|||||||
@@ -41,17 +41,10 @@
|
|||||||
android:text="@string/action_import_monster_from_file" />
|
android:text="@string/action_import_monster_from_file" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/button_import_open5e"
|
android:id="@+id/button_import_source"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:text="@string/action_import_from_open5e" />
|
android:text="@string/action_import_from_source" />
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/button_import_github"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:text="@string/action_import_from_github" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -163,7 +163,7 @@
|
|||||||
<string name="snackbar_dashboard_cleared">Dashboard cleared</string>
|
<string name="snackbar_dashboard_cleared">Dashboard cleared</string>
|
||||||
<string name="no_monsters_available">No monsters available in library. Create one first!</string>
|
<string name="no_monsters_available">No monsters available in library. Create one first!</string>
|
||||||
<string name="action_import_from_url">Import URL</string>
|
<string name="action_import_from_url">Import URL</string>
|
||||||
<string name="action_import_from_open5e">From Open5e.com</string>
|
|
||||||
<string name="dialog_import_title">Import</string>
|
<string name="dialog_import_title">Import</string>
|
||||||
<string name="dialog_import_message">Enter or paste a URL, ID, or data payload:</string>
|
<string name="dialog_import_message">Enter or paste a URL, ID, or data payload:</string>
|
||||||
<string name="dialog_import_url_hint">e.g. D&D Beyond URL or Open5e JSON</string>
|
<string name="dialog_import_url_hint">e.g. D&D Beyond URL or Open5e JSON</string>
|
||||||
@@ -226,14 +226,14 @@
|
|||||||
<string name="dialog_remove_all_from_collection_title">Remove All Monsters?</string>
|
<string name="dialog_remove_all_from_collection_title">Remove All Monsters?</string>
|
||||||
<string name="dialog_remove_all_from_collection_message">Are you sure you want to remove all monsters from this collection?</string>
|
<string name="dialog_remove_all_from_collection_message">Are you sure you want to remove all monsters from this collection?</string>
|
||||||
<string name="snackbar_collection_cleared">Removed all monsters from collection</string>
|
<string name="snackbar_collection_cleared">Removed all monsters from collection</string>
|
||||||
<string name="snackbar_importing_open5e">Importing monsters from Open5e…</string>
|
<string name="action_import_from_source">Import from Source Project</string>
|
||||||
|
<string name="dialog_select_import_source">Select Import Source</string>
|
||||||
|
<string name="snackbar_importing_source">Importing from %1$s…</string>
|
||||||
|
<string name="snackbar_import_source_complete">Finished importing %1$d monsters from %2$s.</string>
|
||||||
|
<string name="snackbar_import_source_failed">Failed to import from %1$s.</string>
|
||||||
|
<string name="snackbar_import_source_cancelled">Cancelled import from %1$s.</string>
|
||||||
|
<string name="dialog_import_already_running_title">Import in Progress</string>
|
||||||
|
<string name="dialog_import_already_running_message">An import from %1$s is currently running. Do you want to cancel it and start a new import?</string>
|
||||||
|
<string name="action_cancel_current">Cancel Current</string>
|
||||||
<string name="action_cancel">Cancel</string>
|
<string name="action_cancel">Cancel</string>
|
||||||
<string name="snackbar_open5e_import_complete">Finished importing Open5e monsters.</string>
|
|
||||||
<string name="snackbar_open5e_import_cancelled">Cancelled Open5e import.</string>
|
|
||||||
<string name="snackbar_open5e_import_failed">Failed to import from Open5e.</string>
|
|
||||||
<string name="action_import_from_github">From GitHub Repository</string>
|
|
||||||
<string name="dialog_select_github_repo">Select Repository</string>
|
|
||||||
<string name="snackbar_importing_github">Downloading and importing repository…</string>
|
|
||||||
<string name="snackbar_github_import_complete">Imported %1$d monsters from %2$s.</string>
|
|
||||||
<string name="snackbar_github_import_failed">Failed to import from GitHub repository.</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user