From f222c3732a0ff1a3de661d392a08746ba789cf9d Mon Sep 17 00:00:00 2001 From: AbdurazaaqMohammed Date: Fri, 3 Jul 2026 00:55:42 -0400 Subject: [PATCH 1/5] Create .gitignore --- .gitignore | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0a9dea4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties +/local.properties + +# Log/OS Files +*.log + +# Android Studio generated files and folders +captures/ +.externalNativeBuild/ +.cxx/ +*.apk +output.json + +# IntelliJ +*.iml +.idea/ +misc.xml +deploymentTargetDropDown.xml +render.experimental.xml + +# Keystore files +*.jks +*.keystore + +# Google Services (e.g. APIs or Firebase) +google-services.json + +# Android Profiling +*.hprof \ No newline at end of file From d55d62b37ce96f8f5ac0e053937cef379499738c Mon Sep 17 00:00:00 2001 From: AbdurazaaqMohammed Date: Fri, 3 Jul 2026 01:39:28 -0400 Subject: [PATCH 2/5] Expand StringAdapter to implement functions in strings tab --- .../hub/dexeditor/adapter/StringAdapter.java | 95 +++++++++++++++++-- 1 file changed, 87 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/modder/hub/dexeditor/adapter/StringAdapter.java b/app/src/main/java/modder/hub/dexeditor/adapter/StringAdapter.java index 1c13c36..6466b74 100644 --- a/app/src/main/java/modder/hub/dexeditor/adapter/StringAdapter.java +++ b/app/src/main/java/modder/hub/dexeditor/adapter/StringAdapter.java @@ -35,24 +35,43 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; + import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; + +import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; + import modder.hub.dexeditor.R; + /* * Author - @developer-krushna * this class responsible for listing strings from dex files */ public class StringAdapter extends RecyclerView.Adapter { - private List strings; - private OnStringClickListener listener; + + private static final int COLOR_MODIFIED = 0xFF2E7D32; // green + private static final int COLOR_NORMAL = 0xFF000000; + + // Full, unfiltered dataset - kept as a reference to the activity's backing list + private final List allStrings; + // Subset currently shown (equals allStrings when no filter is active) + private List displayedStrings; + // original string -> pending new value (not yet applied to the dex classes) + private final Map modifiedStrings = new LinkedHashMap<>(); + + private final OnStringClickListener listener; + private String currentFilter = null; public interface OnStringClickListener { void onStringClick(String text); } public StringAdapter(List strings, OnStringClickListener listener) { - this.strings = strings; + this.allStrings = strings; + this.displayedStrings = strings; this.listener = listener; } @@ -65,26 +84,86 @@ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { - final String text = strings.get(position); - holder.stringText.setText(text); + final String original = displayedStrings.get(position); + final boolean isModified = modifiedStrings.containsKey(original); + final String displayText = isModified ? modifiedStrings.get(original) : original; + + holder.stringText.setText(displayText); + holder.stringText.setTextColor(isModified ? COLOR_MODIFIED : COLOR_NORMAL); + holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - if (listener != null) listener.onStringClick(text); + if (listener != null) listener.onStringClick(original); } }); } @Override public int getItemCount() { - return strings.size(); + return displayedStrings.size(); + } + + public void refresh() { + applyFilter(currentFilter); + } + + public void setFilter(String query) { + currentFilter = (query == null || query.trim().isEmpty()) ? null : query.trim(); + applyFilter(currentFilter); + } + + public String getCurrentFilter() { + return currentFilter; + } + + private void applyFilter(String query) { + if (query == null) { + displayedStrings = allStrings; + } else { + String lower = query.toLowerCase(); + List filtered = new ArrayList<>(); + for (String s : allStrings) { + if (s != null && s.toLowerCase().contains(lower)) filtered.add(s); + } + displayedStrings = filtered; + } + notifyDataSetChanged(); + } + + public void markModified(String original, String newValue) { + if (newValue == null || newValue.equals(original)) { + modifiedStrings.remove(original); + } else { + modifiedStrings.put(original, newValue); + } + notifyDataSetChanged(); + } + + public String getPendingValue(String original) { + String v = modifiedStrings.get(original); + return v != null ? v : original; + } + + public boolean hasModifications() { + return !modifiedStrings.isEmpty(); + } + + public Map getModifiedStrings() { + return modifiedStrings; + } + + public void clearModifications() { + modifiedStrings.clear(); + notifyDataSetChanged(); } static class ViewHolder extends RecyclerView.ViewHolder { TextView stringText; + ViewHolder(View itemView) { super(itemView); stringText = itemView.findViewById(R.id.string_text); } } -} +} \ No newline at end of file From 0782955180fab0f0cb2aaa727dc859b5dab9ecc0 Mon Sep 17 00:00:00 2001 From: AbdurazaaqMohammed Date: Fri, 3 Jul 2026 01:39:48 -0400 Subject: [PATCH 3/5] Add icons and layout for strings tab --- .../main/res/drawable/check_circle_24px.xml | 10 +++ app/src/main/res/drawable/filter_alt_24px.xml | 10 +++ app/src/main/res/drawable/refresh_24px.xml | 10 +++ .../res/layout/string_replace_all_dialog.xml | 46 ++++++++++++++ app/src/main/res/layout/strings_header.xml | 62 +++++++++++++++++++ 5 files changed, 138 insertions(+) create mode 100644 app/src/main/res/drawable/check_circle_24px.xml create mode 100644 app/src/main/res/drawable/filter_alt_24px.xml create mode 100644 app/src/main/res/drawable/refresh_24px.xml create mode 100644 app/src/main/res/layout/string_replace_all_dialog.xml create mode 100644 app/src/main/res/layout/strings_header.xml diff --git a/app/src/main/res/drawable/check_circle_24px.xml b/app/src/main/res/drawable/check_circle_24px.xml new file mode 100644 index 0000000..de8ae75 --- /dev/null +++ b/app/src/main/res/drawable/check_circle_24px.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/filter_alt_24px.xml b/app/src/main/res/drawable/filter_alt_24px.xml new file mode 100644 index 0000000..0afa9b5 --- /dev/null +++ b/app/src/main/res/drawable/filter_alt_24px.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/refresh_24px.xml b/app/src/main/res/drawable/refresh_24px.xml new file mode 100644 index 0000000..f4302a5 --- /dev/null +++ b/app/src/main/res/drawable/refresh_24px.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/string_replace_all_dialog.xml b/app/src/main/res/layout/string_replace_all_dialog.xml new file mode 100644 index 0000000..3b02548 --- /dev/null +++ b/app/src/main/res/layout/string_replace_all_dialog.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/strings_header.xml b/app/src/main/res/layout/strings_header.xml new file mode 100644 index 0000000..d5be5ab --- /dev/null +++ b/app/src/main/res/layout/strings_header.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + \ No newline at end of file From 22712fe029e7e8057a665b26094e896236afde26 Mon Sep 17 00:00:00 2001 From: AbdurazaaqMohammed Date: Fri, 3 Jul 2026 01:40:41 -0400 Subject: [PATCH 4/5] Add functionality in strings tab --- .../dexeditor/activity/DexEditorActivity.java | 270 +++++++++++++++++- .../dexeditor/fragment/SearchFragment.java | 22 +- 2 files changed, 283 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/modder/hub/dexeditor/activity/DexEditorActivity.java b/app/src/main/java/modder/hub/dexeditor/activity/DexEditorActivity.java index d5d5f17..33e59a5 100644 --- a/app/src/main/java/modder/hub/dexeditor/activity/DexEditorActivity.java +++ b/app/src/main/java/modder/hub/dexeditor/activity/DexEditorActivity.java @@ -78,8 +78,10 @@ import androidx.viewpager2.adapter.FragmentStateAdapter; import androidx.viewpager2.widget.ViewPager2; +import com.android.tools.smali.dexlib2.iface.ClassDef; import com.android.tools.smali.smali.SmaliOptions; import com.android.tools.smali.smali2.Smali; +import com.google.android.material.checkbox.MaterialCheckBox; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.tabs.TabLayout; @@ -87,8 +89,13 @@ import java.io.File; import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import io.github.rosemoe.sora.text.Content; import io.github.rosemoe.sora.text.Cursor; @@ -146,6 +153,7 @@ public class DexEditorActivity extends AppCompatActivity { public int dexVersion; public List searchNodes = new ArrayList<>(); public String pendingSearchPath = null; + public String pendingStringSearchQuery = null; public TabsAdapter tabsAdapter; private boolean needsModifiedTreeRebuild = true; private boolean needsExplorerRefresh = false; @@ -433,7 +441,7 @@ public void run() { } } - private void loadStrings() { + public void loadStrings() { if (classTree == null) return; showProcessingProgress(true); new Thread(new Runnable() { @@ -1920,6 +1928,13 @@ public void updateUI() { // For History/Modified tab, we need to be careful. // If we use ConcatAdapter, we might need to update sub-adapters. // But for now, let's just fall through if position is 1. + + // Get string adapter from ConcatAdapter of strings tab + List> adapters = ((ConcatAdapter) currentAdapter).getAdapters(); + if(adapters.size() > 1) { + RecyclerView.Adapter adapter = adapters.get(1); + if (adapter instanceof StringAdapter) adapter.notifyDataSetChanged(); + } } else { currentAdapter.notifyDataSetChanged(); } @@ -2074,12 +2089,23 @@ public void onLocate(TreeNode node) { }, true); break; case 3: - currentAdapter = new StringAdapter(activity.stringList, new modder.hub.dexeditor.adapter.StringAdapter.OnStringClickListener() { - @Override - public void onStringClick(String text) { - // TO-DO - } - }); + View header = LayoutInflater.from(getContext()).inflate(R.layout.strings_header, rv, false); + + // holder trick so the click listener can reference the adapter it belongs to + final StringAdapter[] holder = new StringAdapter[1]; + StringAdapter stringAdapter = new StringAdapter(activity.stringList, text -> activity.showStringEditDialog(holder[0], header.findViewById(R.id.btn_strings_apply), text)); + holder[0] = stringAdapter; + currentAdapter = new ConcatAdapter(new SearchFragment.HeaderViewAdapter(header), stringAdapter); + + /*header.findViewById(R.id.btn_strings_reload).setOnClickListener(v -> { + stringAdapter.clearModifications(); + stringAdapter.setFilter(null); + btnApply.setVisibility(View.GONE); + activity.loadStrings(); + });*/ // It doesnt look like reload working maybe whole loadStrings implementation would need to change to get it to work + header.findViewById(R.id.btn_strings_filter).setOnClickListener(v -> activity.showStringFilterDialog(stringAdapter)); + header.findViewById(R.id.btn_strings_replace).setOnClickListener(v -> activity.showStringReplaceAllDialog()); + header.findViewById(R.id.btn_strings_apply).setOnClickListener(v -> activity.applyStringChanges(stringAdapter, header.findViewById(R.id.btn_strings_apply))); break; } if (currentAdapter != null) { @@ -2088,6 +2114,104 @@ public void onStringClick(String text) { } } + public void showStringEditDialog(final StringAdapter adapter, final View btnApply, final String original) { + final EditText editText = new EditText(this); + editText.setText(adapter.getPendingValue(original)); + editText.setSelection(editText.getText().length()); + ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + editText.setLayoutParams(params); + editText.setGravity(android.view.Gravity.TOP); + + int pad = (int) getDip(16); + LinearLayout container = new LinearLayout(this); + container.setOrientation(LinearLayout.VERTICAL); + container.setPadding(pad, pad, pad, pad); + container.addView(editText); + container.setLayoutParams(params); + + final AlertDialog dialog = new MaterialAlertDialogBuilder(this) + .setTitle("Edit string") + .setView(container) + .setPositiveButton("OK", null) + .setNeutralButton("Search", null) + .setNegativeButton("Cancel", null) + .create(); + dialog.show(); + + // Custom click listeners so "Search" doesn't auto-dismiss before we can read the field. + dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> { + String newValue = editText.getText().toString(); + adapter.markModified(original, newValue); + btnApply.setVisibility(adapter.hasModifications() ? View.VISIBLE : View.GONE); + dialog.dismiss(); + }); + dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(v -> { + dialog.dismiss(); + searchStringInClasses(original); + }); + } + + public void showStringFilterDialog(final StringAdapter adapter) { + final EditText editText = new EditText(this); + ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + editText.setLayoutParams(params); + editText.setHint("Type to filter..."); + if (adapter.getCurrentFilter() != null) editText.setText(adapter.getCurrentFilter()); + + int pad = (int) getDip(16); + LinearLayout container = new LinearLayout(this); + container.setPadding(pad, pad, pad, pad); + container.setLayoutParams(params); + container.addView(editText); + + new MaterialAlertDialogBuilder(this) + .setTitle("Filter strings") + .setView(container) + .setPositiveButton("Apply", (d, w) -> adapter.setFilter(editText.getText().toString())) + .setNegativeButton("Clear", (d, w) -> adapter.setFilter(null)) + .show(); + } + + public void showStringReplaceAllDialog() { + View container = LayoutInflater.from(this).inflate(R.layout.string_replace_all_dialog, null); + TextView etFind = container.findViewById(R.id.etFind), etReplace = container.findViewById(R.id.etReplace); + MaterialCheckBox swMatchCase = container.findViewById(R.id.swMatchCase); + + new MaterialAlertDialogBuilder(this) + .setTitle("Replace in all strings") + .setView(container) + .setPositiveButton("Replace", (d, w) -> { + String find = etFind.getText().toString(); + String replace = etReplace.getText().toString(); + if (find.isEmpty()) return; + new StringBatchTask(this, null, find, replace, swMatchCase.isChecked(), null).start(); + }) + .setNegativeButton("Cancel", null) + .show(); + } + + public void applyStringChanges(final StringAdapter adapter, final View btnApply) { + final Map changes = new LinkedHashMap<>(adapter.getModifiedStrings()); + if (changes.isEmpty()) return; + new StringBatchTask(this, changes, null, null, true, () -> { + adapter.clearModifications(); + btnApply.setVisibility(View.GONE); + loadStrings(); + }).start(); + } + + public void searchStringInClasses(String query) { + if (explorerViewPager == null) return; + explorerViewPager.setCurrentItem(2, true); + Fragment f = getSupportFragmentManager().findFragmentByTag("f2002"); + if (f instanceof SearchFragment) { + ((SearchFragment) f).runStringSearch(query); + } else { + // Fragment not created/attached yet - SearchFragment.onResume() will pick this up. + pendingStringSearchQuery = query; + } + } + private static class ExplorerTabAdapter extends FragmentStateAdapter { public ExplorerTabAdapter(@NonNull AppCompatActivity activity) { super(activity); @@ -2189,6 +2313,138 @@ public void onClick(DialogInterface dialog, int which) { } } + private static class StringBatchTask { + private final java.lang.ref.WeakReference activityRef; + private final Map exactReplacements; + private final String findSubstring; + private final String replaceSubstring; + private final boolean matchCase; + private final Runnable onDone; + private final Handler mainHandler = new Handler(Looper.getMainLooper()); + private AlertProgress progressDialog; + private volatile boolean isStopped = false; + + StringBatchTask(DexEditorActivity activity, Map exactReplacements, + String findSubstring, String replaceSubstring, boolean matchCase, Runnable onDone) { + this.activityRef = new java.lang.ref.WeakReference<>(activity); + this.exactReplacements = exactReplacements; + this.findSubstring = findSubstring; + this.replaceSubstring = replaceSubstring; + this.matchCase = matchCase; + this.onDone = onDone; + } + + void start() { + final DexEditorActivity activity = activityRef.get(); + if (activity == null || classTree == null) return; + + progressDialog = new AlertProgress(activity); + progressDialog.setTitle("Applying changes..."); + progressDialog.setCancelable(false); + progressDialog.setOnCancelListener(() -> isStopped = true); + progressDialog.show(); + + final Map openTabsContent = new HashMap<>(); + for (int i = 0; i < tabs.size(); i++) { + EditorTab tab = tabs.get(i); + if (tab.type == 0) { + EditorFragment ef = activity.getFragmentAtIndex(i); + if (ef != null && ef.getEditor() != null) { + openTabsContent.put(tab.className, ef.getEditor().getText().toString()); + } else { + openTabsContent.put(tab.className, tab.content); + } + } + } + + new Thread(() -> { + List classes = new ArrayList<>(classTree.classMap.values()); + int total = classes.size(); + int processed = 0, replacedCount = 0, affectedClasses = 0; + final Map updatedTabs = new HashMap<>(); + Pattern literalPattern = Pattern.compile("\"((?:\\\\.|[^\"\\\\])*)\""); + + for (ClassDef classDef : classes) { + if (isStopped) break; + String fullType = classDef.getType(); + String className = fullType.substring(1, fullType.length() - 1); + try { + String original = openTabsContent.containsKey(className) ? openTabsContent.get(className) : classTree.getSmaliByType(classDef); + + Matcher m = literalPattern.matcher(original); + StringBuffer sb = new StringBuffer(); + int countInClass = 0; + while (m.find()) { + String literal = m.group(1); + String replaced = applyRules(literal); + if (!replaced.equals(literal)) countInClass++; + m.appendReplacement(sb, Matcher.quoteReplacement("\"" + replaced + "\"")); + } + m.appendTail(sb); + + if (countInClass > 0) { + String modified = sb.toString(); + try { + ClassDef newDef = Smali.assemble(modified, new SmaliOptions(), activity.dexVersion); + classTree.saveClassDef(newDef); + } catch (Exception e) { + classTree.saveSmali(className, modified); + } + replacedCount += countInClass; + affectedClasses++; + if (openTabsContent.containsKey(className)) updatedTabs.put(className, modified); + } + } catch (Exception ignored) { + } + + processed++; + final int fp = processed, ft = total; + mainHandler.post(() -> { + if (progressDialog != null && progressDialog.isShowing()) progressDialog.setProgress(fp, ft); + }); + } + + final int finalReplaced = replacedCount, finalAffected = affectedClasses; + mainHandler.post(() -> { + if (progressDialog != null && progressDialog.isShowing()) progressDialog.dismiss(); + if (!updatedTabs.isEmpty()) { + for (Map.Entry e : updatedTabs.entrySet()) { + for (int i = 0; i < tabs.size(); i++) { + EditorTab tab = tabs.get(i); + if (tab.className.equals(e.getKey()) && tab.type == 0) { + tab.content = e.getValue(); + EditorFragment ef = activity.getFragmentAtIndex(i); + if (ef != null && ef.getEditor() != null) ef.getEditor().setText(e.getValue()); + } + } + } + } + Notify_MT.Notify(activity, "Info", "Replaced " + finalReplaced + " occurrence(s) in " + finalAffected + " class(es).", "Close"); + isChanged = true; + activity.needsModifiedTreeRebuild = true; + activity.refreshExplorerPage(1); + if (onDone != null) onDone.run(); + }); + }).start(); + } + + private String applyRules(String literal) { + if (exactReplacements != null) { + String rep = exactReplacements.get(literal); + if (rep != null) return rep; // exact whole-literal match (used by "Apply changes") + } + if (findSubstring != null && !findSubstring.isEmpty()) { + if (matchCase) { + return literal.replace(findSubstring, replaceSubstring); + } else { + Pattern p = Pattern.compile(Pattern.quote(findSubstring), Pattern.CASE_INSENSITIVE); + return p.matcher(literal).replaceAll(Matcher.quoteReplacement(replaceSubstring)); + } + } + return literal; + } + } + private class SaveAndExitClickListener implements DialogInterface.OnClickListener { private volatile boolean isStopped = false; diff --git a/app/src/main/java/modder/hub/dexeditor/fragment/SearchFragment.java b/app/src/main/java/modder/hub/dexeditor/fragment/SearchFragment.java index 11cc542..4c45579 100644 --- a/app/src/main/java/modder/hub/dexeditor/fragment/SearchFragment.java +++ b/app/src/main/java/modder/hub/dexeditor/fragment/SearchFragment.java @@ -223,6 +223,11 @@ public void onResume() { activity.pendingSearchPath = null; showSearchDialogWithPath(path); } + if (activity != null && activity.pendingStringSearchQuery != null) { + String q = activity.pendingStringSearchQuery; + activity.pendingStringSearchQuery = null; + runStringSearch(q); + } } public void refreshUI() { @@ -236,9 +241,22 @@ public void showSearchDialogWithPath(String path) { showSearchDialog(false, path); } - private static class HeaderViewAdapter extends RecyclerView.Adapter { + public void runStringSearch(String query) { + lastSearchQuery = query; + lastSearchType = "String"; + lastMatchCase = true; + lastIsRegex = false; + lastExactlyMatch = false; + searchResults.clear(); + currentQuery = null; + if (adapter != null) adapter.refreshVisibleNodes(); + updateUIState(); + new SearchTask(this, query, "/", "String", true, true, false, false, false, null, false).start(); + } + + public static class HeaderViewAdapter extends RecyclerView.Adapter { private final View view; - HeaderViewAdapter(View view) { + public HeaderViewAdapter(View view) { this.view = view; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { From 810247f4d62253dbde0f353ad4e41e91792dc0c8 Mon Sep 17 00:00:00 2001 From: AbdurazaaqMohammed Date: Fri, 3 Jul 2026 01:47:26 -0400 Subject: [PATCH 5/5] use xml and material edittext --- .../dexeditor/activity/DexEditorActivity.java | 24 ++++--------------- .../main/res/layout/string_edit_dialog.xml | 22 +++++++++++++++++ 2 files changed, 26 insertions(+), 20 deletions(-) create mode 100644 app/src/main/res/layout/string_edit_dialog.xml diff --git a/app/src/main/java/modder/hub/dexeditor/activity/DexEditorActivity.java b/app/src/main/java/modder/hub/dexeditor/activity/DexEditorActivity.java index 33e59a5..f5de4b7 100644 --- a/app/src/main/java/modder/hub/dexeditor/activity/DexEditorActivity.java +++ b/app/src/main/java/modder/hub/dexeditor/activity/DexEditorActivity.java @@ -2115,19 +2115,10 @@ public void onLocate(TreeNode node) { } public void showStringEditDialog(final StringAdapter adapter, final View btnApply, final String original) { - final EditText editText = new EditText(this); + View container = LayoutInflater.from(this).inflate(R.layout.string_edit_dialog, null); + final EditText editText = container.findViewById(R.id.string_edit_text); editText.setText(adapter.getPendingValue(original)); editText.setSelection(editText.getText().length()); - ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - editText.setLayoutParams(params); - editText.setGravity(android.view.Gravity.TOP); - - int pad = (int) getDip(16); - LinearLayout container = new LinearLayout(this); - container.setOrientation(LinearLayout.VERTICAL); - container.setPadding(pad, pad, pad, pad); - container.addView(editText); - container.setLayoutParams(params); final AlertDialog dialog = new MaterialAlertDialogBuilder(this) .setTitle("Edit string") @@ -2152,18 +2143,11 @@ public void showStringEditDialog(final StringAdapter adapter, final View btnAppl } public void showStringFilterDialog(final StringAdapter adapter) { - final EditText editText = new EditText(this); - ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - editText.setLayoutParams(params); + View container = LayoutInflater.from(this).inflate(R.layout.string_edit_dialog, null); + TextView editText = container.findViewById(R.id.string_edit_text); editText.setHint("Type to filter..."); if (adapter.getCurrentFilter() != null) editText.setText(adapter.getCurrentFilter()); - int pad = (int) getDip(16); - LinearLayout container = new LinearLayout(this); - container.setPadding(pad, pad, pad, pad); - container.setLayoutParams(params); - container.addView(editText); - new MaterialAlertDialogBuilder(this) .setTitle("Filter strings") .setView(container) diff --git a/app/src/main/res/layout/string_edit_dialog.xml b/app/src/main/res/layout/string_edit_dialog.xml new file mode 100644 index 0000000..5271407 --- /dev/null +++ b/app/src/main/res/layout/string_edit_dialog.xml @@ -0,0 +1,22 @@ + + + + + + + + \ No newline at end of file