Release 0.2.1

This commit is contained in:
hajdam
2024-09-27 19:30:46 +02:00
parent a9e146aca4
commit 3860f62924
17 changed files with 135 additions and 105 deletions
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AppInsightsSettings">
<option name="selectedTabId" value="Android Vitals" />
</component>
</project>
+2 -2
View File
@@ -4,10 +4,10 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2024-09-26T11:10:09.819583563Z">
<DropdownSelection timestamp="2024-09-27T15:24:14.646928879Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=/home/hajdam/.config/.android/avd/Pixel_8_API_27.avd" />
<DeviceId pluginId="LocalEmulator" identifier="path=/home/hajdam/.config/.android/avd/Pixel_Tablet_API_34.avd" />
</handle>
</Target>
</DropdownSelection>
+5 -5
View File
@@ -3,13 +3,13 @@ plugins {
}
android {
compileSdkVersion 34
compileSdk 34
defaultConfig {
applicationId "org.exbin.bined.editor.android"
minSdkVersion 27
targetSdkVersion 34
versionCode 4
versionName "0.2.1-SNAPSHOT"
minSdk 27
targetSdk 34
versionCode 5
versionName "0.2.1"
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
buildTypes {
+5 -3
View File
@@ -1,12 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:icon="@mipmap/bined"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
tools:targetApi="34">
<activity
android:name=".SettingsActivity"
android:exported="false"
@@ -29,6 +31,6 @@
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="33" />
android:maxSdkVersion="32" />
</manifest>
@@ -21,6 +21,7 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.LocaleList;
import android.provider.DocumentsContract;
import android.text.Editable;
import android.text.InputType;
import android.text.method.KeyListener;
@@ -81,6 +82,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -119,8 +121,10 @@ public class MainActivity extends AppCompatActivity {
private Menu menu;
private static ByteArrayEditableData fileData = null;
private Uri currentFileUri = null;
private Uri pickerInitialUri = null;
private final BinaryStatusHandler binaryStatus = new BinaryStatusHandler(this);
private BinarySearchService searchService;
private Runnable postSaveAsAction = null;
private final BinarySearchService.SearchStatusListener searchStatusListener = new BinarySearchService.SearchStatusListener() {
@Override
public void setStatus(BinarySearchService.FoundMatches foundMatches, SearchParameters.MatchMode matchMode) {
@@ -319,33 +323,10 @@ public class MainActivity extends AppCompatActivity {
codeArea.addSelectionChangedListener(this::updateEditActionsState);
updateEditActionsState();
menu.findItem(R.id.code_colorization).setChecked(appPreferences.getCodeAreaPreferences().isCodeColorization());
int bytesPerRow = appPreferences.getCodeAreaPreferences().getMaxBytesPerRow();
switch (bytesPerRow) {
case 0: {
menu.findItem(R.id.bytes_per_row_fill).setChecked(true);
break;
}
case 4: {
menu.findItem(R.id.bytes_per_row_4).setChecked(true);
break;
}
case 8: {
menu.findItem(R.id.bytes_per_row_8).setChecked(true);
break;
}
case 12: {
menu.findItem(R.id.bytes_per_row_12).setChecked(true);
break;
}
case 16: {
menu.findItem(R.id.bytes_per_row_16).setChecked(true);
break;
}
}
updateViewActionsState();
MenuItem searchMenuItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) searchMenuItem.getActionView();
SearchView searchView = Objects.requireNonNull((SearchView) searchMenuItem.getActionView());
searchView.setSubmitButtonEnabled(true);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
@@ -371,9 +352,9 @@ public class MainActivity extends AppCompatActivity {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuItem selectionStartMenuItem = menu.add(0, SELECTION_START_POPUP_ID, 0, getResources().getString(R.string.action_selection_start));
MenuItem selectionEndMenuItem = menu.add(0, SELECTION_END_POPUP_ID, 1, getResources().getString(R.string.action_selection_end));
MenuItem clearSelectionMenuItem = menu.add(0, CLEAR_SELECTION_POPUP_ID, 2, getResources().getString(R.string.action_clear_selection));
menu.add(0, SELECTION_START_POPUP_ID, 0, getResources().getString(R.string.action_selection_start));
menu.add(0, SELECTION_END_POPUP_ID, 1, getResources().getString(R.string.action_selection_end));
menu.add(0, CLEAR_SELECTION_POPUP_ID, 2, getResources().getString(R.string.action_clear_selection));
MenuItem cutMenuItem = menu.add(1, CUT_ACTION_POPUP_ID, 3, getResources().getString(R.string.action_cut));
cutMenuItem.setEnabled(codeArea.isEditable() && codeArea.hasSelection());
MenuItem copyMenuItem = menu.add(1, COPY_ACTION_POPUP_ID, 4, getResources().getString(R.string.action_copy));
@@ -384,7 +365,7 @@ public class MainActivity extends AppCompatActivity {
menu.add(1, PASTE_FROM_CODE_ACTION_POPUP_ID, 5, getResources().getString(R.string.action_paste_from_code));
MenuItem deleteMenuItem = menu.add(1, DELETE_ACTION_POPUP_ID, 7, getResources().getString(R.string.action_delete));
deleteMenuItem.setEnabled(codeArea.isEditable() && codeArea.hasSelection());
MenuItem selectAllMenuItem = menu.add(1, SELECT_ALL_ACTION_POPUP_ID, 8, getResources().getString(R.string.action_select_all));
menu.add(1, SELECT_ALL_ACTION_POPUP_ID, 8, getResources().getString(R.string.action_select_all));
}
@Override
@@ -459,33 +440,30 @@ public class MainActivity extends AppCompatActivity {
int id = item.getItemId();
if (id == R.id.action_new) {
releaseFile(successful -> {
if (successful) {
codeArea.setContentData(new ByteArrayEditableData());
undoRedo.clear();
releaseFile(() -> {
codeArea.setContentData(new ByteArrayEditableData());
undoRedo.clear();
currentFileUri = null;
documentOriginalSize = 0;
}
documentOriginalSize = 0;
});
return true;
} else if (id == R.id.action_open) {
releaseFile(successful -> {
if (successful) {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.putExtra(Intent.EXTRA_LOCALE_LIST, getLanguageLocaleList());
}
// Optionally, specify a URI for the file that should appear in the
// system file picker when it loads.
// intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri);
// startActivityForResult(intent, 1);
openFileLauncher.launch(Intent.createChooser(intent, getResources().getString(R.string.select_file)));
releaseFile(() -> {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.putExtra(Intent.EXTRA_LOCALE_LIST, getLanguageLocaleList());
}
if (pickerInitialUri != null) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri);
}
// startActivityForResult(intent, 1);
openFileLauncher.launch(Intent.createChooser(intent, getResources().getString(R.string.select_file)));
});
return true;
@@ -513,10 +491,8 @@ public class MainActivity extends AppCompatActivity {
return true;
} else if (id == R.id.action_exit) {
releaseFile(successful -> {
if (successful) {
System.exit(0);
}
releaseFile(() -> {
System.exit(0);
});
return true;
@@ -660,29 +636,37 @@ public class MainActivity extends AppCompatActivity {
return super.onOptionsItemSelected(item);
}
public void releaseFile(PostReleaseAction postReleaseAction) {
public void releaseFile(Runnable postReleaseAction) {
if (!undoRedo.isModified()) {
postReleaseAction.released(true);
postReleaseAction.run();
return;
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.file_modified);
builder.setPositiveButton(R.string.button_save, (dialog, which) -> {
saveFile(currentFileUri);
postReleaseAction.released(true);
if (currentFileUri == null) {
saveAs();
} else {
saveFile(currentFileUri);
}
postReleaseAction.run();
});
builder.setNeutralButton(R.string.button_discard, (dialog, which) -> {
postReleaseAction.released(true);
});
builder.setNegativeButton(R.string.button_cancel, (dialog, which) -> {
postReleaseAction.released(false);
postReleaseAction.run();
});
builder.setNegativeButton(R.string.button_cancel, null);
AlertDialog alertDialog = builder.create();
alertDialog.show();
}
public void saveAs() {
saveAs(null);
}
public void saveAs(@Nullable Runnable postSaveAsAction) {
this.postSaveAsAction = postSaveAsAction;
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
@@ -690,9 +674,9 @@ public class MainActivity extends AppCompatActivity {
intent.putExtra(Intent.EXTRA_LOCALE_LIST, getLanguageLocaleList());
}
// Optionally, specify a URI for the file that should appear in the
// system file picker when it loads.
// intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri);
if (pickerInitialUri != null) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri);
}
saveFileLauncher.launch(Intent.createChooser(intent, getResources().getString(R.string.save_as_file)));
}
@@ -710,6 +694,7 @@ public class MainActivity extends AppCompatActivity {
undoRedo.clear();
codeArea.setContentData(fileData);
currentFileUri = fileUri;
pickerInitialUri = fileUri;
} catch (IOException ex) {
Logger.getLogger(MainActivity.class.getName()).log(Level.SEVERE, null, ex);
}
@@ -727,6 +712,7 @@ public class MainActivity extends AppCompatActivity {
documentOriginalSize = contentData.getDataSize();
undoRedo.setSyncPosition();
currentFileUri = fileUri;
pickerInitialUri = fileUri;
} catch (IOException ex) {
Logger.getLogger(MainActivity.class.getName()).log(Level.SEVERE, null, ex);
}
@@ -846,6 +832,33 @@ public class MainActivity extends AppCompatActivity {
deleteMenuItem.setEnabled(codeArea.isEditable() && codeArea.hasSelection());
}
private void updateViewActionsState() {
menu.findItem(R.id.code_colorization).setChecked(appPreferences.getCodeAreaPreferences().isCodeColorization());
int bytesPerRow = appPreferences.getCodeAreaPreferences().getMaxBytesPerRow();
switch (bytesPerRow) {
case 0: {
menu.findItem(R.id.bytes_per_row_fill).setChecked(true);
break;
}
case 4: {
menu.findItem(R.id.bytes_per_row_4).setChecked(true);
break;
}
case 8: {
menu.findItem(R.id.bytes_per_row_8).setChecked(true);
break;
}
case 12: {
menu.findItem(R.id.bytes_per_row_12).setChecked(true);
break;
}
case 16: {
menu.findItem(R.id.bytes_per_row_16).setChecked(true);
break;
}
}
}
private void updateUndoState() {
MenuItem saveMenuItem = menu.findItem(R.id.action_save);
saveMenuItem.setEnabled(currentFileUri == null || undoRedo.isModified());
@@ -878,15 +891,15 @@ public class MainActivity extends AppCompatActivity {
}
saveFile(data.getData());
if (postSaveAsAction != null) {
postSaveAsAction.run();
postSaveAsAction = null;
}
}
private void settingsResultCallback(ActivityResult activityResult) {
int resultCode = activityResult.getResultCode();
if (resultCode != MainActivity.RESULT_OK) {
return;
}
applySettings();
updateViewActionsState();
}
public void buttonAction0(View view) {
@@ -992,8 +1005,4 @@ public class MainActivity extends AppCompatActivity {
public void buttonActionTab(View view) {
codeArea.getCommandHandler().keyPressed(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_TAB));
}
public interface PostReleaseAction {
void released(boolean successful);
}
}
@@ -15,6 +15,8 @@
*/
package org.exbin.bined.editor.android;
import android.app.Activity;
import android.app.Instrumentation;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
@@ -22,6 +24,7 @@ import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.os.LocaleListCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentResultListener;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
@@ -33,9 +36,11 @@ import org.exbin.bined.basic.CodeAreaViewMode;
import org.exbin.bined.editor.android.preference.BinaryEditorPreferences;
import org.exbin.bined.editor.android.preference.CodeAreaPreferences;
import org.exbin.bined.editor.android.preference.EncodingPreference;
import org.exbin.bined.editor.android.preference.FontPreference;
import org.exbin.bined.editor.android.preference.MainPreferences;
import org.exbin.bined.editor.android.preference.PreferencesWrapper;
import org.exbin.bined.editor.android.preference.TextEncodingPreferences;
import org.exbin.bined.editor.android.preference.TextFontPreferences;
import java.util.Locale;
@@ -50,6 +55,7 @@ public class SettingsActivity extends AppCompatActivity implements
public static final String LANGUAGE_KEY = "language";
public static final String THEME_KEY = "theme";
public static final String FONT_KEY = "font";
public static final String ENCODING_KEY = "encoding";
public static final String BYTES_PER_ROW_KEY = "bytes_per_row";
public static final String VIEW_MODE_KEY = "view_mode";
@@ -121,14 +127,12 @@ public class SettingsActivity extends AppCompatActivity implements
getClassLoader(),
pref.getFragment());
fragment.setArguments(args);
// TODO: Replace deprecated
// fragmentManager.setFragmentResultListener(0, fragment, new FragmentResultListener() {
// @Override
// public void onFragmentResult(@NonNull String requestKey, @NonNull Bundle result) {
// caller.result
// }
// });
fragment.setTargetFragment(caller, 0);
fragmentManager.setFragmentResultListener("requestKey", fragment, new FragmentResultListener() {
@Override
public void onFragmentResult(@Nonnull String requestKey, @Nonnull Bundle result) {
caller.getParentFragmentManager().setFragmentResult(requestKey, result);
}
});
// Replace the existing Fragment with the new Fragment
fragmentManager.beginTransaction()
.replace(R.id.settings, fragment)
@@ -211,6 +215,8 @@ public class SettingsActivity extends AppCompatActivity implements
// Load from preferences
SettingsActivity activity = (SettingsActivity) requireActivity();
CodeAreaPreferences codeAreaPreferences = activity.appPreferences.getCodeAreaPreferences();
TextFontPreferences fontPreferences = activity.appPreferences.getFontPreferences();
((FontPreference) findPreference(FONT_KEY)).setText(String.valueOf(fontPreferences.getFontSize()));
TextEncodingPreferences encodingPreferences = activity.appPreferences.getEncodingPreferences();
((EncodingPreference) findPreference(ENCODING_KEY)).setText(encodingPreferences.getDefaultEncoding());
((ListPreference) findPreference(BYTES_PER_ROW_KEY)).setValue(String.valueOf(codeAreaPreferences.getMaxBytesPerRow()));
@@ -225,6 +231,8 @@ public class SettingsActivity extends AppCompatActivity implements
// Save to preferences
SettingsActivity activity = (SettingsActivity) requireActivity();
CodeAreaPreferences codeAreaPreferences = activity.appPreferences.getCodeAreaPreferences();
TextFontPreferences fontPreferences = activity.appPreferences.getFontPreferences();
fontPreferences.setFontSize(Integer.parseInt(((FontPreference) findPreference(FONT_KEY)).getText()));
TextEncodingPreferences encodingPreferences = activity.appPreferences.getEncodingPreferences();
encodingPreferences.setDefaultEncoding(((EncodingPreference) findPreference(ENCODING_KEY)).getText());
codeAreaPreferences.setMaxBytesPerRow(Integer.parseInt(((ListPreference) findPreference(BYTES_PER_ROW_KEY)).getValue()));
+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">BinEd</string>
<string name="app_about">Název: BinEd binární/hexadecimální editor\nVerze: 0.2.1-SNAPSHOT\nDodavatel: <a href="https://exbin.org">Projekt ExBin</a>\nLicence: <a href="https://www.apache.org/licenses/LICENSE-2.0">Licence Apache, verze 2.0</a>\nDomovská stránka: <a href="https://bined.exbin.org/android ">https://bined.exbin.org/android</a></string>
<string name="app_about">Název: BinEd binární/hexadecimální editor\nVerze: 0.2.1\nDodavatel: <a href="https://exbin.org">Projekt ExBin</a>\nLicence: <a href="https://www.apache.org/licenses/LICENSE-2.0">Licence Apache, verze 2.0</a>\nDomovská stránka: <a href="https://bined.exbin.org/android ">https://bined.exbin.org/android</a></string>
<string name="bined_logo_description">Logo BinEd</string>
<string name="title_activity_settings">Nastavení</string>
+1 -1
View File
@@ -1,6 +1,6 @@
<resources>
<string name="app_name">BinEd</string>
<string name="app_about">Name: BinEd - Binary/Hex Editor\nVersion: 0.2.1-SNAPSHOT\nVendor: <a href="https://exbin.org">ExBin Project</a>\nLicense: <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>\nHomepage: <a href="https://bined.exbin.org/android">https://bined.exbin.org/android</a></string>
<string name="app_about">Name: BinEd - Binary/Hex Editor\nVersion: 0.2.1\nVendor: <a href="https://exbin.org">ExBin Project</a>\nLicense: <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>\nHomepage: <a href="https://bined.exbin.org/android">https://bined.exbin.org/android</a></string>
<string name="bined_logo_description">BinEd Logo</string>
<!-- Actions & menu -->
+1 -1
View File
@@ -1,4 +1,4 @@
0.2.1
0.2.1 (2024-09-27)
- Basic support for selection / clipboard
- Changed file dialog
- Added settings and preferences
@@ -1,2 +1,2 @@
* Initial release
* Limited functionality
- Initial release
- Limited functionality
@@ -0,0 +1,5 @@
- Basic support for selection / clipboard
- Changed file dialog
- Added settings and preferences
- Added dark theme and language switching
- Added menu icons
@@ -5,10 +5,10 @@ App is currently beta with limited functionality.
Features
--------
* Visualize data as numerical (hexadecimal) codes and text representation
* Codes can be also binary, octal or decimal
* Support for Unicode, UTF-8 and other charsets
* Insert and overwrite edit modes
* TODO: Searching for text / hexadecimal code with matching highlighting
* Support for undo/redo
* TODO: Support for files with size up to exabytes
- Visualize data as numerical (hexadecimal) codes and text representation
- Codes can be also binary, octal or decimal
- Support for Unicode, UTF-8 and other charsets
- Insert and overwrite edit modes
- TODO: Searching for text / hexadecimal code with matching highlighting
- Support for undo/redo
- TODO: Support for files with size up to exabytes
Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

After

Width:  |  Height:  |  Size: 433 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 KiB

+1 -1
View File
@@ -20,4 +20,4 @@ android.useAndroidX=true
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
android.enableJetifier=false
android.nonFinalResIds=false
android.nonFinalResIds=true