Skip to content

Commit d497762

Browse files
committed
compliance;
1 parent b0aabaf commit d497762

19 files changed

Lines changed: 496 additions & 92 deletions

File tree

app/build.gradle

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ android {
77
applicationId "top.yztz.msggo"
88
minSdkVersion 26
99
targetSdkVersion 35
10-
versionCode 26000303
11-
versionName "3.3"
10+
versionCode 26000304
11+
versionName "3.4"
1212
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
1313
// buildConfigField "long", "BUILD_TIME", "${System.currentTimeMillis()}L"
1414
// multiDexEnabled true
@@ -68,4 +68,6 @@ dependencies {
6868

6969
implementation "io.noties.markwon:core:4.6.2"
7070
implementation "io.noties.markwon:ext-tables:4.6.2"
71+
72+
implementation 'com.github.houbb:sensitive-word:0.29.4'
7173
}

app/src/main/java/top/yztz/msggo/activities/ChooserActivity.java

Lines changed: 98 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,12 @@
2929
import android.util.Log;
3030
import android.util.SparseBooleanArray;
3131
import android.view.Gravity;
32+
import android.view.LayoutInflater;
3233
import android.view.View;
3334
import android.view.ViewGroup;
35+
import android.view.inputmethod.EditorInfo;
3436
import android.widget.Button;
37+
import android.widget.EditText;
3538
import android.widget.LinearLayout;
3639
import android.widget.ScrollView;
3740
import android.widget.TextView;
@@ -40,6 +43,7 @@
4043
import com.google.android.material.bottomsheet.BottomSheetDialog;
4144
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
4245
import com.google.android.material.progressindicator.LinearProgressIndicator;
46+
import com.google.android.material.textfield.TextInputLayout;
4347

4448
import java.io.File;
4549
import java.util.ArrayList;
@@ -287,9 +291,100 @@ private void startSending(ArrayList<Integer> itemIndices) {
287291
messages.add(new Message(phoneNumber, content));
288292
}
289293

290-
MessageService.startSending(this, messages, DataModel.getSubId(), SettingManager.getDelay(), SettingManager.isRandomizeDelay());
291-
showProgressDialog();
294+
// Start sensitive word check process
295+
checkAndSendMessages(messages, 0);
292296
}
297+
298+
/**
299+
* Recursively check messages for sensitive words and prompt user for action if found.
300+
* @param messages The list of messages to send
301+
* @param index The current index being checked
302+
*/
303+
private void checkAndSendMessages(List<Message> messages, int index) {
304+
// Skip already-null (skipped) messages
305+
while (index < messages.size() && messages.get(index) == null) {
306+
index++;
307+
}
308+
309+
if (index >= messages.size()) {
310+
// All messages checked, filter out nulls and send
311+
List<Message> validMessages = new ArrayList<>();
312+
for (Message m : messages) {
313+
if (m != null) {
314+
validMessages.add(m);
315+
}
316+
}
317+
if (validMessages.isEmpty()) {
318+
ToastUtil.show(this, R.string.sending_completed);
319+
return;
320+
}
321+
MessageService.startSending(this, validMessages, DataModel.getSubId(), SettingManager.getDelay(), SettingManager.isRandomizeDelay());
322+
showProgressDialog();
323+
return;
324+
}
325+
326+
Message message = messages.get(index);
327+
List<String> sensitiveWords = top.yztz.msggo.util.SensitiveWordUtil.findAll(message.getContent());
328+
329+
if (sensitiveWords.isEmpty()) {
330+
// No sensitive words, proceed to next message
331+
checkAndSendMessages(messages, index + 1);
332+
} else {
333+
// Sensitive words detected, show dialog
334+
final int currentIndex = index;
335+
String wordsDisplay = TextUtils.join(", ", sensitiveWords);
336+
337+
new MaterialAlertDialogBuilder(this)
338+
.setTitle(getString(R.string.sensitive_word_detected_title))
339+
.setMessage(getString(R.string.sensitive_word_detected_msg, currentIndex + 1, wordsDisplay))
340+
.setCancelable(false)
341+
.setPositiveButton(getString(R.string.skip_message), (dialog, which) -> {
342+
// Skip this message
343+
messages.set(currentIndex, null);
344+
checkAndSendMessages(messages, currentIndex + 1);
345+
})
346+
.setNeutralButton(getString(R.string.edit_message), (dialog, which) -> {
347+
// Show edit dialog
348+
showEditMessageDialog(messages, currentIndex);
349+
})
350+
.setNegativeButton(getString(R.string.cancel_send), (dialog, which) -> {
351+
// Cancel entire sending process
352+
ToastUtil.show(this, getString(R.string.sending_cancelled));
353+
})
354+
.show();
355+
}
356+
}
357+
358+
/**
359+
* Show a dialog to edit the message content. Re-checks for sensitive words after saving.
360+
*/
361+
private void showEditMessageDialog(List<Message> messages, int index) {
362+
Message message = messages.get(index);
363+
364+
View dialogView = LayoutInflater.from(this).inflate(R.layout.dialog_edit_text, null);
365+
TextInputLayout container = dialogView.findViewById(R.id.edit_text_container);
366+
367+
EditText editText = dialogView.findViewById(R.id.edit_text);
368+
editText.setText(message.getContent());
369+
editText.setSelection(editText.getText().length());
370+
371+
new MaterialAlertDialogBuilder(this)
372+
.setTitle(getString(R.string.edit_sensitive_message_title))
373+
.setView(dialogView)
374+
.setCancelable(false)
375+
.setPositiveButton(getString(R.string.save), (dialog, which) -> {
376+
String newContent = editText.getText().toString();
377+
messages.set(index, new Message(message.getPhone(), newContent));
378+
// Re-check this message
379+
checkAndSendMessages(messages, index);
380+
})
381+
.setNegativeButton(getString(R.string.cancel), (dialog, which) -> {
382+
// Go back to the check dialog
383+
checkAndSendMessages(messages, index);
384+
})
385+
.show();
386+
}
387+
293388

294389
private void showProgressDialog() {
295390
if (progressDialog == null) {
@@ -404,7 +499,7 @@ private void observeSending() {
404499
tvProgressTitle.setText(getString(R.string.sending));
405500
progressDialog.setCancelable(false);
406501
progressDialog.setCanceledOnTouchOutside(false);
407-
btnCancel.setText(getString(R.string.cancel));
502+
btnCancel.setText(getString(R.string.cancel_send));
408503
break;
409504
}
410505
}

app/src/main/java/top/yztz/msggo/activities/MainActivity.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -221,10 +221,6 @@ protected void onCreate(Bundle savedInstanceState) {
221221
Uri uri = data.getData();
222222
if (uri != null) {
223223
Log.d(TAG, "File URI: " + uri.getEncodedPath());
224-
if (FileUtil.getFileSize(this, uri) > FileUtil.MAX_FILE_SIZE) {
225-
ToastUtil.show(this, getString(R.string.file_too_large));
226-
return;
227-
}
228224
String path = getFilePathFromContentUri(this, uri);
229225
Log.i(TAG, "Importing file from picker: " + path);
230226
LoadService.load(this, path);
@@ -328,10 +324,6 @@ private void checkShare() {
328324

329325
if (uri != null) {
330326
Log.i(TAG, "load outside link: " + uri);
331-
if (FileUtil.getFileSize(this, uri) > FileUtil.MAX_FILE_SIZE) {
332-
ToastUtil.show(this, getString(R.string.file_too_large));
333-
return;
334-
}
335327
LoadService.load(this, FileUtil.getFilePathFromContentUri(this, uri));
336328
}
337329
}

app/src/main/java/top/yztz/msggo/data/DataModel.java

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222

2323
import java.io.Serializable;
2424
import java.util.HashMap;
25+
import java.util.HashSet;
26+
import java.util.Iterator;
2527
import java.util.List;
28+
import java.util.Set;
2629

2730
import top.yztz.msggo.exception.DataLoadFailed;
2831
import top.yztz.msggo.services.SMSSender;
@@ -48,12 +51,11 @@ public static boolean loaded() {
4851
/**
4952
* Must be called in the non-UI thread
5053
*
51-
* @param context context
5254
* @param path excel file to load
5355
*/
54-
public static synchronized void load(Context context, String path) throws DataLoadFailed {
56+
public static synchronized void load(String path) throws DataLoadFailed {
5557
ExcelReader reader = new ExcelReader();
56-
reader.read(context, path);
58+
reader.read(path);
5759
DataModel.data = reader.readExcelContent();
5860
DataModel.titles = reader.getTitles();
5961
DataModel.path = path;
@@ -120,6 +122,34 @@ public static void setSubId(int subId) {
120122
DataModel.subId = subId;
121123
}
122124

125+
public static int deduplicate() {
126+
if (!loaded || numberColumn == null || numberColumn.isEmpty()) {
127+
return 0;
128+
}
129+
130+
int originalCount = data.size();
131+
132+
Set<String> seen = new HashSet<>();
133+
Iterator<HashMap<String, String>> iterator = data.iterator();
134+
135+
while (iterator.hasNext()) {
136+
HashMap<String, String> row = iterator.next();
137+
String number = row.get(numberColumn);
138+
// normalization might be needed? User just said "deduplicate based on number column"
139+
// Let's assume exact string match for now, or basic trimming.
140+
if (number == null) number = "";
141+
number = number.trim();
142+
143+
if (number.isEmpty() || seen.contains(number)) {
144+
iterator.remove();
145+
} else {
146+
seen.add(number);
147+
}
148+
}
149+
150+
return originalCount - data.size();
151+
}
152+
123153
public static void clear() {
124154
data = null;
125155
titles = null;

app/src/main/java/top/yztz/msggo/data/Settings.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,8 @@ public class Settings {
3535
public static final boolean DISCLAIMER_ACCEPTED_DEFAULT = false;
3636
// language
3737
public static final String LANGUAGE_DEFAULT = "auto";
38+
39+
public static final int EXCEL_ROW_COUNT_MAX = 100;
40+
public static final long EXCEL_FILE_SIZE_MAX = 50 * 1024 * 1024; // 50MB
41+
3842
}

app/src/main/java/top/yztz/msggo/exception/DataLoadFailed.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,21 @@
1717

1818
package top.yztz.msggo.exception;
1919

20+
import top.yztz.msggo.R;
21+
2022
public class DataLoadFailed extends Exception {
21-
public final String msg;
23+
// public final String msg;
24+
public final int res_id;
25+
public Exception e = null;
26+
// public DataLoadFailed(String msg) {
27+
// this.msg = msg;
28+
// }
2229

23-
public DataLoadFailed(String msg) {
24-
this.msg = msg;
30+
public DataLoadFailed(int res_id) {
31+
this.res_id = res_id;
2532
}
26-
public DataLoadFailed() {
27-
this.msg = "unknown error";
33+
public DataLoadFailed(Exception e) {
34+
this.res_id = R.string.unknown_error;
35+
this.e = e;
2836
}
2937
}

app/src/main/java/top/yztz/msggo/fragments/HomeFrag.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public class HomeFrag extends Fragment {
6666

6767
private View rowCurrentFile, rowNumberColumn, rowEditContent, rowSelectSim, rowSend, cardSend;
6868
private ViewGroup containerHome;
69-
private TextView tvSimInfo, tvSubtitleSend, tvSubtitleEdit, tvEmptyHistory;
69+
private TextView tvSimInfo, tvSubtitleEdit, tvEmptyHistory;
7070
private TextView tvCurrentFilePath, tvCurrentNumberColumn;
7171
private RecyclerView rvHistory;
7272
private HistoryAdapter historyAdapter;
@@ -106,7 +106,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
106106

107107
// Initialize views
108108
tvSimInfo = view.findViewById(R.id.tv_sim_info);
109-
tvSubtitleSend = view.findViewById(R.id.tv_subtitle_send);
109+
// tvSubtitleSend = view.findViewById(R.id.tv_subtitle_send);
110110
tvSubtitleEdit = view.findViewById(R.id.tv_subtitle_edit);
111111
rvHistory = view.findViewById(R.id.rv_history);
112112
tvEmptyHistory = view.findViewById(R.id.tv_empty_history);
@@ -139,6 +139,11 @@ private void setupClickListeners() {
139139
} else if (TextUtils.isEmpty(DataModel.getTemplate())) {
140140
ToastUtil.show(context, getString(R.string.error_edit_content_first));
141141
} else {
142+
int removed = DataModel.deduplicate();
143+
if (removed > 0) {
144+
ToastUtil.show(context, getString(R.string.deduplication_result, removed));
145+
// updateStatus();
146+
}
142147
startActivity(new Intent(context, ChooserActivity.class));
143148
}
144149
});
@@ -304,7 +309,7 @@ public void updateStatus() {
304309
rowSelectSim.setVisibility(View.VISIBLE);
305310
cardSend.setVisibility(View.VISIBLE);
306311
updateSimDisplay();
307-
tvSubtitleSend.setText(getString(R.string.data_ready_format, DataModel.getRowCount()));
312+
// tvSubtitleSend.setText(getString(R.string.data_ready_format, DataModel.getRowCount()));
308313
} else {
309314
cardSend.setVisibility(View.GONE);
310315
rowSelectSim.setVisibility(View.GONE);

app/src/main/java/top/yztz/msggo/fragments/SettingFrag.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import android.view.LayoutInflater;
2828
import android.view.View;
2929
import android.view.ViewGroup;
30+
import android.view.inputmethod.EditorInfo;
3031
import android.widget.EditText;
3132
import android.widget.LinearLayout;
3233
import android.widget.TextView;
@@ -46,6 +47,7 @@
4647
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
4748
import com.google.android.material.materialswitch.MaterialSwitch;
4849
import com.google.android.material.slider.Slider;
50+
import com.google.android.material.textfield.TextInputLayout;
4951
import com.google.android.material.transition.MaterialSharedAxis;
5052

5153
import top.yztz.msggo.data.DataCleaner;
@@ -138,8 +140,13 @@ private void setupListeners() {
138140
// SMS Rate
139141
mCardSmsRate.setOnClickListener(v -> {
140142
View dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_edit_text, null);
143+
TextInputLayout container = dialogView.findViewById(R.id.edit_text_container);
144+
container.setHint(R.string.hint_sms_rate);
145+
container.setPrefixText(getString(R.string.currency_unit));
146+
141147
EditText editText = dialogView.findViewById(R.id.edit_text);
142-
editText.setText(SettingManager.getSmsRate() + "");
148+
editText.setInputType(EditorInfo.TYPE_NUMBER_FLAG_DECIMAL | EditorInfo.TYPE_CLASS_NUMBER);
149+
editText.setText(String.format(Locale.getDefault(), "%f", SettingManager.getSmsRate()));
143150
editText.setSelection(editText.getText().length());
144151

145152
new com.google.android.material.dialog.MaterialAlertDialogBuilder(context)

app/src/main/java/top/yztz/msggo/services/LoadService.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
import androidx.annotation.Nullable;
2727
import androidx.lifecycle.MutableLiveData;
2828

29+
import java.util.Locale;
30+
31+
import top.yztz.msggo.R;
2932
import top.yztz.msggo.data.DataModel;
3033
import top.yztz.msggo.exception.DataLoadFailed;
3134

@@ -38,13 +41,13 @@ public class LoadService extends Service {
3841
public static MutableLiveData<LoadStatus> getLoadStatus() {
3942
return loadStatus;
4043
}
41-
44+
4245
public static class LoadStatus {
4346
public final boolean isLoading;
4447
public final boolean isSuccessful;
4548
public final String errorMsg;
4649
public final String path;
47-
50+
4851
public LoadStatus(boolean isLoading, boolean isSuccessful, String path, String errorMsg) {
4952
this.isLoading = isLoading;
5053
this.isSuccessful = isSuccessful;
@@ -74,19 +77,18 @@ public int onStartCommand(final Intent intent, int flags, int startId) {
7477
try {
7578
postStatus(true, false, path);
7679

77-
java.io.File file = new java.io.File(path);
78-
if (file.exists() && file.length() > top.yztz.msggo.util.FileUtil.MAX_FILE_SIZE) {
79-
throw new DataLoadFailed(getApplicationContext().getString(top.yztz.msggo.R.string.file_too_large));
80-
}
81-
82-
DataModel.load(getApplicationContext(), path);
80+
DataModel.load(path);
8381

8482
postStatus(false, true, path);
8583
Log.d(TAG, "数据加载成功");
8684
stopSelf();
8785
} catch (DataLoadFailed dataLoadFailed) {
88-
Log.d(TAG, "数据加载失败: " + dataLoadFailed.msg);
89-
postStatus(false, false, path, dataLoadFailed.msg);
86+
String msg = getString(dataLoadFailed.res_id);
87+
if (dataLoadFailed.res_id == R.string.unknown_error) {
88+
msg = String.format(Locale.getDefault(), "%s (%s)", msg, dataLoadFailed.e.getMessage());
89+
}
90+
Log.d(TAG, "数据加载失败: " + msg);
91+
postStatus(false, false, path, msg);
9092
stopSelf();
9193
}
9294
}).start();

0 commit comments

Comments
 (0)