Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -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
254 changes: 247 additions & 7 deletions app/src/main/java/modder/hub/dexeditor/activity/DexEditorActivity.java

Large diffs are not rendered by default.

95 changes: 87 additions & 8 deletions app/src/main/java/modder/hub/dexeditor/adapter/StringAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<StringAdapter.ViewHolder> {
private List<String> 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<String> allStrings;
// Subset currently shown (equals allStrings when no filter is active)
private List<String> displayedStrings;
// original string -> pending new value (not yet applied to the dex classes)
private final Map<String, String> modifiedStrings = new LinkedHashMap<>();

private final OnStringClickListener listener;
private String currentFilter = null;

public interface OnStringClickListener {
void onStringClick(String text);
}

public StringAdapter(List<String> strings, OnStringClickListener listener) {
this.strings = strings;
this.allStrings = strings;
this.displayedStrings = strings;
this.listener = listener;
}

Expand All @@ -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<String> 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<String, String> 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);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -236,9 +241,22 @@ public void showSearchDialogWithPath(String path) {
showSearchDialog(false, path);
}

private static class HeaderViewAdapter extends RecyclerView.Adapter<HeaderViewAdapter.ViewHolder> {
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<HeaderViewAdapter.ViewHolder> {
private final View view;
HeaderViewAdapter(View view) {
public HeaderViewAdapter(View view) {
this.view = view;
}
@NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/res/drawable/check_circle_24px.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M424,664L706,382L650,326L424,552L310,438L254,494L424,664ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880Z"/>
</vector>
10 changes: 10 additions & 0 deletions app/src/main/res/drawable/filter_alt_24px.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M440,800Q423,800 411.5,788.5Q400,777 400,760L400,520L168,224Q153,204 163.5,182Q174,160 200,160L760,160Q786,160 796.5,182Q807,204 792,224L560,520L560,760Q560,777 548.5,788.5Q537,800 520,800L440,800ZM480,492L678,240L282,240L480,492ZM480,492L480,492L480,492Z"/>
</vector>
10 changes: 10 additions & 0 deletions app/src/main/res/drawable/refresh_24px.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M480,800Q346,800 253,707Q160,614 160,480Q160,346 253,253Q346,160 480,160Q549,160 612,188.5Q675,217 720,270L720,160L800,160L800,440L520,440L520,360L688,360Q656,304 600.5,272Q545,240 480,240Q380,240 310,310Q240,380 240,480Q240,580 310,650Q380,720 480,720Q557,720 619,676Q681,632 706,560L790,560Q762,666 676,733Q590,800 480,800Z"/>
</vector>
22 changes: 22 additions & 0 deletions app/src/main/res/layout/string_edit_dialog.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">

<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:hintEnabled="false">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/string_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:gravity="top"/>

</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
46 changes: 46 additions & 0 deletions app/src/main/res/layout/string_replace_all_dialog.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilFind"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:hintEnabled="true">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etFind"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Find" />
</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilReplace"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:hintEnabled="true"
android:layout_marginTop="8dp">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etReplace"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Replace with" />
</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/swMatchCase"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Match case"
android:checked="false" />

</LinearLayout>
62 changes: 62 additions & 0 deletions app/src/main/res/layout/strings_header.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">

<!-- <com.google.android.material.button.MaterialButton
android:id="@+id/btn_strings_reload"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="start"
android:background="?attr/selectableItemBackground"
android:text="Reload"
android:textSize="13sp"
android:textColor="?attr/colorOnSurface"
app:iconTint="?attr/colorOnSurface"
app:icon="@drawable/refresh_24px" /> -->

<com.google.android.material.button.MaterialButton
android:id="@+id/btn_strings_filter"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="start"
android:background="?attr/selectableItemBackground"
android:textColor="?attr/colorOnSurface"
app:iconTint="?attr/colorOnSurface"
app:icon="@drawable/filter_alt_24px"
android:text="Filter"
android:textSize="13sp" />

<com.google.android.material.button.MaterialButton
android:id="@+id/btn_strings_replace"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="start"
android:background="?attr/selectableItemBackground"
android:text="@string/sora_editor_replace"
android:textColor="?attr/colorOnSurface"
app:iconTint="?attr/colorOnSurface"
app:icon="@drawable/ic_search_replace"
android:textSize="13sp"/>

<com.google.android.material.button.MaterialButton
android:id="@+id/btn_strings_apply"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="start"
android:background="?attr/selectableItemBackground"
android:text="Apply changes"
android:textSize="13sp"
android:textStyle="bold"
android:textColor="?attr/colorOnSurface"
app:iconTint="?attr/colorOnSurface"
app:icon="@drawable/check_circle_24px"
android:visibility="gone" />
</LinearLayout>