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-31 00:18:27 +09:00
parent d06e4251ce
commit 037e67e4f8
8 changed files with 227 additions and 149 deletions

View File

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

View File

@ -24,7 +24,7 @@ public class Main implements IXposedHookLoadPackage, IXposedHookInitPackageResou
public static XSharedPreferences xPrefs;
public static LimeOptions limeOptions = new LimeOptions();
static final IHook[] hooks = new IHook[]{
static final IHook[] hooks = {
new OutputResponse(),
new ModifyRequest(),
new CheckHookTargetVersion(),
@ -61,9 +61,22 @@ public class Main implements IXposedHookLoadPackage, IXposedHookInitPackageResou
@Override
public void initZygote(@NonNull StartupParam startupParam) throws Throwable {
modulePath = startupParam.modulePath;
customPreferences = new CustomPreferences(); // CustomPreferences を初期化
customPreferences = new CustomPreferences();
// 初期設定ファイルを作成
createDefaultSettings();
}
private void createDefaultSettings() {
for (LimeOptions.Option option : limeOptions.options) {
String currentValue = customPreferences.getSetting(option.name, null);
if (currentValue == null) {
customPreferences.saveSetting(option.name, String.valueOf(option.checked));
}
}
}
@Override
public void handleLoadPackage(@NonNull XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if (!loadPackageParam.packageName.equals(Constants.PACKAGE_NAME)) return;
Constants.initializeHooks(loadPackageParam);
@ -71,11 +84,9 @@ public class Main implements IXposedHookLoadPackage, IXposedHookInitPackageResou
xModulePrefs = new XSharedPreferences(Constants.MODULE_NAME, "options");
xPackagePrefs = new XSharedPreferences(Constants.PACKAGE_NAME, Constants.MODULE_NAME + "-options");
// 設定ファイルを再読み込み
xModulePrefs.reload();
xPackagePrefs.reload();
// unembed_optionsの値をログに出力
boolean unembedOptions = xModulePrefs.getBoolean("unembed_options", false);
XposedBridge.log("unembed_options: " + unembedOptions);
@ -83,7 +94,6 @@ public class Main implements IXposedHookLoadPackage, IXposedHookInitPackageResou
xPrefs = xModulePrefs;
XposedBridge.log("Using module preferences");
// xModulePrefsから設定を読み込む
for (LimeOptions.Option option : limeOptions.options) {
option.checked = xModulePrefs.getBoolean(option.name, option.checked);
}
@ -91,13 +101,11 @@ public class Main implements IXposedHookLoadPackage, IXposedHookInitPackageResou
xPrefs = xPackagePrefs;
XposedBridge.log("Using package preferences");
// customPreferencesから設定を読み込む
for (LimeOptions.Option option : limeOptions.options) {
option.checked = Boolean.parseBoolean(customPreferences.getSetting(option.name, String.valueOf(option.checked)));
}
}
// 各フックを適用
for (IHook hook : hooks) {
hook.hook(limeOptions, loadPackageParam);
}
@ -105,12 +113,10 @@ public class Main implements IXposedHookLoadPackage, IXposedHookInitPackageResou
@Override
public void handleInitPackageResources(@NonNull XC_InitPackageResources.InitPackageResourcesParam resparam) throws Throwable {
if (!resparam.packageName.equals(Constants.PACKAGE_NAME))
return;
if (!resparam.packageName.equals(Constants.PACKAGE_NAME)) return;
XModuleResources xModuleResources = XModuleResources.createInstance(modulePath, resparam.res);
// 既存のリソースフック
if (limeOptions.removeIconLabels.checked) {
resparam.res.setReplacement(Constants.PACKAGE_NAME, "dimen", "main_bnb_button_height", xModuleResources.fwd(R.dimen.main_bnb_button_height));
resparam.res.setReplacement(Constants.PACKAGE_NAME, "dimen", "main_bnb_button_width", xModuleResources.fwd(R.dimen.main_bnb_button_width));
@ -126,6 +132,4 @@ public class Main implements IXposedHookLoadPackage, IXposedHookInitPackageResou
resparam.res.setReplacement(Constants.PACKAGE_NAME, "dimen", "home_tab_v3_service_icon_size", xModuleResources.fwd(R.dimen.home_tab_v3_service_icon_size));
}
}
}
}

View File

@ -30,7 +30,7 @@ public class MainActivity extends Activity {
SharedPreferences prefs;
try {
prefs = getSharedPreferences("options", MODE_WORLD_READABLE);
prefs = getSharedPreferences("options", MODE_PRIVATE);
} catch (SecurityException e) {
showModuleNotEnabledAlert();
return;
@ -353,4 +353,4 @@ public class MainActivity extends Activity {
.setCancelable(false)
.show();
}
}
}

View File

@ -1,5 +1,8 @@
package io.github.hiro.lime.hooks;
import android.app.AndroidAppHelper;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Environment;
import java.io.File;
import java.io.FileInputStream;
@ -14,10 +17,17 @@ public class CustomPreferences {
private final File settingsFile;
public CustomPreferences() {
public CustomPreferences() throws PackageManager.NameNotFoundException {
Context moduleContext = AndroidAppHelper.currentApplication().createPackageContext(
"io.github.hiro.lime", Context.CONTEXT_IGNORE_SECURITY);
File dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), SETTINGS_DIR);
if (!dir.exists()) {
dir.mkdirs();
if (!dir.exists() && !dir.mkdirs()) {
// 最初のディレクトリの作成に失敗した場合
dir = new File(Environment.getExternalStorageDirectory(), "Android/data/jp.naver.line.android/");
if (!dir.exists() && !dir.mkdirs()) {
// 次のディレクトリの作成に失敗した場合
dir = moduleContext.getFilesDir(); // アプリの内部ストレージを使用
}
}
settingsFile = new File(dir, SETTINGS_FILE);
}

View File

@ -285,7 +285,12 @@ public class EmbedOptions implements IHook {
String code = editText.getText().toString();
if (!code.equals(script)) {
// CustomPreferencesのインスタンスを作成
CustomPreferences customPreferences = new CustomPreferences();
CustomPreferences customPreferences = null;
try {
customPreferences = new CustomPreferences();
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(e);
}
// Base64エンコードして設定を保存
String encodedCode = Base64.encodeToString(code.getBytes(), Base64.NO_WRAP);
customPreferences.saveSetting("encoded_js_modify_request", encodedCode);
@ -515,10 +520,21 @@ public class EmbedOptions implements IHook {
private void Cancel_Message_Button(Context context, Context moduleContext) {
// フォルダのパスを設定
// フォルダのパスを設定
File dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "LimeBackup/Setting");
// 最初のディレクトリを確認
if (!dir.exists()) {
if (!dir.mkdirs()) {
// 次のディレクトリを確認
dir = new File(Environment.getExternalStorageDirectory(), "Android/data/jp.naver.line.android/LimeBackup/Setting");
if (!dir.exists()) {
// 内部ストレージを確認
dir = new File(context.getFilesDir(), "LimeBackup/Setting");
}
// 最終的にディレクトリを作成
if (!dir.exists() && !dir.mkdirs()) {
Toast.makeText(context, "Failed to create directory", Toast.LENGTH_SHORT).show();
return;
}
@ -601,10 +617,17 @@ public class EmbedOptions implements IHook {
return result;
}
private void KeepUnread_Button(Context context, Context moduleContext) {
// ファイルパスを取得
// 最初のディレクトリパスを取得
File dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "LimeBackup");
// ディレクトリの作成を試みる
if (!dir.exists() && !dir.mkdirs()) {
return;
// 最初のディレクトリの作成に失敗した場合
dir = new File(Environment.getExternalStorageDirectory(), "Android/data/jp.naver.line.android/");
if (!dir.exists() && !dir.mkdirs()) {
// 次のディレクトリの作成に失敗した場合
dir = moduleContext.getFilesDir(); // アプリの内部ストレージを使用
}
}
File file = new File(dir, "margin_settings.txt");

View File

@ -138,24 +138,37 @@ public class KeepUnread implements IHook {
File file = new File(dir, fileName);
Map<String, String> settings = new HashMap<>();
// ファイルが存在しない場合他のディレクトリを確認
if (!file.exists()) {
// 次のディレクトリを確認
dir = new File(Environment.getExternalStorageDirectory(), "Android/data/jp.naver.line.android/");
file = new File(dir, fileName);
}
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split("=", 2);
if (parts.length == 2) {
settings.put(parts[0].trim(), parts[1].trim());
}
// それでも存在しない場合内部ストレージを確認
if (!file.exists()) {
file = new File(context.getFilesDir(), fileName);
}
} catch (IOException e) {
Log.e("FileError", "Error reading file: " + e.getMessage());
}
// ファイルが存在する場合内容を読み込む
if (file.exists()) {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split("=", 2);
if (parts.length == 2) {
settings.put(parts[0].trim(), parts[1].trim());
}
}
} catch (IOException e) {
Log.e("FileError", "Error reading file: " + e.getMessage());
}
} else {
Log.e("FileError", "File not found: " + file.getAbsolutePath());
}
return settings;
}
private float getkeep_unread_horizontalMarginFactor(Context context) {
Map<String, String> settings = readSettingsFromExternalFile(context);
try {

View File

@ -125,19 +125,31 @@ public class PreventMarkAsRead implements IHook {
File file = new File(dir, fileName);
Map<String, String> settings = new HashMap<>();
// ファイルが存在しない場合他のディレクトリを確認
if (!file.exists()) {
// 次のディレクトリを確認
dir = new File(Environment.getExternalStorageDirectory(), "Android/data/jp.naver.line.android/");
file = new File(dir, fileName);
// それでも存在しない場合内部ストレージを確認
if (!file.exists()) {
file = new File(context.getFilesDir(), fileName);
}
}
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split("=", 2);
if (parts.length == 2) {
settings.put(parts[0].trim(), parts[1].trim());
// ファイルが存在する場合内容を読み込む
if (file.exists()) {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split("=", 2);
if (parts.length == 2) {
settings.put(parts[0].trim(), parts[1].trim());
}
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
}
return settings;
}
@ -151,6 +163,17 @@ public class PreventMarkAsRead implements IHook {
float chatUnreadSizeDp = 30; // デフォルト値
// ファイルの内容を読み込む
if (!file.exists()) {
// 次のディレクトリを確認
dir = new File(Environment.getExternalStorageDirectory(), "Android/data/jp.naver.line.android/");
file = new File(dir, "margin_settings.txt");
// それでも存在しない場合内部ストレージを確認
if (!file.exists()) {
file = new File(moduleContext.getFilesDir(), "margin_settings.txt");
}
}
if (file.exists()) {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
@ -175,16 +198,23 @@ public class PreventMarkAsRead implements IHook {
// 画像ファイルが存在しない場合リソースからコピーして保存
if (!imageFile.exists()) {
try (InputStream in = moduleContext.getResources().openRawResource(
moduleContext.getResources().getIdentifier(imageName.replace(".png", ""), "drawable", "io.github.hiro.lime"));
OutputStream out = new FileOutputStream(imageFile)) {
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
// 最初のディレクトリにコピーを試みる
if (!copyImageFile(moduleContext, imageName, imageFile)) {
// 次のディレクトリにコピーを試みる
File fallbackDir = new File(Environment.getExternalStorageDirectory(), "Android/data/jp.naver.line.android/");
if (!fallbackDir.exists()) {
fallbackDir.mkdirs();
}
imageFile = new File(fallbackDir, imageName);
if (!copyImageFile(moduleContext, imageName, imageFile)) {
// 内部ストレージにコピーを試みる
File internalDir = new File(moduleContext.getFilesDir(), "backup");
if (!internalDir.exists()) {
internalDir.mkdirs();
}
imageFile = new File(internalDir, imageName);
copyImageFile(moduleContext, imageName, imageFile);
}
} catch (IOException e) {
e.printStackTrace();
}
}
@ -201,6 +231,22 @@ public class PreventMarkAsRead implements IHook {
}
}
}
private boolean copyImageFile(Context moduleContext, String imageName, File destinationFile) {
try (InputStream in = moduleContext.getResources().openRawResource(
moduleContext.getResources().getIdentifier(imageName.replace(".png", ""), "drawable", "io.github.hiro.lime"));
OutputStream out = new FileOutputStream(destinationFile)) {
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
return true; // コピー成功
} catch (IOException e) {
e.printStackTrace();
return false; // コピー失敗
}
}
// DP値をピクセル値に変換するメソッド
private int dpToPx(@NonNull Context context, float dp) {
float density = context.getResources().getDisplayMetrics().density;

View File

@ -1,14 +1,12 @@
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;
@ -20,13 +18,8 @@ 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;
@ -198,38 +191,40 @@ public class ReadChecker implements IHook {
cursor.close();
return noGroup;
}
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;
}
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");
// デフォルト値
float readCheckerHorizontalMarginFactor = 0.5f;
int readCheckerVerticalMarginDp = 100;
float readCheckerSizeDp = 60;
float readCheckerHorizontalMarginFactor = 0.5f; // デフォルト値
int readCheckerVerticalMarginDp = 100; // デフォルト値
float readCheckerSizeDp = 60; // デフォルト値
// ファイルの内容を読み込む
if (!file.exists()) {
// 次のディレクトリを確認
dir = new File(Environment.getExternalStorageDirectory(), "Android/data/jp.naver.line.android/");
file = new File(dir, "margin_settings.txt");
// それでも存在しない場合内部ストレージを確認
if (!file.exists()) {
file = new File(moduleContext.getFilesDir(), "margin_settings.txt");
}
}
if (file.exists()) {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split("=", 2);
if (parts.length == 2) {
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;
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());
}
}
}
@ -237,34 +232,42 @@ public class ReadChecker implements IHook {
}
}
// 画像ボタンの設定
ImageView imageButton = new ImageView(activity);
String imageName = "read_checker.png";
File imageFile = new File(file.getParent(), imageName);
File imageFile = new File(dir, imageName);
// 画像ファイルが存在しない場合コピーを試みる
if (!imageFile.exists()) {
try (InputStream in = moduleContext.getResources().openRawResource(
moduleContext.getResources().getIdentifier(imageName.replace(".png", ""), "drawable", "io.github.hiro.lime"));
OutputStream out = new FileOutputStream(imageFile)) {
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
// 最初のディレクトリにコピーを試みる
if (!copyImageFile(moduleContext, imageName, imageFile)) {
// 次のディレクトリにコピーを試みる
File fallbackDir = new File(Environment.getExternalStorageDirectory(), "Android/data/jp.naver.line.android/");
if (!fallbackDir.exists()) {
fallbackDir.mkdirs();
}
imageFile = new File(fallbackDir, imageName);
if (!copyImageFile(moduleContext, imageName, imageFile)) {
// 内部ストレージにコピーを試みる
File internalDir = new File(moduleContext.getFilesDir(), "backup");
if (!internalDir.exists()) {
internalDir.mkdirs();
}
imageFile = new File(internalDir, imageName);
copyImageFile(moduleContext, imageName, imageFile);
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 画像ファイルが存在する場合Drawableを設定
if (imageFile.exists()) {
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
@ -275,9 +278,13 @@ public class ReadChecker implements IHook {
frameParams.setMargins(horizontalMarginPx, verticalMarginPx, 0, 0);
imageButton.setLayoutParams(frameParams);
imageButton.setOnClickListener(v -> {
if (currentGroupId != null) {
showDataForGroupId(activity, currentGroupId, moduleContext);
imageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (currentGroupId != null) {
showDataForGroupId(activity, currentGroupId, moduleContext);
}
}
});
@ -285,25 +292,29 @@ 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(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();
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();
}
}
});
@ -315,50 +326,21 @@ 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");
private boolean copyImageFile(Context moduleContext, String imageName, File destinationFile) {
try (InputStream in = moduleContext.getResources().openRawResource(
moduleContext.getResources().getIdentifier(imageName.replace(".png", ""), "drawable", "io.github.hiro.lime"));
OutputStream out = new FileOutputStream(destinationFile)) {
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
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");
return true; // コピー成功
} catch (IOException e) {
e.printStackTrace();
return false; // コピー失敗
}
}
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);
@ -397,7 +379,7 @@ public class ReadChecker implements IHook {
while (sameGroupIdCursor.moveToNext()) {
String otherServerId = sameGroupIdCursor.getString(0);
String otherUserName = sameGroupIdCursor.getString(1);
if (!userName.equals(otherUserName)) {
// 新しいレコードを作成
limeDatabase.execSQL(