1
0
mirror of https://github.com/areteruhiro/LIME-beta-hiro.git synced 2025-02-15 01:41:36 +09:00

Compare commits

...

3 Commits

Author SHA1 Message Date
areteruhiro
b0d9f39ab1 test 2025-01-30 01:22:45 +09:00
areteruhiro
f112129775 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	app/build.gradle
2025-01-29 23:25:22 +09:00
areteruhiro
a76ab155ab 取り消しメッセージのバグ修正 2025-01-29 23:24:18 +09:00
3 changed files with 120 additions and 64 deletions

View File

@ -10,7 +10,7 @@ android {
minSdk 28
targetSdk 35
versionCode 11501
versionName "1.16.01beta"
versionName "1.16.00beta"
multiDexEnabled false
proguardFiles += 'proguard-rules.pro'
buildConfigField 'String', 'HOOK_TARGET_VERSION', '"141910383"'

View File

@ -1,12 +1,14 @@
package io.github.hiro.lime.hooks;
import static android.content.ContentValues.TAG;
import static io.github.hiro.lime.Main.limeOptions;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AndroidAppHelper;
import android.app.Application;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
@ -18,8 +20,13 @@ import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
@ -192,16 +199,19 @@ public class ReadChecker implements IHook {
return noGroup;
}
private void addButton(Activity activity, Context moduleContext) {
// ファイルパスを取得
File dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "LimeBackup");
File file = new File(dir, "margin_settings.txt");
private static final String TAG = "FileHandler";
public void addButton(Activity activity, Context moduleContext) {
// ファイル取得処理フォールバック対応
File file = getFile(activity);
if (file == null) {
Log.e(TAG, "Failed to get a valid file.");
return;
}
// デフォルト値
float readCheckerHorizontalMarginFactor = 0.5f; // デフォルト値
int readCheckerVerticalMarginDp = 100; // デフォルト値
float readCheckerSizeDp = 60; // デフォルト値
float readCheckerHorizontalMarginFactor = 0.5f;
int readCheckerVerticalMarginDp = 100;
float readCheckerSizeDp = 60;
// ファイルの内容を読み込む
if (file.exists()) {
@ -210,12 +220,16 @@ public class ReadChecker implements IHook {
while ((line = reader.readLine()) != null) {
String[] parts = line.split("=", 2);
if (parts.length == 2) {
if (parts[0].trim().equals("Read_checker_horizontalMarginFactor")) {
readCheckerHorizontalMarginFactor = Float.parseFloat(parts[1].trim());
} else if (parts[0].trim().equals("Read_checker_verticalMarginDp")) {
readCheckerVerticalMarginDp = Integer.parseInt(parts[1].trim());
} else if (parts[0].trim().equals("chat_read_check_size")) {
readCheckerSizeDp = Float.parseFloat(parts[1].trim());
switch (parts[0].trim()) {
case "Read_checker_horizontalMarginFactor":
readCheckerHorizontalMarginFactor = Float.parseFloat(parts[1].trim());
break;
case "Read_checker_verticalMarginDp":
readCheckerVerticalMarginDp = Integer.parseInt(parts[1].trim());
break;
case "chat_read_check_size":
readCheckerSizeDp = Float.parseFloat(parts[1].trim());
break;
}
}
}
@ -223,9 +237,10 @@ public class ReadChecker implements IHook {
}
}
// 画像ボタンの設定
ImageView imageButton = new ImageView(activity);
String imageName = "read_checker.png";
File imageFile = new File(dir, imageName);
File imageFile = new File(file.getParent(), imageName);
if (!imageFile.exists()) {
try (InputStream in = moduleContext.getResources().openRawResource(
@ -245,11 +260,11 @@ public class ReadChecker implements IHook {
Drawable drawable = Drawable.createFromPath(imageFile.getAbsolutePath());
if (drawable != null) {
int sizeInPx = dpToPx(moduleContext, readCheckerSizeDp);
drawable = scaleDrawable(drawable, sizeInPx, sizeInPx);
imageButton.setImageDrawable(drawable);
}
}
// 画像ボタンのレイアウト
FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT
@ -260,13 +275,9 @@ public class ReadChecker implements IHook {
frameParams.setMargins(horizontalMarginPx, verticalMarginPx, 0, 0);
imageButton.setLayoutParams(frameParams);
imageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (currentGroupId != null) {
showDataForGroupId(activity, currentGroupId, moduleContext);
}
imageButton.setOnClickListener(v -> {
if (currentGroupId != null) {
showDataForGroupId(activity, currentGroupId, moduleContext);
}
});
@ -274,29 +285,25 @@ public class ReadChecker implements IHook {
if (limeOptions.ReadCheckerChatdataDelete.checked) {
Button deleteButton = new Button(activity);
deleteButton.setText(moduleContext.getResources().getString(R.string.Delete));
deleteButton.setBackgroundColor(Color.RED); // ボタンの背景色を赤に設定
deleteButton.setTextColor(Color.WHITE); // ボタンのテキスト色を白に設定
deleteButton.setBackgroundColor(Color.RED);
deleteButton.setTextColor(Color.WHITE);
FrameLayout.LayoutParams deleteButtonParams = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT
);
// Delete ボタンの位置を画像ボタンの右側に設定
deleteButtonParams.setMargins(horizontalMarginPx + dpToPx(moduleContext, readCheckerSizeDp) + 20, verticalMarginPx, 0, 0);
deleteButton.setLayoutParams(deleteButtonParams);
deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (currentGroupId != null) {
new AlertDialog.Builder(activity)
.setTitle(moduleContext.getResources().getString(R.string.check))
.setMessage(moduleContext.getResources().getString(R.string.really_delete))
.setPositiveButton(moduleContext.getResources().getString(R.string.yes), (confirmDialog, confirmWhich) -> deleteGroupData(currentGroupId, activity, moduleContext))
.setNegativeButton(moduleContext.getResources().getString(R.string.no), null)
.show();
}
deleteButton.setOnClickListener(v -> {
if (currentGroupId != null) {
new AlertDialog.Builder(activity)
.setTitle(moduleContext.getResources().getString(R.string.check))
.setMessage(moduleContext.getResources().getString(R.string.really_delete))
.setPositiveButton(moduleContext.getResources().getString(R.string.yes), (dialog, which) -> deleteGroupData(currentGroupId, activity, moduleContext))
.setNegativeButton(moduleContext.getResources().getString(R.string.no), null)
.show();
}
});
@ -308,6 +315,50 @@ public class ReadChecker implements IHook {
layout.addView(imageButton);
}
private File getFile(Activity activity) {
File dir;
File file;
try {
dir = new File(activity.getExternalFilesDir(null), "LimeBackup");
if (!dir.exists() && !dir.mkdirs()) {
throw new IOException("Failed to create directory");
}
file = new File(dir, "margin_settings.txt");
if (!file.exists() && !file.createNewFile()) {
throw new IOException("Failed to create file");
}
return file;
} catch (Exception e) {
Log.e(TAG, "getExternalFilesDir failed, falling back to MediaStore.", e);
return getFileFromMediaStore(activity, "LimeBackup/margin_settings.txt");
}
}
private File getFileFromMediaStore(Context context, String relativePath) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ContentResolver resolver = context.getContentResolver();
ContentValues values = new ContentValues();
values.put(MediaStore.Downloads.DISPLAY_NAME, "margin_settings.txt");
values.put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS + "/LimeBackup");
values.put(MediaStore.Downloads.MIME_TYPE, "text/plain");
Uri fileUri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values);
if (fileUri != null) {
try (ParcelFileDescriptor pfd = resolver.openFileDescriptor(fileUri, "rw")) {
if (pfd != null) {
return new File(context.getFilesDir(), "margin_settings.txt");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
private int dpToPx(@NonNull Context context, float dp) {
float density = context.getResources().getDisplayMetrics().density;
return Math.round(dp * density);

View File

@ -316,27 +316,21 @@ public class UnsentRec implements IHook {
private String queryDatabase(SQLiteDatabase db, String query, String... selectionArgs) {
private String queryDatabase(SQLiteDatabase db, String query, String... selectionArgs) {
if (db == null) {
return null;
}
Cursor cursor = db.rawQuery(query, selectionArgs);
String result = null;
if (cursor != null && cursor.moveToFirst()) {
do {
result = cursor.getString(0);
XposedBridge.log("Query Result: " + result); // Log each result found
} while (cursor.moveToNext()); // In case there are multiple rows
} else {
XposedBridge.log("No rows found for query: " + query);
if (cursor.moveToFirst()) {
result = cursor.getString(0);
}
cursor.close();
return result;
}
private int countLinesInFile(File file) {
int count = 0;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) {
@ -387,16 +381,14 @@ public class UnsentRec implements IHook {
String param12 = null;
String param22 = null;
String operationContent = null;
String serverId = null;
String talkId = null;
String serverId = null; // serverIdをここで宣言
String[] parts = operation.split(",");
for (String part : parts) {
part = part.trim();
if (part.startsWith("param1:")) {
talkId = part.substring("param1:".length()).trim();
} else if (part.startsWith("param2:")) {
serverId = part.substring("param2:".length()).trim();
} else if (part.startsWith("revision:")) {
revision = part.substring("revision:".length()).trim();
} else if (part.startsWith("createdTime:")) {
@ -414,10 +406,23 @@ public class UnsentRec implements IHook {
}
}
if (serverId != null && talkId != null) {
// 新しいメソッドを呼び出してメッセージを取り消し済みとして更新
// typeがNOTIFIED_DESTROY_MESSAGEの場合のみserverIdを設定
if ("NOTIFIED_DESTROY_MESSAGE".equals(type)) {
for (String part : parts) {
part = part.trim();
if (part.startsWith("param2:")) {
serverId = part.substring("param2:".length()).trim();
break; // param2が見つかったらループを抜ける
}
}
updateMessageAsCanceled(db1, serverId,context,moduleContext);
// serverIdを使用した処理をここに追加
XposedBridge.log("Server ID for NOTIFIED_DESTROY_MESSAGE: " + serverId);
}
// serverIdとtalkIdが両方ともnullでない場合に処理を行う
if (serverId != null && talkId != null) {
XposedBridge.log(paramValue + serverId);
String content = queryDatabase(db1, "SELECT content FROM chat_history WHERE server_id=?", serverId);
String imageCheck = queryDatabase(db1, "SELECT attachement_image FROM chat_history WHERE server_id=?", serverId);
String timeEpochStr = queryDatabase(db1, "SELECT created_time FROM chat_history WHERE server_id=?", serverId);
@ -459,6 +464,8 @@ public class UnsentRec implements IHook {
break;
}
}
XposedBridge.log("S" + serverId);
// 新しいメソッドを呼び出してメッセージを取り消し済みとして更新
String logEntry = (timeFormatted != null ? timeFormatted : "No Time: ")
+ name
@ -482,21 +489,16 @@ public class UnsentRec implements IHook {
}
}
}
private void canceled_message(XC_LoadPackage.LoadPackageParam loadPackageParam, Context context, SQLiteDatabase db1, SQLiteDatabase db2, Context moduleContext) {
Class<?> chatHistoryRequestClass = XposedHelpers.findClass("com.linecorp.line.chat.request.ChatHistoryRequest", loadPackageParam.classLoader);
XposedHelpers.findAndHookMethod(chatHistoryRequestClass, "getChatId", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
String chatId = (String) param.getResult();
// チャット ID をログに出力
XposedBridge.log("Chat ID: " + chatId);
String canceledContent = getCanceledContentFromFile(context, moduleContext);
// チェックボックスの状態を確認
if (limeOptions.hide_canceled_message.checked) {
XposedBridge.log("hide_canceled_message is checked");
// content server_id, chat_id を取得 (複数レコードを想定)
Cursor cursor = db1.rawQuery("SELECT content, server_id, chat_id, parameter FROM chat_history WHERE chat_id=?", new String[]{chatId});
@ -530,10 +532,9 @@ public class UnsentRec implements IHook {
cursor.close();
}
} else {
XposedBridge.log("No rows found for chat_id: " + chatId);
}
} else {
XposedBridge.log("hide_canceled_message is NOT checked");
// hide_canceled_message.checked false の場合
String chatId1 = "/" + (String) param.getResult();
@ -578,10 +579,10 @@ public class UnsentRec implements IHook {
private void updateMessageAsCanceled(SQLiteDatabase db1, String serverId, Context context, Context moduleContext) {
// canceledContent をファイルから取得
String canceledContent = getCanceledContentFromFile(context, moduleContext);
// 既存のメッセージを取得
Cursor cursor = db1.rawQuery("SELECT * FROM chat_history WHERE server_id=?", new String[]{serverId});
if (cursor.moveToFirst()) {
// カラムの値を取得null の場合もそのまま代入
String type = cursor.isNull(cursor.getColumnIndex("type")) ? null : cursor.getString(cursor.getColumnIndex("type"));
@ -609,6 +610,7 @@ public class UnsentRec implements IHook {
// 既存のレコードがあるか確認
Cursor existingCursor = db1.rawQuery("SELECT * FROM chat_history WHERE server_id=? AND content=?", new String[]{serverId, chatId});
if (!existingCursor.moveToFirst()) {
XposedBridge.log(serverId);
// 新しいレコードを挿入
ContentValues values = new ContentValues();
values.put("server_id", serverId);
@ -626,11 +628,14 @@ public class UnsentRec implements IHook {
values.put("location_phone", locationPhone);
if (locationLatitude != null) values.put("location_latitude", locationLatitude);
if (locationLongitude != null) values.put("location_longitude", locationLongitude);
values.put("attachement_image", attachmentImage);
values.put("attachement_image", "0");
if (attachmentImageHeight != null) values.put("attachement_image_height", attachmentImageHeight);
else values.put("attachement_image_height", (String) null);
if (attachmentImageWidth != null) values.put("attachement_image_width", attachmentImageWidth);
else values.put("attachement_image_width", (String) null);
if (attachmentImageSize != null) values.put("attachement_image_size", attachmentImageSize);
values.put("attachement_type", attachmentType);
else values.put("attachement_image_size", (String) null);
values.put("attachement_type", "0");
values.put("attachement_local_uri", attachmentLocalUri);
values.put("parameter", "LIMEsUnsend"); // ここを修正
values.put("chunks", chunks);