1
0
mirror of https://github.com/areteruhiro/LIME-beta-hiro.git synced 2025-02-05 21:11:39 +09:00

設定ボタンをラインラボにも追加するように

This commit is contained in:
areteruhiro 2025-01-23 23:11:06 +09:00
parent be24fe1a53
commit 5f7f245d29
6 changed files with 461 additions and 35 deletions

View File

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

View File

@ -57,7 +57,7 @@ public class LimeOptions {
public Option PhotoAddNotification = new Option("PhotoAddNotification", R.string.PhotoAddNotification, false);
public Option GroupNotification = new Option("GroupNotification", R.string.GroupNotification, false);
public Option RemoveVoiceRecord = new Option("RemoveVoiceRecord", R.string.RemoveVoiceRecord, false);
public Option LINELabOnly = new Option("LINELabOnly", R.string.LINELabOnly, false);
public Option[] options = {
removeVoom,
removeWallet,
@ -91,7 +91,8 @@ public class LimeOptions {
MuteGroup,
PhotoAddNotification,GroupNotification,
RemoveVoiceRecord,
AgeCheckSkip
AgeCheckSkip,
LINELabOnly
};

View File

@ -57,8 +57,417 @@ public class EmbedOptions implements IHook {
@Override
public void hook(LimeOptions limeOptions, XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if (Main.xModulePrefs.getBoolean("unembed_options", false)) return;
if (limeOptions.LINELabOnly.checked) {
XposedBridge.hookAllMethods(
loadPackageParam.classLoader.loadClass("com.linecorp.line.settings.main.LineUserMainSettingsFragment"),
"onViewCreated",
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
Context moduleContext = AndroidAppHelper.currentApplication().createPackageContext(
"io.github.hiro.lime", Context.CONTEXT_IGNORE_SECURITY);
ViewGroup viewGroup = ((ViewGroup) param.args[0]);
Context context = viewGroup.getContext();
Utils.addModuleAssetPath(context);
SharedPreferences prefs = context.getSharedPreferences(Constants.MODULE_NAME + "-options", Context.MODE_PRIVATE);
LinearLayout layout = new LinearLayout(context);
layout.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT));
layout.setOrientation(LinearLayout.VERTICAL);
layout.setPadding(Utils.dpToPx(20, context), Utils.dpToPx(20, context), Utils.dpToPx(20, context), Utils.dpToPx(20, context));
Switch switchRedirectWebView = null;
for (LimeOptions.Option option : limeOptions.options) {
final String name = option.name;
Switch switchView = new Switch(context);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = Utils.dpToPx(20, context);
switchView.setLayoutParams(params);
switchView.setText(option.id);
switchView.setChecked(option.checked);
if (name.equals("redirect_webview"))
switchRedirectWebView = switchView;
else if (name.equals("open_in_browser")) {
switchRedirectWebView.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (isChecked) switchView.setEnabled(true);
else {
switchView.setChecked(false);
switchView.setEnabled(false);
}
});
switchView.setEnabled(limeOptions.redirectWebView.checked);
}
layout.addView(switchView);
}
{
final String script = new String(Base64.decode(prefs.getString("encoded_js_modify_request", ""), Base64.NO_WRAP));
LinearLayout layoutModifyRequest = new LinearLayout(context);
layoutModifyRequest.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT));
layoutModifyRequest.setOrientation(LinearLayout.VERTICAL);
layoutModifyRequest.setPadding(Utils.dpToPx(20, context), Utils.dpToPx(20, context), Utils.dpToPx(20, context), Utils.dpToPx(20, context));
EditText editText = new EditText(context);
editText.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
editText.setTypeface(Typeface.MONOSPACE);
editText.setInputType(InputType.TYPE_CLASS_TEXT |
InputType.TYPE_TEXT_FLAG_MULTI_LINE |
InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS |
InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE);
editText.setMovementMethod(new ScrollingMovementMethod());
editText.setTextIsSelectable(true);
editText.setHorizontallyScrolling(true);
editText.setVerticalScrollBarEnabled(true);
editText.setHorizontalScrollBarEnabled(true);
editText.setText(script);
layoutModifyRequest.addView(editText);
LinearLayout buttonLayout = new LinearLayout(context);
LinearLayout.LayoutParams buttonParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
buttonParams.topMargin = Utils.dpToPx(10, context);
buttonLayout.setLayoutParams(buttonParams);
buttonLayout.setOrientation(LinearLayout.HORIZONTAL);
Button copyButton = new Button(context);
copyButton.setText(R.string.button_copy);
copyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("", editText.getText().toString());
clipboard.setPrimaryClip(clip);
}
});
buttonLayout.addView(copyButton);
Button pasteButton = new Button(context);
pasteButton.setText(R.string.button_paste);
pasteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
if (clipboard != null && clipboard.hasPrimaryClip()) {
ClipData clip = clipboard.getPrimaryClip();
if (clip != null && clip.getItemCount() > 0) {
CharSequence pasteData = clip.getItemAt(0).getText();
editText.setText(pasteData);
}
}
}
});
buttonLayout.addView(pasteButton);
layoutModifyRequest.addView(buttonLayout);
ScrollView scrollView = new ScrollView(context);
scrollView.addView(layoutModifyRequest);
AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setTitle(R.string.modify_request);
builder.setView(scrollView);
Button backupButton = new Button(context);
buttonParams.topMargin = Utils.dpToPx(20, context);
backupButton.setLayoutParams(buttonParams);
backupButton.setText(moduleContext.getResources().getString(R.string.Back_Up));
backupButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
backupChatHistory(context, moduleContext);
}
});
layout.addView(backupButton);
Button restoreButton = new Button(context);
restoreButton.setLayoutParams(buttonParams);
restoreButton.setText(moduleContext.getResources().getString(R.string.Restore));
restoreButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
restoreChatHistory(context, moduleContext);
}
});
layout.addView(restoreButton);
Button backupfolderButton = new Button(context);
backupfolderButton.setLayoutParams(buttonParams);
backupfolderButton.setText(moduleContext.getResources().getString(R.string.Talk_Picture_Back_up));
backupfolderButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
backupChatsFolder(context, moduleContext);
}
});
layout.addView(backupfolderButton);
Button restorefolderButton = new Button(context);
restorefolderButton.setLayoutParams(buttonParams);
restorefolderButton.setText(moduleContext.getResources().getString(R.string.Picure_Restore));
restorefolderButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
restoreChatsFolder(context, moduleContext);
}
});
layout.addView(restorefolderButton);
if (limeOptions.MuteGroup.checked) {
Button MuteGroups_Button = new Button(context);
MuteGroups_Button.setLayoutParams(buttonParams);
MuteGroups_Button.setText(moduleContext.getResources().getString(R.string.Mute_Group));
MuteGroups_Button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MuteGroups_Button(context, moduleContext);
}
});
layout.addView(MuteGroups_Button);
}
Button KeepUnread_Button = new Button(context);
KeepUnread_Button.setLayoutParams(buttonParams);
KeepUnread_Button.setText(moduleContext.getResources().getString(R.string.edit_margin_settings));
KeepUnread_Button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
KeepUnread_Button(context, moduleContext);
}
});
layout.addView(KeepUnread_Button);
builder.setPositiveButton(R.string.positive_button, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String code = editText.getText().toString();
if (!code.equals(script)) {
prefs.edit().putString("encoded_js_modify_request", Base64.encodeToString(code.getBytes(), Base64.NO_WRAP)).commit();
Toast.makeText(context.getApplicationContext(), context.getString(R.string.restarting), Toast.LENGTH_SHORT).show();
Process.killProcess(Process.myPid());
context.startActivity(new Intent().setClassName(Constants.PACKAGE_NAME, "jp.naver.line.android.activity.SplashActivity"));
}
}
});
builder.setNegativeButton(R.string.negative_button, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
editText.setText(script);
}
});
AlertDialog dialog = builder.create();
Button button = new Button(context);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = Utils.dpToPx(20, context);
button.setLayoutParams(params);
button.setText(R.string.modify_request);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dialog.show();
}
});
layout.addView(button);
}
{
final String script = new String(Base64.decode(prefs.getString("encoded_js_modify_response", ""), Base64.NO_WRAP));
LinearLayout layoutModifyResponse = new LinearLayout(context);
layoutModifyResponse.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT));
layoutModifyResponse.setOrientation(LinearLayout.VERTICAL);
layoutModifyResponse.setPadding(Utils.dpToPx(20, context), Utils.dpToPx(20, context), Utils.dpToPx(20, context), Utils.dpToPx(20, context));
EditText editText = new EditText(context);
editText.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
editText.setTypeface(Typeface.MONOSPACE);
editText.setInputType(InputType.TYPE_CLASS_TEXT |
InputType.TYPE_TEXT_FLAG_MULTI_LINE |
InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS |
InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE);
editText.setMovementMethod(new ScrollingMovementMethod());
editText.setTextIsSelectable(true);
editText.setHorizontallyScrolling(true);
editText.setVerticalScrollBarEnabled(true);
editText.setHorizontalScrollBarEnabled(true);
editText.setText(script);
layoutModifyResponse.addView(editText);
LinearLayout buttonLayout = new LinearLayout(context);
LinearLayout.LayoutParams buttonParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
buttonParams.topMargin = Utils.dpToPx(10, context);
buttonLayout.setLayoutParams(buttonParams);
buttonLayout.setOrientation(LinearLayout.HORIZONTAL);
Button copyButton = new Button(context);
copyButton.setText(R.string.button_copy);
copyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("", editText.getText().toString());
clipboard.setPrimaryClip(clip);
}
});
buttonLayout.addView(copyButton);
Button pasteButton = new Button(context);
pasteButton.setText(R.string.button_paste);
pasteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
if (clipboard != null && clipboard.hasPrimaryClip()) {
ClipData clip = clipboard.getPrimaryClip();
if (clip != null && clip.getItemCount() > 0) {
CharSequence pasteData = clip.getItemAt(0).getText();
editText.setText(pasteData);
}
}
}
});
buttonLayout.addView(pasteButton);
layoutModifyResponse.addView(buttonLayout);
ScrollView scrollView = new ScrollView(context);
scrollView.addView(layoutModifyResponse);
AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setTitle(R.string.modify_response);
builder.setView(scrollView);
builder.setPositiveButton(R.string.positive_button, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String code = editText.getText().toString();
if (!code.equals(script)) {
prefs.edit().putString("encoded_js_modify_response", Base64.encodeToString(code.getBytes(), Base64.NO_WRAP)).commit();
Toast.makeText(context.getApplicationContext(), context.getString(R.string.restarting), Toast.LENGTH_SHORT).show();
Process.killProcess(Process.myPid());
context.startActivity(new Intent().setClassName(Constants.PACKAGE_NAME, "jp.naver.line.android.activity.SplashActivity"));
}
}
});
builder.setNegativeButton(R.string.negative_button, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
editText.setText(script);
}
});
AlertDialog dialog = builder.create();
Button button = new Button(context);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = Utils.dpToPx(20, context);
button.setLayoutParams(params);
button.setText(R.string.modify_response);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dialog.show();
}
});
layout.addView(button);
}
ScrollView scrollView = new ScrollView(context);
scrollView.addView(layout);
AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setTitle(R.string.options_title);
builder.setView(scrollView);
builder.setPositiveButton(R.string.positive_button, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
boolean optionChanged = false;
for (int i = 0; i < limeOptions.options.length; ++i) {
Switch switchView = (Switch) layout.getChildAt(i);
if (limeOptions.options[i].checked != switchView.isChecked()) {
optionChanged = true;
}
prefs.edit().putBoolean(limeOptions.options[i].name, switchView.isChecked()).commit();
}
if (optionChanged) {
Toast.makeText(context.getApplicationContext(), context.getString(R.string.restarting), Toast.LENGTH_SHORT).show();
Process.killProcess(Process.myPid());
context.startActivity(new Intent().setClassName(Constants.PACKAGE_NAME, "jp.naver.line.android.activity.SplashActivity"));
}
}
});
builder.setNegativeButton(R.string.negative_button, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
for (int i = 0; i < limeOptions.options.length; ++i) {
Switch switchView = (Switch) layout.getChildAt(i);
switchView.setChecked(limeOptions.options[i].checked);
}
}
});
AlertDialog dialog = builder.create();
Button button = new Button(context);
button.setText(R.string.app_name);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
layoutParams.gravity = Gravity.TOP | Gravity.END;
layoutParams.rightMargin = Utils.dpToPx(10, context);
// ステータスバーの高さを取得
int statusBarHeight = getStatusBarHeight(context);
// ステータスバーの高さに係数0.1を掛けて調整
layoutParams.topMargin = (int) (statusBarHeight * 0.1); // ステータスバーの高さの10%をマージンに設定
button.setLayoutParams(layoutParams);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dialog.show();
}
});
FrameLayout frameLayout = new FrameLayout(context);
frameLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
frameLayout.addView(button);
viewGroup.addView(frameLayout);
}
}
);
}
XposedBridge.hookAllMethods(
loadPackageParam.classLoader.loadClass("com.linecorp.line.settings.main.LineUserMainSettingsFragment"),
loadPackageParam.classLoader.loadClass("com.linecorp.line.settings.lab.LineUserLabSettingsFragment"),
"onViewCreated",
new XC_MethodHook() {
@Override
@ -220,7 +629,7 @@ public class EmbedOptions implements IHook {
restoreChatsFolder(context,moduleContext);
}
});
layout.addView(restorefolderButton);
layout.addView(restorefolderButton);
if (limeOptions.MuteGroup.checked) {
Button MuteGroups_Button = new Button(context);
MuteGroups_Button.setLayoutParams(buttonParams);
@ -234,17 +643,17 @@ public class EmbedOptions implements IHook {
layout.addView(MuteGroups_Button);
}
Button KeepUnread_Button = new Button(context);
KeepUnread_Button.setLayoutParams(buttonParams);
KeepUnread_Button.setText(moduleContext.getResources().getString(R.string.edit_margin_settings));
KeepUnread_Button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
KeepUnread_Button(context,moduleContext);
}
});
layout.addView(KeepUnread_Button);
Button KeepUnread_Button = new Button(context);
KeepUnread_Button.setLayoutParams(buttonParams);
KeepUnread_Button.setText(moduleContext.getResources().getString(R.string.edit_margin_settings));
KeepUnread_Button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
KeepUnread_Button(context,moduleContext);
}
});
layout.addView(KeepUnread_Button);
builder.setPositiveButton(R.string.positive_button, new DialogInterface.OnClickListener() {
@ -431,40 +840,53 @@ public class EmbedOptions implements IHook {
}
}
});
AlertDialog dialog = builder.create();
Button button = new Button(context);
button.setText(R.string.app_name);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
layoutParams.gravity = Gravity.TOP | Gravity.END;
layoutParams.rightMargin = Utils.dpToPx(10, context);
// 新しい項目ボタンを作成
android.view.View view = (android.view.View) param.args[0];
android.widget.Button newButton = new android.widget.Button(context);
newButton.setText(R.string.app_name); // ボタンのテキストを設定
// ステータスバーの高さを取得
int statusBarHeight = getStatusBarHeight(context);
// ボタンのレイアウトパラメータを設定
android.widget.FrameLayout.LayoutParams layoutParams = new android.widget.FrameLayout.LayoutParams(
android.widget.FrameLayout.LayoutParams.WRAP_CONTENT, //
android.widget.FrameLayout.LayoutParams.WRAP_CONTENT // 高さ
);
layoutParams.gravity = Gravity.BOTTOM | Gravity.END; // 右下に配置
layoutParams.bottomMargin = Utils.dpToPx(16, context); // 下マージンを16dpに設定
layoutParams.rightMargin = Utils.dpToPx(16, context); // 右マージンを16dpに設定
// ステータスバーの高さに係数0.1を掛けて調整
layoutParams.topMargin = (int) (statusBarHeight * 0.1); // ステータスバーの高さの10%をマージンに設定
newButton.setLayoutParams(layoutParams);
button.setLayoutParams(layoutParams);
button.setOnClickListener(new View.OnClickListener() {
// ボタンのクリックリスナーを設定
newButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dialog.show();
dialog.show(); // ボタンクリックで AlertDialog を表示
}
});
FrameLayout frameLayout = new FrameLayout(context);
frameLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
frameLayout.addView(button);
viewGroup.addView(frameLayout);
// ボタンをビューに追加
if (view instanceof android.view.ViewGroup) {
android.view.ViewGroup viewGroup1 = (android.view.ViewGroup) view;
// FrameLayout を作成してボタンを追加
android.widget.FrameLayout frameLayout = new android.widget.FrameLayout(context);
frameLayout.setLayoutParams(new android.view.ViewGroup.LayoutParams(
android.view.ViewGroup.LayoutParams.MATCH_PARENT,
android.view.ViewGroup.LayoutParams.MATCH_PARENT
));
frameLayout.addView(newButton);
// FrameLayout を親ビューに追加
viewGroup1.addView(frameLayout);
}
}
}
);
}
public int getStatusBarHeight(Context context) {
int result = 0;

View File

@ -148,6 +148,7 @@
<string name="ReadCheckerChatdataDelete">(緊急用)既読確認ボタンの右にデータ削除ボタンを作成する</string>
<string name="AgeCheckSkip">年齢確認をスキップ</string>
<string name="GroupNotification">GroupNotification</string>
<string name="LINELabOnly">設定ボタンをLINEラボ画面のみに追加する</string>
</resources>

View File

@ -140,5 +140,6 @@
<string name="chat_read_check_size">讀取確認按鈕的大小</string>
<string name="ReadCheckerChatdataDelete">(緊急)在聊天室內已讀確認按鈕右邊設定一個刪除紀錄按鈕</string>
<string name="AgeCheckSkip">跳過年齡驗證</string>
<string name="LINELabOnly">只在LINE Lab畫面中加入設定按鈕</string>
</resources>

View File

@ -154,4 +154,5 @@
<string name="ReadCheckerChatdataDelete">(For emergencies) Create a data deletion button to the right of the read confirmation button</string>
<string name="AgeCheckSkip">Skip Age Verification</string>
<string name="GroupNotification">GroupNotification</string>
<string name="LINELabOnly">Add the settings button exclusively to the LINE Lab screen.</string>
</resources>