-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #114 from Carifio24/export-all
Add importing/exporting app content
- Loading branch information
Showing
22 changed files
with
881 additions
and
77 deletions.
There are no files selected for viewing
14 changes: 14 additions & 0 deletions
14
app/src/androidTest/java/dnd/jon/spellbook/AndroidTestUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package dnd.jon.spellbook; | ||
|
||
import java.util.Collection; | ||
|
||
import static org.junit.Assert.*; | ||
|
||
public class AndroidTestUtils { | ||
|
||
static <T> void assertCollectionsSameUnordered(Collection<T> collection1, Collection<T> collection2) { | ||
assertEquals(collection1.size(), collection2.size()); | ||
assertTrue(collection1.containsAll(collection2)); | ||
assertTrue(collection2.containsAll(collection1)); | ||
} | ||
} |
292 changes: 236 additions & 56 deletions
292
app/src/androidTest/java/dnd/jon/spellbook/InstrumentTest.java
Large diffs are not rendered by default.
Oops, something went wrong.
83 changes: 83 additions & 0 deletions
83
app/src/main/java/dnd/jon/spellbook/ExportAllContentDialog.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package dnd.jon.spellbook; | ||
|
||
import android.app.AlertDialog; | ||
import android.app.Dialog; | ||
import android.os.Bundle; | ||
import android.util.Log; | ||
import android.view.View; | ||
import android.widget.Toast; | ||
|
||
import androidx.activity.result.ActivityResultLauncher; | ||
import androidx.activity.result.contract.ActivityResultContracts; | ||
import androidx.annotation.NonNull; | ||
import androidx.fragment.app.DialogFragment; | ||
import androidx.fragment.app.FragmentActivity; | ||
import androidx.lifecycle.ViewModelProvider; | ||
|
||
import org.json.JSONException; | ||
import org.json.JSONObject; | ||
|
||
import java.io.IOException; | ||
import java.io.OutputStream; | ||
import java.nio.charset.StandardCharsets; | ||
|
||
import dnd.jon.spellbook.databinding.ExportAllContentBinding; | ||
|
||
public class ExportAllContentDialog extends DialogFragment { | ||
|
||
private static final String TAG = "EXPORT_ALL_CONTENT_DIALOG"; | ||
private SpellbookViewModel viewModel; | ||
|
||
@NonNull | ||
@Override | ||
public Dialog onCreateDialog(Bundle savedInstanceState) { | ||
final FragmentActivity activity = requireActivity(); | ||
viewModel = new ViewModelProvider(activity, activity.getDefaultViewModelProviderFactory()) | ||
.get(SpellbookViewModel.class); | ||
|
||
AlertDialog.Builder builder = new AlertDialog.Builder(activity); | ||
|
||
final ExportAllContentBinding binding = ExportAllContentBinding.inflate(getLayoutInflater()); | ||
builder.setView(binding.getRoot()); | ||
|
||
final ActivityResultLauncher<String> chooser = registerForActivityResult(new ActivityResultContracts.CreateDocument("application/json"), uri -> { | ||
if (uri == null || uri.getPath() == null) { | ||
Toast.makeText(activity, R.string.error_exporting_app_content, Toast.LENGTH_SHORT).show(); | ||
return; | ||
} | ||
|
||
try { | ||
final OutputStream outputStream = activity.getContentResolver().openOutputStream(uri); | ||
final JSONObject json = viewModel.allCreatedContent(); | ||
final String content = json.toString(); | ||
final byte[] bytes = content.getBytes(StandardCharsets.UTF_8); | ||
outputStream.write(bytes); | ||
} catch (IOException | JSONException e) { | ||
final String errorMessage = getString(R.string.error_exporting_app_content); | ||
Log.e(TAG, e.getMessage()); | ||
Toast.makeText(activity, errorMessage, Toast.LENGTH_SHORT).show(); | ||
} | ||
}); | ||
|
||
binding.exportContentCancelButton.setOnClickListener((View view) -> this.dismiss()); | ||
binding.exportContentFileButton.setOnClickListener((View view) -> chooser.launch(getString(R.string.default_export_content_filename))); | ||
binding.exportContentClipboardButton.setOnClickListener((View view) -> { | ||
String message; | ||
try { | ||
final JSONObject json = viewModel.allCreatedContent(); | ||
final String content = json.toString(); | ||
final String label = getString(R.string.default_export_content_cliplabel); | ||
AndroidUtils.copyToClipboard(activity, content, label); | ||
message = getString(R.string.app_content_clipboard_success); | ||
} catch (JSONException e) { | ||
message = getString(R.string.error_exporting_app_content); | ||
Log.e(TAG, e.getMessage()); | ||
} | ||
Toast.makeText(activity, message, Toast.LENGTH_SHORT).show(); | ||
}); | ||
|
||
final AlertDialog dialog = builder.create(); | ||
dialog.setCanceledOnTouchOutside(true); | ||
return dialog; | ||
} | ||
} |
110 changes: 110 additions & 0 deletions
110
app/src/main/java/dnd/jon/spellbook/ImportContentDialog.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package dnd.jon.spellbook; | ||
|
||
import android.app.AlertDialog; | ||
import android.app.Dialog; | ||
import android.os.Bundle; | ||
import android.util.Log; | ||
import android.view.View; | ||
import android.widget.Toast; | ||
|
||
import androidx.activity.result.ActivityResultLauncher; | ||
import androidx.activity.result.contract.ActivityResultContracts; | ||
import androidx.annotation.NonNull; | ||
import androidx.fragment.app.DialogFragment; | ||
import androidx.fragment.app.FragmentActivity; | ||
import androidx.lifecycle.ViewModelProvider; | ||
|
||
import org.json.JSONException; | ||
import org.json.JSONObject; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.FileNotFoundException; | ||
import java.io.InputStream; | ||
import java.io.InputStreamReader; | ||
import java.util.stream.Collectors; | ||
|
||
import dnd.jon.spellbook.databinding.ImportContentBinding; | ||
|
||
public class ImportContentDialog extends DialogFragment { | ||
|
||
private static final String TAG = "IMPORT_CONTENT_DIALOG"; | ||
private ImportContentBinding binding; | ||
private FragmentActivity activity; | ||
private SpellbookViewModel viewModel; | ||
private ActivityResultLauncher<String[]> importContentFileChooser; | ||
|
||
@Override | ||
public void onCreate(Bundle savedInstanceState) { | ||
super.onCreate(savedInstanceState); | ||
importContentFileChooser = registerForActivityResult(new ActivityResultContracts.OpenDocument(), uri -> { | ||
final FragmentActivity activity = requireActivity(); | ||
boolean complete = false; | ||
int messageID; | ||
if (uri == null || uri.getPath() == null) { | ||
Toast.makeText(activity, getString(R.string.selected_path_null), Toast.LENGTH_SHORT).show(); | ||
return; | ||
} | ||
|
||
try { | ||
final InputStream inputStream = activity.getContentResolver().openInputStream(uri); | ||
final String text = new BufferedReader(new InputStreamReader(inputStream)) | ||
.lines().collect(Collectors.joining()); | ||
final JSONObject json = new JSONObject(text); | ||
final boolean success = viewModel.loadCreatedContent(json); | ||
messageID = success ? R.string.content_loaded_successfully : R.string.issues_loading_some_content; | ||
complete = success; | ||
} catch (FileNotFoundException | JSONException e) { | ||
Log.e(TAG, e.getMessage()); | ||
messageID = R.string.json_import_error; | ||
} | ||
|
||
Toast.makeText(activity, messageID, Toast.LENGTH_SHORT).show(); | ||
if (complete) { | ||
this.dismiss(); | ||
} | ||
}); | ||
} | ||
|
||
@NonNull | ||
@Override | ||
public Dialog onCreateDialog(Bundle savedInstanceState) { | ||
|
||
activity = requireActivity(); | ||
viewModel = new ViewModelProvider(activity, activity.getDefaultViewModelProviderFactory()) | ||
.get(SpellbookViewModel.class); | ||
|
||
AlertDialog.Builder builder = new AlertDialog.Builder(activity); | ||
binding = ImportContentBinding.inflate(getLayoutInflater()); | ||
builder.setView(binding.getRoot()); | ||
|
||
binding.contentImportButton.setOnClickListener(this::importContentFromText); | ||
binding.contentImportFileButton.setOnClickListener(this::importContentFromFile); | ||
binding.contentImportCancelButton.setOnClickListener((v) -> this.dismiss()); | ||
|
||
return builder.create(); | ||
} | ||
|
||
private void importContentFromText(View view) { | ||
final String jsonString = binding.contentImportEditText.getText().toString(); | ||
int messageID; | ||
boolean complete = true; | ||
try { | ||
final JSONObject json = new JSONObject(jsonString); | ||
final boolean success = viewModel.loadCreatedContent(json); | ||
messageID = success ? R.string.content_loaded_successfully : R.string.issues_loading_some_content; | ||
complete = success; | ||
} catch (JSONException e) { | ||
Log.e(TAG, e.getMessage()); | ||
messageID = R.string.json_import_error; | ||
} | ||
|
||
Toast.makeText(activity, messageID, Toast.LENGTH_SHORT).show(); | ||
if (complete) { | ||
this.dismiss(); | ||
} | ||
} | ||
|
||
private void importContentFromFile(View view) { | ||
importContentFileChooser.launch(new String[]{"application/json"}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.