Skip to content

Commit

Permalink
feat: Remote Chat Extra Buttons
Browse files Browse the repository at this point in the history
  • Loading branch information
omg-xtao committed Jul 24, 2024
1 parent c4c3cf8 commit 3da6b2e
Show file tree
Hide file tree
Showing 6 changed files with 253 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@
import tw.nekomimi.nekogram.NekoConfig;
import tw.nekomimi.nekogram.cc.CCConverter;
import tw.nekomimi.nekogram.cc.CCTarget;
import tw.nekomimi.nekogram.helpers.remote.ChatExtraButtonsHelper;
import tw.nekomimi.nekogram.transtale.TranslateDb;
import tw.nekomimi.nekogram.transtale.Translator;
import tw.nekomimi.nekogram.transtale.TranslatorKt;
Expand Down Expand Up @@ -4358,6 +4359,20 @@ public boolean onTouch(View v, MotionEvent event) {
ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getContext(), true, false);
int dlps = delegate.getDisableLinkPreviewStatus();

long _chatId = -1;
if (parentFragment != null) {
TLRPC.Chat chat = parentFragment.getCurrentChat();
TLRPC.User user = parentFragment.getCurrentUser();
if (chat != null) {
_chatId = chat.id;
} else if (user != null) {
_chatId = user.id;
} else {
_chatId = -1;
}
}
final long chatId = _chatId;

if (!isInInput) {

cell.setTextAndIcon(LocaleController.getString("ChatAttachEnterMenuRecordAudio", R.string.ChatAttachEnterMenuRecordAudio), R.drawable.input_mic);
Expand Down Expand Up @@ -4451,18 +4466,6 @@ public boolean onTouch(View v, MotionEvent event) {

}

TLRPC.Chat chat = parentFragment.getCurrentChat();
TLRPC.User user = parentFragment.getCurrentUser();

long chatId;
if (chat != null) {
chatId = chat.id;
} else if (user != null) {
chatId = user.id;
} else {
chatId = -1;
}

cell.setTextAndIcon(LocaleController.getString("Translate", R.string.Translate), R.drawable.ic_translate);
cell.setOnClickListener(v -> {
if (menuPopupWindow != null && menuPopupWindow.isShowing()) {
Expand Down Expand Up @@ -4560,6 +4563,8 @@ public boolean onTouch(View v, MotionEvent event) {
menuPopupLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 0, 48 * a++, 0, 0));
}

addChatExtraButtons(chatId, a, menuPopupLayout);

menuPopupLayout.setupRadialSelectors(Theme.getColor(Theme.key_dialogButtonSelector));

menuPopupWindow = new ActionBarPopupWindow(menuPopupLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT);
Expand Down Expand Up @@ -4596,6 +4601,44 @@ public boolean onTouch(View v, MotionEvent event) {

}

private int addChatExtraButtons(long chatId, int a, ActionBarPopupWindow.ActionBarPopupWindowLayout menuPopupLayout) {
ArrayList<ChatExtraButtonsHelper.ChatExtraButtonInfo> buttonInfos = ChatExtraButtonsHelper.getInstance().getChatExtraButtons(chatId);
if (buttonInfos == null) {
return a;
}
for (ChatExtraButtonsHelper.ChatExtraButtonInfo info : buttonInfos) {
ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getContext(), false, true);

switch (info.type) {
case ChatExtraButtonsHelper.CHAT_BUTTON_TYPE_LINK:
cell.setTextAndIcon(
info.name.isEmpty() ? LocaleController.getString("OpenUrlTitle", R.string.OpenUrlTitle) : info.name,
R.drawable.msg_openin
);
break;
case ChatExtraButtonsHelper.CHAT_BUTTON_TYPE_SEARCH:
cell.setTextAndIcon(
info.name.isEmpty() ? LocaleController.getString("Search", R.string.Search) : info.name,
R.drawable.msg_search
);
break;
}

cell.setOnClickListener(v -> {
if (menuPopupWindow != null && menuPopupWindow.isShowing()) {
menuPopupWindow.dismiss();
}
if (parentActivity != null) {
Browser.openUrl(parentActivity, Uri.parse(info.url), true, true);
}
});

cell.setMinimumWidth(AndroidUtilities.dp(196));
menuPopupLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 0, 48 * a++, 0, 0));
}
return a;
}

private ActionBarMenuSubItem actionScheduleButton;
private boolean onSendLongClick(View view) {
if (isInScheduleMode() || parentFragment != null && parentFragment.getChatMode() == ChatActivity.MODE_QUICK_REPLIES) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
import kotlin.text.StringsKt;
import tw.nekomimi.nekogram.InternalUpdater;
import tw.nekomimi.nekogram.helpers.SettingsHelper;
import tw.nekomimi.nekogram.helpers.remote.ChatExtraButtonsHelper;
import tw.nekomimi.nekogram.helpers.remote.EmojiHelper;
import tw.nekomimi.nekogram.helpers.remote.PagePreviewRulesHelper;
import tw.nekomimi.nekogram.helpers.remote.PeerColorHelper;
Expand Down Expand Up @@ -1077,6 +1078,7 @@ public void onViewDetachedFromWindow(View v) {
WallpaperHelper.getInstance().checkWallPaper();
PeerColorHelper.getInstance().checkPeerColor();
PagePreviewRulesHelper.getInstance().checkPagePreviewRules();
ChatExtraButtonsHelper.getInstance().checkChatExtraButtons();
BackupAgent.requestBackup(this);

RestrictedLanguagesSelectActivity.checkRestrictedLanguages(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ public void doAutoSync() {

private void syncToCloud(Utilities.Callback2<Boolean, String> callback) {
try {
String setting = NekoSettingsActivity.backupSettingsJson();
String setting = NekoSettingsActivity.backupSettingsJson(0);
// 分块存储
int chunkSize = 4000; // 每个分块的最大长度
int numChunks = (int) Math.ceil((double) setting.length() / chunkSize); // 计算总分块数
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package tw.nekomimi.nekogram.helpers.remote;

import android.text.TextUtils;
import android.util.Base64;

import org.json.JSONException;
import org.json.JSONObject;
import org.telegram.messenger.FileLog;
import org.telegram.tgnet.AbstractSerializedData;
import org.telegram.tgnet.SerializedData;

import java.util.ArrayList;
import java.util.HashMap;

public class ChatExtraButtonsHelper extends BaseRemoteHelper {
private static final String CHAT_EXTRA_BUTTONS_TAG = "chatButtonsV1";
private static volatile ChatExtraButtonsHelper Instance;
private final ArrayList<ChatExtraButtonInfo> buttons = new ArrayList<>();
private final HashMap<Long, ArrayList<ChatExtraButtonInfo>> buttonsMap = new HashMap<>();
private boolean loading = false;

public static ChatExtraButtonsHelper getInstance() {
ChatExtraButtonsHelper localInstance = Instance;
if (localInstance == null) {
synchronized (ChatExtraButtonsHelper.class) {
localInstance = Instance;
if (localInstance == null) {
Instance = localInstance = new ChatExtraButtonsHelper();
}
return localInstance;
}
}
return localInstance;
}

@Override
protected void onError(String text, Delegate delegate) {

}

@Override
protected String getTag() {
return CHAT_EXTRA_BUTTONS_TAG;
}

@Override
protected void onLoadSuccess(ArrayList<JSONObject> responses, Delegate delegate) {
var tag = getTag();
var json = !responses.isEmpty() ? responses.get(0) : null;
if (json == null) {
preferences.edit()
.remove(tag + "_update_time")
.remove(tag)
.apply();
return;
}

try {
ArrayList<ChatExtraButtonInfo> buttonInfo = new ArrayList<>();
var array = json.getJSONArray("buttons");

for (int i = 0; i < array.length(); i++) {
var obj = array.getJSONObject(i);
int type = obj.getInt("type");
long chatId = obj.getLong("chat_id");
String name = obj.getString("name");
String url = obj.getString("url");
var info = new ChatExtraButtonInfo(
type,
chatId,
name,
url
);
buttonInfo.add(info);
}

buttons.clear();
buttons.addAll(buttonInfo);
buttonsMap.clear();
for (ChatExtraButtonInfo info : buttons) {
putToMap(info);
}
saveChatExtraButtons();
} catch (JSONException e) {
FileLog.e(e);
}
}

private void putToMap(ChatExtraButtonInfo info) {
ArrayList<ChatExtraButtonInfo> arrayList = buttonsMap.get(info.chatId);
if (arrayList == null) {
arrayList = new ArrayList<>();
}
arrayList.add(info);
buttonsMap.put(info.chatId, arrayList);
}

public ArrayList<ChatExtraButtonInfo> getChatExtraButtons(long chatId) {
return buttonsMap.get(chatId);
}

public void loadPagePreviewRules() {
var tag = getTag();
String list = preferences.getString(tag, "");
buttons.clear();
buttonsMap.clear();
if (!TextUtils.isEmpty(list)) {
byte[] bytes = Base64.decode(list, Base64.DEFAULT);
SerializedData data = new SerializedData(bytes);
int count = data.readInt32(false);
for (int a = 0; a < count; a++) {
ChatExtraButtonInfo info = ChatExtraButtonInfo.deserialize(data);
buttons.add(info);
putToMap(info);
}
data.cleanup();
}
}

public void saveChatExtraButtons() {
var tag = getTag();
SerializedData serializedData = new SerializedData();
serializedData.writeInt32(buttons.size());
for (ChatExtraButtonInfo info : buttons) {
info.serializeToStream(serializedData);
}
preferences.edit()
.putLong(tag + "_update_time", System.currentTimeMillis())
.putString(tag, Base64.encodeToString(serializedData.toByteArray(), Base64.NO_WRAP | Base64.NO_PADDING))
.apply();
serializedData.cleanup();
}

public boolean needUpdate() {
var tag = getTag();
long oldTime = preferences.getLong(tag + "_update_time", 0L);
long nowTime = System.currentTimeMillis();
int TTL = 15 * 60;
return oldTime + TTL <= nowTime;
}

public void checkChatExtraButtons() {
if (loading) {
return;
}
loading = true;
loadPagePreviewRules();
if (needUpdate()) {
load();
}
loading = false;
}

public static final int CHAT_BUTTON_TYPE_LINK = 1;
public static final int CHAT_BUTTON_TYPE_SEARCH = 2;

public static class ChatExtraButtonInfo {
public int type;
public long chatId;
public String name;
public String url;

public ChatExtraButtonInfo() {}

public ChatExtraButtonInfo(int type, long chatId, String name, String url) {
this.type = type;
this.chatId = chatId;
this.name = name;
this.url = url;
}

public static ChatExtraButtonInfo deserialize(AbstractSerializedData stream) {
ChatExtraButtonInfo chatExtraButtonInfo = new ChatExtraButtonInfo();
chatExtraButtonInfo.type = stream.readInt32(false);
chatExtraButtonInfo.chatId = stream.readInt64(false);
chatExtraButtonInfo.name = stream.readString(false);
chatExtraButtonInfo.url = stream.readString(false);
return chatExtraButtonInfo;
}

public void serializeToStream(AbstractSerializedData serializedData) {
serializedData.writeInt32(type);
serializedData.writeInt64(chatId);
serializedData.writeString(name);
serializedData.writeString(url);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import org.json.JSONException;
import org.json.JSONObject;
import org.telegram.messenger.BuildConfig;
import org.telegram.messenger.BuildVars;
import org.telegram.tgnet.TLObject;
import org.telegram.tgnet.TLRPC;

Expand All @@ -17,7 +16,7 @@
import tw.nekomimi.nekogram.NekoXConfig;

public class UpdateHelper extends BaseRemoteHelper {
public static final String UPDATE_TAG = NekoXConfig.autoUpdateReleaseChannel == 2 ? "updatetest" : "updatev1";
public static final String UPDATE_TAG = NekoXConfig.autoUpdateReleaseChannel == 2 ? "updatetest" : "updatev2";

private static final class InstanceHolder {
private static final UpdateHelper instance = new UpdateHelper();
Expand Down Expand Up @@ -81,7 +80,6 @@ private Update getShouldUpdateVersion(List<JSONObject> responses) {
string.getInt("sticker"),
string.getInt("message"),
jsonToMap(string.getJSONObject("gcm")),
jsonToMap(string.getJSONObject("nogcm")),
string.getString("url")
);
break;
Expand Down Expand Up @@ -188,17 +186,15 @@ public static class Update {
public Integer sticker;
public Integer message;
public Map<String, Integer> gcm;
public Map<String, Integer> nogcm;
public String url;

public Update(Boolean canNotSkip, String version, int versionCode, int sticker, int message, Map<String, Integer> gcm, Map<String, Integer> nogcm, String url) {
public Update(Boolean canNotSkip, String version, int versionCode, int sticker, int message, Map<String, Integer> gcm, String url) {
this.canNotSkip = canNotSkip;
this.version = version;
this.versionCode = versionCode;
this.sticker = sticker;
this.message = message;
this.gcm = gcm;
this.nogcm = nogcm;
this.url = url;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,10 @@ private void backupSettings() {
}

public static String backupSettingsJson() throws JSONException {
return backupSettingsJson(4);
}

public static String backupSettingsJson(int indentSpaces) throws JSONException {

JSONObject configJson = new JSONObject();

Expand Down Expand Up @@ -529,7 +533,7 @@ public static String backupSettingsJson() throws JSONException {
spToJSON("nkmrcfg", configJson, null);
spToJSON("nekodialogconfig", configJson, null);

return configJson.toString(4);
return configJson.toString(indentSpaces);
}

private static void spToJSON(String sp, JSONObject object, Function<String, Boolean> filter) throws JSONException {
Expand Down

0 comments on commit 3da6b2e

Please sign in to comment.