Skip to content

Commit d8d1152

Browse files
committed
feat: Implement global search and enhance deleted message recovery with original timestamp display and improved UI.
1 parent 41ae377 commit d8d1152

22 files changed

Lines changed: 1456 additions & 954 deletions

app/src/main/java/com/wmods/wppenhacer/UpdateChecker.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
public class UpdateChecker implements Runnable {
2424

2525
private static final String TAG = "WAE_UpdateChecker";
26-
private static final String LATEST_RELEASE_API = "https://api.github.com/repos/mubashardev/WaEnhancer/releases/latest";
26+
private static final String LATEST_RELEASE_API = "https://api.github.com/repos/Dev4Mod/WaEnhancer/releases/latest";
2727
private static final String RELEASE_TAG_PREFIX = "debug-";
28-
private static final String TELEGRAM_UPDATE_URL = "https://github.com/mubashardev/WaEnhancer/releases";
28+
private static final String TELEGRAM_UPDATE_URL = "https://github.com/Dev4Mod/WaEnhancer/releases";
2929

3030
// Singleton OkHttpClient - expensive to create, reuse across all checks
3131
private static OkHttpClient httpClient;

app/src/main/java/com/wmods/wppenhacer/activities/AboutActivity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
2727
binding.btnGithub.setOnClickListener(view -> {
2828
Intent intent = new Intent();
2929
intent.setAction(Intent.ACTION_VIEW);
30-
intent.setData(Uri.parse("https://github.com/mubashardev/WaEnhancer"));
30+
intent.setData(Uri.parse("https://github.com/Dev4Mod/WaEnhancer"));
3131
startActivity(intent);
3232
});
3333
binding.btnDonate.setOnClickListener(view -> {

app/src/main/java/com/wmods/wppenhacer/activities/MessageListActivity.java

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ protected void onCreate(Bundle savedInstanceState) {
5151
delMessageStore = DelMessageStore.getInstance(this);
5252
adapter = new MessageListAdapter(this);
5353

54-
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
54+
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
55+
layoutManager.setStackFromEnd(true);
56+
binding.recyclerView.setLayoutManager(layoutManager);
5557
binding.recyclerView.setAdapter(adapter);
5658

5759
loadMessages();
@@ -68,6 +70,7 @@ private void loadMessages() {
6870
binding.emptyView.setVisibility(View.GONE);
6971
binding.recyclerView.setVisibility(View.VISIBLE);
7072
adapter.setMessages(messages);
73+
binding.recyclerView.scrollToPosition(messages.size() - 1);
7174
}
7275
});
7376
}).start();
@@ -104,8 +107,97 @@ public boolean onOptionsItemSelected(MenuItem item) {
104107
return super.onOptionsItemSelected(item);
105108
}
106109

110+
private androidx.appcompat.view.ActionMode actionMode;
111+
private final androidx.appcompat.view.ActionMode.Callback actionModeCallback = new androidx.appcompat.view.ActionMode.Callback() {
112+
@Override
113+
public boolean onCreateActionMode(androidx.appcompat.view.ActionMode mode, android.view.Menu menu) {
114+
mode.getMenuInflater().inflate(R.menu.menu_context_delete, menu);
115+
return true;
116+
}
117+
118+
@Override
119+
public boolean onPrepareActionMode(androidx.appcompat.view.ActionMode mode, android.view.Menu menu) {
120+
return false;
121+
}
122+
123+
@Override
124+
public boolean onActionItemClicked(androidx.appcompat.view.ActionMode mode, android.view.MenuItem item) {
125+
if (item.getItemId() == R.id.action_delete) {
126+
deleteSelectedMessages();
127+
mode.finish();
128+
return true;
129+
}
130+
return false;
131+
}
132+
133+
@Override
134+
public void onDestroyActionMode(androidx.appcompat.view.ActionMode mode) {
135+
adapter.clearSelection();
136+
actionMode = null;
137+
}
138+
};
139+
140+
private void deleteSelectedMessages() {
141+
List<String> selected = adapter.getSelectedItems();
142+
if (selected.isEmpty())
143+
return;
144+
145+
new androidx.appcompat.app.AlertDialog.Builder(this)
146+
.setTitle("Delete Messages?")
147+
.setMessage("Are you sure you want to delete " + selected.size() + " message(s)?")
148+
.setPositiveButton("Delete", (dialog, which) -> {
149+
new Thread(() -> {
150+
delMessageStore.deleteMessages(selected);
151+
runOnUiThread(() -> {
152+
loadMessages();
153+
Toast.makeText(this, "Messages deleted", Toast.LENGTH_SHORT).show();
154+
});
155+
}).start();
156+
})
157+
.setNegativeButton("Cancel", null)
158+
.show();
159+
}
160+
107161
@Override
108162
public void onRestoreClick(DeletedMessage message) {
109-
Toast.makeText(this, "Restore feature coming soon!", Toast.LENGTH_SHORT).show();
163+
com.google.android.material.bottomsheet.BottomSheetDialog bottomSheetDialog = new com.google.android.material.bottomsheet.BottomSheetDialog(
164+
this);
165+
View sheetView = getLayoutInflater().inflate(R.layout.layout_restore_coming_soon, null);
166+
bottomSheetDialog.setContentView(sheetView);
167+
168+
sheetView.findViewById(R.id.btn_follow_dev).setOnClickListener(v -> {
169+
android.content.Intent intent = new android.content.Intent(android.content.Intent.ACTION_VIEW);
170+
intent.setData(android.net.Uri.parse("https://github.com/mubashardev"));
171+
startActivity(intent);
172+
bottomSheetDialog.dismiss();
173+
});
174+
175+
bottomSheetDialog.show();
176+
}
177+
178+
@Override
179+
public boolean onItemLongClick(DeletedMessage message) {
180+
if (actionMode == null) {
181+
actionMode = startSupportActionMode(actionModeCallback);
182+
}
183+
toggleSelection(message.getKeyId());
184+
return true;
185+
}
186+
187+
@Override
188+
public void onItemClick(DeletedMessage message) {
189+
if (actionMode != null) {
190+
toggleSelection(message.getKeyId());
191+
}
192+
}
193+
194+
private void toggleSelection(String keyId) {
195+
adapter.toggleSelection(keyId);
196+
int count = adapter.getSelectedCount();
197+
if (count == 0) {
198+
actionMode.finish();
199+
} else {
200+
actionMode.setTitle(count + " selected");
201+
}
110202
}
111203
}

app/src/main/java/com/wmods/wppenhacer/activities/SearchActivity.java

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,85 +23,85 @@
2323
* Activity for searching and navigating to app features.
2424
*/
2525
public class SearchActivity extends BaseActivity implements SearchAdapter.OnFeatureClickListener {
26-
26+
2727
private ActivitySearchBinding binding;
2828
private SearchAdapter adapter;
29-
29+
3030
@Override
3131
protected void onCreate(Bundle savedInstanceState) {
3232
super.onCreate(savedInstanceState);
33-
33+
3434
binding = ActivitySearchBinding.inflate(getLayoutInflater());
3535
setContentView(binding.getRoot());
36-
36+
3737
// Setup toolbar
3838
setSupportActionBar(binding.toolbar);
3939
if (getSupportActionBar() != null) {
4040
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
4141
getSupportActionBar().setTitle(R.string.search_features_title);
4242
}
43-
43+
4444
// Setup RecyclerView
4545
adapter = new SearchAdapter(this);
4646
binding.searchResults.setLayoutManager(new LinearLayoutManager(this));
4747
binding.searchResults.setAdapter(adapter);
48-
48+
4949
// Setup search input
5050
setupSearchInput();
51-
51+
5252
// Show all features by default (grouped by category)
5353
loadAllFeatures();
54-
54+
5555
// Focus on search input
5656
binding.searchInput.requestFocus();
5757
}
58-
58+
5959
private void setupSearchInput() {
6060
binding.searchInput.addTextChangedListener(new TextWatcher() {
6161
@Override
6262
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
6363
}
64-
64+
6565
@Override
6666
public void onTextChanged(CharSequence s, int start, int before, int count) {
6767
performSearch(s.toString());
6868
}
69-
69+
7070
@Override
7171
public void afterTextChanged(Editable s) {
7272
}
7373
});
7474
}
75-
75+
7676
private void loadAllFeatures() {
7777
List<SearchableFeature> allFeatures = FeatureCatalog.getAllFeatures(this);
7878
adapter.setFeatures(allFeatures);
7979
adapter.setSearchQuery("");
8080
updateEmptyState(false, "");
8181
}
82-
82+
8383
private void performSearch(String query) {
8484
if (query.trim().isEmpty()) {
8585
// Show all features when search is empty
8686
loadAllFeatures();
8787
return;
8888
}
89-
89+
9090
// Search features
9191
List<SearchableFeature> results = FeatureCatalog.search(this, query);
92-
92+
9393
// Update adapter
9494
adapter.setFeatures(results);
9595
adapter.setSearchQuery(query);
96-
96+
9797
// Update empty state
9898
if (results.isEmpty()) {
9999
updateEmptyState(true, getString(R.string.search_no_results));
100100
} else {
101101
updateEmptyState(false, "");
102102
}
103103
}
104-
104+
105105
private void updateEmptyState(boolean show, String message) {
106106
if (show) {
107107
binding.emptyState.setVisibility(View.VISIBLE);
@@ -112,9 +112,16 @@ private void updateEmptyState(boolean show, String message) {
112112
binding.searchResults.setVisibility(View.VISIBLE);
113113
}
114114
}
115-
115+
116116
@Override
117117
public void onFeatureClick(SearchableFeature feature) {
118+
if (feature.getFragmentType() == SearchableFeature.FragmentType.ACTIVITY) {
119+
if ("deleted_messages_activity".equals(feature.getKey())) {
120+
startActivity(new Intent(this, DeletedMessagesActivity.class));
121+
}
122+
return;
123+
}
124+
118125
// Navigate back to MainActivity with feature information
119126
Intent intent = new Intent(this, MainActivity.class);
120127
intent.putExtra("navigate_to_fragment", feature.getFragmentType().getPosition());
@@ -124,7 +131,7 @@ public void onFeatureClick(SearchableFeature feature) {
124131
startActivity(intent);
125132
finish();
126133
}
127-
134+
128135
@Override
129136
public boolean onSupportNavigateUp() {
130137
onBackPressed();

app/src/main/java/com/wmods/wppenhacer/adapter/DeletedMessagesAdapter.java

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,15 @@
2323
public class DeletedMessagesAdapter extends RecyclerView.Adapter<DeletedMessagesAdapter.ViewHolder> {
2424

2525
private List<DeletedMessage> messages = new ArrayList<>();
26+
private java.util.Set<String> selectedItems = new java.util.HashSet<>();
2627
private final Map<String, android.graphics.drawable.Drawable> iconCache = new HashMap<>();
2728
private final OnItemClickListener listener;
2829

2930
public interface OnItemClickListener {
3031
void onItemClick(DeletedMessage message);
3132

33+
boolean onItemLongClick(DeletedMessage message);
34+
3235
void onRestoreClick(DeletedMessage message);
3336
}
3437

@@ -175,7 +178,54 @@ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
175178
holder.appBadge.setVisibility(View.GONE);
176179
}
177180

178-
holder.itemView.setOnClickListener(v -> listener.onItemClick(message));
181+
// Selection Logic
182+
if (selectedItems.contains(message.getChatJid())) {
183+
holder.itemView.setBackgroundColor(
184+
holder.itemView.getContext().getResources().getColor(R.color.selected_item_color, null)); // You
185+
// might
186+
// need to
187+
// define
188+
// this
189+
// color
190+
} else {
191+
android.util.TypedValue outValue = new android.util.TypedValue();
192+
holder.itemView.getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue,
193+
true);
194+
holder.itemView.setBackgroundResource(outValue.resourceId);
195+
}
196+
197+
holder.itemView.setOnClickListener(v -> {
198+
if (listener != null)
199+
listener.onItemClick(message);
200+
});
201+
202+
holder.itemView.setOnLongClickListener(v -> {
203+
if (listener != null)
204+
return listener.onItemLongClick(message);
205+
return false;
206+
});
207+
}
208+
209+
public void toggleSelection(String chatJid) {
210+
if (selectedItems.contains(chatJid)) {
211+
selectedItems.remove(chatJid);
212+
} else {
213+
selectedItems.add(chatJid);
214+
}
215+
notifyDataSetChanged();
216+
}
217+
218+
public void clearSelection() {
219+
selectedItems.clear();
220+
notifyDataSetChanged();
221+
}
222+
223+
public int getSelectedCount() {
224+
return selectedItems.size();
225+
}
226+
227+
public java.util.List<String> getSelectedItems() {
228+
return new ArrayList<>(selectedItems);
179229
}
180230

181231
@Override

0 commit comments

Comments
 (0)