This commit is contained in:
世界 2020-04-02 10:13:15 +08:00
parent 8832d06e0c
commit 1fa159f440
No known key found for this signature in database
GPG Key ID: CD109927C34A63C4
16 changed files with 326 additions and 89 deletions

View File

@ -28,6 +28,17 @@ data class AngConfig(
var configVersion: Int = 2,
var testResult: String = "") {
override fun equals(other: Any?): Boolean {
return super.equals(other) || (other is VmessBean &&
address == other.address &&
port == other.port &&
id == other.id &&
network == other.network &&
headerType == other.headerType &&
requestHost == other.requestHost &&
path == other.path)
}
override fun toString(): String {
if (configType == V2RayConfig.EConfigType.Vmess) {
@ -52,7 +63,7 @@ data class AngConfig(
val remark = "#" + Utils.urlEncode(remarks)
val url = String.format("%s:%s@%s:%s",security, id, address, port)
val url = String.format("%s:%s@%s:%s", security, id, address, port)
return SS_PROTOCOL + Base64.encodeToString(url.toByteArray(charset("UTF-8")), Base64.NO_WRAP) + remark

View File

@ -38,15 +38,6 @@ object Utils {
* base64 decode
*/
fun decode(text: String): String {
try {
return Base64.decode(text, Base64.NO_WRAP).toString(charset("UTF-8"))
} catch (e: Exception) {
e.printStackTrace()
return ""
}
}
fun decodeUrlSafe(text: String): String {
val flags = Base64.NO_PADDING or Base64.URL_SAFE or Base64.NO_WRAP
try {
return Base64.decode(text, flags).toString(charset("UTF-8"))

View File

@ -21,23 +21,20 @@ public class KeepAliveJob extends JobIntentService {
private static final Object sync = new Object();
public static void startJob() {
Utilities.globalQueue.postRunnable(new Runnable() {
@Override
public void run() {
if (startingJob || countDownLatch != null) {
return;
Utilities.globalQueue.postRunnable(() -> {
if (startingJob || countDownLatch != null) {
return;
}
try {
if (BuildVars.LOGS_ENABLED) {
FileLog.d("starting keep-alive job");
}
try {
if (BuildVars.LOGS_ENABLED) {
FileLog.d("starting keep-alive job");
}
synchronized (sync) {
startingJob = true;
}
enqueueWork(ApplicationLoader.applicationContext, KeepAliveJob.class, 1000, new Intent());
} catch (Exception ignore) {
synchronized (sync) {
startingJob = true;
}
enqueueWork(ApplicationLoader.applicationContext, KeepAliveJob.class, 1000, new Intent());
} catch (Exception ignore) {
}
}
});
}

View File

@ -2104,7 +2104,7 @@ public class NotificationsController extends BaseController {
intent.putExtra("currentAccount", currentAccount);
PendingIntent pintent = PendingIntent.getService(ApplicationLoader.applicationContext, 0, intent, 0);
SharedPreferences preferences = getAccountInstance().getNotificationsSettings();
int minutes = preferences.getInt("repeat_messages", 60);
int minutes = preferences.getInt("repeat_messages", 5);
if (minutes > 0 && personal_count > 0) {
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + minutes * 60 * 1000, pintent);
} else {

View File

@ -78,4 +78,5 @@ public class NotificationsService extends Service {
}
}
}
}

View File

@ -20,6 +20,8 @@ import android.text.TextUtils;
import android.util.Base64;
import android.util.SparseArray;
import androidx.annotation.Nullable;
import com.v2ray.ang.V2RayConfig;
import com.v2ray.ang.dto.AngConfig;
@ -27,6 +29,7 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.telegram.tgnet.ConnectionsManager;
import org.telegram.ui.ProxyListActivity;
import java.io.File;
import java.io.RandomAccessFile;
@ -42,6 +45,7 @@ import tw.nekomimi.nekogram.ProxyManager;
import tw.nekomimi.nekogram.ShadowsocksLoader;
import tw.nekomimi.nekogram.VmessLoader;
import tw.nekomimi.nekogram.utils.FileUtil;
import tw.nekomimi.nekogram.utils.ProxyUtil;
import tw.nekomimi.nekogram.utils.StrUtil;
import tw.nekomimi.nekogram.utils.UIUtil;
@ -187,11 +191,11 @@ public class SharedConfig {
if (StrUtil.isBlank(remarks)) {
return "[MTProto] " + address + ":" + port;
return "[MTProto] " + address + ":" + port;
} else {
return "[MTProto] " + remarks;
return "[MTProto] " + remarks;
}
@ -361,6 +365,22 @@ public class SharedConfig {
}
@Override
public int hashCode() {
return (address + port).hashCode();
}
@Override
public boolean equals(@Nullable Object obj) {
return super.equals(obj) || (
obj != null &&
obj.getClass().equals(ProxyInfo.class) &&
address.equals(((ProxyInfo) obj).address) &&
port == ((ProxyInfo) obj).port
);
}
}
public abstract static class ExternalSocks5Proxy extends ProxyInfo {
@ -374,6 +394,8 @@ public class SharedConfig {
}
public abstract boolean isStarted();
public abstract void start();
public abstract void stop();
@ -417,16 +439,23 @@ public class SharedConfig {
if (StrUtil.isBlank(getRemarks())) {
return "[Vmess] " + bean.getAddress() + ":" + bean.getPort();
return "[Vmess] " + bean.getAddress() + ":" + bean.getPort();
} else {
return "[Vmess] " + getRemarks();
return "[Vmess] " + getRemarks();
}
}
@Override
public boolean isStarted() {
return loader != null;
}
@Override
public void start() {
@ -478,6 +507,16 @@ public class SharedConfig {
}
@Override
public int hashCode() {
return (bean.getAddress() + bean.getPort() + bean.getId() + bean.getNetwork() + bean.getPath()).hashCode();
}
@Override
public boolean equals(@Nullable Object obj) {
return super.equals(obj) || (obj instanceof VmessProxy && bean.equals(((VmessProxy) obj).bean));
}
}
public static class ShadowsocksProxy extends ExternalSocks5Proxy {
@ -502,16 +541,23 @@ public class SharedConfig {
if (StrUtil.isBlank(getRemarks())) {
return "[SS] " + bean.getHost() + ":" + bean.getRemotePort();
return "[SS] " + bean.getHost() + ":" + bean.getRemotePort();
} else {
return "[SS] " + getRemarks();
return "[SS] " + getRemarks();
}
}
@Override
public boolean isStarted() {
return loader != null;
}
@Override
public void start() {
@ -564,6 +610,18 @@ public class SharedConfig {
}
@Override
public int hashCode() {
return (bean.getHost() + bean.getRemotePort() + bean.getMethod()).hashCode();
}
@Override
public boolean equals(@Nullable Object obj) {
return super.equals(obj) || (obj instanceof ShadowsocksProxy && bean.equals(((ShadowsocksProxy) obj).bean));
}
}
public static class ShadowsocksRProxy extends ExternalSocks5Proxy {
@ -588,16 +646,22 @@ public class SharedConfig {
if (StrUtil.isBlank(getRemarks())) {
return "[SSR] " + bean.getHost() + ":" + bean.getRemotePort();
return "[SSR] " + bean.getHost() + ":" + bean.getRemotePort();
} else {
return "[SSR] " + getRemarks();
return "[SSR] " + getRemarks();
}
}
@Override
public boolean isStarted() {
return loader != null;
}
@Override
public void start() {
@ -650,6 +714,18 @@ public class SharedConfig {
}
@Override
public int hashCode() {
return (bean.getHost() + bean.getRemotePort() + bean.getMethod() + bean.getProtocol() + bean.getProtocol_param() + bean.getObfs() + bean.getObfs_param()).hashCode();
}
@Override
public boolean equals(@Nullable Object obj) {
return super.equals(obj) || (obj instanceof ShadowsocksRProxy && bean.equals(((ShadowsocksRProxy) obj).bean));
}
}
public static LinkedList<ProxyInfo> proxyList = new LinkedList<>();
@ -1318,12 +1394,19 @@ public class SharedConfig {
currentProxy = info;
MessagesController.getGlobalMainSettings().edit().putInt("current_proxy", info.hashCode()).apply();
saveProxyList();
setProxyEnable(true);
}
public static void reloadProxyList() {
proxyListLoaded = false;
loadProxyList();
}
public static void loadProxyList() {
if (proxyListLoaded) {
return;
@ -1333,8 +1416,72 @@ public class SharedConfig {
proxyList.clear();
currentProxy = null;
int current = MessagesController.getGlobalMainSettings().getInt("curent_proxy", 0);
proxyList.add(publicProxy);
File remoteProxyListFile = ProxyUtil.cacheFile;
if (remoteProxyListFile.isFile()) {
try {
JSONArray proxyArray = new JSONArray(FileUtil.readUtf8String(remoteProxyListFile));
for (int a = 0; a < proxyArray.length(); a++) {
JSONObject proxyObj = proxyArray.getJSONObject(a);
ProxyInfo info;
try {
if (!proxyObj.isNull("proxy")) {
// old remote protocol
info = parseProxyInfo(proxyObj.getString("proxy"));
} else {
info = ProxyInfo.fromJson(proxyObj);
}
} catch (Exception ex) {
FileLog.e("load proxy failed", ex);
continue;
}
info.isInternal = true;
proxyList.add(info);
if (info.hashCode() == current) {
currentProxy = info;
if (info instanceof ExternalSocks5Proxy) {
((ExternalSocks5Proxy) info).start();
}
}
}
} catch (Exception ex) {
FileLog.e("invalid proxy list json format", ex);
}
}
File proxyListFile = new File(ApplicationLoader.applicationContext.getFilesDir().getParentFile(), "nekox/proxy_list.json");
if (proxyListFile.isFile()) {
@ -1361,11 +1508,12 @@ public class SharedConfig {
}
if (proxyObj.optBoolean("internal", false)) continue;
if (!proxyObj.isNull("internal")) continue;
if (info.getTitle().toLowerCase().contains("nekox.me")) continue;
proxyList.add(info);
if (proxyObj.optBoolean("current", false)) {
if (info.hashCode() == current) {
currentProxy = info;
@ -1517,11 +1665,8 @@ public class SharedConfig {
int count = proxyList.size();
for (int a = 0; a < count; a++) {
ProxyInfo info = proxyList.get(a);
try {
if (info.toJson().equals(proxyInfo.toJson())) {
return info;
}
} catch (JSONException e) {
if (info.equals(proxyInfo)) {
return info;
}
}
proxyList.add(proxyInfo);
@ -1542,6 +1687,8 @@ public class SharedConfig {
public static void deleteAllProxy() {
setProxyEnable(false);
proxyListLoaded = false;
proxyList.clear();
@ -1552,6 +1699,32 @@ public class SharedConfig {
}
public static void deleteUnavailableProxy() {
setProxyEnable(false);
proxyListLoaded = false;
Iterator<ProxyInfo> iter = proxyList.iterator();
while (iter.hasNext()) {
ProxyInfo info = iter.next();
if (!info.checking && !info.available && info.availableCheckTime != 0) {
iter.remove();
}
}
saveProxyList();
loadProxyList();
}
public static void checkSaveToGalleryFiles() {
try {
File telegramPath;

View File

@ -14964,7 +14964,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null);
showDialog(builder.create());
}
} else if (locFile.getName().toLowerCase().endsWith(".nekox.json")) {
} else if (locFile.getName().toLowerCase().endsWith(".json")) {
File finalLocFile = locFile;
AlertUtil.showConfirm(getParentActivity(),

View File

@ -67,6 +67,8 @@ import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
import tw.nekomimi.nekogram.utils.AlertUtil;
public class NotificationsSettingsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate {
public static class NotificationException {
@ -580,7 +582,7 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif
} else if (position == notificationsServiceRow) {
if (XiaomiUtilities.isMIUI() && !XiaomiUtilities.isCustomPermissionGranted(XiaomiUtilities.OP_AUTO_START)) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Telegram");
builder.setTitle(LocaleController.getString("NekoX",R.string.NekoX));
builder.setMessage(LocaleController.getString("MIUIPermissionNote",R.string.MIUIPermissionNote));
builder.setPositiveButton(LocaleController.getString("OK",R.string.OK),(_x,_y) -> {
@ -594,9 +596,9 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
if (openNotificationListenSettings()) {
if (isNotificationListenerEnabled()) {
AlertsCreator.showSimpleToast(null, LocaleController.getString("DisablePushAlert", R.string.DisablePushAlert));
AlertUtil.showToast( LocaleController.getString("DisablePushAlert", R.string.DisablePushAlert));
} else {
AlertsCreator.showSimpleToast(null, LocaleController.getString("EnablePushAlert", R.string.EnablePushAlert));
AlertUtil.showToast(LocaleController.getString("EnablePushAlert", R.string.EnablePushAlert));
}
}
} else {
@ -993,7 +995,7 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif
textCell.setTextAndValue(LocaleController.getString("Vibrate", R.string.Vibrate), LocaleController.getString("OnlyIfSilent", R.string.OnlyIfSilent), true);
}
} else if (position == repeatRow) {
int minutes = preferences.getInt("repeat_messages", 60);
int minutes = preferences.getInt("repeat_messages", 5);
String value;
if (minutes == 0) {
value = LocaleController.getString("RepeatNotificationsNever", R.string.RepeatNotificationsNever);

View File

@ -168,9 +168,6 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente
colorKey = Theme.key_windowBackgroundWhiteBlueText6;
if (currentInfo.ping != 0) {
valueTextView.setText(LocaleController.getString("Connected", R.string.Connected) + ", " + LocaleController.formatString("Ping", R.string.Ping, currentInfo.ping));
} else if (currentInfo.checking) {
valueTextView.setText(LocaleController.getString("Connected", R.string.Connected) + ", " + LocaleController.formatString("Checking", R.string.Checking));
colorKey = Theme.key_windowBackgroundWhiteGrayText2;
} else {
valueTextView.setText(LocaleController.getString("Connected", R.string.Connected));
}
@ -264,6 +261,28 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente
updateRows(true);
UIUtil.runOnIoDispatcher(() -> {
int times = 0;
while (!ProxyUtil.reloadProxyList()) {
if (times > 5) return;
times++;
try {
Thread.sleep(10 * 1000L);
} catch (InterruptedException e) {
}
}
SharedConfig.reloadProxyList();
UIUtil.runOnUIThread(() -> updateRows(true));
});
return true;
}
@ -289,6 +308,7 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente
private int menu_export_json = 12;
private int menu_import_json = 13;
private int menu_delete_all = 14;
private int menu_delete_unavailable = 15;
public void processProxyList(ArrayList<String> files) {
@ -351,7 +371,7 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente
} catch (Exception ex) {
errors.put(proxyUrl, ex.getMessage());
errors.put(proxyUrl.length() < 15 ? proxyUrl : (proxyUrl.substring(0, 15) + "..."), ex.getMessage());
}
@ -509,14 +529,23 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente
presentFragment(fragment);
} else if (id == menu_delete_all) {
AlertUtil.showConfirm(getParentActivity(),
LocaleController.getString("DeleteAllProxies", R.string.DeleteAllProxies),
LocaleController.getString("DeleteAllProxies", R.string.DeleteAllProxiesAlert),
LocaleController.getString("DeleteAllServer", R.string.DeleteAllServer),
LocaleController.getString("DeleteAllServerConfirm", R.string.DeleteAllServerConfirm),
LocaleController.getString("Delete", R.string.Delete),
true, (d, v) -> {
SharedConfig.deleteAllProxy();
updateRows(true);
});
}
} else if (id == menu_delete_unavailable) {
AlertUtil.showConfirm(getParentActivity(),
LocaleController.getString("DeleteUnavailableServer", R.string.DeleteUnavailableServer),
LocaleController.getString("DeleteUnavailableServerConfirm", R.string.DeleteUnavailableServerConfirm),
LocaleController.getString("Delete", R.string.Delete),
true, (d, v) -> {
SharedConfig.deleteUnavailableProxy();
updateRows(true);
});
}
}
});
@ -613,7 +642,8 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente
otherItem.addSubItem(menu_reorder_by_ping, LocaleController.getString("ReorderByPing", R.string.ReorderByPing));
otherItem.addSubItem(menu_export_json, LocaleController.getString("ExportProxies", R.string.ExportProxies));
otherItem.addSubItem(menu_import_json, LocaleController.getString("ImportProxies", R.string.ImportProxies));
otherItem.addSubItem(menu_delete_all, LocaleController.getString("DeleteAllProxies", R.string.DeleteAllProxies));
otherItem.addSubItem(menu_delete_all, LocaleController.getString("DeleteAllServer", R.string.DeleteAllServer));
otherItem.addSubItem(menu_delete_unavailable, LocaleController.getString("DeleteUnavailableServer", R.string.DeleteUnavailableServer));
listAdapter = new ListAdapter(context);
@ -791,7 +821,7 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente
if (alert != null) {
AlertUtil.showSimpleAlert(context,alert);
AlertUtil.showSimpleAlert(context, alert);
alert = null;
}
@ -955,29 +985,49 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente
if (proxyInfo.checking || (SystemClock.elapsedRealtime() - proxyInfo.availableCheckTime < 2 * 60 * 1000L && !force)) {
continue;
}
proxyInfo.checking = true;
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxyCheckDone, proxyInfo);
checkSingleProxy(proxyInfo);
}
}
if (proxyInfo instanceof SharedConfig.ExternalSocks5Proxy && proxyInfo != SharedConfig.currentProxy) {
((SharedConfig.ExternalSocks5Proxy) proxyInfo).start();
}
private void checkSingleProxy(SharedConfig.ProxyInfo proxyInfo) {
proxyInfo.proxyCheckPingId = ConnectionsManager.getInstance(currentAccount).checkProxy(proxyInfo.address, proxyInfo.port, proxyInfo.username, proxyInfo.password, proxyInfo.secret, time -> AndroidUtilities.runOnUIThread(() -> {
proxyInfo.availableCheckTime = SystemClock.elapsedRealtime();
proxyInfo.checking = false;
if (time == -1) {
checkSingleProxy(proxyInfo, proxyInfo instanceof SharedConfig.ExternalSocks5Proxy ? 3 : 0);
}
private void checkSingleProxy(SharedConfig.ProxyInfo proxyInfo, int repeat) {
proxyInfo.checking = true;
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxyCheckDone, proxyInfo);
if (proxyInfo instanceof SharedConfig.ExternalSocks5Proxy && !((SharedConfig.ExternalSocks5Proxy) proxyInfo).isStarted()) {
((SharedConfig.ExternalSocks5Proxy) proxyInfo).start();
}
proxyInfo.proxyCheckPingId = ConnectionsManager.getInstance(currentAccount).checkProxy(proxyInfo.address, proxyInfo.port, proxyInfo.username, proxyInfo.password, proxyInfo.secret, time -> AndroidUtilities.runOnUIThread(() -> {
proxyInfo.availableCheckTime = SystemClock.elapsedRealtime();
if (time == -1) {
if (repeat > 0) {
UIUtil.runOnIoDispatcher(() -> {
checkSingleProxy(proxyInfo, repeat - 1);
});
} else {
proxyInfo.checking = false;
proxyInfo.available = false;
proxyInfo.ping = 0;
} else {
proxyInfo.ping = time;
proxyInfo.available = true;
if (proxyInfo instanceof SharedConfig.ExternalSocks5Proxy && proxyInfo != SharedConfig.currentProxy) {
((SharedConfig.ExternalSocks5Proxy) proxyInfo).stop();
}
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxyCheckDone, proxyInfo);
}
} else {
proxyInfo.checking = false;
proxyInfo.ping = time;
proxyInfo.available = true;
if (proxyInfo instanceof SharedConfig.ExternalSocks5Proxy && proxyInfo != SharedConfig.currentProxy) {
((SharedConfig.ExternalSocks5Proxy) proxyInfo).stop();
}
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxyCheckDone, proxyInfo);
}));
}
}
}));
}
@Override
@ -1019,6 +1069,8 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente
if (holder != null && holder.itemView instanceof TextDetailProxyCell) {
TextDetailProxyCell cell = (TextDetailProxyCell) holder.itemView;
cell.updateStatus();
} else {
updateRows(true);
}
}
}

View File

@ -1,7 +1,6 @@
package tw.nekomimi.nekogram
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
@ -12,6 +11,7 @@ import android.service.notification.NotificationListenerService
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import org.telegram.messenger.ApplicationLoader
import org.telegram.messenger.KeepAliveJob
import org.telegram.messenger.LocaleController
import org.telegram.messenger.R
import org.telegram.ui.LaunchActivity
@ -23,6 +23,7 @@ class NekoXPushService : NotificationListenerService() {
override fun onCreate() {
super.onCreate()
ApplicationLoader.postInitApplication()
KeepAliveJob.startJob()
if (NekoConfig.residentNotification) {
val activityIntent = Intent(this, LaunchActivity::class.java)
val pendingIntent = PendingIntent.getActivity(this, 0, activityIntent, 0)

View File

@ -14,7 +14,7 @@ object ProxyManager {
@JvmStatic
fun getPortForBean(bean: AngConfig.VmessBean): Int {
val hash = (bean.address + bean.port + bean.path).hashCode().toString()
val hash = (bean.address + bean.port + bean.id + bean.network + bean.path).hashCode().toString()
var port = pref.getInt(hash, -1)

View File

@ -1,6 +1,7 @@
package tw.nekomimi.nekogram
import com.v2ray.ang.V2RayConfig.SS_PROTOCOL
import com.v2ray.ang.dto.AngConfig
import com.v2ray.ang.util.Utils
import kotlinx.coroutines.runBlocking
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
@ -77,6 +78,9 @@ class ShadowsocksLoader {
var method: String = "aes-256-cfb",
var remarks: String? = null
) {
override fun equals(other: Any?): Boolean {
return super.equals(other) || (other is Bean && hash == other.hash)
}
/*
init {
@ -126,7 +130,7 @@ class ShadowsocksLoader {
}
val methodAndPswd = Utils.decodeUrlSafe(link.username)
val methodAndPswd = Utils.decode(link.username)
return Bean(
link.host,

View File

@ -87,6 +87,10 @@ class ShadowsocksRLoader {
val hash = (host + remotePort + password + protocol + obfs + method).hashCode()
override fun equals(other: Any?): Boolean {
return super.equals(other) || (other is Bean && hash == other.hash)
}
/*
init {
@ -134,13 +138,13 @@ class ShadowsocksRLoader {
runCatching {
bean.obfs_param = Utils.decodeUrlSafe(httpUrl.queryParameter("obfsparam")!!)
bean.obfs_param = Utils.decode(httpUrl.queryParameter("obfsparam")!!)
}
runCatching {
bean.protocol_param = Utils.decodeUrlSafe(httpUrl.queryParameter("protoparam")!!)
bean.protocol_param = Utils.decode(httpUrl.queryParameter("protoparam")!!)
}
@ -150,7 +154,7 @@ class ShadowsocksRLoader {
if (remarks?.isNotBlank() == true) {
bean.remarks = Utils.decodeUrlSafe(remarks)
bean.remarks = Utils.decode(remarks)
}

View File

@ -35,8 +35,8 @@ import java.util.*
object ProxyUtil {
@JvmStatic
val cacheFile = File(ApplicationLoader.applicationContext.filesDir.parent, "nekox/proxy_list.json")
@JvmField
val cacheFile = File(ApplicationLoader.applicationContext.filesDir.parentFile, "nekox/remote_proxy_list.json")
@JvmStatic
fun isVPNEnabled(): Boolean {
@ -214,7 +214,7 @@ object ProxyUtil {
FileLog.e(it)
AlertUtil.showToast(LocaleController.getString("BrokenLink", R.string.BrokenLink))
AlertUtil.showToast("${LocaleController.getString("BrokenLink", R.string.BrokenLink)}: ${it.message}")
}
@ -257,9 +257,9 @@ object ProxyUtil {
}.getOrThrow()
if (SharedConfig.addProxy(info) != info) {
if (!(SharedConfig.addProxy(info) === info)) {
error("proxy already exists")
error("already exists")
}

View File

@ -7,13 +7,12 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import okhttp3.Dispatcher
import org.telegram.messenger.ApplicationLoader
object UIUtil {
val handler = Handler(Looper.getMainLooper())
@JvmStatic
fun runOnUIThread(runnable: Runnable) = handler.post(runnable)
fun runOnUIThread(runnable: Runnable) = ApplicationLoader.applicationHandler.post(runnable)
@JvmStatic
fun runOnIoDispatcher(runnable: Runnable) {

View File

@ -102,15 +102,17 @@
<string name="ReorderByPing">Reorder servers by ping</string>
<string name="ExportProxies">Export servers to file</string>
<string name="ImportProxies">Import servers from file</string>
<string name="ImportProxyList">Import proxy servers</string>
<string name="ImportProxyList">Import proxy servers</string>
<string name="ImportProxyListConfirm">Are you sure you want to **import proxy servers**?</string>
<string name="InvalidProxyFile">Invalid proxy list file: </string>
<string name="ImportedProxies">Imported proxy servers: </string>
<string name="ErrorsInImport">Import errors: </string>
<string name="NoProxy">You haven\'t added any proxy servers.</string>
<string name="DeleteAllProxies">Delete all servers</string>
<string name="DeleteAllProxiesAlert">Warning! This will **delete all proxies**.</string>
<string name="DeleteAllServer">Delete all servers</string>
<string name="DeleteUnavailableServer">Delete unavailable servers</string>
<string name="DeleteAllServerConfirm">Are you sure you want to **delete all servers**?</string>
<string name="DeleteUnavailableServerConfirm">Are you sure you want to **delete unavailable servers**?</string>
<string name="MinApi21Required">Sorry, you need at least Android 5 (API21).</string>