proxy: remove all ss, ssr and v2ray stuff. fix proxy selection saving

This commit is contained in:
luvletter2333 2024-06-17 14:37:24 +08:00
parent 34b440b867
commit a66f24ccef
No known key found for this signature in database
GPG Key ID: 9EB7723F3A0ACF92
75 changed files with 710 additions and 9482 deletions

View File

@ -146,103 +146,11 @@ jobs:
run: |
export NATIVE_TARGET="${{ matrix.flavor }}"
./run libs native
v2ray:
name: Native Build (V2ray)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Fetch Status
run: git submodule status v2ray > v2ray_status
- name: V2ray Cache
id: cache
uses: actions/cache@v2
with:
path: |
TMessagesProj/libs/libv2ray.aar
key: ${{ hashFiles('bin/libs/v2ray/*', 'v2ray_status') }}
- name: Setup Android SDK Tools
uses: android-actions/setup-android@v2
if: steps.cache.outputs.cache-hit != 'true'
- name: Install NDK
if: steps.cache.outputs.cache-hit != 'true'
run: |
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
echo "sdk.dir=${ANDROID_HOME}" > local.properties
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
- name: Install Golang
uses: actions/setup-go@v2
if: steps.cache.outputs.cache-hit != 'true'
with:
go-version: 1.16
- name: Native Build
if: steps.cache.outputs.cache-hit != 'true'
run: ./run libs v2ray
shadowsocks:
name: Native Build (Shadowsocks)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Fetch Status
run: git submodule status ss-rust/src/main/rust/shadowsocks-rust > shadowsocks_status
- name: Shadowsocks Cache
id: cache
uses: actions/cache@v2
with:
path: |
TMessagesProj/libs/ss-rust-release.aar
key: ${{ hashFiles('shadowsocks_status') }}
- name: Setup Android SDK Tools
uses: android-actions/setup-android@v2
if: steps.cache.outputs.cache-hit != 'true'
- name: Install NDK
if: steps.cache.outputs.cache-hit != 'true'
run: |
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
echo "sdk.dir=${ANDROID_HOME}" > local.properties
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
- name: Install Rust
if: steps.cache.outputs.cache-hit != 'true'
run: ./run init action shadowsocks
- name: Native Build
if: steps.cache.outputs.cache-hit != 'true'
run: ./run libs shadowsocks
shadowsocksr:
name: Native Build (ShadowsocksR)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Fetch Status
run: git submodule status 'ssr-libev/*' > shadowsocksr_status
- name: ShadowsocksR Cache
id: cache
uses: actions/cache@v2
with:
path: |
TMessagesProj/libs/ssr-libev-release.aar
key: ${{ hashFiles('shadowsocksr_status') }}
- name: Setup Android SDK Tools
uses: android-actions/setup-android@v2
if: steps.cache.outputs.cache-hit != 'true'
- name: Install NDK
if: steps.cache.outputs.cache-hit != 'true'
run: |
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
echo "sdk.dir=${ANDROID_HOME}" > local.properties
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
- name: Native Build
if: steps.cache.outputs.cache-hit != 'true'
run: ./run libs ssr
build:
name: Gradle Build
runs-on: ubuntu-latest
needs:
- native
- v2ray
- shadowsocks
- shadowsocksr
strategy:
matrix:
flavor:
@ -360,7 +268,6 @@ jobs:
if: ${{ github.event_name != 'pull_request' && success() }}
needs:
- native
- v2ray
- telegram-bot-api
steps:
- name: Checkout
@ -376,9 +283,6 @@ jobs:
run: |
git submodule status TMessagesProj/jni/ffmpeg > ffmpeg_status
git submodule status TMessagesProj/jni/boringssl > boringssl_status
git submodule status ss-rust/src/main/rust/shadowsocks-rust > shadowsocks_status
git submodule status 'ssr-libev/*' > shadowsocksr_status
git submodule status v2ray > v2ray_status
- name: Native Cache (armeabi-v7a)
uses: actions/cache@v2
with:
@ -403,20 +307,12 @@ jobs:
path: |
TMessagesProj/src/main/libs
key: ${{ hashFiles('TMessagesProj/jni/**', 'ffmpeg_status', 'boringssl_status') }}-x86_64
- name: V2ray Cache
uses: actions/cache@v2
with:
path: |
TMessagesProj/libs/libv2ray.aar
key: ${{ hashFiles('bin/libs/v2ray/*', 'v2ray_status') }}
- name: Build Cache
uses: actions/cache@v3
with:
path: |
TMessagesProj/build
TMessagesProj/.cxx
ss-rust/build
ssr-rust/build
openpgp-api/build
key: build-cache
- name: Configure Gradle

View File

@ -155,106 +155,11 @@ jobs:
run: |
export NATIVE_TARGET="${{ matrix.flavor }}"
./run libs native
v2ray:
name: Native Build (V2ray)
runs-on: ubuntu-latest
needs: check
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Fetch Status
run: git submodule status v2ray > v2ray_status
- name: V2ray Cache
id: cache
uses: actions/cache@v2
with:
path: |
TMessagesProj/libs/libv2ray.aar
key: ${{ hashFiles('bin/libs/v2ray/*', 'v2ray_status') }}
- name: Setup Android SDK Tools
uses: android-actions/setup-android@v2
if: steps.cache.outputs.cache-hit != 'true'
- name: Install NDK
if: steps.cache.outputs.cache-hit != 'true'
run: |
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
echo "sdk.dir=${ANDROID_HOME}" > local.properties
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
- name: Install Golang
uses: actions/setup-go@v2
if: steps.cache.outputs.cache-hit != 'true'
with:
go-version: 1.16
- name: Native Build
if: steps.cache.outputs.cache-hit != 'true'
run: ./run libs v2ray
shadowsocks:
name: Native Build (Shadowsocks)
runs-on: ubuntu-latest
needs: check
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Fetch Status
run: git submodule status ss-rust/src/main/rust/shadowsocks-rust > shadowsocks_status
- name: Shadowsocks Cache
id: cache
uses: actions/cache@v2
with:
path: |
TMessagesProj/libs/ss-rust-release.aar
key: ${{ hashFiles('shadowsocks_status') }}
- name: Setup Android SDK Tools
uses: android-actions/setup-android@v2
if: steps.cache.outputs.cache-hit != 'true'
- name: Install NDK
if: steps.cache.outputs.cache-hit != 'true'
run: |
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
echo "sdk.dir=${ANDROID_HOME}" > local.properties
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
- name: Install Rust
if: steps.cache.outputs.cache-hit != 'true'
run: ./run init action shadowsocks
- name: Native Build
if: steps.cache.outputs.cache-hit != 'true'
run: ./run libs shadowsocks
shadowsocksr:
name: Native Build (ShadowsocksR)
runs-on: ubuntu-latest
needs: check
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Fetch Status
run: git submodule status 'ssr-libev/*' > shadowsocksr_status
- name: ShadowsocksR Cache
id: cache
uses: actions/cache@v2
with:
path: |
TMessagesProj/libs/ssr-libev-release.aar
key: ${{ hashFiles('shadowsocksr_status') }}
- name: Setup Android SDK Tools
uses: android-actions/setup-android@v2
if: steps.cache.outputs.cache-hit != 'true'
- name: Install NDK
if: steps.cache.outputs.cache-hit != 'true'
run: |
echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.4.7075529" --sdk_root=${ANDROID_SDK_ROOT} &> /dev/null
echo "sdk.dir=${ANDROID_HOME}" > local.properties
echo "ndk.dir=${ANDROID_HOME}/ndk/21.4.7075529" >> local.properties
- name: Native Build
if: steps.cache.outputs.cache-hit != 'true'
run: ./run libs ssr
build:
name: Gradle Build
runs-on: ubuntu-latest
needs:
- native
- v2ray
- shadowsocks
- shadowsocksr
strategy:
matrix:
flavor:
@ -276,9 +181,6 @@ jobs:
run: |
git submodule status TMessagesProj/jni/ffmpeg > ffmpeg_status
git submodule status TMessagesProj/jni/boringssl > boringssl_status
git submodule status ss-rust/src/main/rust/shadowsocks-rust > shadowsocks_status
git submodule status 'ssr-libev/*' > shadowsocksr_status
git submodule status v2ray > v2ray_status
- name: Native Cache (armeabi-v7a)
uses: actions/cache@v2
with:
@ -303,24 +205,6 @@ jobs:
path: |
TMessagesProj/src/main/libs
key: ${{ hashFiles('TMessagesProj/jni/**', 'ffmpeg_status', 'boringssl_status') }}-x86_64
- name: V2ray Cache
uses: actions/cache@v2
with:
path: |
TMessagesProj/libs/libv2ray.aar
key: ${{ hashFiles('bin/libs/v2ray/*', 'v2ray_status') }}
- name: Shadowsocks Cache
uses: actions/cache@v2
with:
path: |
TMessagesProj/libs/ss-rust-release.aar
key: ${{ hashFiles('shadowsocks_status') }}
- name: ShadowsocksR Cache
uses: actions/cache@v2
with:
path: |
TMessagesProj/libs/ssr-libev-release.aar
key: ${{ hashFiles('shadowsocksr_status') }}
- name: Fix Gradle Memoery
run: |
sed -i -e "s/16384/6144/g" gradle.properties

26
.gitmodules vendored
View File

@ -14,29 +14,3 @@
url = https://github.com/webmproject/libvpx
ignore = dirty
[submodule "ss-rust/src/main/rust/shadowsocks-rust"]
path = ss-rust/src/main/rust/shadowsocks-rust
url = https://github.com/shadowsocks/shadowsocks-rust.git
[submodule "shadowsocksr-libev"]
path = ssr-libev/src/main/jni/shadowsocks-libev
url = https://github.com/shadowsocksRb/shadowsocksr-libev.git
[submodule "ssr-libev/src/main/jni/libancillary"]
path = ssr-libev/src/main/jni/libancillary
url = https://github.com/shadowsocks/libancillary.git
[submodule "ssr-libev/src/main/jni/mbedtls"]
path = ssr-libev/src/main/jni/mbedtls
url = https://github.com/ARMmbed/mbedtls
[submodule "ssr-libev/src/main/jni/pcre"]
path = ssr-libev/src/main/jni/pcre
url = https://android.googlesource.com/platform/external/pcre
[submodule "ssr-libev/src/main/jni/libsodium"]
path = ssr-libev/src/main/jni/libsodium
url = https://github.com/jedisct1/libsodium.git
branch = stable
[submodule "ssr-libev/src/main/jni/re2"]
path = ssr-libev/src/main/jni/re2
url = https://github.com/google/re2.git
[submodule "v2ray"]
path = v2ray
url = https://github.com/nekohasekai/AndroidLibV2rayLite

View File

@ -169,6 +169,7 @@ import java.io.RandomAccessFile;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.IDN;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
@ -198,7 +199,6 @@ import tw.nekomimi.nekogram.NekoXConfig;
import tw.nekomimi.nekogram.utils.AlertUtil;
import tw.nekomimi.nekogram.utils.EnvUtil;
import tw.nekomimi.nekogram.utils.FileUtil;
import tw.nekomimi.nekogram.utils.ProxyUtil;
import tw.nekomimi.nekogram.utils.UIUtil;
import static com.v2ray.ang.V2RayConfig.SSR_PROTOCOL;
@ -3636,27 +3636,68 @@ public class AndroidUtilities {
if (intent == null) {
return false;
}
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
return false;
}
Uri data = intent.getData();
if (data == null) return false;
String link = data.toString();
if (link.startsWith("tg://proxy") ||
link.startsWith("tg://socks") ||
link.startsWith("http://t.me/proxy?") ||
link.startsWith("http://t.me/socks?") ||
link.startsWith("https://t.me/proxy?") ||
link.startsWith("https://t.me/socks?") ||
link.startsWith(VMESS_PROTOCOL) ||
link.startsWith(VMESS1_PROTOCOL) ||
link.startsWith(SS_PROTOCOL) ||
link.startsWith(SSR_PROTOCOL) ||
link.startsWith(WS_PROTOCOL) ||
link.startsWith(WSS_PROTOCOL) ||
link.startsWith(TROJAN_PROTOCOL)/*||
data.startsWith(RB_PROTOCOL)*/) {
return ProxyUtil.importProxy(activity, link);
try {
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
return false;
}
Uri data = intent.getData();
if (data != null) {
String user = null;
String password = null;
String port = null;
String address = null;
String secret = null;
String scheme = data.getScheme();
if (scheme != null) {
if ((scheme.equals("http") || scheme.equals("https"))) {
String host = data.getHost().toLowerCase();
if (host.equals("telegram.me") || host.equals("t.me") || host.equals("telegram.dog")) {
String path = data.getPath();
if (path != null) {
if (path.startsWith("/socks") || path.startsWith("/proxy")) {
address = data.getQueryParameter("server");
if (AndroidUtilities.checkHostForPunycode(address)) {
address = IDN.toASCII(address, IDN.ALLOW_UNASSIGNED);
}
port = data.getQueryParameter("port");
user = data.getQueryParameter("user");
password = data.getQueryParameter("pass");
secret = data.getQueryParameter("secret");
}
}
}
} else if (scheme.equals("tg")) {
String url = data.toString();
if (url.startsWith("tg:proxy") || url.startsWith("tg://proxy") || url.startsWith("tg:socks") || url.startsWith("tg://socks")) {
url = url.replace("tg:proxy", "tg://telegram.org").replace("tg://proxy", "tg://telegram.org").replace("tg://socks", "tg://telegram.org").replace("tg:socks", "tg://telegram.org");
data = Uri.parse(url);
address = data.getQueryParameter("server");
if (AndroidUtilities.checkHostForPunycode(address)) {
address = IDN.toASCII(address, IDN.ALLOW_UNASSIGNED);
}
port = data.getQueryParameter("port");
user = data.getQueryParameter("user");
password = data.getQueryParameter("pass");
secret = data.getQueryParameter("secret");
}
}
}
if (!TextUtils.isEmpty(address) && !TextUtils.isEmpty(port)) {
if (user == null) {
user = "";
}
if (password == null) {
password = "";
}
if (secret == null) {
secret = "";
}
showProxyAlert(activity, address, port, user, password, secret, "");
return true;
}
}
} catch (Exception ignore) {
}
return false;
}
@ -3782,640 +3823,42 @@ public class AndroidUtilities {
pickerBottomLayout.cancelButton.setTextColor(Theme.getColor(Theme.key_dialogTextBlue2));
pickerBottomLayout.cancelButton.setText(LocaleController.getString("Cancel", R.string.Cancel).toUpperCase());
pickerBottomLayout.cancelButton.setOnClickListener(view -> dismissRunnable.run());
pickerBottomLayout.doneButtonTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlue2));
pickerBottomLayout.doneButton.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0);
pickerBottomLayout.doneButtonBadgeTextView.setVisibility(View.GONE);
pickerBottomLayout.middleButtonTextView.setText(LocaleController.getString("Save", R.string.Save).toUpperCase());
pickerBottomLayout.middleButton.setVisibility(View.VISIBLE);
pickerBottomLayout.middleButton.setOnClickListener((it) -> {
pickerBottomLayout.doneButtonTextView.setText(LocaleController.getString("ConnectingConnectProxy", R.string.ConnectingConnectProxy).toUpperCase());
pickerBottomLayout.doneButton.setOnClickListener(v -> {
SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit();
editor.putBoolean("proxy_enabled", true);
editor.putString("proxy_ip", address);
int p = Utilities.parseInt(port);
editor.putInt("proxy_port", p);
SharedConfig.ProxyInfo info;
if (TextUtils.isEmpty(secret)) {
info = new SharedConfig.ProxyInfo(address, p, user, password, "");
} else {
info = new SharedConfig.ProxyInfo(address, p, "", "", secret);
}
info.setRemarks(remarks);
SharedConfig.addProxy(info);
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged);
dismissRunnable.run();
});
pickerBottomLayout.doneButtonTextView.setText(LocaleController.getString("ConnectingConnectProxy", R.string.ConnectingConnectProxy).toUpperCase());
pickerBottomLayout.doneButton.setOnClickListener(v -> {
int p = Utilities.parseInt(port);
SharedConfig.ProxyInfo info;
if (TextUtils.isEmpty(secret)) {
info = new SharedConfig.ProxyInfo(address, p, user, password, "");
} else {
info = new SharedConfig.ProxyInfo(address, p, "", "", secret);
}
info.setRemarks(remarks);
SharedConfig.setCurrentProxy(SharedConfig.addProxy(info));
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged);
dismissRunnable.run();
});
builder.show();
}
public static void showVmessAlert(Context activity, final SharedConfig.VmessProxy info) {
BottomSheet.Builder builder = new BottomSheet.Builder(activity);
final Runnable dismissRunnable = builder.getDismissRunnable();
builder.setApplyTopPadding(false);
builder.setApplyBottomPadding(false);
LinearLayout linearLayout = new LinearLayout(activity);
builder.setCustomView(linearLayout);
linearLayout.setOrientation(LinearLayout.VERTICAL);
for (int a = 0; a < 8; a++) {
String text = null;
String detail = null;
if (a == 0) {
text = info.bean.getAddress();
detail = LocaleController.getString("UseProxyAddress", R.string.UseProxyAddress);
} else if (a == 1) {
text = "" + info.bean.getPort();
detail = LocaleController.getString("UseProxyPort", R.string.UseProxyPort);
} else if (a == 2) {
text = info.bean.getId();
detail = LocaleController.getString("VmessUserId", R.string.VmessUserId);
} else if (a == 3) {
text = info.bean.getSecurity();
if ("none".equals(text)) continue;
detail = LocaleController.getString("VmessSecurity", R.string.VmessSecurity);
} else if (a == 4) {
text = info.bean.getNetwork() + (StrUtil.isBlank(info.bean.getStreamSecurity()) ? "" : ", tls");
detail = LocaleController.getString("VmessNetwork", R.string.VmessNetwork);
} else if (a == 5) {
text = info.bean.getHeaderType();
if ("none".equals(text)) continue;
detail = LocaleController.getString("VmessHeadType", R.string.VmessHeadType);
} else if (a == 6) {
text = info.bean.getRequestHost();
detail = LocaleController.getString("VmessRequestHost", R.string.VmessRequestHost);
} else {
text = LocaleController.getString("Checking", R.string.Checking);
detail = LocaleController.getString("Checking", R.string.Checking);
}
if (TextUtils.isEmpty(text)) {
continue;
}
TextDetailSettingsCell cell = new TextDetailSettingsCell(activity);
cell.setTextAndValue(text, detail, true);
cell.getTextView().setTextColor(Theme.getColor(Theme.key_dialogTextBlack));
cell.getValueTextView().setTextColor(Theme.getColor(Theme.key_dialogTextGray3));
linearLayout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
AtomicInteger count = new AtomicInteger();
if (a == 7) {
RequestTimeDelegate callback = new RequestTimeDelegate() {
@Override
public void run(long time) {
int c = count.getAndIncrement();
String colorKey;
if (time != -1) {
info.stop();
cell.setTextAndValue(LocaleController.getString("Available", R.string.Available), LocaleController.formatString("Ping", R.string.Ping, time), true);
colorKey = Theme.key_windowBackgroundWhiteGreenText;
} else if (c < 2) {
ConnectionsManager.getInstance(UserConfig.selectedAccount).checkProxy(info.address, info.port, "", "", "", t -> AndroidUtilities.runOnUIThread(() -> run(t), 500));
colorKey = Theme.key_windowBackgroundWhiteGreenText;
} else {
info.stop();
cell.setTextAndValue(LocaleController.getString("Unavailable", R.string.Unavailable), LocaleController.getString("Unavailable", R.string.Unavailable), true);
colorKey = Theme.key_windowBackgroundWhiteRedText4;
}
cell.getValueTextView().setTextColor(Theme.getColor(colorKey));
}
};
UIUtil.runOnIoDispatcher(() -> {
try {
info.start();
ConnectionsManager.getInstance(UserConfig.selectedAccount).checkProxy(info.address, info.port, "", "", "", time -> AndroidUtilities.runOnUIThread(() -> callback.run(time)));
} catch (Exception e) {
FileLog.e(e);
AlertUtil.showToast(e);
}
});
}
}
PickerBottomLayout pickerBottomLayout = new PickerBottomLayout(activity, false);
pickerBottomLayout.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground));
linearLayout.addView(pickerBottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM));
pickerBottomLayout.cancelButton.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0);
pickerBottomLayout.cancelButton.setTextColor(Theme.getColor(Theme.key_dialogTextBlue2));
pickerBottomLayout.cancelButton.setText(LocaleController.getString("Cancel", R.string.Cancel).toUpperCase());
pickerBottomLayout.cancelButton.setOnClickListener(view -> {
info.stop();
dismissRunnable.run();
});
pickerBottomLayout.doneButtonTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlue2));
pickerBottomLayout.doneButton.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0);
pickerBottomLayout.doneButtonBadgeTextView.setVisibility(View.GONE);
pickerBottomLayout.middleButtonTextView.setText(LocaleController.getString("Save", R.string.Save).toUpperCase());
pickerBottomLayout.middleButton.setVisibility(View.VISIBLE);
pickerBottomLayout.middleButton.setOnClickListener((it) -> {
SharedConfig.addProxy(info);
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged);
dismissRunnable.run();
});
pickerBottomLayout.doneButtonTextView.setText(LocaleController.getString("ConnectingConnectProxy", R.string.ConnectingConnectProxy).toUpperCase());
pickerBottomLayout.doneButton.setOnClickListener(v -> {
SharedConfig.setCurrentProxy(SharedConfig.addProxy(info));
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged);
if (activity instanceof LaunchActivity) {
INavigationLayout layout = ((LaunchActivity) activity).getActionBarLayout();
BaseFragment fragment = layout.getLastFragment();
if (fragment instanceof ChatActivity) {
((ChatActivity) fragment).getUndoView().showWithAction(0, UndoView.ACTION_PROXY_ADDED, null);
editor.remove("proxy_secret");
if (TextUtils.isEmpty(password)) {
editor.remove("proxy_pass");
} else {
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_SUCCESS, LocaleController.getString(R.string.ProxyAddedSuccess));
editor.putString("proxy_pass", password);
}
} else {
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_SUCCESS, LocaleController.getString(R.string.ProxyAddedSuccess));
}
dismissRunnable.run();
});
builder.show();
}
public static void showTrojanAlert(Context activity, final SharedConfig.VmessProxy info) {
BottomSheet.Builder builder = new BottomSheet.Builder(activity);
final Runnable dismissRunnable = builder.getDismissRunnable();
builder.setApplyTopPadding(false);
builder.setApplyBottomPadding(false);
LinearLayout linearLayout = new LinearLayout(activity);
builder.setCustomView(linearLayout);
linearLayout.setOrientation(LinearLayout.VERTICAL);
for (int a = 0; a < 4; a++) {
String text = null;
String detail = null;
if (a == 0) {
text = info.bean.getAddress();
detail = LocaleController.getString("UseProxyAddress", R.string.UseProxyAddress);
} else if (a == 1) {
text = "" + info.bean.getPort();
detail = LocaleController.getString("UseProxyPort", R.string.UseProxyPort);
} else if (a == 2) {
text = info.bean.getId();
detail = LocaleController.getString("SSPassword", R.string.SSPassword);
} else {
text = LocaleController.getString("Checking", R.string.Checking);
detail = LocaleController.getString("Checking", R.string.Checking);
}
if (TextUtils.isEmpty(text)) {
continue;
}
TextDetailSettingsCell cell = new TextDetailSettingsCell(activity);
cell.setTextAndValue(text, detail, true);
cell.getTextView().setTextColor(Theme.getColor(Theme.key_dialogTextBlack));
cell.getValueTextView().setTextColor(Theme.getColor(Theme.key_dialogTextGray3));
linearLayout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
AtomicInteger count = new AtomicInteger();
if (a == 3) {
RequestTimeDelegate callback = new RequestTimeDelegate() {
@Override
public void run(long time) {
int c = count.getAndIncrement();
String colorKey;
if (time != -1) {
info.stop();
cell.setTextAndValue(LocaleController.getString("Available", R.string.Available), LocaleController.formatString("Ping", R.string.Ping, time), true);
colorKey = Theme.key_windowBackgroundWhiteGreenText;
} else if (c < 2) {
ConnectionsManager.getInstance(UserConfig.selectedAccount).checkProxy(info.address, info.port, "", "", "", t -> AndroidUtilities.runOnUIThread(() -> run(t), 500));
colorKey = Theme.key_windowBackgroundWhiteGreenText;
} else {
info.stop();
cell.setTextAndValue(LocaleController.getString("Unavailable", R.string.Unavailable), LocaleController.getString("Unavailable", R.string.Unavailable), true);
colorKey = Theme.key_windowBackgroundWhiteRedText4;
}
cell.getValueTextView().setTextColor(Theme.getColor(colorKey));
}
};
UIUtil.runOnIoDispatcher(() -> {
try {
info.start();
ConnectionsManager.getInstance(UserConfig.selectedAccount).checkProxy(info.address, info.port, "", "", "", time -> AndroidUtilities.runOnUIThread(() -> callback.run(time)));
} catch (Exception e) {
FileLog.e(e);
AlertUtil.showToast(e);
}
});
}
}
PickerBottomLayout pickerBottomLayout = new PickerBottomLayout(activity, false);
pickerBottomLayout.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground));
linearLayout.addView(pickerBottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM));
pickerBottomLayout.cancelButton.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0);
pickerBottomLayout.cancelButton.setTextColor(Theme.getColor(Theme.key_dialogTextBlue2));
pickerBottomLayout.cancelButton.setText(LocaleController.getString("Cancel", R.string.Cancel).toUpperCase());
pickerBottomLayout.cancelButton.setOnClickListener(view -> {
info.stop();
dismissRunnable.run();
});
pickerBottomLayout.doneButtonTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlue2));
pickerBottomLayout.doneButton.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0);
pickerBottomLayout.doneButtonBadgeTextView.setVisibility(View.GONE);
pickerBottomLayout.middleButtonTextView.setText(LocaleController.getString("Save", R.string.Save).toUpperCase());
pickerBottomLayout.middleButton.setVisibility(View.VISIBLE);
pickerBottomLayout.middleButton.setOnClickListener((it) -> {
SharedConfig.addProxy(info);
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged);
dismissRunnable.run();
});
pickerBottomLayout.doneButtonTextView.setText(LocaleController.getString("ConnectingConnectProxy", R.string.ConnectingConnectProxy).toUpperCase());
pickerBottomLayout.doneButton.setOnClickListener(v -> {
SharedConfig.setCurrentProxy(SharedConfig.addProxy(info));
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged);
dismissRunnable.run();
});
builder.show();
}
public static void showShadowsocksAlert(Context activity, final SharedConfig.ShadowsocksProxy info) {
try {
BottomSheet.Builder builder = new BottomSheet.Builder(activity);
final Runnable dismissRunnable = builder.getDismissRunnable();
builder.setApplyTopPadding(false);
builder.setApplyBottomPadding(false);
LinearLayout linearLayout = new LinearLayout(activity);
builder.setCustomView(linearLayout);
linearLayout.setOrientation(LinearLayout.VERTICAL);
for (int a = 0; a < 5; a++) {
String text = null;
String detail = null;
if (a == 0) {
text = info.bean.getHost();
detail = LocaleController.getString("UseProxyAddress", R.string.UseProxyAddress);
} else if (a == 1) {
text = "" + info.bean.getRemotePort();
detail = LocaleController.getString("UseProxyPort", R.string.UseProxyPort);
} else if (a == 2) {
text = info.bean.getPassword();
detail = LocaleController.getString("UseProxyPassword", R.string.UseProxyPassword);
} else if (a == 3) {
text = info.bean.getMethod();
detail = LocaleController.getString("SSMethod", R.string.SSMethod);
if (TextUtils.isEmpty(user)) {
editor.remove("proxy_user");
} else {
text = LocaleController.getString("Checking", R.string.Checking);
detail = LocaleController.getString("Checking", R.string.Checking);
editor.putString("proxy_user", user);
}
if (TextUtils.isEmpty(text)) {
continue;
}
TextDetailSettingsCell cell = new TextDetailSettingsCell(activity);
cell.setTextAndValue(text, detail, true);
cell.getTextView().setTextColor(Theme.getColor(Theme.key_dialogTextBlack));
cell.getValueTextView().setTextColor(Theme.getColor(Theme.key_dialogTextGray3));
linearLayout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
AtomicInteger count = new AtomicInteger();
if (a == 4) {
RequestTimeDelegate callback = new RequestTimeDelegate() {
@Override
public void run(long time) {
int c = count.getAndIncrement();
String colorKey;
if (time != -1) {
info.stop();
cell.setTextAndValue(LocaleController.getString("Available", R.string.Available), LocaleController.formatString("Ping", R.string.Ping, time), true);
colorKey = Theme.key_windowBackgroundWhiteGreenText;
} else if (c < 2) {
ConnectionsManager.getInstance(UserConfig.selectedAccount).checkProxy(info.address, info.port, "", "", "", t -> AndroidUtilities.runOnUIThread(() -> run(t), 500));
colorKey = Theme.key_windowBackgroundWhiteGreenText;
} else {
info.stop();
cell.setTextAndValue(LocaleController.getString("Unavailable", R.string.Unavailable), LocaleController.getString("Unavailable", R.string.Unavailable), true);
colorKey = Theme.key_windowBackgroundWhiteRedText4;
}
cell.getValueTextView().setTextColor(Theme.getColor(colorKey));
}
};
UIUtil.runOnIoDispatcher(() -> {
try {
info.start();
ConnectionsManager.getInstance(UserConfig.selectedAccount).checkProxy(info.address, info.port, "", "", "", time -> AndroidUtilities.runOnUIThread(() -> callback.run(time)));
} catch (Exception e) {
FileLog.e(e);
AlertUtil.showToast(e);
}
});
}
}
PickerBottomLayout pickerBottomLayout = new PickerBottomLayout(activity, false);
pickerBottomLayout.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground));
linearLayout.addView(pickerBottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM));
pickerBottomLayout.cancelButton.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0);
pickerBottomLayout.cancelButton.setTextColor(Theme.getColor(Theme.key_dialogTextBlue2));
pickerBottomLayout.cancelButton.setText(LocaleController.getString("Cancel", R.string.Cancel).toUpperCase());
pickerBottomLayout.cancelButton.setOnClickListener(view -> {
info.stop();
dismissRunnable.run();
});
pickerBottomLayout.doneButtonTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlue2));
pickerBottomLayout.doneButton.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0);
pickerBottomLayout.doneButtonBadgeTextView.setVisibility(View.GONE);
pickerBottomLayout.middleButtonTextView.setText(LocaleController.getString("Save", R.string.Save).toUpperCase());
pickerBottomLayout.middleButton.setVisibility(View.VISIBLE);
pickerBottomLayout.middleButton.setOnClickListener((it) -> {
SharedConfig.addProxy(info);
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged);
dismissRunnable.run();
});
pickerBottomLayout.doneButtonTextView.setText(LocaleController.getString("ConnectingConnectProxy", R.string.ConnectingConnectProxy).toUpperCase());
pickerBottomLayout.doneButton.setOnClickListener(v -> {
SharedConfig.setCurrentProxy(SharedConfig.addProxy(info));
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged);
dismissRunnable.run();
});
builder.show();
} catch (Exception e) {
FileLog.e(e);
AlertUtil.showToast(e);
}
}
public static void showShadowsocksRAlert(Context activity, final SharedConfig.ShadowsocksRProxy info) {
BottomSheet.Builder builder = new BottomSheet.Builder(activity);
final Runnable dismissRunnable = builder.getDismissRunnable();
builder.setApplyTopPadding(false);
builder.setApplyBottomPadding(false);
LinearLayout linearLayout = new LinearLayout(activity);
builder.setCustomView(linearLayout);
linearLayout.setOrientation(LinearLayout.VERTICAL);
for (int a = 0; a < 7; a++) {
String text = null;
String detail = null;
if (a == 0) {
text = info.bean.getHost();
detail = LocaleController.getString("UseProxyAddress", R.string.UseProxyAddress);
} else if (a == 1) {
text = "" + info.bean.getRemotePort();
detail = LocaleController.getString("UseProxyPort", R.string.UseProxyPort);
} else if (a == 2) {
text = info.bean.getPassword();
detail = LocaleController.getString("SSPassword", R.string.SSPassword);
} else if (a == 3) {
text = info.bean.getMethod();
detail = LocaleController.getString("SSMethod", R.string.SSMethod);
} else if (a == 4) {
text = info.bean.getProtocol();
if (!StrUtil.isBlank(info.bean.getProtocol_param())) {
text += ", " + info.bean.getProtocol_param();
}
detail = LocaleController.getString("SSRProtocol", R.string.SSRProtocol);
} else if (a == 5) {
text = info.bean.getObfs();
if (!StrUtil.isBlank(info.bean.getObfs_param())) {
text += ", " + info.bean.getObfs_param();
}
detail = LocaleController.getString("SSRObfs", R.string.SSRObfs);
info = new SharedConfig.ProxyInfo(address, p, user, password, "");
} else {
text = LocaleController.getString("Checking", R.string.Checking);
detail = LocaleController.getString("Checking", R.string.Checking);
editor.remove("proxy_pass");
editor.remove("proxy_user");
editor.putString("proxy_secret", secret);
info = new SharedConfig.ProxyInfo(address, p, "", "", secret);
}
if (TextUtils.isEmpty(text)) {
continue;
}
TextDetailSettingsCell cell = new TextDetailSettingsCell(activity);
cell.setTextAndValue(text, detail, true);
cell.getTextView().setTextColor(Theme.getColor(Theme.key_dialogTextBlack));
cell.getValueTextView().setTextColor(Theme.getColor(Theme.key_dialogTextGray3));
linearLayout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
AtomicInteger count = new AtomicInteger();
if (a == 6) {
RequestTimeDelegate callback = new RequestTimeDelegate() {
@Override
public void run(long time) {
int c = count.getAndIncrement();
String colorKey;
if (time != -1) {
info.stop();
cell.setTextAndValue(LocaleController.getString("Available", R.string.Available), LocaleController.formatString("Ping", R.string.Ping, time), true);
colorKey = Theme.key_windowBackgroundWhiteGreenText;
} else if (c < 2) {
ConnectionsManager.getInstance(UserConfig.selectedAccount).checkProxy(info.address, info.port, "", "", "", t -> AndroidUtilities.runOnUIThread(() -> run(t), 500));
colorKey = Theme.key_windowBackgroundWhiteGreenText;
} else {
info.stop();
cell.setTextAndValue(LocaleController.getString("Unavailable", R.string.Unavailable), LocaleController.getString("Unavailable", R.string.Unavailable), true);
colorKey = Theme.key_windowBackgroundWhiteRedText4;
}
cell.getValueTextView().setTextColor(Theme.getColor(colorKey));
}
};
UIUtil.runOnIoDispatcher(() -> {
try {
info.start();
ConnectionsManager.getInstance(UserConfig.selectedAccount).checkProxy(info.address, info.port, "", "", "", time -> AndroidUtilities.runOnUIThread(() -> callback.run(time)));
} catch (Exception e) {
FileLog.e(e);
AlertUtil.showToast(e);
}
});
}
}
PickerBottomLayout pickerBottomLayout = new PickerBottomLayout(activity, false);
pickerBottomLayout.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground));
linearLayout.addView(pickerBottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM));
pickerBottomLayout.cancelButton.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0);
pickerBottomLayout.cancelButton.setTextColor(Theme.getColor(Theme.key_dialogTextBlue2));
pickerBottomLayout.cancelButton.setText(LocaleController.getString("Cancel", R.string.Cancel).toUpperCase());
pickerBottomLayout.cancelButton.setOnClickListener(view -> {
info.stop();
dismissRunnable.run();
});
pickerBottomLayout.doneButtonTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlue2));
pickerBottomLayout.doneButton.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0);
pickerBottomLayout.doneButtonBadgeTextView.setVisibility(View.GONE);
pickerBottomLayout.middleButtonTextView.setText(LocaleController.getString("Save", R.string.Save).toUpperCase());
pickerBottomLayout.middleButton.setVisibility(View.VISIBLE);
pickerBottomLayout.middleButton.setOnClickListener((it) -> {
SharedConfig.addProxy(info);
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged);
dismissRunnable.run();
});
pickerBottomLayout.doneButtonTextView.setText(LocaleController.getString("ConnectingConnectProxy", R.string.ConnectingConnectProxy).toUpperCase());
pickerBottomLayout.doneButton.setOnClickListener(v -> {
editor.apply();
SharedConfig.setCurrentProxy(SharedConfig.addProxy(info));
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged);
dismissRunnable.run();
});
builder.show();
}
public static void showWsAlert(Context activity, final SharedConfig.WsProxy info) {
BottomSheet.Builder builder = new BottomSheet.Builder(activity);
final Runnable dismissRunnable = builder.getDismissRunnable();
builder.setApplyTopPadding(false);
builder.setApplyBottomPadding(false);
LinearLayout linearLayout = new LinearLayout(activity);
builder.setCustomView(linearLayout);
linearLayout.setOrientation(LinearLayout.VERTICAL);
for (int a = 0; a < 4; a++) {
String text = null;
String detail = null;
if (a == 0) {
text = info.bean.getServer();
detail = LocaleController.getString("UseProxyAddress", R.string.UseProxyAddress);
} else if (a == 1) {
text = info.bean.getTls() ? "Y" : "N";
detail = LocaleController.getString("VmessTls", R.string.VmessTls);
} else {
text = LocaleController.getString("Checking", R.string.Checking);
detail = LocaleController.getString("Checking", R.string.Checking);
}
if (TextUtils.isEmpty(text)) {
continue;
}
TextDetailSettingsCell cell = new TextDetailSettingsCell(activity);
cell.setTextAndValue(text, detail, true);
cell.getTextView().setTextColor(Theme.getColor(Theme.key_dialogTextBlack));
cell.getValueTextView().setTextColor(Theme.getColor(Theme.key_dialogTextGray3));
linearLayout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
AtomicInteger count = new AtomicInteger();
if (a == 3) {
RequestTimeDelegate callback = new RequestTimeDelegate() {
@Override
public void run(long time) {
int c = count.getAndIncrement();
String colorKey;
if (time != -1) {
info.stop();
cell.setTextAndValue(LocaleController.getString("Available", R.string.Available), LocaleController.formatString("Ping", R.string.Ping, time), true);
colorKey = Theme.key_windowBackgroundWhiteGreenText;
} else if (c < 2) {
ConnectionsManager.getInstance(UserConfig.selectedAccount).checkProxy(info.address, info.port, "", "", "", t -> AndroidUtilities.runOnUIThread(() -> run(t), 500));
colorKey = Theme.key_windowBackgroundWhiteGreenText;
} else {
info.stop();
cell.setTextAndValue(LocaleController.getString("Unavailable", R.string.Unavailable), LocaleController.getString("Unavailable", R.string.Unavailable), true);
colorKey = Theme.key_windowBackgroundWhiteRedText4;
}
cell.getValueTextView().setTextColor(Theme.getColor(colorKey));
}
};
UIUtil.runOnIoDispatcher(() -> {
try {
info.start();
ConnectionsManager.getInstance(UserConfig.selectedAccount).checkProxy(info.address, info.port, "", "", "", time -> AndroidUtilities.runOnUIThread(() -> callback.run(time)));
} catch (Exception e) {
FileLog.e(e);
AlertUtil.showToast(e);
}
});
}
}
PickerBottomLayout pickerBottomLayout = new PickerBottomLayout(activity, false);
pickerBottomLayout.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground));
linearLayout.addView(pickerBottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM));
pickerBottomLayout.cancelButton.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0);
pickerBottomLayout.cancelButton.setTextColor(Theme.getColor(Theme.key_dialogTextBlue2));
pickerBottomLayout.cancelButton.setText(LocaleController.getString("Cancel", R.string.Cancel).toUpperCase());
pickerBottomLayout.cancelButton.setOnClickListener(view -> {
info.stop();
dismissRunnable.run();
});
pickerBottomLayout.doneButtonTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlue2));
pickerBottomLayout.doneButton.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0);
pickerBottomLayout.doneButtonBadgeTextView.setVisibility(View.GONE);
pickerBottomLayout.middleButtonTextView.setText(LocaleController.getString("Save", R.string.Save).toUpperCase());
pickerBottomLayout.middleButton.setVisibility(View.VISIBLE);
pickerBottomLayout.middleButton.setOnClickListener((it) -> {
SharedConfig.addProxy(info);
ConnectionsManager.setProxySettings(true, address, p, user, password, secret);
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged);
if (activity instanceof LaunchActivity) {
INavigationLayout layout = ((LaunchActivity) activity).getActionBarLayout();
@ -4435,17 +3878,6 @@ public class AndroidUtilities {
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_SUCCESS, LocaleController.getString(R.string.ProxyAddedSuccess));
}
dismissRunnable.run();
});
pickerBottomLayout.doneButtonTextView.setText(LocaleController.getString("ConnectingConnectProxy", R.string.ConnectingConnectProxy).toUpperCase());
pickerBottomLayout.doneButton.setOnClickListener(v -> {
SharedConfig.setCurrentProxy(SharedConfig.addProxy(info));
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged);
dismissRunnable.run();
});
builder.show();
}

View File

@ -83,7 +83,7 @@ public class ProxyRotationController implements NotificationCenter.NotificationC
}
editor.apply();
SharedConfig.currentProxy = info;
SharedConfig.setCurrentProxy(info);
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged);
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxyChangedByRotation);
ConnectionsManager.setProxySettings(true, SharedConfig.currentProxy.address, SharedConfig.currentProxy.port, SharedConfig.currentProxy.username, SharedConfig.currentProxy.password, SharedConfig.currentProxy.secret);

View File

@ -57,7 +57,6 @@ import javax.net.ssl.SSLException;
import cn.hutool.core.util.StrUtil;
import tw.nekomimi.nekogram.NekoConfig;
import tw.nekomimi.nekogram.parts.ProxySwitcher;
import tw.nekomimi.nekogram.utils.DnsFactory;
public class ConnectionsManager extends BaseController {
@ -472,9 +471,6 @@ SharedPreferences mainPreferences;
SharedConfig.loadProxyList();
if (SharedConfig.proxyEnabled && SharedConfig.currentProxy != null) {
if (SharedConfig.currentProxy instanceof SharedConfig.ExternalSocks5Proxy) {
((SharedConfig.ExternalSocks5Proxy) SharedConfig.currentProxy).start();
}
native_setProxySettings(currentAccount, SharedConfig.currentProxy.address, SharedConfig.currentProxy.port, SharedConfig.currentProxy.username, SharedConfig.currentProxy.password, SharedConfig.currentProxy.secret);
}
checkConnection();
@ -628,7 +624,6 @@ SharedPreferences mainPreferences;
try {
AndroidUtilities.runOnUIThread(() -> {
getInstance(currentAccount).connectionState = state;
ProxySwitcher.didReceivedNotification(state);
AccountInstance.getInstance(currentAccount).getNotificationCenter().postNotificationName(NotificationCenter.didUpdateConnectionState);
});
} catch (Exception e) {

View File

@ -187,7 +187,7 @@ import tw.nekomimi.nekogram.NekoConfig;
import tw.nekomimi.nekogram.parts.ArticleTransKt;
import tw.nekomimi.nekogram.transtale.TranslateDb;
import tw.nekomimi.nekogram.utils.AlertUtil;
import tw.nekomimi.nekogram.utils.ProxyUtil;
import tw.nekomimi.nekogram.utils.QrUtil;
public class ArticleViewer implements NotificationCenter.NotificationCenterDelegate {
@ -1267,7 +1267,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg
if (which == 0 ) {
Browser.openUrl(parentActivity, urlFinal);
} else {
ProxyUtil.showQrDialog(parentActivity, urlFinal);
QrUtil.showQrDialog(parentActivity, urlFinal);
}
} else if (which == 1) {
String url = urlFinal;

View File

@ -68,7 +68,7 @@ import tw.nekomimi.nekogram.NekoConfig;
import tw.nekomimi.nekogram.transtale.TranslateDb;
import tw.nekomimi.nekogram.transtale.Translator;
import tw.nekomimi.nekogram.utils.AlertUtil;
import tw.nekomimi.nekogram.utils.ProxyUtil;
import tw.nekomimi.nekogram.utils.QrUtil;
import static com.google.zxing.common.detector.MathUtils.distance;
import static org.telegram.ui.ActionBar.FloatingToolbar.STYLE_THEME;
@ -1362,7 +1362,7 @@ public abstract class TextSelectionHelper<Cell extends TextSelectionHelper.Selec
return true;
}
String urlFinal = textS.toString();
Activity activity = ProxyUtil.getOwnerActivity((((View) selectedView).getContext()));
Activity activity = QrUtil.getOwnerActivity((((View) selectedView).getContext()));
TranslateDb db = TranslateDb.currentTarget();
if (db.contains(urlFinal)) {
AlertUtil.showCopyAlert(activity, db.query(urlFinal));

View File

@ -137,7 +137,7 @@ import kotlin.Unit;
import tw.nekomimi.nekogram.ui.BottomBuilder;
import tw.nekomimi.nekogram.NekoConfig;
import tw.nekomimi.nekogram.utils.AlertUtil;
import tw.nekomimi.nekogram.utils.ProxyUtil;
import tw.nekomimi.nekogram.utils.QrUtil;
public class ChannelAdminLogActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate {
@ -2508,7 +2508,7 @@ public class ChannelAdminLogActivity extends BaseFragment implements Notificatio
if (which == 0) {
Browser.openUrl(getParentActivity(), urlFinal);
} else {
ProxyUtil.showQrDialog(getParentActivity(), urlFinal);
QrUtil.showQrDialog(getParentActivity(), urlFinal);
}
} else if (which == 1) {
String url1 = urlFinal;

View File

@ -343,7 +343,7 @@ import tw.nekomimi.nekogram.settings.NekoSettingsActivity;
import tw.nekomimi.nekogram.transtale.Translator;
import tw.nekomimi.nekogram.utils.AlertUtil;
import tw.nekomimi.nekogram.utils.PGPUtil;
import tw.nekomimi.nekogram.utils.ProxyUtil;
import tw.nekomimi.nekogram.utils.QrUtil;
import tw.nekomimi.nekogram.utils.TelegramUtil;
@SuppressWarnings("unchecked")
@ -26260,18 +26260,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
showDialog(builder.create());
}
} else if (locFile.getName().toLowerCase().endsWith(".nekox.json")) {
//TODO wtf
File finalLocFile1 = locFile;
AlertUtil.showConfirm(getParentActivity(),
LocaleController.getString("ImportProxyList", R.string.ImportProxyList),
R.drawable.baseline_security_24, LocaleController.getString("Import", R.string.Import),
false, () -> {
String status = ProxyListActivity.processProxyListFile(getParentActivity(), finalLocFile1);
if (!StrUtil.isBlank(status)) {
presentFragment(new ProxyListActivity(status));
}
});
Toast.makeText(getContext(), "Not Supportred now", Toast.LENGTH_SHORT).show();
// File finalLocFile1 = locFile;
// AlertUtil.showConfirm(getParentActivity(),
// LocaleController.getString("ImportProxyList", R.string.ImportProxyList),
// R.drawable.baseline_security_24, LocaleController.getString("Import", R.string.Import),
// false, () -> {
// String status = ProxyListActivity.processProxyListFile(getParentActivity(), finalLocFile1);
// if (!StrUtil.isBlank(status)) {
// presentFragment(new ProxyListActivity(status));
// }
// });
} else if (locFile.getName().toLowerCase().endsWith(".nekox-stickers.json")) {
@ -26284,11 +26283,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
});
} else if (locFile.getName().toLowerCase().endsWith(".nekox-settings.json")) {
File finalLocFile = locFile;
NekoSettingsActivity.importSettings(getParentActivity(), finalLocFile);
}
}
break;
@ -28302,7 +28298,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
}
} else if (which == 2) {
// QRCode
ProxyUtil.showQrDialog(getParentActivity(), urlFinal);
QrUtil.showQrDialog(getParentActivity(), urlFinal);
}
return Unit.INSTANCE;
});
@ -30633,17 +30629,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
AlertUtil.showToast("FILE_NOT_FOUND");
} else if (message.getDocumentName().toLowerCase().endsWith(".nekox.json")) {
AlertUtil.showToast("NOT_SUPPORTED_NOW");
File finalLocFile = locFile;
AlertUtil.showConfirm(getParentActivity(),
LocaleController.getString("ImportProxyList", R.string.ImportProxyList),
R.drawable.baseline_security_24, LocaleController.getString("Import", R.string.Import),
false, () -> {
String status = ProxyListActivity.processProxyListFile(getParentActivity(), finalLocFile);
if (!StrUtil.isBlank(status)) {
presentFragment(new ProxyListActivity(status));
}
});
// File finalLocFile = locFile;
// AlertUtil.showConfirm(getParentActivity(),
// LocaleController.getString("ImportProxyList", R.string.ImportProxyList),
// R.drawable.baseline_security_24, LocaleController.getString("Import", R.string.Import),
// false, () -> {
// String status = ProxyListActivity.processProxyListFile(getParentActivity(), finalLocFile);
// if (!StrUtil.isBlank(status)) {
// presentFragment(new ProxyListActivity(status));
// }
// });
} else if (message.getDocumentName().toLowerCase().endsWith(".nekox-stickers.json")) {

View File

@ -16,7 +16,6 @@ import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Vibrator;
import android.text.Editable;
import android.text.InputType;
import android.text.SpannableStringBuilder;
@ -82,7 +81,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import tw.nekomimi.nekogram.utils.ProxyUtil;
import tw.nekomimi.nekogram.utils.VibrateUtil;
public class ChatEditTypeActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate {

View File

@ -121,7 +121,7 @@ import kotlin.Unit;
import tw.nekomimi.nekogram.NekoXConfig;
import tw.nekomimi.nekogram.ui.BottomBuilder;
import tw.nekomimi.nekogram.utils.AlertUtil;
import tw.nekomimi.nekogram.utils.ProxyUtil;
import tw.nekomimi.nekogram.utils.QrUtil;
@SuppressWarnings("unchecked")
public class SharedMediaLayout extends FrameLayout implements NotificationCenter.NotificationCenterDelegate {
@ -4961,7 +4961,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter
if (which == 0) {
openUrl(urlFinal);
} else {
ProxyUtil.showQrDialog(profileActivity.getParentActivity(), urlFinal);
QrUtil.showQrDialog(profileActivity.getParentActivity(), urlFinal);
}
} else if (which == 1) {
String url1 = urlFinal;

View File

@ -105,7 +105,7 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import tw.nekomimi.nekogram.utils.ProxyUtil;
import tw.nekomimi.nekogram.utils.QrUtil;
public class StickersAlert extends BottomSheet implements NotificationCenter.NotificationCenterDelegate {
@ -1052,11 +1052,11 @@ public class StickersAlert extends BottomSheet implements NotificationCenter.Not
if (child instanceof StickerEmojiCell) {
Bitmap bitmap = ((StickerEmojiCell) child).getImageView().getBitmap();
if (bitmap == null) continue;
ProxyUtil.showQrDialog(getContext(), stickersUrl, imageSize -> Bitmap.createScaledBitmap(bitmap,imageSize,imageSize, true));
QrUtil.showQrDialog(getContext(), stickersUrl, imageSize -> Bitmap.createScaledBitmap(bitmap,imageSize,imageSize, true));
return;
}
}
ProxyUtil.showQrDialog(getContext(), stickersUrl);
QrUtil.showQrDialog(getContext(), stickersUrl);
} else if (id == menu_archive) {
dismiss();
MediaDataController.getInstance(currentAccount).toggleStickerSet(parentActivity, stickerSet, 1, parentFragment, false, true);

View File

@ -215,7 +215,7 @@ import tw.nekomimi.nekogram.InternalUpdater;
import tw.nekomimi.nekogram.NekoConfig;
import tw.nekomimi.nekogram.NekoXConfig;
import tw.nekomimi.nekogram.utils.PrivacyUtil;
import tw.nekomimi.nekogram.utils.ProxyUtil;
import tw.nekomimi.nekogram.utils.QrUtil;
import tw.nekomimi.nekogram.utils.UIUtil;
import tw.nekomimi.nekogram.utils.UpdateUtil;
import tw.nekomimi.nekogram.utils.VibrateUtil;
@ -5350,7 +5350,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter.
@Override
public void didFindQr(String text) {
ProxyUtil.showLinkAlert(getParentActivity(), text);
QrUtil.showLinkAlert(getParentActivity(), text);
}
@Override

View File

@ -81,7 +81,7 @@ import java.util.Locale;
import kotlin.Unit;
import tw.nekomimi.nekogram.ui.BottomBuilder;
import tw.nekomimi.nekogram.utils.AlertUtil;
import tw.nekomimi.nekogram.utils.ProxyUtil;
import tw.nekomimi.nekogram.utils.QrUtil;
public class FilteredSearchView extends FrameLayout implements NotificationCenter.NotificationCenterDelegate {
@ -1103,7 +1103,7 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente
if (which == 0) {
openUrl(urlFinal);
} else {
ProxyUtil.showQrDialog(parentActivity, urlFinal);
QrUtil.showQrDialog(parentActivity, urlFinal);
}
} else if (which == 1) {
String url1 = urlFinal;

View File

@ -42,7 +42,7 @@ import org.telegram.ui.Components.RecyclerListView;
import java.util.ArrayList;
import tw.nekomimi.nekogram.utils.ProxyUtil;
import tw.nekomimi.nekogram.utils.QrUtil;
public class GroupInviteActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate {
@ -156,7 +156,7 @@ public class GroupInviteActivity extends BaseFragment implements NotificationCen
if (invite == null) {
return;
}
ProxyUtil.showQrDialog(getParentActivity(),invite.link);
QrUtil.showQrDialog(getParentActivity(),invite.link);
} else if (position == revokeLinkRow) {
AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity());
builder.setMessage(LocaleController.getString("RevokeAlert", R.string.RevokeAlert));

View File

@ -205,12 +205,10 @@ import cn.hutool.core.util.StrUtil;
import kotlin.Unit;
import kotlin.text.StringsKt;
import tw.nekomimi.nekogram.InternalUpdater;
import tw.nekomimi.nekogram.settings.NekoSettingsActivity;
import tw.nekomimi.nekogram.ui.BottomBuilder;
import tw.nekomimi.nekogram.NekoConfig;
import tw.nekomimi.nekogram.NekoXConfig;
import tw.nekomimi.nekogram.settings.NekoSettingsActivity;
import tw.nekomimi.nekogram.proxy.SubInfo;
import tw.nekomimi.nekogram.proxy.SubManager;
import tw.nekomimi.nekogram.utils.AlertUtil;
import tw.nekomimi.nekogram.utils.UIUtil;
@ -897,22 +895,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati
FileLog.e(e);
}
MediaController.getInstance().setBaseActivity(this, true);
UIUtil.runOnIoDispatcher(() -> {
// ExternalGcm.checkUpdate(this);
if (NekoConfig.autoUpdateSubInfo.Bool())
for (SubInfo subInfo : SubManager.getSubList().find()) {
if (subInfo == null || !subInfo.enable) continue;
try {
subInfo.proxies = subInfo.reloadProxies();
subInfo.lastFetch = System.currentTimeMillis();
SubManager.getSubList().update(subInfo, true);
SharedConfig.reloadProxyList();
} catch (IOException allTriesFailed) {
FileLog.e(allTriesFailed);
}
}
}, 4000);
SharedConfig.reloadProxyList();
//FileLog.d("UI create time = " + (SystemClock.elapsedRealtime() - ApplicationLoader.startTime));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

View File

@ -46,7 +46,6 @@ import android.telephony.PhoneNumberUtils;
import android.text.Editable;
import android.text.InputType;
import android.text.Layout;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextPaint;
@ -55,7 +54,6 @@ import android.text.TextWatcher;
import android.text.method.PasswordTransformationMethod;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.ImageSpan;
import android.text.style.ReplacementSpan;
import android.util.Base64;
import android.util.TypedValue;
@ -84,7 +82,6 @@ import android.widget.ViewSwitcher;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.ColorUtils;
//import com.google.android.gms.auth.api.signin.GoogleSignIn;
@ -94,10 +91,7 @@ import androidx.core.graphics.ColorUtils;
//import com.google.android.gms.common.api.ApiException;
//import com.google.android.gms.safetynet.SafetyNet;
import org.json.JSONException;
import org.json.JSONObject;
import org.telegram.PhoneFormat.PhoneFormat;
import org.telegram.messenger.AccountInstance;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.ApplicationLoader;
import org.telegram.messenger.AuthTokensHelper;
@ -113,7 +107,6 @@ import org.telegram.messenger.MessageObject;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.MessagesStorage;
import org.telegram.messenger.NotificationCenter;
import org.telegram.messenger.PushListenerController;
import org.telegram.messenger.R;
import org.telegram.messenger.SRPHelper;
import org.telegram.messenger.SharedConfig;
@ -125,7 +118,6 @@ import org.telegram.tgnet.SerializedData;
import org.telegram.tgnet.TLObject;
import org.telegram.tgnet.TLRPC;
import org.telegram.ui.ActionBar.ActionBar;
import org.telegram.ui.ActionBar.ActionBarMenu;
import org.telegram.ui.ActionBar.ActionBarMenuItem;
import org.telegram.ui.ActionBar.AlertDialog;
import org.telegram.ui.ActionBar.BaseFragment;
@ -147,7 +139,6 @@ import org.telegram.ui.Components.ImageUpdater;
import org.telegram.ui.Components.LayoutHelper;
import org.telegram.ui.Components.LinkPath;
import org.telegram.ui.Components.LoadingDrawable;
import org.telegram.ui.Components.LoginOrView;
import org.telegram.ui.Components.OutlineTextContainerView;
import org.telegram.ui.Components.RLottieDrawable;
import org.telegram.ui.Components.RLottieImageView;
@ -184,7 +175,7 @@ import tw.nekomimi.nekogram.NekoConfig;
import tw.nekomimi.nekogram.NekoXConfig;
import tw.nekomimi.nekogram.ui.EditTextAutoFill;
import tw.nekomimi.nekogram.utils.AlertUtil;
import tw.nekomimi.nekogram.utils.ProxyUtil;
import tw.nekomimi.nekogram.utils.QrUtil;
@SuppressLint("HardwareIds")
public class LoginActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate {
@ -8426,7 +8417,7 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No
} catch (Exception ignore) {
}
if (response instanceof TLRPC.TL_auth_loginToken) {
exportLoginTokenDialog = ProxyUtil.showQrDialog(getParentActivity(), "tg://login?token=" + cn.hutool.core.codec.Base64.encodeUrlSafe(((TLRPC.TL_auth_loginToken) response).token));
exportLoginTokenDialog = QrUtil.showQrDialog(getParentActivity(), "tg://login?token=" + cn.hutool.core.codec.Base64.encodeUrlSafe(((TLRPC.TL_auth_loginToken) response).token));
int delay = (int) (((TLRPC.TL_auth_loginToken) response).expires - System.currentTimeMillis() / 1000);
if (delay < 0 || delay > 20) delay = 20;
if (BuildVars.DEBUG_VERSION) {

View File

@ -267,7 +267,7 @@ import tw.nekomimi.nekogram.transtale.TranslateDb;
import tw.nekomimi.nekogram.transtale.Translator;
import tw.nekomimi.nekogram.ui.BottomBuilder;
import tw.nekomimi.nekogram.utils.AlertUtil;
import tw.nekomimi.nekogram.utils.ProxyUtil;
import tw.nekomimi.nekogram.utils.QrUtil;
@SuppressLint("WrongConstant")
@SuppressWarnings("unchecked")
@ -4350,7 +4350,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
showDownloadAlert();
return;
}
ProxyUtil.tryReadQR(parentActivity, bitmap);
QrUtil.tryReadQR(parentActivity, bitmap);
} catch (Exception ignored) {
AlertUtil.showToast(LocaleController.getString("NoQrFound", R.string.NoQrFound));
}

View File

@ -23,7 +23,6 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ConfigurationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.DataSetObserver;
@ -79,7 +78,6 @@ import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.collection.LongSparseArray;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import androidx.core.graphics.ColorUtils;
import androidx.core.math.MathUtils;
import androidx.core.view.NestedScrollingParent3;
@ -207,7 +205,6 @@ import org.telegram.ui.Components.SharedMediaLayout;
import org.telegram.ui.Components.SizeNotifierFrameLayout;
import org.telegram.ui.Components.StickerEmptyView;
import org.telegram.ui.Components.TimerDrawable;
import org.telegram.ui.Components.TranslateAlert2;
import org.telegram.ui.Components.TypefaceSpan;
import org.telegram.ui.Components.UndoView;
import org.telegram.ui.Components.VectorAvatarThumbDrawable;
@ -237,7 +234,6 @@ import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.core.util.StrUtil;
import kotlin.Unit;
import libv2ray.Libv2ray;
import tw.nekomimi.nekogram.NekoConfig;
import tw.nekomimi.nekogram.NekoXConfig;
import tw.nekomimi.nekogram.parts.DialogTransKt;
@ -245,10 +241,9 @@ import tw.nekomimi.nekogram.settings.NekoSettingsActivity;
import tw.nekomimi.nekogram.settings.NekoXSettingActivity;
import tw.nekomimi.nekogram.ui.BottomBuilder;
import tw.nekomimi.nekogram.utils.AlertUtil;
import tw.nekomimi.nekogram.utils.EnvUtil;
import tw.nekomimi.nekogram.utils.FileUtil;
import tw.nekomimi.nekogram.utils.LangsKt;
import tw.nekomimi.nekogram.utils.ProxyUtil;
import tw.nekomimi.nekogram.utils.QrUtil;
import tw.nekomimi.nekogram.utils.ShareUtil;
import tw.nekomimi.nekogram.utils.UIUtil;
@ -1697,7 +1692,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter.
final int reqId = getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> {
if (error == null) {
TLRPC.TL_chatInviteExported invite = (TLRPC.TL_chatInviteExported) response;
ProxyUtil.showQrDialog(getParentActivity(), invite.link, imageSize -> Bitmap.createScaledBitmap(avatarImage.getImageReceiver().getBitmap(), imageSize, imageSize, true));
QrUtil.showQrDialog(getParentActivity(), invite.link, imageSize -> Bitmap.createScaledBitmap(avatarImage.getImageReceiver().getBitmap(), imageSize, imageSize, true));
} else {
AlertUtil.showToast(error);
}
@ -2091,7 +2086,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter.
intent.putExtra(Intent.EXTRA_TEXT, text);
startActivityForResult(Intent.createChooser(intent, LocaleController.getString("BotShare", R.string.BotShare)), 500);
} else {
ProxyUtil.showQrDialog(getParentActivity(), text, avatarImage.getImageReceiver().getBitmap() == null ? null : imageSize -> Bitmap.createScaledBitmap(avatarImage.getImageReceiver().getBitmap(), imageSize, imageSize, true));
QrUtil.showQrDialog(getParentActivity(), text, avatarImage.getImageReceiver().getBitmap() == null ? null : imageSize -> Bitmap.createScaledBitmap(avatarImage.getImageReceiver().getBitmap(), imageSize, imageSize, true));
}
} catch (Exception e) {
FileLog.e(e);
@ -3538,14 +3533,6 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter.
BottomBuilder builder = new BottomBuilder(getParentActivity());
String message = cell.getTextView().getText().toString();
try {
if (!BuildVars.isMini) {
message += "\n" + Libv2ray.checkVersionX()
.replace("Lib", "AndroidLibV2rayLite")
.replace("Core", "v2ray-core");
}
} catch (Exception ignored) {
}
builder.addTitle(message);
String finalMessage = message;
builder.addItem(LocaleController.getString("Copy", R.string.Copy), R.drawable.baseline_content_copy_24, (it) -> {

View File

@ -12,7 +12,6 @@ import android.animation.ValueAnimator;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@ -42,6 +41,8 @@ import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import androidx.core.graphics.ColorUtils;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.MessagesController;
@ -56,6 +57,8 @@ import org.telegram.ui.ActionBar.ActionBarMenuItem;
import org.telegram.ui.ActionBar.BaseFragment;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.ActionBar.ThemeDescription;
import org.telegram.ui.Cells.HeaderCell;
import org.telegram.ui.Cells.RadioCell;
import org.telegram.ui.Cells.ShadowSectionCell;
import org.telegram.ui.Cells.TextInfoPrivacyCell;
import org.telegram.ui.Cells.TextSettingsCell;
@ -80,17 +83,18 @@ public class ProxySettingsActivity extends BaseFragment {
private final static int FIELD_USER = 2;
private final static int FIELD_PASSWORD = 3;
private final static int FIELD_SECRET = 4;
private final static int FIELD_REMARKS = 5;
private EditTextBoldCursor[] inputFields;
private ScrollView scrollView;
private LinearLayout linearLayout2;
private LinearLayout inputFieldsContainer;
private HeaderCell headerCell;
private ShadowSectionCell[] sectionCell = new ShadowSectionCell[3];
private TextInfoPrivacyCell[] bottomCells = new TextInfoPrivacyCell[2];
private TextSettingsCell shareCell;
private TextSettingsCell pasteCell;
private ActionBarMenuItem doneItem;
// private RadioCell[] typeCell = new RadioCell[2];
private RadioCell[] typeCell = new RadioCell[2];
private int currentType = -1;
private int pasteType = -1;
@ -134,7 +138,7 @@ public class ProxySettingsActivity extends BaseFragment {
addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 23 + 48 : 21, 0, LocaleController.isRTL ? 21 : 23, 0));
checkImage = new ImageView(context);
checkImage.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_featuredStickers_addedIcon), PorterDuff.Mode.SRC_IN));
checkImage.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_featuredStickers_addedIcon), PorterDuff.Mode.MULTIPLY));
checkImage.setImageResource(R.drawable.sticker_added);
addView(checkImage, LayoutHelper.createFrame(19, 14, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL, 21, 0, 21, 0));
}
@ -157,16 +161,15 @@ public class ProxySettingsActivity extends BaseFragment {
@Override
protected void onDraw(Canvas canvas) {
if (needDivider) {
canvas.drawLine(0, getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight() - 1, Theme.dividerPaint);
canvas.drawLine(LocaleController.isRTL ? 0 : AndroidUtilities.dp(20), getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? AndroidUtilities.dp(20) : 0), getMeasuredHeight() - 1, Theme.dividerPaint);
}
}
}
public ProxySettingsActivity(int type) {
public ProxySettingsActivity() {
super();
currentProxyInfo = new SharedConfig.ProxyInfo("", 1080, "", "", "");
addingNewProxy = true;
currentType = type;
}
public ProxySettingsActivity(SharedConfig.ProxyInfo proxyInfo) {
@ -210,7 +213,6 @@ public class ProxySettingsActivity extends BaseFragment {
}
currentProxyInfo.address = inputFields[FIELD_IP].getText().toString();
currentProxyInfo.port = Utilities.parseInt(inputFields[FIELD_PORT].getText().toString());
currentProxyInfo.setRemarks(inputFields[FIELD_REMARKS].getText().toString());
if (currentType == 0) {
currentProxyInfo.secret = "";
currentProxyInfo.username = inputFields[FIELD_USER].getText().toString();
@ -223,11 +225,14 @@ public class ProxySettingsActivity extends BaseFragment {
SharedPreferences preferences = MessagesController.getGlobalMainSettings();
SharedPreferences.Editor editor = preferences.edit();
boolean enabled;
if (addingNewProxy) {
SharedConfig.addProxy(currentProxyInfo);
SharedConfig.setCurrentProxy(currentProxyInfo);
SharedConfig.currentProxy = currentProxyInfo;
editor.putBoolean("proxy_enabled", true);
enabled = true;
} else {
SharedConfig.setProxyEnable(false);
enabled = preferences.getBoolean("proxy_enabled", false);
SharedConfig.saveProxyList();
}
if (addingNewProxy || SharedConfig.currentProxy == currentProxyInfo) {
@ -236,21 +241,13 @@ public class ProxySettingsActivity extends BaseFragment {
editor.putString("proxy_user", currentProxyInfo.username);
editor.putInt("proxy_port", currentProxyInfo.port);
editor.putString("proxy_secret", currentProxyInfo.secret);
if (currentProxyInfo instanceof SharedConfig.VmessProxy) {
editor.putString("vmess_link", ((SharedConfig.VmessProxy) currentProxyInfo).bean.toString());
} else if (currentProxyInfo instanceof SharedConfig.ShadowsocksProxy) {
editor.putString("vmess_link", ((SharedConfig.ShadowsocksProxy) currentProxyInfo).bean.toString());
} else if (currentProxyInfo instanceof SharedConfig.ShadowsocksRProxy) {
editor.putString("vmess_link", ((SharedConfig.ShadowsocksRProxy) currentProxyInfo).bean.toString());
}
ConnectionsManager.setProxySettings(SharedConfig.proxyEnabled, currentProxyInfo.address, currentProxyInfo.port, currentProxyInfo.username, currentProxyInfo.password, currentProxyInfo.secret);
ConnectionsManager.setProxySettings(enabled, currentProxyInfo.address, currentProxyInfo.port, currentProxyInfo.username, currentProxyInfo.password, currentProxyInfo.secret);
}
editor.apply();
editor.commit();
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged);
finishFragment();
}
}
});
@ -271,7 +268,23 @@ public class ProxySettingsActivity extends BaseFragment {
linearLayout2.setOrientation(LinearLayout.VERTICAL);
scrollView.addView(linearLayout2, new ScrollView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
final View.OnClickListener typeCellClickListener = view -> setProxyType((Integer) view.getTag(), true);
for (int a = 0; a < 2; a++) {
typeCell[a] = new RadioCell(context);
typeCell[a].setBackground(Theme.getSelectorDrawable(true));
typeCell[a].setTag(a);
if (a == 0) {
typeCell[a].setText(LocaleController.getString("UseProxySocks5", R.string.UseProxySocks5), a == currentType, true);
} else {
typeCell[a].setText(LocaleController.getString("UseProxyTelegram", R.string.UseProxyTelegram), a == currentType, false);
}
linearLayout2.addView(typeCell[a], LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 50));
typeCell[a].setOnClickListener(typeCellClickListener);
}
sectionCell[0] = new ShadowSectionCell(context);
linearLayout2.addView(sectionCell[0], LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
inputFieldsContainer = new LinearLayout(context);
inputFieldsContainer.setOrientation(LinearLayout.VERTICAL);
@ -283,8 +296,8 @@ public class ProxySettingsActivity extends BaseFragment {
}
linearLayout2.addView(inputFieldsContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
inputFields = new EditTextBoldCursor[6];
for (int a = 0; a < 6; a++) {
inputFields = new EditTextBoldCursor[5];
for (int a = 0; a < 5; a++) {
FrameLayout container = new FrameLayout(context);
inputFieldsContainer.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
@ -399,10 +412,6 @@ public class ProxySettingsActivity extends BaseFragment {
inputFields[a].setHintText(LocaleController.getString("UseProxySecret", R.string.UseProxySecret));
inputFields[a].setText(currentProxyInfo.secret);
break;
case FIELD_REMARKS:
inputFields[a].setHintText(LocaleController.getString("ProxyRemarks", R.string.ProxyRemarks));
inputFields[a].setText(currentProxyInfo.getRemarks());
break;
}
inputFields[a].setSelection(inputFields[a].length());
@ -482,6 +491,63 @@ public class ProxySettingsActivity extends BaseFragment {
linearLayout2.addView(sectionCell[2], 1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
sectionCell[2].setVisibility(View.GONE);
shareCell = new TextSettingsCell(context);
shareCell.setBackgroundDrawable(Theme.getSelectorDrawable(true));
shareCell.setText(LocaleController.getString("ShareFile", R.string.ShareFile), false);
shareCell.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4));
linearLayout2.addView(shareCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
shareCell.setOnClickListener(v -> {
StringBuilder params = new StringBuilder();
String address = inputFields[FIELD_IP].getText().toString();
String password = inputFields[FIELD_PASSWORD].getText().toString();
String user = inputFields[FIELD_USER].getText().toString();
String port = inputFields[FIELD_PORT].getText().toString();
String secret = inputFields[FIELD_SECRET].getText().toString();
String url;
try {
if (!TextUtils.isEmpty(address)) {
params.append("server=").append(URLEncoder.encode(address, "UTF-8"));
}
if (!TextUtils.isEmpty(port)) {
if (params.length() != 0) {
params.append("&");
}
params.append("port=").append(URLEncoder.encode(port, "UTF-8"));
}
if (currentType == 1) {
url = "https://t.me/proxy?";
if (params.length() != 0) {
params.append("&");
}
params.append("secret=").append(URLEncoder.encode(secret, "UTF-8"));
} else {
url = "https://t.me/socks?";
if (!TextUtils.isEmpty(user)) {
if (params.length() != 0) {
params.append("&");
}
params.append("user=").append(URLEncoder.encode(user, "UTF-8"));
}
if (!TextUtils.isEmpty(password)) {
if (params.length() != 0) {
params.append("&");
}
params.append("pass=").append(URLEncoder.encode(password, "UTF-8"));
}
}
} catch (Exception ignore) {
return;
}
if (params.length() == 0) {
return;
}
String link = url + params.toString();
QRCodeBottomSheet alert = new QRCodeBottomSheet(context, LocaleController.getString("ShareQrCode", R.string.ShareQrCode), link, LocaleController.getString("QRCodeLinkHelpProxy", R.string.QRCodeLinkHelpProxy), true);
Bitmap icon = SvgHelper.getBitmap(RLottieDrawable.readRes(null, R.raw.qr_dog), AndroidUtilities.dp(60), AndroidUtilities.dp(60), false);
alert.setCenterImage(icon);
showDialog(alert);
});
sectionCell[1] = new ShadowSectionCell(context);
sectionCell[1].setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow));
linearLayout2.addView(sectionCell[1], LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
@ -492,19 +558,8 @@ public class ProxySettingsActivity extends BaseFragment {
shareDoneProgress = 1f;
checkShareDone(false);
if (currentType == -1) {
setProxyType(TextUtils.isEmpty(currentProxyInfo.secret) ? 0 : 1, false);
} else {
int t = currentType;
currentType = -1;
setProxyType(t, false);
}
currentType = -1;
setProxyType(TextUtils.isEmpty(currentProxyInfo.secret) ? 0 : 1, false);
pasteType = -1;
pasteString = null;
@ -612,6 +667,7 @@ public class ProxySettingsActivity extends BaseFragment {
shareDoneAnimator.setDuration(200);
shareDoneAnimator.addUpdateListener(a -> {
shareDoneProgress = AndroidUtilities.lerp(shareDoneProgressAnimValues, a.getAnimatedFraction());
shareCell.setTextColor(ColorUtils.blendARGB(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2), Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4), shareDoneProgress));
doneItem.setAlpha(shareDoneProgress / 2f + 0.5f);
});
}
@ -621,15 +677,17 @@ public class ProxySettingsActivity extends BaseFragment {
shareDoneAnimator.start();
} else {
shareDoneProgress = enabled ? 1f : 0f;
shareCell.setTextColor(enabled ? Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4) : Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2));
doneItem.setAlpha(enabled ? 1f : .5f);
}
shareCell.setEnabled(enabled);
doneItem.setEnabled(enabled);
shareDoneEnabled = enabled;
}
}
private void checkShareDone(boolean animated) {
if (doneItem == null || inputFields[FIELD_IP] == null || inputFields[FIELD_PORT] == null) {
if (shareCell == null || doneItem == null || inputFields[FIELD_IP] == null || inputFields[FIELD_PORT] == null) {
return;
}
setShareDoneEnabled(inputFields[FIELD_IP].length() != 0 && Utilities.parseInt(inputFields[FIELD_PORT].getText().toString()) != 0, animated);
@ -693,6 +751,8 @@ public class ProxySettingsActivity extends BaseFragment {
((View) inputFields[FIELD_PASSWORD].getParent()).setVisibility(View.GONE);
((View) inputFields[FIELD_USER].getParent()).setVisibility(View.GONE);
}
typeCell[0].setChecked(currentType == 0, animated);
typeCell[1].setChecked(currentType == 1, animated);
}
}
@ -707,6 +767,9 @@ public class ProxySettingsActivity extends BaseFragment {
@Override
public ArrayList<ThemeDescription> getThemeDescriptions() {
final ThemeDescription.ThemeDescriptionDelegate delegate = () -> {
if (shareCell != null && (shareDoneAnimator == null || !shareDoneAnimator.isRunning())) {
shareCell.setTextColor(shareDoneEnabled ? Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4) : Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2));
}
if (inputFields != null) {
for (int i = 0; i < inputFields.length; i++) {
inputFields[i].setLineColors(Theme.getColor(Theme.key_windowBackgroundWhiteInputField),
@ -727,10 +790,23 @@ public class ProxySettingsActivity extends BaseFragment {
arrayList.add(new ThemeDescription(inputFieldsContainer, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundWhite));
arrayList.add(new ThemeDescription(linearLayout2, 0, new Class[]{View.class}, Theme.dividerPaint, null, null, Theme.key_divider));
arrayList.add(new ThemeDescription(shareCell, ThemeDescription.FLAG_SELECTORWHITE, null, null, null, null, Theme.key_windowBackgroundWhite));
arrayList.add(new ThemeDescription(shareCell, ThemeDescription.FLAG_SELECTORWHITE, null, null, null, null, Theme.key_listSelector));
arrayList.add(new ThemeDescription(null, 0, null, null, null, null, delegate, Theme.key_windowBackgroundWhiteBlueText4));
arrayList.add(new ThemeDescription(null, 0, null, null, null, null, delegate, Theme.key_windowBackgroundWhiteGrayText2));
arrayList.add(new ThemeDescription(pasteCell, ThemeDescription.FLAG_SELECTORWHITE, null, null, null, null, Theme.key_windowBackgroundWhite));
arrayList.add(new ThemeDescription(pasteCell, ThemeDescription.FLAG_SELECTORWHITE, null, null, null, null, Theme.key_listSelector));
arrayList.add(new ThemeDescription(pasteCell, 0, new Class[]{TextSettingsCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueText4));
for (int a = 0; a < typeCell.length; a++) {
arrayList.add(new ThemeDescription(typeCell[a], ThemeDescription.FLAG_SELECTORWHITE, null, null, null, null, Theme.key_windowBackgroundWhite));
arrayList.add(new ThemeDescription(typeCell[a], ThemeDescription.FLAG_SELECTORWHITE, null, null, null, null, Theme.key_listSelector));
arrayList.add(new ThemeDescription(typeCell[a], 0, new Class[]{RadioCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(typeCell[a], ThemeDescription.FLAG_CHECKBOX, new Class[]{RadioCell.class}, new String[]{"radioButton"}, null, null, null, Theme.key_radioBackground));
arrayList.add(new ThemeDescription(typeCell[a], ThemeDescription.FLAG_CHECKBOXCHECK, new Class[]{RadioCell.class}, new String[]{"radioButton"}, null, null, null, Theme.key_radioBackgroundChecked));
}
if (inputFields != null) {
for (int a = 0; a < inputFields.length; a++) {
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
@ -745,6 +821,8 @@ public class ProxySettingsActivity extends BaseFragment {
arrayList.add(new ThemeDescription(null, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(null, ThemeDescription.FLAG_HINTTEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteHintText));
}
arrayList.add(new ThemeDescription(headerCell, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundWhite));
arrayList.add(new ThemeDescription(headerCell, 0, new Class[]{HeaderCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueHeader));
for (int a = 0; a < sectionCell.length; a++) {
if (sectionCell[a] != null) {
arrayList.add(new ThemeDescription(sectionCell[a], ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{ShadowSectionCell.class}, null, null, null, Theme.key_windowBackgroundGrayShadow));

View File

@ -2,7 +2,6 @@ package tw.nekomimi.nekogram.database
import org.dizitart.no2.Nitrite
import org.telegram.messenger.ApplicationLoader
import tw.nekomimi.nekogram.proxy.SubInfo
import tw.nekomimi.nekogram.utils.FileUtil
import java.io.File
@ -22,10 +21,6 @@ fun mkDatabase(name: String, delete: Boolean = false): Nitrite {
val test = nitrite.openSharedPreference("shared_preferences")
test.connection.close()
val subs = nitrite.getRepository("proxy_sub", SubInfo::class.java)
subs.close()
return nitrite
}

View File

@ -1,187 +0,0 @@
package tw.nekomimi.nekogram.parts
import android.os.SystemClock
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.telegram.messenger.AndroidUtilities
import org.telegram.messenger.NotificationCenter
import org.telegram.messenger.SharedConfig
import org.telegram.messenger.SharedConfig.ExternalSocks5Proxy
import org.telegram.messenger.UserConfig
import org.telegram.tgnet.ConnectionsManager
import org.telegram.ui.ProxyListActivity
import tw.nekomimi.nekogram.utils.UIUtil
import java.util.concurrent.ExecutorService
import java.util.concurrent.atomic.AtomicBoolean
private suspend fun postCheckSingleProxy(proxyInfo: SharedConfig.ProxyInfo, repeat: Int) {
val lock = AtomicBoolean()
if (proxyInfo is ExternalSocks5Proxy && !proxyInfo.isStarted) {
proxyInfo.start()
delay(233L)
}
var time = -1L
val startAt = SystemClock.elapsedRealtime()
proxyInfo.proxyCheckPingId = ConnectionsManager.getInstance(UserConfig.selectedAccount).checkProxy(proxyInfo.address, proxyInfo.port, proxyInfo.username, proxyInfo.password, proxyInfo.secret) {
time = it
lock.set(true)
}
while (!lock.get() && SystemClock.elapsedRealtime() - startAt < 4000L) delay(100L)
if (!lock.get()) {
proxyInfo.availableCheckTime = SystemClock.elapsedRealtime()
proxyInfo.checking = false
proxyInfo.available = false
proxyInfo.ping = 0
if (proxyInfo is ExternalSocks5Proxy && proxyInfo !== SharedConfig.currentProxy) {
proxyInfo.stop()
}
return
}
if (time == -1L) {
if (repeat > 0) {
postCheckSingleProxy(proxyInfo, repeat - 1)
} else {
proxyInfo.availableCheckTime = SystemClock.elapsedRealtime()
proxyInfo.checking = false
proxyInfo.available = false
proxyInfo.ping = -1L
if (proxyInfo is ExternalSocks5Proxy && proxyInfo !== SharedConfig.currentProxy) {
proxyInfo.stop()
}
}
} else {
proxyInfo.availableCheckTime = SystemClock.elapsedRealtime()
proxyInfo.checking = false
proxyInfo.ping = time
proxyInfo.available = true
if (proxyInfo is ExternalSocks5Proxy && proxyInfo !== SharedConfig.currentProxy) {
proxyInfo.stop()
}
}
}
fun postCheckProxyList() = GlobalScope.launch(Dispatchers.IO) {
SharedConfig.getProxyList().forEach { proxyInfo ->
if (proxyInfo.checking || SystemClock.elapsedRealtime() - proxyInfo.availableCheckTime < 2 * 60 * 1000L) {
return@forEach
}
synchronized(proxyInfo) {
if (proxyInfo.checking || SystemClock.elapsedRealtime() - proxyInfo.availableCheckTime < 2 * 60 * 1000L) {
return@forEach
}
proxyInfo.checking = true
}
runCatching {
postCheckSingleProxy(proxyInfo, 1)
}.onFailure {
proxyInfo.availableCheckTime = SystemClock.elapsedRealtime()
proxyInfo.checking = false
proxyInfo.available = false
proxyInfo.ping = 0
}
}
}
fun ProxyListActivity.checkProxyList(force: Boolean, context: ExecutorService) {
GlobalScope.launch(Dispatchers.IO) {
SharedConfig.proxyList.toList().forEach {
if (it.checking || SystemClock.elapsedRealtime() - it.availableCheckTime < 2 * 60 * 1000L && !force) {
return@forEach
}
it.checking = true
runCatching {
context.execute {
runCatching {
val lock = AtomicBoolean()
val startAt = SystemClock.elapsedRealtime()
UIUtil.runOnUIThread { NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxyCheckDone, it) }
checkSingleProxy(it, if (it is ExternalSocks5Proxy) 3 else 1) {
AndroidUtilities.runOnUIThread {
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxyCheckDone, it)
}
lock.set(true)
}
while (!lock.get() && SystemClock.elapsedRealtime() - startAt < 4000L) Thread.sleep(100L)
if (!lock.get()) {
it.availableCheckTime = SystemClock.elapsedRealtime()
it.checking = false
it.available = false
it.ping = 0
if (it is ExternalSocks5Proxy && it !== SharedConfig.currentProxy) {
it.stop()
}
AndroidUtilities.runOnUIThread {
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxyCheckDone, it)
}
}
}
}
}.onFailure {
return@launch
}
}
}
}

View File

@ -1,108 +0,0 @@
package tw.nekomimi.nekogram.parts
import android.util.Base64
import cn.hutool.http.HttpResponse
import cn.hutool.http.HttpUtil
import kotlinx.coroutines.*
import org.telegram.messenger.FileLog
import tw.nekomimi.nekogram.utils.DnsFactory
import tw.nekomimi.nekogram.utils.ProxyUtil.parseProxies
import tw.nekomimi.nekogram.NekoConfig
import tw.nekomimi.nekogram.utils.StrUtil
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
fun loadProxiesPublic(urls: List<String>, exceptions: MutableMap<String, Exception>): List<String> {
if (!NekoConfig.enablePublicProxy.Bool())
return emptyList()
// Try DoH first ( github.com is often blocked
try {
val content = DnsFactory.getTxts("nachonekodayo.sekai.icu").joinToString()
val proxiesString = StrUtil.getSubString(content, "#NekoXStart#", "#NekoXEnd#")
if (proxiesString.equals(content)) {
throw Exception("DoH get public proxy: Not found")
}
return parseProxies(proxiesString)
} catch (e: Exception) {
FileLog.e(e)
}
// Try Other Urls
return loadProxies(urls, exceptions)
}
fun loadProxies(urls: List<String>, exceptions: MutableMap<String, Exception>): List<String> {
return runBlocking {
suspendCoroutine {
val ret = AtomicBoolean()
val cl = AtomicInteger(urls.size)
var defer: List<String>? = null
for (url in urls) {
launch(Dispatchers.IO) {
try {
var subX = ""
var subY = ""
var urlFinal = url
if (url.count { it == '@' } == 2) {
subX = url.substringAfter("@")
.substringBefore("@")
subY = url.substringAfterLast("@")
urlFinal = url.substringBefore("@")
}
var nextUrl = url
var resp: HttpResponse
while (true) {
resp = HttpUtil.createGet(nextUrl).timeout(10 * 1000).execute();
if (resp.status == 301 || resp.status == 302 || resp.status == 307) {
nextUrl = resp.header("Location");
continue;
}
break;
}
var content = resp.body()
if (subX.isNotBlank()) {
content = content.substringAfter(subX)
.substringBefore(subY)
}
if (url.contains("https://api.github.com")) {
content = content.replace("\\n", "", false)
content = String(Base64.decode(content, Base64.NO_PADDING))
}
val proxies = parseProxies(content)
if (urlFinal.contains("https://gitee.com/") && cl.decrementAndGet() > 0) {
defer = proxies
} else {
if (ret.getAndSet(true)) return@launch
it.resume(proxies)
}
FileLog.d(url)
FileLog.d("Success")
} catch (e: Exception) {
FileLog.d(url)
FileLog.e(e)
exceptions[url] = e
if (cl.decrementAndGet() == 0) {
if (defer != null) {
it.resume(defer!!)
} else {
it.resumeWithException(e)
}
}
}
}
}
}
}
}

View File

@ -1,108 +0,0 @@
package tw.nekomimi.nekogram.parts
import org.telegram.messenger.SharedConfig
import org.telegram.tgnet.ConnectionsManager
import tw.nekomimi.nekogram.NekoConfig
import java.util.*
object ProxySwitcher {
var currentConnectionState = ConnectionsManager.ConnectionStateWaitingForNetwork
val switchTimer by lazy { Timer("Proxy Switch Timer") }
var currentTask: SwitchTask? = null
fun cancel() {
currentTask = null
switchTimer.purge()
}
fun reschedule() {
cancel()
switchTimer.schedule(SwitchTask().also { currentTask = it }, 3333L)
}
@JvmStatic
fun didReceivedNotification(connectionState: Int) {
if (!NekoConfig.proxyAutoSwitch.Bool()) return
currentConnectionState = connectionState
if (currentConnectionState == ConnectionsManager.ConnectionStateConnectingToProxy) {
reschedule()
} else {
cancel()
}
}
class SwitchTask : TimerTask() {
override fun run() {
if (this != currentTask) return
if (currentConnectionState != ConnectionsManager.ConnectionStateConnectingToProxy) return
var proxyList = SharedConfig.getProxyList().takeIf { it.size > 1 } ?: return
val current = SharedConfig.currentProxy ?: return
val currIndex = proxyList.indexOf(current)
if (currIndex > 0) {
val proxyListNew = LinkedList<SharedConfig.ProxyInfo>()
proxyListNew.addAll(proxyList.subList(currIndex, proxyList.size))
proxyListNew.addAll(proxyList.subList(0, currIndex + 1))
proxyList = proxyListNew
}
if (proxyList.all { it.availableCheckTime == 0L }) {
if (proxyList.all { !it.checking }) {
repeat(3) { postCheckProxyList() }
}
if (currentConnectionState != ConnectionsManager.ConnectionStateConnectingToProxy) return
SharedConfig.setCurrentProxy(proxyList[0])
reschedule()
return
}
proxyList.forEach {
if (it.availableCheckTime != 0L && !it.available) return@forEach
if (currentConnectionState != ConnectionsManager.ConnectionStateConnectingToProxy) return
SharedConfig.setCurrentProxy(it)
reschedule()
return
}
}
}
}

View File

@ -1,115 +0,0 @@
/*******************************************************************************
* *
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
package tw.nekomimi.nekogram.proxy
import android.os.Build
import android.os.SystemClock
import android.system.OsConstants
import androidx.annotation.MainThread
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import org.telegram.messenger.ApplicationLoader
import org.telegram.messenger.FileLog
import java.io.File
import java.io.IOException
import java.io.InputStream
import kotlin.concurrent.thread
class GuardedProcessPool(private val onFatal: suspend (IOException) -> Unit) : CoroutineScope {
companion object {
private const val TAG = "GuardedProcessPool"
}
private inner class Guard(private val cmd: List<String>) {
private lateinit var process: Process
private fun streamLogger(input: InputStream, logger: (String) -> Unit) = try {
input.bufferedReader().forEachLine(logger)
} catch (_: IOException) { } // ignore
fun start() {
process = ProcessBuilder(cmd).directory(ApplicationLoader.applicationContext.cacheDir).start()
}
suspend fun looper(onRestartCallback: (suspend () -> Unit)?) {
var running = true
val cmdName = File(cmd.first()).nameWithoutExtension
val exitChannel = Channel<Int>()
try {
while (true) {
thread(name = "stderr-$cmdName") {
streamLogger(process.errorStream) {
FileLog.e("[$cmdName]$it")
}
}
thread(name = "stdout-$cmdName") {
streamLogger(process.inputStream) {
FileLog.d("[$cmdName]$it")
}
// this thread also acts as a daemon thread for waitFor
runBlocking { exitChannel.send(process.waitFor()) }
}
val startTime = SystemClock.elapsedRealtime()
val exitCode = exitChannel.receive()
running = false
when {
SystemClock.elapsedRealtime() - startTime < 1000 -> throw IOException(
"$cmdName exits too fast (exit code: $exitCode)")
exitCode == 128 + OsConstants.SIGKILL -> FileLog.w("$cmdName was killed")
else -> FileLog.e(IOException("$cmdName unexpectedly exits with code $exitCode"))
}
start()
running = true
onRestartCallback?.invoke()
}
} catch (e: IOException) {
FileLog.w("error occurred. stop guard: " + cmd.joinToString(" "))
GlobalScope.launch(Dispatchers.Main) { onFatal(e) }
} finally {
if (running) withContext(NonCancellable) {
process.destroy() // kill the process
if (Build.VERSION.SDK_INT >= 26) {
if (withTimeoutOrNull(1000) { exitChannel.receive() } != null) return@withContext
process.destroyForcibly() // Force to kill the process if it's still alive
}
exitChannel.receive()
} // otherwise process already exited, nothing to be done
}
}
}
override val coroutineContext = Dispatchers.Main.immediate + Job()
@MainThread
fun start(cmd: List<String>, onRestartCallback: (suspend () -> Unit)? = null) {
FileLog.d("start process: " + cmd.joinToString (" "))
Guard(cmd).apply {
start() // if start fails, IOException will be thrown directly
launch { looper(onRestartCallback) }
}
}
@MainThread
fun close(scope: CoroutineScope) {
cancel()
coroutineContext[Job]!!.also { job -> scope.launch { job.join() } }
}
}

View File

@ -1,51 +0,0 @@
package tw.nekomimi.nekogram.proxy
import java.net.InetSocketAddress
import java.net.ServerSocket
import kotlin.random.Random
object ProxyManager {
@JvmStatic
fun mkPort(): Int {
var port: Int
do {
port = mkNewPort()
} while (!isProxyAvailable(port))
return port
}
private fun mkNewPort() = Random.nextInt(2048, 32768)
@JvmStatic
fun isProxyAvailable(port: Int): Boolean {
if (port !in 2048 until 32768) return false
runCatching {
val server = ServerSocket()
server.bind(InetSocketAddress("127.0.0.1",port))
server.close()
Thread.sleep(1000L)
}.onFailure {
return false
}
return true
}
}

View File

@ -1,290 +0,0 @@
package tw.nekomimi.nekogram.proxy
import android.annotation.SuppressLint
import cn.hutool.core.codec.Base64
import com.github.shadowsocks.plugin.PluginConfiguration
import com.github.shadowsocks.plugin.PluginManager
import com.github.shadowsocks.plugin.PluginOptions
import com.v2ray.ang.V2RayConfig.SS_PROTOCOL
import kotlinx.coroutines.runBlocking
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.json.JSONObject
import org.telegram.messenger.ApplicationLoader
import org.telegram.messenger.FileLog
import tw.nekomimi.nekogram.utils.AlertUtil
import tw.nekomimi.nekogram.utils.FileUtil
import java.io.File
import kotlin.concurrent.thread
import kotlin.properties.Delegates
@SuppressLint("NewApi")
class ShadowsocksLoader {
lateinit var bean: Bean
var port by Delegates.notNull<Int>()
var shadowsocksProcess: GuardedProcessPool? = null
fun initConfig(bean: Bean, port: Int) {
this.bean = bean
this.port = port
}
fun start() {
stop()
val cacheCfg = File(ApplicationLoader.applicationContext.cacheDir, "ss_cfg_${bean.hash}.json")
shadowsocksProcess = GuardedProcessPool {
FileLog.e(it)
}.apply {
runCatching {
cacheCfg.writeText(bean.toJson().toString())
start(listOf(FileUtil.extLib("ss-local").path,
"--local-addr", "127.0.0.1:$port",
"--config", cacheCfg.path)) {
cacheCfg.delete()
}
}.onFailure { it ->
AlertUtil.showToast("${it.javaClass.simpleName}: ${it.message}")
cacheCfg.delete()
FileLog.e(it)
}
}
}
fun stop() {
if (shadowsocksProcess != null) {
val proc = shadowsocksProcess!!
thread {
runCatching {
runBlocking { proc.close(this) }
}
}
shadowsocksProcess = null
}
}
data class Bean(
var host: String = "",
var remotePort: Int = 443,
var password: String = "",
var method: String = "aes-256-cfb",
var plugin: String = "",
var remarks: String? = null
) {
init {
if (method == "plain") method = "none"
val pl = PluginConfiguration(plugin)
if (pl.selected.contains("v2ray") && pl.selected != "v2ray-plugin") {
pl.pluginsOptions["v2ray-plugin"] = pl.getOptions().apply { id = "v2ray-plugin" }
pl.pluginsOptions.remove(pl.selected)
pl.selected = "v2ray-plugin"
// reslove v2ray plugin
}
if (pl.selected == "obfs") {
pl.pluginsOptions["obfs-local"] = pl.getOptions().apply { id = "obfs-local" }
pl.pluginsOptions.remove(pl.selected)
pl.selected = "obfs-local"
// reslove clash obfs
}
plugin = pl.toString()
}
override fun equals(other: Any?): Boolean {
return super.equals(other) || (other is Bean && hash == other.hash)
}
/*
init {
if (method !in methods) error("method $method not supported")
}
*/
val hash = (host + remotePort + password + method).hashCode()
val pluginInitResult by lazy {
PluginManager.init(PluginConfiguration(plugin ?: ""))
}
fun toJson(): JSONObject = JSONObject().apply {
put("server", host)
put("server_port", remotePort)
put("password", password)
put("method", method)
put("ipv6", true)
if (pluginInitResult != null) {
put("plugin", pluginInitResult!!.first)
put("plugin_opts", pluginInitResult!!.second.toString())
}
}
companion object {
fun parseJson(ssObj: JSONObject): Bean {
var pluginStr = ""
val pId = ssObj.optString("plugin")
if (!pId.isNullOrBlank()) {
val plugin = PluginOptions(pId, ssObj.optString("plugin_opts"))
pluginStr = plugin.toString(false)
}
return Bean(
ssObj.getString("server"),
ssObj.getInt("server_port"),
ssObj.getString("password"),
ssObj.getString("method"),
pluginStr,
ssObj.optString("remarks")
)
}
fun parse(url: String): Bean {
if (url.contains("@")) {
// ss-android style
val link = url.replace(SS_PROTOCOL, "https://").toHttpUrlOrNull()
?: error("invalid ss-android link $url")
if (link.password.isNotBlank()) {
return Bean(
link.host,
link.port,
link.password,
link.username,
link.queryParameter("plugin") ?: "",
link.fragment
)
}
val methodAndPswd = Base64.decodeStr(link.username)
return Bean(
link.host,
link.port,
methodAndPswd.substringAfter(":"),
methodAndPswd.substringBefore(":"),
link.queryParameter("plugin") ?: "",
link.fragment
)
} else {
// v2rayNG style
var v2Url = url
if (v2Url.contains("#")) v2Url = v2Url.substringBefore("#")
val link = ("https://" + Base64.decodeStr(v2Url.substringAfter(SS_PROTOCOL))).toHttpUrlOrNull()
?: error("invalid v2rayNG link $url")
return Bean(
link.host,
link.port,
link.password,
link.username,
"",
link.fragment
)
}
}
}
override fun toString(): String {
val url = HttpUrl.Builder()
.scheme("https")
.encodedUsername(Base64.encodeUrlSafe("$method:$password"))
.host(host)
.port(remotePort)
if (!remarks.isNullOrBlank()) url.fragment(remarks)
if (plugin.isNotBlank()) url.addQueryParameter("plugin", plugin)
return url.build().toString().replace("https://", "ss://")
}
}
companion object {
val methods = arrayOf(
"none",
"rc4-md5",
"aes-128-cfb",
"aes-192-cfb",
"aes-256-cfb",
"aes-128-ctr",
"aes-192-ctr",
"aes-256-ctr",
"bf-cfb",
"camellia-128-cfb",
"camellia-192-cfb",
"camellia-256-cfb",
"salsa20",
"chacha20",
"chacha20-ietf",
"aes-128-gcm",
"aes-192-gcm",
"aes-256-gcm",
"chacha20-ietf-poly1305",
"xchacha20-ietf-poly1305"
)
}
}

View File

@ -1,242 +0,0 @@
package tw.nekomimi.nekogram.proxy
import cn.hutool.core.codec.Base64
import com.v2ray.ang.V2RayConfig.SSR_PROTOCOL
import kotlinx.coroutines.runBlocking
import okhttp3.HttpUrl.Companion.toHttpUrl
import org.json.JSONObject
import org.telegram.messenger.ApplicationLoader
import org.telegram.messenger.FileLog
import tw.nekomimi.nekogram.utils.FileUtil
import java.io.File
import java.util.*
import kotlin.concurrent.thread
import kotlin.properties.Delegates
class ShadowsocksRLoader {
lateinit var bean: Bean
var port by Delegates.notNull<Int>()
var shadowsocksProcess: GuardedProcessPool? = null
fun initConfig(bean: Bean, port: Int) {
this.bean = bean
this.port = port
}
fun start() {
stop()
val cacheCfg = File(ApplicationLoader.applicationContext.cacheDir, "ssr_cfg_${bean.hash}.json")
cacheCfg.writeText(bean.toJson().toString())
shadowsocksProcess = GuardedProcessPool {
FileLog.e(it)
}.apply {
runCatching {
start(listOf(FileUtil.extLib("ssr-local").path,
"-b", "127.0.0.1",
"--host", bean.host,
"-t", "600",
"-c", cacheCfg.path,
"-l", port.toString())) {
cacheCfg.delete()
}
}.onFailure {
cacheCfg.delete()
FileLog.e(it)
}
}
}
fun stop() {
if (shadowsocksProcess != null) {
val proc = shadowsocksProcess!!
thread {
runCatching {
runBlocking { proc.close(this) }
}
}
shadowsocksProcess = null
}
}
data class Bean(
var host: String = "",
var remotePort: Int = 443,
var password: String = "",
var protocol: String = "origin",
var protocol_param: String = "",
var obfs: String = "plain",
var obfs_param: String = "",
var method: String = "aes-256-cfb",
var remarks: String? = null
) {
val hash get() = (host + remotePort + password + protocol + obfs + method).hashCode()
override fun equals(other: Any?): Boolean {
return super.equals(other) || (other is Bean && hash == other.hash)
}
/*
init {
if (method !in methods) error("method $method not supported")
if (protocol !in protocols) error("protocol $protocol not supported")
if (obfs !in obfses) error("obfs $obfs not supported")
}
*/
fun toJson(): JSONObject = JSONObject().apply {
put("server", host)
put("server_port", remotePort)
put("password", password)
put("method", method)
put("protocol", protocol)
put("protocol_param", protocol_param)
put("obfs", obfs)
put("obfs_param", obfs_param)
put("remarks", remarks)
put("route", "all")
put("remote_dns", "8.8.8.8:53")
put("ipv6", true)
put("metered", false)
put("proxy_apps", JSONObject().apply {
put("enabled", false)
})
put("udpdns", false)
}
companion object {
fun parse(url: String): Bean {
val params = Base64.decodeStr(url.substringAfter(SSR_PROTOCOL)).split(":")
val bean = Bean(params[0],
params[1].toInt(),
protocol = params[2],
method = params[3],
obfs = params[4],
password = Base64.decodeStr(params[5].substringBefore("/")))
val httpUrl = ("https://localhost" + params[5].substringAfter("/")).toHttpUrl()
runCatching {
bean.obfs_param = Base64.decodeStr(httpUrl.queryParameter("obfsparam")!!)
}
runCatching {
bean.protocol_param = Base64.decodeStr(httpUrl.queryParameter("protoparam")!!)
}
runCatching {
val remarks = httpUrl.queryParameter("remarks")
if (remarks?.isNotBlank() == true) {
bean.remarks = Base64.decodeStr(remarks)
}
}
return bean
}
}
override fun toString(): String {
return "ssr://" + Base64.encodeUrlSafe("%s:%d:%s:%s:%s:%s/?obfsparam=%s&protoparam=%s&remarks=%s".format(Locale.ENGLISH, host, remotePort, protocol, method, obfs,
Base64.encodeUrlSafe("%s".format(Locale.ENGLISH, password)),
Base64.encodeUrlSafe("%s".format(Locale.ENGLISH, obfs_param)),
Base64.encodeUrlSafe("%s".format(Locale.ENGLISH, protocol_param)),
Base64.encodeUrlSafe("%s".format(Locale.ENGLISH, remarks ?: ""))))
}
}
companion object {
val methods = arrayOf(
"none",
"table",
"rc4",
"rc4-md5",
"rc4-md5-6",
"aes-128-cfb",
"aes-192-cfb",
"aes-256-cfb",
"aes-128-ctr",
"aes-192-ctr",
"aes-256-ctr",
"bf-cfb",
"camellia-128-cfb",
"camellia-192-cfb",
"camellia-256-cfb",
"salsa20",
"chacha20",
"chacha20-ietf"
)
val protocols = arrayOf(
"origin",
"verify_simple",
"verify_sha1",
"auth_sha1",
"auth_sha1_v2",
"auth_sha1_v4",
"auth_aes128_sha1",
"auth_aes128_md5",
"auth_chain_a",
"auth_chain_b"
)
val obfses = arrayOf(
"plain",
"http_simple",
"http_post",
"tls_simple",
"tls1.2_ticket_auth"
)
}
}

View File

@ -1,469 +0,0 @@
/*
* This is the source code of Telegram for Android v. 5.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2018.
*/
package tw.nekomimi.nekogram.proxy;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.os.Build;
import android.text.InputType;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.R;
import org.telegram.messenger.SharedConfig;
import org.telegram.messenger.Utilities;
import org.telegram.ui.ActionBar.ActionBar;
import org.telegram.ui.ActionBar.ActionBarMenuItem;
import org.telegram.ui.ActionBar.BaseFragment;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.ActionBar.ThemeDescription;
import org.telegram.ui.Cells.TextInfoPrivacyCell;
import org.telegram.ui.Cells.TextSettingsCell;
import org.telegram.ui.Components.EditTextBoldCursor;
import org.telegram.ui.Components.LayoutHelper;
import java.util.ArrayList;
import cn.hutool.core.util.StrUtil;
import kotlin.Unit;
import tw.nekomimi.nekogram.ui.PopupBuilder;
public class ShadowsocksRSettingsActivity extends BaseFragment {
private EditTextBoldCursor[] inputFields;
private EditTextBoldCursor ipField;
private EditTextBoldCursor portField;
private EditTextBoldCursor passwordField;
private TextSettingsCell methodField;
private TextSettingsCell protocolField;
private EditTextBoldCursor protocolParamField;
private TextSettingsCell obfsField;
private EditTextBoldCursor obfsParamField;
private EditTextBoldCursor remarksField;
private ScrollView scrollView;
private LinearLayout linearLayout2;
private LinearLayout inputFieldsContainer;
private TextInfoPrivacyCell bottomCell;
private SharedConfig.ShadowsocksRProxy currentProxyInfo;
private ShadowsocksRLoader.Bean currentBean;
private boolean ignoreOnTextChange;
private static final int done_button = 1;
public class TypeCell extends FrameLayout {
private TextView textView;
private ImageView checkImage;
private boolean needDivider;
public TypeCell(Context context) {
super(context);
setWillNotDraw(false);
textView = new TextView(context);
textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
textView.setLines(1);
textView.setMaxLines(1);
textView.setSingleLine(true);
textView.setEllipsize(TextUtils.TruncateAt.END);
textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL);
addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 23 + 48 : 21, 0, LocaleController.isRTL ? 21 : 23, 0));
checkImage = new ImageView(context);
checkImage.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_featuredStickers_addedIcon), PorterDuff.Mode.SRC_IN));
checkImage.setImageResource(R.drawable.sticker_added);
addView(checkImage, LayoutHelper.createFrame(19, 14, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL, 21, 0, 21, 0));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50) + (needDivider ? 1 : 0), MeasureSpec.EXACTLY));
}
public void setValue(String name, boolean checked, boolean divider) {
textView.setText(name);
checkImage.setVisibility(checked ? VISIBLE : INVISIBLE);
needDivider = divider;
}
public void setTypeChecked(boolean value) {
checkImage.setVisibility(value ? VISIBLE : INVISIBLE);
}
@Override
protected void onDraw(Canvas canvas) {
if (needDivider) {
canvas.drawLine(0, getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight() - 1, Theme.dividerPaint);
}
}
}
public ShadowsocksRSettingsActivity() {
super();
currentBean = new ShadowsocksRLoader.Bean();
}
public ShadowsocksRSettingsActivity(SharedConfig.ShadowsocksRProxy proxyInfo) {
super();
currentProxyInfo = proxyInfo;
currentBean = proxyInfo.bean;
}
@Override
public void onResume() {
super.onResume();
AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid);
}
@Override
public View createView(Context context) {
actionBar.setTitle(LocaleController.getString("ProxyDetails", R.string.ProxyDetails));
actionBar.setBackButtonImage(R.drawable.ic_ab_back);
actionBar.setAllowOverlayTitle(false);
if (AndroidUtilities.isTablet()) {
actionBar.setOccupyStatusBar(false);
}
actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() {
@Override
public void onItemClick(int id) {
if (id == -1) {
finishFragment();
} else if (id == done_button) {
if (getParentActivity() == null) {
return;
}
if (StrUtil.isBlank(ipField.getText())) {
ipField.requestFocus();
AndroidUtilities.showKeyboard(ipField);
return;
}
if (StrUtil.isBlank(portField.getText())) {
portField.requestFocus();
AndroidUtilities.showKeyboard(portField);
return;
}
if (StrUtil.isBlank(passwordField.getText())) {
passwordField.requestFocus();
AndroidUtilities.showKeyboard(passwordField);
return;
}
currentBean.setHost(ipField.getText().toString());
currentBean.setRemotePort(Utilities.parseInt(portField.getText().toString()));
currentBean.setPassword(passwordField.getText().toString());
currentBean.setMethod(methodField.getValueTextView().getText().toString());
currentBean.setProtocol(protocolField.getValueTextView().getText().toString());
currentBean.setProtocol_param(protocolParamField.getText().toString());
currentBean.setObfs(obfsField.getValueTextView().getText().toString());
currentBean.setObfs_param(obfsParamField.getText().toString());
currentBean.setRemarks(remarksField.getText().toString());
if (currentProxyInfo == null) {
currentProxyInfo = new SharedConfig.ShadowsocksRProxy(currentBean);
SharedConfig.addProxy(currentProxyInfo);
SharedConfig.setCurrentProxy(currentProxyInfo);
} else {
currentProxyInfo.proxyCheckPingId = 0;
currentProxyInfo.availableCheckTime = 0;
currentProxyInfo.ping = 0;
SharedConfig.saveProxyList();
SharedConfig.setProxyEnable(false);
}
finishFragment();
}
}
});
ActionBarMenuItem doneItem = actionBar.createMenu().addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56));
doneItem.setContentDescription(LocaleController.getString("Done", R.string.Done));
fragmentView = new FrameLayout(context);
FrameLayout frameLayout = (FrameLayout) fragmentView;
fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray));
scrollView = new ScrollView(context);
scrollView.setFillViewport(true);
AndroidUtilities.setScrollViewEdgeEffectColor(scrollView, Theme.getColor(Theme.key_actionBarDefault));
frameLayout.addView(scrollView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
linearLayout2 = new LinearLayout(context);
linearLayout2.setOrientation(LinearLayout.VERTICAL);
scrollView.addView(linearLayout2, new ScrollView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
inputFieldsContainer = new LinearLayout(context);
inputFieldsContainer.setOrientation(LinearLayout.VERTICAL);
inputFieldsContainer.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// bring to front for transitions
inputFieldsContainer.setElevation(AndroidUtilities.dp(1f));
inputFieldsContainer.setOutlineProvider(null);
}
linearLayout2.addView(inputFieldsContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
inputFields = new EditTextBoldCursor[6];
for (int a = 0; a < 6; a++) {
FrameLayout container = new FrameLayout(context);
EditTextBoldCursor cursor = mkCursor();
inputFields[a] = cursor;
cursor.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI);
switch (a) {
case 0:
ipField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("UseProxyAddress", R.string.UseProxyAddress));
cursor.setText(currentBean.getHost());
break;
case 1:
portField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_NUMBER);
cursor.setHintText(LocaleController.getString("UseProxyPort", R.string.UseProxyPort));
cursor.setText("" + currentBean.getRemotePort());
break;
case 2:
passwordField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("UseProxyPassword", R.string.UseProxyPassword));
cursor.setText(currentBean.getPassword());
break;
case 3:
protocolParamField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("SSRProtocolParams", R.string.SSRProtocolParams));
cursor.setText(currentBean.getProtocol_param());
break;
case 4:
obfsParamField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("SSRObfsParam", R.string.SSRObfsParam));
cursor.setText(currentBean.getObfs_param());
break;
case 5:
remarksField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("ProxyRemarks", R.string.ProxyRemarks));
cursor.setText(currentBean.getRemarks());
break;
}
cursor.setSelection(cursor.length());
cursor.setPadding(0, 0, 0, 0);
container.addView(cursor, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 17, a == 0 ? 12 : 0, 17, 0));
}
inputFieldsContainer.addView((View) ipField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
inputFieldsContainer.addView((View) portField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
inputFieldsContainer.addView((View) passwordField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
FrameLayout container = new FrameLayout(context);
methodField = new TextSettingsCell(context);
methodField.setBackground(Theme.getSelectorDrawable(false));
methodField.setTextAndValue(LocaleController.getString("SSMethod", R.string.SSMethod), currentBean.getMethod(), false);
container.addView(methodField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 0));
methodField.setOnClickListener((v) -> {
PopupBuilder select = new PopupBuilder(v);
select.setItems(ShadowsocksRLoader.Companion.getMethods(), (__,value) -> {
methodField.getValueTextView().setText(value);
return Unit.INSTANCE;
});
select.show();
});
inputFieldsContainer.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
container = new FrameLayout(context);
protocolField = new TextSettingsCell(context);
protocolField.setBackground(Theme.getSelectorDrawable(false));
protocolField.setTextAndValue(LocaleController.getString("SSRProtocol", R.string.SSRProtocol), currentBean.getProtocol(), false);
container.addView(protocolField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 0));
protocolField.setOnClickListener((v) -> {
PopupBuilder select = new PopupBuilder(v);
select.setItems(ShadowsocksRLoader.Companion.getProtocols(), (__,value) -> {
protocolField.getValueTextView().setText(value);
return Unit.INSTANCE;
});
select.show();
});
inputFieldsContainer.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
inputFieldsContainer.addView((View) protocolParamField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
container = new FrameLayout(context);
obfsField = new TextSettingsCell(context);
obfsField.setBackground(Theme.getSelectorDrawable(false));
obfsField.setTextAndValue(LocaleController.getString("SSRObfs", R.string.SSRObfs), currentBean.getObfs(), false);
container.addView(obfsField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 0));
obfsField.setOnClickListener((v) -> {
PopupBuilder select = new PopupBuilder(v);
select.setItems(ShadowsocksRLoader.Companion.getObfses(), (__,value) -> {
obfsField.getValueTextView().setText(value);
return Unit.INSTANCE;
});
select.show();
});
inputFieldsContainer.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
inputFieldsContainer.addView((View) obfsParamField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
inputFieldsContainer.addView((View) remarksField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
bottomCell = new TextInfoPrivacyCell(context);
bottomCell.setBackground(Theme.getThemedDrawable(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow));
bottomCell.setText(LocaleController.getString("ProxyInfoSSR", R.string.ProxyInfoSSR));
linearLayout2.addView(bottomCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
return fragmentView;
}
EditTextBoldCursor mkCursor() {
EditTextBoldCursor cursor = new EditTextBoldCursor(getParentActivity());
cursor.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
cursor.setHintColor(Theme.getColor(Theme.key_windowBackgroundWhiteHintText));
cursor.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
cursor.setBackground(null);
cursor.setCursorColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
cursor.setCursorSize(AndroidUtilities.dp(20));
cursor.setCursorWidth(1.5f);
cursor.setSingleLine(true);
cursor.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL);
cursor.setHeaderHintColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueHeader));
cursor.setTransformHintToHeader(true);
cursor.setLineColors(Theme.getColor(Theme.key_windowBackgroundWhiteInputField), Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated), Theme.getColor(Theme.key_windowBackgroundWhiteRedText3));
return cursor;
}
@Override
public void onTransitionAnimationEnd(boolean isOpen, boolean backward) {
if (isOpen && !backward && currentProxyInfo == null) {
ipField.requestFocus();
AndroidUtilities.showKeyboard(ipField);
}
}
@Override
public ArrayList<ThemeDescription> getThemeDescriptions() {
final ThemeDescription.ThemeDescriptionDelegate delegate = () -> {
if (inputFields != null) {
for (int i = 0; i < inputFields.length; i++) {
inputFields[i].setLineColors(Theme.getColor(Theme.key_windowBackgroundWhiteInputField),
Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated),
Theme.getColor(Theme.key_windowBackgroundWhiteRedText3));
}
}
};
ArrayList<ThemeDescription> arrayList = new ArrayList<>();
arrayList.add(new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundGray));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_actionBarDefault));
arrayList.add(new ThemeDescription(scrollView, ThemeDescription.FLAG_LISTGLOWCOLOR, null, null, null, null, Theme.key_actionBarDefault));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_ITEMSCOLOR, null, null, null, null, Theme.key_actionBarDefaultIcon));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_TITLECOLOR, null, null, null, null, Theme.key_actionBarDefaultTitle));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SELECTORCOLOR, null, null, null, null, Theme.key_actionBarDefaultSelector));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SEARCH, null, null, null, null, Theme.key_actionBarDefaultSearch));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SEARCHPLACEHOLDER, null, null, null, null, Theme.key_actionBarDefaultSearchPlaceholder));
arrayList.add(new ThemeDescription(inputFieldsContainer, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundWhite));
arrayList.add(new ThemeDescription(linearLayout2, 0, new Class[]{View.class}, Theme.dividerPaint, null, null, Theme.key_divider));
arrayList.add(new ThemeDescription(null, 0, null, null, null, null, delegate, Theme.key_windowBackgroundWhiteBlueText4));
arrayList.add(new ThemeDescription(null, 0, null, null, null, null, delegate, Theme.key_windowBackgroundWhiteGrayText2));
if (inputFields != null) {
for (int a = 0; a < inputFields.length; a++) {
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_HINTTEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteHintText));
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_HINTTEXTCOLOR | ThemeDescription.FLAG_PROGRESSBAR, null, null, null, null, Theme.key_windowBackgroundWhiteBlueHeader));
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_CURSORCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(null, 0, null, null, null, delegate, Theme.key_windowBackgroundWhiteInputField));
arrayList.add(new ThemeDescription(null, 0, null, null, null, delegate, Theme.key_windowBackgroundWhiteInputFieldActivated));
arrayList.add(new ThemeDescription(null, 0, null, null, null, delegate, Theme.key_windowBackgroundWhiteRedText3));
}
} else {
arrayList.add(new ThemeDescription(null, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(null, ThemeDescription.FLAG_HINTTEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteHintText));
}
arrayList.add(new ThemeDescription(bottomCell, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{TextInfoPrivacyCell.class}, null, null, null, Theme.key_windowBackgroundGrayShadow));
arrayList.add(new ThemeDescription(bottomCell, 0, new Class[]{TextInfoPrivacyCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText4));
arrayList.add(new ThemeDescription(bottomCell, ThemeDescription.FLAG_LINKCOLOR, new Class[]{TextInfoPrivacyCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteLinkText));
return arrayList;
}
}

View File

@ -1,569 +0,0 @@
/*
* This is the source code of Telegram for Android v. 5.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2018.
*/
package tw.nekomimi.nekogram.proxy;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.os.Build;
import android.text.InputType;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import androidx.annotation.RequiresApi;
import com.github.shadowsocks.plugin.PluginConfiguration;
import com.github.shadowsocks.plugin.PluginContract;
import com.github.shadowsocks.plugin.PluginList;
import com.github.shadowsocks.plugin.PluginManager;
import com.github.shadowsocks.plugin.PluginOptions;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.R;
import org.telegram.messenger.SharedConfig;
import org.telegram.messenger.Utilities;
import org.telegram.ui.ActionBar.ActionBar;
import org.telegram.ui.ActionBar.ActionBarMenuItem;
import org.telegram.ui.ActionBar.BaseFragment;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.ActionBar.ThemeDescription;
import org.telegram.ui.Cells.TextInfoPrivacyCell;
import org.telegram.ui.Cells.TextSettingsCell;
import org.telegram.ui.Components.EditTextBoldCursor;
import org.telegram.ui.Components.LayoutHelper;
import java.util.ArrayList;
import cn.hutool.core.util.StrUtil;
import kotlin.Unit;
import tw.nekomimi.nekogram.ui.BottomBuilder;
import tw.nekomimi.nekogram.ui.PopupBuilder;
import tw.nekomimi.nekogram.utils.AlertUtil;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class ShadowsocksSettingsActivity extends BaseFragment {
private EditTextBoldCursor[] inputFields;
private EditTextBoldCursor ipField;
private EditTextBoldCursor portField;
private EditTextBoldCursor passwordField;
private TextSettingsCell methodField;
private TextSettingsCell pluginField;
private TextSettingsCell pluginOptsField;
private EditTextBoldCursor remarksField;
private ScrollView scrollView;
private LinearLayout linearLayout2;
private LinearLayout inputFieldsContainer;
private TextInfoPrivacyCell bottomCell;
private SharedConfig.ShadowsocksProxy currentProxyInfo;
private ShadowsocksLoader.Bean currentBean;
private PluginConfiguration plugin;
private boolean ignoreOnTextChange;
private static final int done_button = 1;
public class TypeCell extends FrameLayout {
private TextView textView;
private ImageView checkImage;
private boolean needDivider;
public TypeCell(Context context) {
super(context);
setWillNotDraw(false);
textView = new TextView(context);
textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
textView.setLines(1);
textView.setMaxLines(1);
textView.setSingleLine(true);
textView.setEllipsize(TextUtils.TruncateAt.END);
textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL);
addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 23 + 48 : 21, 0, LocaleController.isRTL ? 21 : 23, 0));
checkImage = new ImageView(context);
checkImage.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_featuredStickers_addedIcon), PorterDuff.Mode.SRC_IN));
checkImage.setImageResource(R.drawable.sticker_added);
addView(checkImage, LayoutHelper.createFrame(19, 14, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL, 21, 0, 21, 0));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50) + (needDivider ? 1 : 0), MeasureSpec.EXACTLY));
}
public void setValue(String name, boolean checked, boolean divider) {
textView.setText(name);
checkImage.setVisibility(checked ? VISIBLE : INVISIBLE);
needDivider = divider;
}
public void setTypeChecked(boolean value) {
checkImage.setVisibility(value ? VISIBLE : INVISIBLE);
}
@Override
protected void onDraw(Canvas canvas) {
if (needDivider) {
canvas.drawLine(0, getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight() - 1, Theme.dividerPaint);
}
}
}
public ShadowsocksSettingsActivity() {
super();
currentBean = new ShadowsocksLoader.Bean();
plugin = new PluginConfiguration("");
}
public ShadowsocksSettingsActivity(SharedConfig.ShadowsocksProxy proxyInfo) {
super();
currentProxyInfo = proxyInfo;
currentBean = proxyInfo.bean;
plugin = new PluginConfiguration(currentBean.getPlugin());
}
@Override
public void onResume() {
super.onResume();
AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid);
}
@Override
public View createView(Context context) {
actionBar.setTitle(LocaleController.getString("ProxyDetails", R.string.ProxyDetails));
actionBar.setBackButtonImage(R.drawable.ic_ab_back);
actionBar.setAllowOverlayTitle(false);
if (AndroidUtilities.isTablet()) {
actionBar.setOccupyStatusBar(false);
}
actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() {
@Override
public void onItemClick(int id) {
if (id == -1) {
finishFragment();
} else if (id == done_button) {
if (getParentActivity() == null) {
return;
}
if (StrUtil.isBlank(ipField.getText())) {
ipField.requestFocus();
AndroidUtilities.showKeyboard(ipField);
return;
}
if (StrUtil.isBlank(portField.getText())) {
portField.requestFocus();
AndroidUtilities.showKeyboard(portField);
return;
}
if (StrUtil.isBlank(passwordField.getText()) && !"plain".equals(methodField.getTextView().getText().toString().toLowerCase())) {
passwordField.requestFocus();
AndroidUtilities.showKeyboard(passwordField);
return;
}
currentBean.setHost(ipField.getText().toString());
currentBean.setRemotePort(Utilities.parseInt(portField.getText().toString()));
currentBean.setPassword(passwordField.getText().toString());
currentBean.setMethod(methodField.getValueTextView().getText().toString());
currentBean.setPlugin(plugin.toString());
currentBean.setRemarks(remarksField.getText().toString());
if (currentProxyInfo == null) {
currentProxyInfo = new SharedConfig.ShadowsocksProxy(currentBean);
SharedConfig.addProxy(currentProxyInfo);
SharedConfig.setCurrentProxy(currentProxyInfo);
} else {
currentProxyInfo.proxyCheckPingId = 0;
currentProxyInfo.availableCheckTime = 0;
currentProxyInfo.ping = 0;
SharedConfig.saveProxyList();
SharedConfig.setProxyEnable(false);
}
finishFragment();
}
}
});
ActionBarMenuItem doneItem = actionBar.createMenu().addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56));
doneItem.setContentDescription(LocaleController.getString("Done", R.string.Done));
fragmentView = new FrameLayout(context);
FrameLayout frameLayout = (FrameLayout) fragmentView;
fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray));
scrollView = new ScrollView(context);
scrollView.setFillViewport(true);
AndroidUtilities.setScrollViewEdgeEffectColor(scrollView, Theme.getColor(Theme.key_actionBarDefault));
frameLayout.addView(scrollView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
linearLayout2 = new LinearLayout(context);
linearLayout2.setOrientation(LinearLayout.VERTICAL);
scrollView.addView(linearLayout2, new ScrollView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
inputFieldsContainer = new LinearLayout(context);
inputFieldsContainer.setOrientation(LinearLayout.VERTICAL);
inputFieldsContainer.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// bring to front for transitions
inputFieldsContainer.setElevation(AndroidUtilities.dp(1f));
inputFieldsContainer.setOutlineProvider(null);
}
linearLayout2.addView(inputFieldsContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
inputFields = new EditTextBoldCursor[4];
for (int a = 0; a < 4; a++) {
FrameLayout container = new FrameLayout(context);
EditTextBoldCursor cursor = mkCursor();
inputFields[a] = cursor;
cursor.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI);
switch (a) {
case 0:
ipField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("UseProxyAddress", R.string.UseProxyAddress));
cursor.setText(currentBean.getHost());
break;
case 1:
portField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_NUMBER);
cursor.setHintText(LocaleController.getString("UseProxyPort", R.string.UseProxyPort));
cursor.setText("" + currentBean.getRemotePort());
break;
case 2:
passwordField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("UseProxyPassword", R.string.UseProxyPassword));
cursor.setText(currentBean.getPassword());
break;
case 3:
remarksField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("ProxyRemarks", R.string.ProxyRemarks));
cursor.setText(currentBean.getRemarks());
break;
}
cursor.setSelection(cursor.length());
cursor.setPadding(0, 0, 0, 0);
container.addView(cursor, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 17, a == 0 ? 12 : 0, 17, 0));
}
inputFieldsContainer.addView((View) ipField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
inputFieldsContainer.addView((View) portField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
inputFieldsContainer.addView((View) passwordField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
FrameLayout container = new FrameLayout(context);
methodField = new TextSettingsCell(context);
methodField.setBackground(Theme.getSelectorDrawable(false));
methodField.setTextAndValue(LocaleController.getString("SSMethod", R.string.SSMethod), currentBean.getMethod(), false);
container.addView(methodField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 0));
inputFieldsContainer.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
methodField.setOnClickListener((v) -> {
PopupBuilder select = new PopupBuilder(v);
select.setItems(ShadowsocksLoader.Companion.getMethods(), (__, value) -> {
methodField.getValueTextView().setText(value);
return Unit.INSTANCE;
});
select.show();
});
container = new FrameLayout(context);
pluginField = new TextSettingsCell(context);
pluginField.setBackground(Theme.getSelectorDrawable(false));
pluginField.setTextAndValue(LocaleController.getString("SSPlugin", R.string.SSPlugin), plugin.getSelectedName(), false);
container.addView(pluginField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 0));
inputFieldsContainer.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
pluginField.setOnClickListener((v) -> {
PluginList plugins = PluginManager.fetchPlugins();
PopupBuilder select = new PopupBuilder(v);
try {
select.setItems(plugins.getLookupNames(), (index, __) -> {
String pluginId = plugins.get(index).getId();
plugin.setSelected(pluginId);
((View) pluginOptsField.getParent()).setVisibility(StrUtil.isBlank(pluginId) ? View.GONE : View.VISIBLE);
pluginField.getValueTextView().setText(plugin.getSelectedName());
pluginOptsField.getValueTextView().setText(plugin.getOptions(pluginId).toString());
return Unit.INSTANCE;
});
select.show();
} catch (Exception e) {
AlertUtil.showSimpleAlert(getParentActivity(),e.getMessage());
}
});
container = new FrameLayout(context);
pluginOptsField = new TextSettingsCell(context);
pluginOptsField.setBackground(Theme.getSelectorDrawable(false));
pluginOptsField.setTextAndValue(LocaleController.getString("SSPluginOpts", R.string.SSPluginOpts), plugin.getOptions().toString(), false);
container.addView(pluginOptsField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 0));
inputFieldsContainer.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
pluginOptsField.setOnClickListener((v) -> {
Intent intent = PluginManager.buildIntent(plugin.getSelected(), PluginContract.ACTION_CONFIGURE);
intent.putExtra(PluginContract.EXTRA_OPTIONS, plugin.getOptions().toString());
if (intent.resolveActivity(getParentActivity().getPackageManager()) == null) {
showPluginEditor();
} else {
startActivityForResult(intent, 1919);
}
});
((View) pluginOptsField.getParent()).setVisibility(StrUtil.isBlank(plugin.getSelected()) ? View.GONE : View.VISIBLE);
inputFieldsContainer.addView((View) remarksField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
bottomCell = new TextInfoPrivacyCell(context);
bottomCell.setBackground(Theme.getThemedDrawable(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow));
bottomCell.setText(LocaleController.getString("ProxyInfoSS", R.string.ProxyInfoSS));
linearLayout2.addView(bottomCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
return fragmentView;
}
@Override public void onActivityResultFragment(int requestCode, int resultCode, Intent data) {
if (requestCode == 1919) {
if (resultCode == Activity.RESULT_OK) {
String options = data.getStringExtra(PluginContract.EXTRA_OPTIONS);
if (options != null) {
onPreferenceChange(options);
}
} else if (resultCode == PluginContract.RESULT_FALLBACK) {
showPluginEditor();
}
} else if (requestCode == 810) {
if (resultCode == Activity.RESULT_OK) {
CharSequence helpMessage = data.getCharSequenceExtra(PluginContract.EXTRA_HELP_MESSAGE);
if (StrUtil.isBlank(helpMessage)) {
helpMessage = "No Help :(";
}
AlertUtil.showSimpleAlert(getParentActivity(),LocaleController.getString("BotHelp",R.string.BotHelp),helpMessage.toString());
} else {
AlertUtil.showSimpleAlert(getParentActivity(),"Get Help Message Error :(");
}
}
}
private void showPluginEditor() {
BottomBuilder builder = new BottomBuilder(getParentActivity());
builder.addTitle(LocaleController.getString("SSPluginOpts", R.string.SSPluginOpts));
EditText options = builder.addEditText();
options.setSingleLine(false);
options.setGravity(Gravity.TOP | LocaleController.generateFlagStart());
options.setMinLines(3);
options.setText(plugin.getOptions().toString());
Intent intent = PluginManager.buildIntent(plugin.getSelected(), PluginContract.ACTION_HELP);
intent.putExtra(PluginContract.EXTRA_OPTIONS, plugin.getOptions().toString());
if (intent.resolveActivity(getParentActivity().getPackageManager()) != null) {
builder.addButton(LocaleController.getString("BotHelp", R.string.BotHelp), false,true, (it) -> {
getParentActivity().startActivityForResult(intent, 810);
return Unit.INSTANCE;
});
builder.addCancelButton(false);
} else {
builder.addCancelButton();
}
builder.addOkButton((it) -> {
onPreferenceChange(options.getText().toString());
return Unit.INSTANCE;
});
builder.show();
}
private void onPreferenceChange(String newValue) {
String selected = plugin.getSelected();
plugin.getPluginsOptions().put(selected, new PluginOptions(selected, newValue));
pluginOptsField.getValueTextView().setText(newValue);
}
EditTextBoldCursor mkCursor() {
EditTextBoldCursor cursor = new EditTextBoldCursor(getParentActivity());
cursor.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
cursor.setHintColor(Theme.getColor(Theme.key_windowBackgroundWhiteHintText));
cursor.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
cursor.setBackground(null);
cursor.setCursorColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
cursor.setCursorSize(AndroidUtilities.dp(20));
cursor.setCursorWidth(1.5f);
cursor.setSingleLine(true);
cursor.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL);
cursor.setHeaderHintColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueHeader));
cursor.setTransformHintToHeader(true);
cursor.setLineColors(Theme.getColor(Theme.key_windowBackgroundWhiteInputField), Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated), Theme.getColor(Theme.key_windowBackgroundWhiteRedText3));
return cursor;
}
@Override
public void onTransitionAnimationEnd(boolean isOpen, boolean backward) {
if (isOpen && !backward && currentProxyInfo == null) {
ipField.requestFocus();
AndroidUtilities.showKeyboard(ipField);
}
}
@Override
public ArrayList<ThemeDescription> getThemeDescriptions() {
final ThemeDescription.ThemeDescriptionDelegate delegate = () -> {
if (inputFields != null) {
for (int i = 0; i < inputFields.length; i++) {
inputFields[i].setLineColors(Theme.getColor(Theme.key_windowBackgroundWhiteInputField),
Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated),
Theme.getColor(Theme.key_windowBackgroundWhiteRedText3));
}
}
};
ArrayList<ThemeDescription> arrayList = new ArrayList<>();
arrayList.add(new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundGray));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_actionBarDefault));
arrayList.add(new ThemeDescription(scrollView, ThemeDescription.FLAG_LISTGLOWCOLOR, null, null, null, null, Theme.key_actionBarDefault));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_ITEMSCOLOR, null, null, null, null, Theme.key_actionBarDefaultIcon));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_TITLECOLOR, null, null, null, null, Theme.key_actionBarDefaultTitle));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SELECTORCOLOR, null, null, null, null, Theme.key_actionBarDefaultSelector));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SEARCH, null, null, null, null, Theme.key_actionBarDefaultSearch));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SEARCHPLACEHOLDER, null, null, null, null, Theme.key_actionBarDefaultSearchPlaceholder));
arrayList.add(new ThemeDescription(inputFieldsContainer, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundWhite));
arrayList.add(new ThemeDescription(linearLayout2, 0, new Class[]{View.class}, Theme.dividerPaint, null, null, Theme.key_divider));
arrayList.add(new ThemeDescription(null, 0, null, null, null, null, delegate, Theme.key_windowBackgroundWhiteBlueText4));
arrayList.add(new ThemeDescription(null, 0, null, null, null, null, delegate, Theme.key_windowBackgroundWhiteGrayText2));
if (inputFields != null) {
for (int a = 0; a < inputFields.length; a++) {
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_HINTTEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteHintText));
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_HINTTEXTCOLOR | ThemeDescription.FLAG_PROGRESSBAR, null, null, null, null, Theme.key_windowBackgroundWhiteBlueHeader));
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_CURSORCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(null, 0, null, null, null, delegate, Theme.key_windowBackgroundWhiteInputField));
arrayList.add(new ThemeDescription(null, 0, null, null, null, delegate, Theme.key_windowBackgroundWhiteInputFieldActivated));
arrayList.add(new ThemeDescription(null, 0, null, null, null, delegate, Theme.key_windowBackgroundWhiteRedText3));
}
} else {
arrayList.add(new ThemeDescription(null, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(null, ThemeDescription.FLAG_HINTTEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteHintText));
}
arrayList.add(new ThemeDescription(bottomCell, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{TextInfoPrivacyCell.class}, null, null, null, Theme.key_windowBackgroundGrayShadow));
arrayList.add(new ThemeDescription(bottomCell, 0, new Class[]{TextInfoPrivacyCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText4));
arrayList.add(new ThemeDescription(bottomCell, ThemeDescription.FLAG_LINKCOLOR, new Class[]{TextInfoPrivacyCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteLinkText));
return arrayList;
}
}

View File

@ -1,147 +0,0 @@
package tw.nekomimi.nekogram.proxy;
import androidx.annotation.NonNull;
import org.dizitart.no2.Document;
import org.dizitart.no2.mapper.Mappable;
import org.dizitart.no2.mapper.NitriteMapper;
import org.dizitart.no2.objects.Id;
import org.dizitart.no2.objects.Index;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.R;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import cn.hutool.core.util.StrUtil;
import tw.nekomimi.nekogram.NekoConfig;
import tw.nekomimi.nekogram.parts.ProxyLoadsKt;
@Index("id")
@SuppressWarnings("unchecked")
public class SubInfo implements Mappable {
@Id
public long id;
public String name;
public List<String> urls = new LinkedList<>();
public List<String> proxies = new LinkedList<>();
public Long lastFetch = -1L;
public boolean enable = true;
public boolean internal;
public String displayName() {
if (id == SubManager.publicProxySubID)
return LocaleController.getString("PublicPrefix", R.string.PublicPrefix);
if (name.length() < 10) return name;
return name.substring(0, 10) + "...";
}
public List<String> reloadProxies() throws IOException {
HashMap<String, Exception> exceptions = new HashMap<>();
try {
if (id == SubManager.publicProxySubID) {
if (!NekoConfig.enablePublicProxy.Bool())
return new ArrayList<>();
List<String> pubs = ProxyLoadsKt.loadProxiesPublic(urls, exceptions);
if (!NekoConfig.enablePublicProxy.Bool())
return new ArrayList<>();
else
return pubs;
} else {
return ProxyLoadsKt.loadProxies(urls, exceptions);
}
// return id == SubManager.publicProxySubID ? :
} catch (Exception ignored) {
}
throw new AllTriesFailed(exceptions);
}
public static class AllTriesFailed extends IOException {
public AllTriesFailed(HashMap<String, Exception> exceptions) {
this.exceptions = exceptions;
}
public HashMap<String, Exception> exceptions;
@NonNull
@Override
public String toString() {
StringBuilder errors = new StringBuilder();
for (Map.Entry<String, Exception> e : exceptions.entrySet()) {
errors.append(e.getKey()).append(": ");
errors.append(e.getValue().getClass().getSimpleName());
if (!StrUtil.isBlank(e.getValue().getMessage())) {
errors.append(" ( ");
errors.append(e.getValue().getMessage());
errors.append(" )");
}
errors.append("\n\n");
}
return errors.toString();
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SubInfo subInfo = (SubInfo) o;
return id == subInfo.id;
}
@Override
public Document write(NitriteMapper mapper) {
Document document = new Document();
document.put("id", id);
document.put("name", name);
document.put("urls", urls);
document.put("proxies", proxies);
document.put("lastFetch", lastFetch);
document.put("enable", enable);
document.put("internal", internal);
return document;
}
@Override
public void read(NitriteMapper mapper, Document document) {
id = document.get("id", Long.class);
name = document.get("name", String.class);
urls = (List<String>) document.get("urls");
proxies = (List<String>) document.get("proxies");
lastFetch = document.get("lastFetch", Long.class);
enable = document.get("enable", Boolean.class);
internal = document.get("internal", Boolean.class);
}
}

View File

@ -1,48 +0,0 @@
package tw.nekomimi.nekogram.proxy
import org.dizitart.no2.objects.filters.ObjectFilters
import org.telegram.messenger.LocaleController
import org.telegram.messenger.R
import tw.nekomimi.nekogram.database.mkDatabase
object SubManager {
val database by lazy { mkDatabase("proxy_sub") }
const val publicProxySubID = 1L
@JvmStatic
val count
get() = subList.find().totalCount()
@JvmStatic
val subList by lazy {
database.getRepository("proxy_sub", SubInfo::class.java).apply {
val public = find(ObjectFilters.eq("id", publicProxySubID)).firstOrDefault()
update(SubInfo().apply {
// SubManager.kt -> SubInfo.java -> ProxyLoads.kt
name = LocaleController.getString("NekoXProxy", R.string.NekoXProxy)
enable = public?.enable ?: true
urls = listOf(
"https://nekox.pages.dev/proxy_list_pro", // Note: NO DoH apply to here and neko.services now.
"https://github.com/NekoX-Dev/ProxyList/blob/master/proxy_list_pro@js-file-line\">@<",
"https://api.github.com/repos/NekoX-Dev/ProxyList/contents/proxy_list_pro?ref=master@\"content\": \"@\"",
)
id = publicProxySubID
internal = true
proxies = public?.proxies ?: listOf()
}, true)
}
}
}

View File

@ -1,347 +0,0 @@
/*
* This is the source code of Telegram for Android v. 5.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2018.
*/
package tw.nekomimi.nekogram.proxy;
import android.content.Context;
import android.os.Build;
import android.text.InputType;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.R;
import org.telegram.messenger.SharedConfig;
import org.telegram.ui.ActionBar.ActionBar;
import org.telegram.ui.ActionBar.ActionBarMenu;
import org.telegram.ui.ActionBar.AlertDialog;
import org.telegram.ui.ActionBar.BaseFragment;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.ActionBar.ThemeDescription;
import org.telegram.ui.Components.EditTextBoldCursor;
import org.telegram.ui.Components.LayoutHelper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import cn.hutool.core.util.StrUtil;
import kotlin.collections.ArraysKt;
import kotlin.collections.CollectionsKt;
import tw.nekomimi.nekogram.utils.AlertUtil;
import tw.nekomimi.nekogram.utils.UIUtil;
public class SubSettingsActivity extends BaseFragment {
private EditText[] inputFields;
private EditText urlsField;
private EditTextBoldCursor remarksField;
private ScrollView scrollView;
private LinearLayout linearLayout2;
private LinearLayout inputFieldsContainer;
private SubInfo subInfo;
private boolean ignoreOnTextChange;
private static int done_button = 1;
private static int menu_delete = 2;
public SubSettingsActivity() {
super();
subInfo = new SubInfo();
subInfo.id = 0L;
}
public SubSettingsActivity(SubInfo subInfo) {
super();
this.subInfo = subInfo;
}
@Override
public void onResume() {
super.onResume();
AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid);
}
@Override
public View createView(Context context) {
actionBar.setTitle(LocaleController.getString("ProxySubDetails", R.string.ProxySubDetails));
actionBar.setBackButtonImage(R.drawable.ic_ab_back);
actionBar.setAllowOverlayTitle(false);
if (AndroidUtilities.isTablet()) {
actionBar.setOccupyStatusBar(false);
}
actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() {
@Override
public void onItemClick(int id) {
if (id == -1) {
finishFragment();
} else if (id == done_button) {
if (getParentActivity() == null) {
return;
}
if (StrUtil.isBlank(urlsField.getText())) {
urlsField.requestFocus();
AndroidUtilities.showKeyboard(urlsField);
return;
}
if (StrUtil.isBlank(remarksField.getText())) {
remarksField.requestFocus();
AndroidUtilities.showKeyboard(remarksField);
return;
}
subInfo.urls = ArraysKt.toList(urlsField.getText().toString().split("\n"));
subInfo.name = remarksField.getText().toString();
doGetProxies();
} else if (id == menu_delete) {
AlertUtil.showConfirm(getParentActivity(),
LocaleController.getString("SubscriptionDelete", R.string.SubscriptionDelete),
R.drawable.baseline_delete_24, LocaleController.getString("Delete", R.string.Delete),
true, () -> {
AlertDialog pro = AlertUtil.showProgress(getParentActivity());
pro.show();
UIUtil.runOnIoDispatcher(() -> {
SubManager.getSubList().remove(subInfo);
SharedConfig.reloadProxyList();
UIUtil.runOnUIThread(() -> {
pro.dismiss();
finishFragment();
});
});
});
}
}
});
ActionBarMenu menu = actionBar.createMenu();
if (subInfo.id != 0) {
menu.addItem(menu_delete, R.drawable.baseline_delete_24, AndroidUtilities.dp(56)).setContentDescription(LocaleController.getString("Delete", R.string.Delete));
}
menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)).setContentDescription(LocaleController.getString("Done", R.string.Done));
fragmentView = new FrameLayout(context);
FrameLayout frameLayout = (FrameLayout) fragmentView;
fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray));
scrollView = new ScrollView(context);
scrollView.setFillViewport(true);
AndroidUtilities.setScrollViewEdgeEffectColor(scrollView, Theme.getColor(Theme.key_actionBarDefault));
frameLayout.addView(scrollView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
linearLayout2 = new LinearLayout(context);
linearLayout2.setOrientation(LinearLayout.VERTICAL);
scrollView.addView(linearLayout2, new ScrollView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
inputFieldsContainer = new LinearLayout(context);
inputFieldsContainer.setOrientation(LinearLayout.VERTICAL);
inputFieldsContainer.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// bring to front for transitions
inputFieldsContainer.setElevation(AndroidUtilities.dp(1f));
inputFieldsContainer.setOutlineProvider(null);
}
linearLayout2.addView(inputFieldsContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
inputFields = new EditText[2];
urlsField = new EditText(context);
inputFields[0] = urlsField;
urlsField.setImeOptions(InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE);
urlsField.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
urlsField.setHint(LocaleController.getString("SubscriptionUrls", R.string.SubscriptionUrls));
urlsField.setText(CollectionsKt.joinToString(subInfo.urls, "\n", "", "", -1, "", null));
urlsField.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
urlsField.setHintTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteHintText));
urlsField.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
urlsField.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP);
urlsField.setHintTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueHeader));
urlsField.setSingleLine(false);
urlsField.setMinLines(6);
inputFieldsContainer.addView(urlsField, LayoutHelper.createLinear(-1, -2, 17, 0, 17, 0));
FrameLayout container = new FrameLayout(context);
remarksField = mkCursor();
inputFields[1] = remarksField;
remarksField.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
remarksField.setHintText(LocaleController.getString("ProxyRemarks", R.string.ProxyRemarks));
remarksField.setText(subInfo.name);
remarksField.setSelection(remarksField.length());
container.addView(remarksField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 17, 0, 17, 0));
inputFieldsContainer.addView((View) remarksField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
return fragmentView;
}
EditTextBoldCursor mkCursor() {
EditTextBoldCursor cursor = new EditTextBoldCursor(getParentActivity());
cursor.setSingleLine(true);
cursor.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
cursor.setHintColor(Theme.getColor(Theme.key_windowBackgroundWhiteHintText));
cursor.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
cursor.setBackground(null);
cursor.setCursorColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
cursor.setCursorSize(AndroidUtilities.dp(20));
cursor.setCursorWidth(1.5f);
cursor.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL);
cursor.setHeaderHintColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueHeader));
cursor.setTransformHintToHeader(true);
cursor.setLineColors(Theme.getColor(Theme.key_windowBackgroundWhiteInputField), Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated), Theme.getColor(Theme.key_windowBackgroundWhiteRedText3));
return cursor;
}
public void doGetProxies() {
AlertDialog pro = AlertUtil.showProgress(getParentActivity(), LocaleController.getString("SubscriptionUpdating", R.string.SubscriptionUpdating));
AtomicBoolean canceled = new AtomicBoolean();
pro.setOnCancelListener((it) -> {
canceled.set(true);
});
pro.show();
UIUtil.runOnIoDispatcher(() -> {
try {
subInfo.proxies = subInfo.reloadProxies();
subInfo.lastFetch = System.currentTimeMillis();
} catch (IOException allTriesFailed) {
if (canceled.get()) return;
UIUtil.runOnUIThread(pro::dismiss);
AlertUtil.showSimpleAlert(getParentActivity(), "tries failed: " + allTriesFailed.toString().trim());
return;
}
if (subInfo.id == 0) subInfo.id = SubManager.getCount() + 10;
do {
try {
SubManager.getSubList().update(subInfo, true);
break;
} catch (Exception ignored) {
}
subInfo.id ++;
} while (true);
SharedConfig.reloadProxyList();
UIUtil.runOnUIThread(() -> {
pro.dismiss();
finishFragment();
});
});
}
@Override
public ArrayList<ThemeDescription> getThemeDescriptions() {
final ThemeDescription.ThemeDescriptionDelegate delegate = () -> {
if (inputFields != null) {
for (int i = 0; i < inputFields.length; i++) {
inputFields[i].setText(Theme.getColor(Theme.key_windowBackgroundWhiteInputField));
}
}
};
ArrayList<ThemeDescription> arrayList = new ArrayList<>();
arrayList.add(new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundGray));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_actionBarDefault));
arrayList.add(new ThemeDescription(scrollView, ThemeDescription.FLAG_LISTGLOWCOLOR, null, null, null, null, Theme.key_actionBarDefault));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_ITEMSCOLOR, null, null, null, null, Theme.key_actionBarDefaultIcon));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_TITLECOLOR, null, null, null, null, Theme.key_actionBarDefaultTitle));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SELECTORCOLOR, null, null, null, null, Theme.key_actionBarDefaultSelector));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SEARCH, null, null, null, null, Theme.key_actionBarDefaultSearch));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SEARCHPLACEHOLDER, null, null, null, null, Theme.key_actionBarDefaultSearchPlaceholder));
arrayList.add(new ThemeDescription(inputFieldsContainer, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundWhite));
arrayList.add(new ThemeDescription(linearLayout2, 0, new Class[]{View.class}, Theme.dividerPaint, null, null, Theme.key_divider));
arrayList.add(new ThemeDescription(null, 0, null, null, null, null, delegate, Theme.key_windowBackgroundWhiteBlueText4));
arrayList.add(new ThemeDescription(null, 0, null, null, null, null, delegate, Theme.key_windowBackgroundWhiteGrayText2));
if (inputFields != null) {
for (int a = 0; a < inputFields.length; a++) {
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_HINTTEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteHintText));
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_HINTTEXTCOLOR | ThemeDescription.FLAG_PROGRESSBAR, null, null, null, null, Theme.key_windowBackgroundWhiteBlueHeader));
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_CURSORCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(null, 0, null, null, null, delegate, Theme.key_windowBackgroundWhiteInputField));
arrayList.add(new ThemeDescription(null, 0, null, null, null, delegate, Theme.key_windowBackgroundWhiteInputFieldActivated));
arrayList.add(new ThemeDescription(null, 0, null, null, null, delegate, Theme.key_windowBackgroundWhiteRedText3));
}
} else {
arrayList.add(new ThemeDescription(null, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(null, ThemeDescription.FLAG_HINTTEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteHintText));
}
return arrayList;
}
}

View File

@ -1,378 +0,0 @@
/*
* This is the source code of Telegram for Android v. 5.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2018.
*/
package tw.nekomimi.nekogram.proxy;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.os.Build;
import android.text.InputType;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import com.v2ray.ang.V2RayConfig;
import com.v2ray.ang.dto.AngConfig;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.R;
import org.telegram.messenger.SharedConfig;
import org.telegram.messenger.Utilities;
import org.telegram.ui.ActionBar.ActionBar;
import org.telegram.ui.ActionBar.ActionBarMenuItem;
import org.telegram.ui.ActionBar.BaseFragment;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.ActionBar.ThemeDescription;
import org.telegram.ui.Cells.TextInfoPrivacyCell;
import org.telegram.ui.Components.EditTextBoldCursor;
import org.telegram.ui.Components.LayoutHelper;
import java.util.ArrayList;
import cn.hutool.core.util.StrUtil;
public class TrojanSettingsActivity extends BaseFragment {
private EditTextBoldCursor[] inputFields;
private EditTextBoldCursor ipField;
private EditTextBoldCursor portField;
private EditTextBoldCursor passwordField;
private EditTextBoldCursor sniField;
private EditTextBoldCursor remarksField;
private ScrollView scrollView;
private LinearLayout linearLayout2;
private LinearLayout inputFieldsContainer;
private TextInfoPrivacyCell bottomCell;
private ActionBarMenuItem doneItem;
private SharedConfig.VmessProxy currentProxyInfo;
private AngConfig.VmessBean currentBean;
private boolean ignoreOnTextChange;
private static final int done_button = 1;
public class TypeCell extends FrameLayout {
private TextView textView;
private ImageView checkImage;
private boolean needDivider;
public TypeCell(Context context) {
super(context);
setWillNotDraw(false);
textView = new TextView(context);
textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
textView.setLines(1);
textView.setMaxLines(1);
textView.setSingleLine(true);
textView.setEllipsize(TextUtils.TruncateAt.END);
textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL);
addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 23 + 48 : 21, 0, LocaleController.isRTL ? 21 : 23, 0));
checkImage = new ImageView(context);
checkImage.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_featuredStickers_addedIcon), PorterDuff.Mode.SRC_IN));
checkImage.setImageResource(R.drawable.sticker_added);
addView(checkImage, LayoutHelper.createFrame(19, 14, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL, 21, 0, 21, 0));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50) + (needDivider ? 1 : 0), MeasureSpec.EXACTLY));
}
public void setValue(String name, boolean checked, boolean divider) {
textView.setText(name);
checkImage.setVisibility(checked ? VISIBLE : INVISIBLE);
needDivider = divider;
}
public void setTypeChecked(boolean value) {
checkImage.setVisibility(value ? VISIBLE : INVISIBLE);
}
@Override
protected void onDraw(Canvas canvas) {
if (needDivider) {
canvas.drawLine(0, getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight() - 1, Theme.dividerPaint);
}
}
}
public TrojanSettingsActivity() {
super();
currentBean = new AngConfig.VmessBean();
currentBean.setConfigType(V2RayConfig.EConfigType.Trojan);
}
public TrojanSettingsActivity(SharedConfig.VmessProxy proxyInfo) {
super();
currentProxyInfo = proxyInfo;
currentBean = proxyInfo.bean;
}
@Override
public void onResume() {
super.onResume();
AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid);
}
@Override
public View createView(Context context) {
actionBar.setTitle(LocaleController.getString("ProxyDetails", R.string.ProxyDetails));
actionBar.setBackButtonImage(R.drawable.ic_ab_back);
actionBar.setAllowOverlayTitle(false);
if (AndroidUtilities.isTablet()) {
actionBar.setOccupyStatusBar(false);
}
actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() {
@Override
public void onItemClick(int id) {
if (id == -1) {
finishFragment();
} else if (id == done_button) {
if (getParentActivity() == null) {
return;
}
if (StrUtil.isBlank(ipField.getText())) {
ipField.requestFocus();
AndroidUtilities.showKeyboard(ipField);
return;
}
if (StrUtil.isBlank(portField.getText())) {
portField.requestFocus();
AndroidUtilities.showKeyboard(portField);
return;
}
if (StrUtil.isBlank(passwordField.getText())) {
passwordField.requestFocus();
AndroidUtilities.showKeyboard(passwordField);
return;
}
currentBean.setAddress(ipField.getText().toString());
currentBean.setPort(Utilities.parseInt(portField.getText().toString()));
currentBean.setId(passwordField.getText().toString());
currentBean.setRequestHost(sniField.getText().toString());
currentBean.setRemarks(remarksField.getText().toString());
if (currentProxyInfo == null) {
currentProxyInfo = new SharedConfig.VmessProxy(currentBean);
SharedConfig.addProxy(currentProxyInfo);
SharedConfig.setCurrentProxy(currentProxyInfo);
} else {
currentProxyInfo.proxyCheckPingId = 0;
currentProxyInfo.availableCheckTime = 0;
currentProxyInfo.ping = 0;
SharedConfig.saveProxyList();
SharedConfig.setProxyEnable(false);
}
finishFragment();
}
}
});
doneItem = actionBar.createMenu().addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56));
doneItem.setContentDescription(LocaleController.getString("Done", R.string.Done));
fragmentView = new FrameLayout(context);
FrameLayout frameLayout = (FrameLayout) fragmentView;
fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray));
scrollView = new ScrollView(context);
scrollView.setFillViewport(true);
AndroidUtilities.setScrollViewEdgeEffectColor(scrollView, Theme.getColor(Theme.key_actionBarDefault));
frameLayout.addView(scrollView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
linearLayout2 = new LinearLayout(context);
linearLayout2.setOrientation(LinearLayout.VERTICAL);
scrollView.addView(linearLayout2, new ScrollView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
inputFieldsContainer = new LinearLayout(context);
inputFieldsContainer.setOrientation(LinearLayout.VERTICAL);
inputFieldsContainer.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// bring to front for transitions
inputFieldsContainer.setElevation(AndroidUtilities.dp(1f));
inputFieldsContainer.setOutlineProvider(null);
}
linearLayout2.addView(inputFieldsContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
inputFields = new EditTextBoldCursor[5];
for (int a = 0; a < 5; a++) {
FrameLayout container = new FrameLayout(context);
EditTextBoldCursor cursor = mkCursor();
inputFields[a] = cursor;
cursor.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI);
switch (a) {
case 0:
ipField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("UseProxyAddress", R.string.UseProxyAddress));
cursor.setText(currentBean.getAddress());
break;
case 1:
portField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_NUMBER);
cursor.setHintText(LocaleController.getString("UseProxyPort", R.string.UseProxyPort));
cursor.setText("" + currentBean.getPort());
break;
case 2:
passwordField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("SSPassword", R.string.SSPassword));
cursor.setText(currentBean.getId());
break;
case 3:
remarksField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("ProxyRemarks", R.string.ProxyRemarks));
cursor.setText(currentBean.getRemarks());
break;
case 4:
sniField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("TrojanSNI", R.string.TrojanSNI));
cursor.setText(currentBean.getRequestHost());
break;
}
cursor.setSelection(cursor.length());
cursor.setPadding(0, 0, 0, 0);
container.addView(cursor, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 17, a == 0 ? 12 : 0, 17, 0));
}
inputFieldsContainer.addView((View) ipField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
inputFieldsContainer.addView((View) portField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
inputFieldsContainer.addView((View) passwordField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
inputFieldsContainer.addView((View) sniField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
inputFieldsContainer.addView((View) remarksField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
bottomCell = new TextInfoPrivacyCell(context);
bottomCell.setBackground(Theme.getThemedDrawable(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow));
bottomCell.setText(LocaleController.getString("ProxyInfoTrojan", R.string.ProxyInfoTrojan));
linearLayout2.addView(bottomCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
return fragmentView;
}
EditTextBoldCursor mkCursor() {
EditTextBoldCursor cursor = new EditTextBoldCursor(getParentActivity());
cursor.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
cursor.setHintColor(Theme.getColor(Theme.key_windowBackgroundWhiteHintText));
cursor.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
cursor.setBackground(null);
cursor.setCursorColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
cursor.setCursorSize(AndroidUtilities.dp(20));
cursor.setCursorWidth(1.5f);
cursor.setSingleLine(true);
cursor.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL);
cursor.setHeaderHintColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueHeader));
cursor.setTransformHintToHeader(true);
cursor.setLineColors(Theme.getColor(Theme.key_windowBackgroundWhiteInputField), Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated), Theme.getColor(Theme.key_windowBackgroundWhiteRedText3));
return cursor;
}
@Override
public void onTransitionAnimationEnd(boolean isOpen, boolean backward) {
if (isOpen && !backward && currentProxyInfo == null) {
ipField.requestFocus();
AndroidUtilities.showKeyboard(ipField);
}
}
@Override
public ArrayList<ThemeDescription> getThemeDescriptions() {
final ThemeDescription.ThemeDescriptionDelegate delegate = () -> {
if (inputFields != null) {
for (int i = 0; i < inputFields.length; i++) {
inputFields[i].setLineColors(Theme.getColor(Theme.key_windowBackgroundWhiteInputField),
Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated),
Theme.getColor(Theme.key_windowBackgroundWhiteRedText3));
}
}
};
ArrayList<ThemeDescription> arrayList = new ArrayList<>();
arrayList.add(new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundGray));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_actionBarDefault));
arrayList.add(new ThemeDescription(scrollView, ThemeDescription.FLAG_LISTGLOWCOLOR, null, null, null, null, Theme.key_actionBarDefault));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_ITEMSCOLOR, null, null, null, null, Theme.key_actionBarDefaultIcon));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_TITLECOLOR, null, null, null, null, Theme.key_actionBarDefaultTitle));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SELECTORCOLOR, null, null, null, null, Theme.key_actionBarDefaultSelector));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SEARCH, null, null, null, null, Theme.key_actionBarDefaultSearch));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SEARCHPLACEHOLDER, null, null, null, null, Theme.key_actionBarDefaultSearchPlaceholder));
arrayList.add(new ThemeDescription(inputFieldsContainer, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundWhite));
arrayList.add(new ThemeDescription(linearLayout2, 0, new Class[]{View.class}, Theme.dividerPaint, null, null, Theme.key_divider));
arrayList.add(new ThemeDescription(null, 0, null, null, null, null, delegate, Theme.key_windowBackgroundWhiteBlueText4));
arrayList.add(new ThemeDescription(null, 0, null, null, null, null, delegate, Theme.key_windowBackgroundWhiteGrayText2));
if (inputFields != null) {
for (int a = 0; a < inputFields.length; a++) {
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_HINTTEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteHintText));
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_HINTTEXTCOLOR | ThemeDescription.FLAG_PROGRESSBAR, null, null, null, null, Theme.key_windowBackgroundWhiteBlueHeader));
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_CURSORCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(null, 0, null, null, null, delegate, Theme.key_windowBackgroundWhiteInputField));
arrayList.add(new ThemeDescription(null, 0, null, null, null, delegate, Theme.key_windowBackgroundWhiteInputFieldActivated));
arrayList.add(new ThemeDescription(null, 0, null, null, null, delegate, Theme.key_windowBackgroundWhiteRedText3));
}
} else {
arrayList.add(new ThemeDescription(null, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(null, ThemeDescription.FLAG_HINTTEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteHintText));
}
arrayList.add(new ThemeDescription(bottomCell, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{TextInfoPrivacyCell.class}, null, null, null, Theme.key_windowBackgroundGrayShadow));
arrayList.add(new ThemeDescription(bottomCell, 0, new Class[]{TextInfoPrivacyCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText4));
arrayList.add(new ThemeDescription(bottomCell, ThemeDescription.FLAG_LINKCOLOR, new Class[]{TextInfoPrivacyCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteLinkText));
return arrayList;
}
}

View File

@ -1,442 +0,0 @@
package tw.nekomimi.nekogram.proxy
import cn.hutool.core.codec.Base64
import com.google.gson.Gson
import com.v2ray.ang.V2RayConfig
import com.v2ray.ang.V2RayConfig.SOCKS_PROTOCOL
import com.v2ray.ang.V2RayConfig.TROJAN_PROTOCOL
import com.v2ray.ang.V2RayConfig.VMESS1_PROTOCOL
import com.v2ray.ang.V2RayConfig.VMESS_PROTOCOL
import com.v2ray.ang.dto.AngConfig.VmessBean
import com.v2ray.ang.dto.VmessQRCode
import com.v2ray.ang.util.Utils
import com.v2ray.ang.util.V2rayConfigUtil
import libv2ray.Libv2ray
import libv2ray.V2RayVPNServiceSupportsSet
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.telegram.messenger.FileLog
import kotlin.concurrent.thread
import kotlin.random.Random
class VmessLoader {
private val point = Libv2ray.newV2RayPoint(EmptyCallback(), false)
companion object {
fun parseVmess1Link(server: String): VmessBean {
val lnk = ("https://" + server.substringAfter(VMESS1_PROTOCOL)).toHttpUrl()
val bean = VmessBean()
bean.configType = V2RayConfig.EConfigType.Vmess
bean.address = lnk.host
bean.port = lnk.port
bean.id = lnk.username
bean.remarks = lnk.fragment ?: ""
lnk.queryParameterNames.forEach {
when (it) {
"tls" -> if (lnk.queryParameter(it) == "true") bean.streamSecurity = "tls"
"network" -> {
bean.network = lnk.queryParameter(it)!!
if (bean.network in arrayOf("http", "ws")) {
bean.path = Utils.urlDecode(lnk.encodedPath)
}
}
"header" -> {
bean.headerType = lnk.queryParameter(it)!!
}
}
}
return bean
}
@JvmStatic
fun parseVmessLink(server: String): VmessBean {
try {
if (server.isBlank()) error("empty link")
var vmess = VmessBean()
if (server.startsWith(VMESS_PROTOCOL)) {
val indexSplit = server.indexOf("?")
if (indexSplit > 0) {
vmess = resolveSimpleVmess1(server)
} else {
var result = server.replace(VMESS_PROTOCOL, "")
result = Base64.decodeStr(result)
if (result.isBlank()) {
error("invalid url format")
}
if (result.contains("= vmess")) {
vmess = resolveSomeIOSAppShitCsvLink(result)
} else {
val vmessQRCode = Gson().fromJson(result, VmessQRCode::class.java)
if (vmessQRCode.add.isBlank()
|| vmessQRCode.port.isBlank()
|| vmessQRCode.id.isBlank()
|| vmessQRCode.aid.isBlank()
|| vmessQRCode.net.isBlank()
) {
error("invalid protocol")
}
vmess.configType = V2RayConfig.EConfigType.Vmess
vmess.security = "auto"
vmess.network = "tcp"
vmess.headerType = "none"
vmess.configVersion = Utils.parseInt(vmessQRCode.v)
vmess.remarks = vmessQRCode.ps
vmess.address = vmessQRCode.add
vmess.port = Utils.parseInt(vmessQRCode.port)
vmess.id = vmessQRCode.id
vmess.alterId = Utils.parseInt(vmessQRCode.aid)
vmess.network = vmessQRCode.net
vmess.headerType = vmessQRCode.type
vmess.requestHost = vmessQRCode.host
vmess.path = vmessQRCode.path
vmess.streamSecurity = vmessQRCode.tls
}
}
upgradeServerVersion(vmess)
return vmess
} else if (server.startsWith(VMESS1_PROTOCOL)) {
return parseVmess1Link(server)
} else if (server.startsWith(TROJAN_PROTOCOL)) {
vmess.configType = V2RayConfig.EConfigType.Trojan
val link = server.replace(TROJAN_PROTOCOL, "https://").toHttpUrlOrNull()
?: error("invalid trojan link $server")
vmess.address = link.host
vmess.port = link.port
vmess.id = link.username
if (link.password.isNotBlank()) {
// https://github.com/trojan-gfw/igniter/issues/318
vmess.id += ":" + link.password
}
vmess.requestHost = link.queryParameter("sni") ?: vmess.requestHost
vmess.remarks = link.fragment ?: ""
return vmess
} else if (server.startsWith(SOCKS_PROTOCOL)) {
var result = server.replace(SOCKS_PROTOCOL, "")
val indexSplit = result.indexOf("#")
if (indexSplit > 0) {
try {
vmess.remarks = Utils.urlDecode(result.substring(indexSplit + 1, result.length))
} catch (e: Exception) {
e.printStackTrace()
}
result = result.substring(0, indexSplit)
}
//part decode
val indexS = result.indexOf(":")
if (indexS < 0) {
result = Base64.decodeStr(result)
}
val legacyPattern = "^(.+?):(\\d+?)$".toRegex()
val match = legacyPattern.matchEntire(result) ?: error("invalid protocol")
vmess.address = match.groupValues[1]
if (vmess.address.firstOrNull() == '[' && vmess.address.lastOrNull() == ']')
vmess.address = vmess.address.substring(1, vmess.address.length - 1)
vmess.port = match.groupValues[2].toInt()
return vmess
} else {
error("invalid protocol")
}
} catch (e: Exception) {
throw IllegalArgumentException(e)
}
}
private fun resolveSomeIOSAppShitCsvLink(csv: String): VmessBean {
val args = csv.split(",")
val bean = VmessBean()
bean.configType = V2RayConfig.EConfigType.Vmess
bean.address = args[1]
bean.port = args[2].toInt()
bean.security = args[3]
bean.id = args[4].replace("\"", "")
args.subList(5, args.size).forEach {
when {
it == "over-tls=true" -> {
bean.streamSecurity = "tls"
}
it.startsWith("tls-host=") -> {
bean.requestHost = it.substringAfter("=")
}
it.startsWith("obfs=") -> {
bean.network = it.substringAfter("=")
}
it.startsWith("obfs-path=") || it.contains("Host:") -> {
runCatching {
bean.path = it
.substringAfter("obfs-path=\"")
.substringBefore("\"obfs")
}
runCatching {
bean.requestHost = it
.substringAfter("Host:")
.substringBefore("[")
}
}
}
}
return bean
}
/**
* upgrade
*/
private fun upgradeServerVersion(vmess: VmessBean): Int {
try {
if (vmess.configVersion == 2) {
return 0
}
when (vmess.network) {
"kcp" -> {
}
"ws" -> {
var path = ""
var host = ""
val lstParameter = vmess.requestHost.split(";")
if (lstParameter.size > 0) {
path = lstParameter.get(0).trim()
}
if (lstParameter.size > 1) {
path = lstParameter.get(0).trim()
host = lstParameter.get(1).trim()
}
vmess.path = path
vmess.requestHost = host
}
"h2" -> {
var path = ""
var host = ""
val lstParameter = vmess.requestHost.split(";")
if (lstParameter.isNotEmpty()) {
path = lstParameter[0].trim()
}
if (lstParameter.size > 1) {
path = lstParameter[0].trim()
host = lstParameter[1].trim()
}
vmess.path = path
vmess.requestHost = host
}
else -> {
}
}
vmess.configVersion = 2
return 0
} catch (e: Exception) {
e.printStackTrace()
return -1
}
}
private fun resolveSimpleVmess1(server: String): VmessBean {
val vmess = VmessBean()
var result = server.replace(VMESS_PROTOCOL, "")
val indexSplit = result.indexOf("?")
if (indexSplit > 0) {
result = result.substring(0, indexSplit)
}
result = Base64.decodeStr(result)
val arr1 = result.split('@')
if (arr1.count() != 2) {
return vmess
}
val arr21 = arr1[0].split(':')
val arr22 = arr1[1].split(':')
if (arr21.count() != 2 || arr21.count() != 2) {
return vmess
}
vmess.address = arr22[0]
vmess.port = Utils.parseInt(arr22[1])
vmess.security = arr21[0]
vmess.id = arr21[1]
vmess.security = "chacha20-poly1305"
vmess.network = "tcp"
vmess.headerType = "none"
vmess.remarks = ""
vmess.alterId = 0
return vmess
}
}
lateinit var bean: VmessBean
fun initConfig(config: VmessBean) {
this.bean = config
}
fun start(): Int {
var retry = 3
do {
try {
val port = Random.nextInt(4096, 32768)
val conf = V2rayConfigUtil.getV2rayConfig(bean, port).content
FileLog.d(conf)
runCatching {
Libv2ray.testConfig(conf)
}.onFailure {
FileLog.e(it)
return -1
}
point.configureFileContent = conf
point.domainName = V2rayConfigUtil.currDomain
point.runLoop(true)
return port
} catch (e: Throwable) {
retry--
if (retry <= 0) {
FileLog.e(e)
return -1
}
}
} while (true)
}
fun stop() {
thread {
runCatching {
point.stopLoop()
}
}
}
class EmptyCallback : V2RayVPNServiceSupportsSet {
override fun onEmitStatus(p0: Long, p1: String?): Long {
return 0
}
override fun setup(p0: String?): Long {
return 0
}
override fun prepare(): Long {
return 0
}
override fun shutdown(): Long {
return 0
}
override fun protect(p0: Long): Boolean {
return true
}
}
}

View File

@ -1,505 +0,0 @@
/*
* This is the source code of Telegram for Android v. 5.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2018.
*/
package tw.nekomimi.nekogram.proxy;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.os.Build;
import android.text.InputType;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import com.v2ray.ang.V2RayConfig;
import com.v2ray.ang.dto.AngConfig;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.R;
import org.telegram.messenger.SharedConfig;
import org.telegram.messenger.Utilities;
import org.telegram.ui.ActionBar.ActionBar;
import org.telegram.ui.ActionBar.ActionBarMenuItem;
import org.telegram.ui.ActionBar.BaseFragment;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.ActionBar.ThemeDescription;
import org.telegram.ui.Cells.TextCheckCell;
import org.telegram.ui.Cells.TextInfoPrivacyCell;
import org.telegram.ui.Cells.TextSettingsCell;
import org.telegram.ui.Components.EditTextBoldCursor;
import org.telegram.ui.Components.LayoutHelper;
import java.util.ArrayList;
import cn.hutool.core.util.StrUtil;
import kotlin.Unit;
import tw.nekomimi.nekogram.ui.PopupBuilder;
public class VmessSettingsActivity extends BaseFragment {
private EditTextBoldCursor[] inputFields;
private EditTextBoldCursor ipField;
private EditTextBoldCursor portField;
private EditTextBoldCursor userIdField;
private EditTextBoldCursor alterIdField;
private TextSettingsCell securityField;
private TextSettingsCell networkField;
private TextSettingsCell headTypeField;
private EditTextBoldCursor requestHostField;
private EditTextBoldCursor pathField;
private TextCheckCell useTlsField;
private EditTextBoldCursor remarksField;
private ScrollView scrollView;
private LinearLayout linearLayout2;
private LinearLayout inputFieldsContainer;
private TextInfoPrivacyCell bottomCell;
private ActionBarMenuItem doneItem;
private SharedConfig.VmessProxy currentProxyInfo;
private AngConfig.VmessBean currentBean;
private boolean ignoreOnTextChange;
private static final int done_button = 1;
private static String[] securitySet = { "chacha20-poly1305","aes-128-gcm","auto","none","zero" };
private static String[] networkSet = { "tcp","kcp","ws","h2","quic" };
private static String[] headTypeSet = { "none","http","srtp","utp","wechat-video","dtls","wireguard" };
public class TypeCell extends FrameLayout {
private TextView textView;
private ImageView checkImage;
private boolean needDivider;
public TypeCell(Context context) {
super(context);
setWillNotDraw(false);
textView = new TextView(context);
textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
textView.setLines(1);
textView.setMaxLines(1);
textView.setSingleLine(true);
textView.setEllipsize(TextUtils.TruncateAt.END);
textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL);
addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 23 + 48 : 21, 0, LocaleController.isRTL ? 21 : 23, 0));
checkImage = new ImageView(context);
checkImage.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_featuredStickers_addedIcon), PorterDuff.Mode.SRC_IN));
checkImage.setImageResource(R.drawable.sticker_added);
addView(checkImage, LayoutHelper.createFrame(19, 14, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL, 21, 0, 21, 0));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50) + (needDivider ? 1 : 0), MeasureSpec.EXACTLY));
}
public void setValue(String name, boolean checked, boolean divider) {
textView.setText(name);
checkImage.setVisibility(checked ? VISIBLE : INVISIBLE);
needDivider = divider;
}
public void setTypeChecked(boolean value) {
checkImage.setVisibility(value ? VISIBLE : INVISIBLE);
}
@Override
protected void onDraw(Canvas canvas) {
if (needDivider) {
canvas.drawLine(0, getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight() - 1, Theme.dividerPaint);
}
}
}
public VmessSettingsActivity() {
super();
currentBean = new AngConfig.VmessBean();
currentBean.setConfigType(V2RayConfig.EConfigType.Vmess);
}
public VmessSettingsActivity(SharedConfig.VmessProxy proxyInfo) {
super();
currentProxyInfo = proxyInfo;
currentBean = proxyInfo.bean;
}
@Override
public void onResume() {
super.onResume();
AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid);
}
@Override
public View createView(Context context) {
actionBar.setTitle(LocaleController.getString("ProxyDetails", R.string.ProxyDetails));
actionBar.setBackButtonImage(R.drawable.ic_ab_back);
actionBar.setAllowOverlayTitle(false);
if (AndroidUtilities.isTablet()) {
actionBar.setOccupyStatusBar(false);
}
actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() {
@Override
public void onItemClick(int id) {
if (id == -1) {
finishFragment();
} else if (id == done_button) {
if (getParentActivity() == null) {
return;
}
if (StrUtil.isBlank(ipField.getText())) {
ipField.requestFocus();
AndroidUtilities.showKeyboard(ipField);
return;
}
if (StrUtil.isBlank(portField.getText())) {
portField.requestFocus();
AndroidUtilities.showKeyboard(portField);
return;
}
if (StrUtil.isBlank(userIdField.getText())) {
userIdField.requestFocus();
AndroidUtilities.showKeyboard(userIdField);
return;
}
if (StrUtil.isBlank(alterIdField.getText())) {
alterIdField.requestFocus();
AndroidUtilities.showKeyboard(alterIdField);
return;
}
currentBean.setAddress(ipField.getText().toString());
currentBean.setPort(Utilities.parseInt(portField.getText().toString()));
currentBean.setId(userIdField.getText().toString());
currentBean.setAlterId(Utilities.parseInt(alterIdField.getText().toString()));
currentBean.setSecurity(securityField.getValueTextView().getText().toString());
currentBean.setNetwork(networkField.getValueTextView().getText().toString());
currentBean.setHeaderType(headTypeField.getValueTextView().getText().toString());
currentBean.setRequestHost(requestHostField.getText().toString());
currentBean.setPath(pathField.getText().toString());
currentBean.setStreamSecurity(useTlsField.isChecked() ? "tls" : "");
currentBean.setRemarks(remarksField.getText().toString());
if (currentProxyInfo == null) {
currentProxyInfo = new SharedConfig.VmessProxy(currentBean);
SharedConfig.addProxy(currentProxyInfo);
SharedConfig.setCurrentProxy(currentProxyInfo);
} else {
currentProxyInfo.proxyCheckPingId = 0;
currentProxyInfo.availableCheckTime = 0;
currentProxyInfo.ping = 0;
SharedConfig.saveProxyList();
SharedConfig.setProxyEnable(false);
}
finishFragment();
}
}
});
doneItem = actionBar.createMenu().addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56));
doneItem.setContentDescription(LocaleController.getString("Done", R.string.Done));
fragmentView = new FrameLayout(context);
FrameLayout frameLayout = (FrameLayout) fragmentView;
fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray));
scrollView = new ScrollView(context);
scrollView.setFillViewport(true);
AndroidUtilities.setScrollViewEdgeEffectColor(scrollView, Theme.getColor(Theme.key_actionBarDefault));
frameLayout.addView(scrollView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
linearLayout2 = new LinearLayout(context);
linearLayout2.setOrientation(LinearLayout.VERTICAL);
scrollView.addView(linearLayout2, new ScrollView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
inputFieldsContainer = new LinearLayout(context);
inputFieldsContainer.setOrientation(LinearLayout.VERTICAL);
inputFieldsContainer.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// bring to front for transitions
inputFieldsContainer.setElevation(AndroidUtilities.dp(1f));
inputFieldsContainer.setOutlineProvider(null);
}
linearLayout2.addView(inputFieldsContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
inputFields = new EditTextBoldCursor[7];
for (int a = 0; a < 7; a++) {
FrameLayout container = new FrameLayout(context);
EditTextBoldCursor cursor = mkCursor();
inputFields[a] = cursor;
cursor.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI);
switch (a) {
case 0:
ipField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("UseProxyAddress", R.string.UseProxyAddress));
cursor.setText(currentBean.getAddress());
break;
case 1:
portField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_NUMBER);
cursor.setHintText(LocaleController.getString("UseProxyPort", R.string.UseProxyPort));
cursor.setText("" + currentBean.getPort());
break;
case 2:
userIdField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("VmessUserId", R.string.VmessUserId));
cursor.setText(currentBean.getId());
break;
case 3:
alterIdField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_NUMBER);
cursor.setHintText(LocaleController.getString("VmessAlterId", R.string.VmessAlterId));
cursor.setText("" + currentBean.getAlterId());
break;
case 4:
requestHostField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("VmessRequestHost", R.string.VmessRequestHost));
cursor.setText(currentBean.getRequestHost());
break;
case 5:
pathField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("VmessPath", R.string.VmessPath));
cursor.setText(currentBean.getPath());
break;
case 6:
remarksField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("ProxyRemarks", R.string.ProxyRemarks));
cursor.setText(currentBean.getRemarks());
break;
}
cursor.setSelection(cursor.length());
cursor.setPadding(0, 0, 0, 0);
container.addView(cursor, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 17, a == 0 ? 12 : 0, 17, 0));
}
inputFieldsContainer.addView((View) ipField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
inputFieldsContainer.addView((View) portField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
inputFieldsContainer.addView((View) userIdField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
inputFieldsContainer.addView((View) alterIdField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
FrameLayout container = new FrameLayout(context);
securityField = new TextSettingsCell(context);
securityField.setBackground(Theme.getSelectorDrawable(false));
securityField.setTextAndValue(LocaleController.getString("VmessSecurity", R.string.VmessSecurity), currentBean.getSecurity(), false);
container.addView(securityField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 0));
securityField.setOnClickListener((v) -> {
PopupBuilder select = new PopupBuilder(v);
select.setItems(securitySet, (__,value) -> {
securityField.getValueTextView().setText(value);
return Unit.INSTANCE;
});
select.show();
});
inputFieldsContainer.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
container = new FrameLayout(context);
networkField = new TextSettingsCell(context);
networkField.setBackground(Theme.getSelectorDrawable(false));
networkField.setTextAndValue(LocaleController.getString("VmessNetwork", R.string.VmessNetwork), currentBean.getNetwork(), false);
container.addView(networkField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 0));
networkField.setOnClickListener((v) -> {
PopupBuilder select = new PopupBuilder(v);
select.setItems(networkSet, (__,value) -> {
networkField.getValueTextView().setText(value);
return Unit.INSTANCE;
});
select.show();
});
inputFieldsContainer.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
container = new FrameLayout(context);
headTypeField = new TextSettingsCell(context);
headTypeField.setBackground(Theme.getSelectorDrawable(false));
headTypeField.setTextAndValue(LocaleController.getString("VmessHeadType", R.string.VmessHeadType), currentBean.getHeaderType(), false);
container.addView(headTypeField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 0));
headTypeField.setOnClickListener((v) -> {
PopupBuilder select = new PopupBuilder(v);
select.setItems(headTypeSet, (__,value) -> {
headTypeField.getValueTextView().setText(value);
return Unit.INSTANCE;
});
select.show();
});
inputFieldsContainer.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
inputFieldsContainer.addView((View) requestHostField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
inputFieldsContainer.addView((View) pathField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
container = new FrameLayout(context);
useTlsField = new TextCheckCell(context);
useTlsField.setBackground(Theme.getSelectorDrawable(false));
useTlsField.setTextAndCheck(LocaleController.getString("VmessTls", R.string.VmessTls), !StrUtil.isBlank(currentBean.getStreamSecurity()), false);
container.addView(useTlsField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 0));
useTlsField.setOnClickListener((v) -> useTlsField.setChecked(!useTlsField.isChecked()));
inputFieldsContainer.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
inputFieldsContainer.addView((View) remarksField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
bottomCell = new TextInfoPrivacyCell(context);
bottomCell.setBackground(Theme.getThemedDrawable(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow));
bottomCell.setText(LocaleController.getString("ProxyInfoVmess", R.string.ProxyInfoVmess));
linearLayout2.addView(bottomCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
return fragmentView;
}
EditTextBoldCursor mkCursor() {
EditTextBoldCursor cursor = new EditTextBoldCursor(getParentActivity());
cursor.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
cursor.setHintColor(Theme.getColor(Theme.key_windowBackgroundWhiteHintText));
cursor.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
cursor.setBackground(null);
cursor.setCursorColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
cursor.setCursorSize(AndroidUtilities.dp(20));
cursor.setCursorWidth(1.5f);
cursor.setSingleLine(true);
cursor.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL);
cursor.setHeaderHintColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueHeader));
cursor.setTransformHintToHeader(true);
cursor.setLineColors(Theme.getColor(Theme.key_windowBackgroundWhiteInputField), Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated), Theme.getColor(Theme.key_windowBackgroundWhiteRedText3));
return cursor;
}
@Override
public void onTransitionAnimationEnd(boolean isOpen, boolean backward) {
if (isOpen && !backward && currentProxyInfo == null) {
ipField.requestFocus();
AndroidUtilities.showKeyboard(ipField);
}
}
@Override
public ArrayList<ThemeDescription> getThemeDescriptions() {
final ThemeDescription.ThemeDescriptionDelegate delegate = () -> {
if (inputFields != null) {
for (int i = 0; i < inputFields.length; i++) {
inputFields[i].setLineColors(Theme.getColor(Theme.key_windowBackgroundWhiteInputField),
Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated),
Theme.getColor(Theme.key_windowBackgroundWhiteRedText3));
}
}
};
ArrayList<ThemeDescription> arrayList = new ArrayList<>();
arrayList.add(new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundGray));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_actionBarDefault));
arrayList.add(new ThemeDescription(scrollView, ThemeDescription.FLAG_LISTGLOWCOLOR, null, null, null, null, Theme.key_actionBarDefault));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_ITEMSCOLOR, null, null, null, null, Theme.key_actionBarDefaultIcon));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_TITLECOLOR, null, null, null, null, Theme.key_actionBarDefaultTitle));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SELECTORCOLOR, null, null, null, null, Theme.key_actionBarDefaultSelector));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SEARCH, null, null, null, null, Theme.key_actionBarDefaultSearch));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SEARCHPLACEHOLDER, null, null, null, null, Theme.key_actionBarDefaultSearchPlaceholder));
arrayList.add(new ThemeDescription(inputFieldsContainer, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundWhite));
arrayList.add(new ThemeDescription(linearLayout2, 0, new Class[]{View.class}, Theme.dividerPaint, null, null, Theme.key_divider));
arrayList.add(new ThemeDescription(null, 0, null, null, null, null, delegate, Theme.key_windowBackgroundWhiteBlueText4));
arrayList.add(new ThemeDescription(null, 0, null, null, null, null, delegate, Theme.key_windowBackgroundWhiteGrayText2));
if (inputFields != null) {
for (int a = 0; a < inputFields.length; a++) {
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_HINTTEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteHintText));
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_HINTTEXTCOLOR | ThemeDescription.FLAG_PROGRESSBAR, null, null, null, null, Theme.key_windowBackgroundWhiteBlueHeader));
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_CURSORCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(null, 0, null, null, null, delegate, Theme.key_windowBackgroundWhiteInputField));
arrayList.add(new ThemeDescription(null, 0, null, null, null, delegate, Theme.key_windowBackgroundWhiteInputFieldActivated));
arrayList.add(new ThemeDescription(null, 0, null, null, null, delegate, Theme.key_windowBackgroundWhiteRedText3));
}
} else {
arrayList.add(new ThemeDescription(null, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(null, ThemeDescription.FLAG_HINTTEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteHintText));
}
arrayList.add(new ThemeDescription(bottomCell, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{TextInfoPrivacyCell.class}, null, null, null, Theme.key_windowBackgroundGrayShadow));
arrayList.add(new ThemeDescription(bottomCell, 0, new Class[]{TextInfoPrivacyCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText4));
arrayList.add(new ThemeDescription(bottomCell, ThemeDescription.FLAG_LINKCOLOR, new Class[]{TextInfoPrivacyCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteLinkText));
return arrayList;
}
}

View File

@ -1,359 +0,0 @@
/*
* This is the source code of Telegram for Android v. 5.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2018.
*/
package tw.nekomimi.nekogram.proxy;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.os.Build;
import android.text.InputType;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.R;
import org.telegram.messenger.SharedConfig;
import org.telegram.ui.ActionBar.ActionBar;
import org.telegram.ui.ActionBar.ActionBarMenuItem;
import org.telegram.ui.ActionBar.BaseFragment;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.ActionBar.ThemeDescription;
import org.telegram.ui.Cells.TextCheckCell;
import org.telegram.ui.Cells.TextInfoPrivacyCell;
import org.telegram.ui.Components.EditTextBoldCursor;
import org.telegram.ui.Components.LayoutHelper;
import java.util.ArrayList;
import cn.hutool.core.util.StrUtil;
import tw.nekomimi.nekogram.proxy.tcp2ws.WsLoader;
public class WsSettingsActivity extends BaseFragment {
private EditTextBoldCursor[] inputFields;
private EditTextBoldCursor ipField;
private EditTextBoldCursor payloadField;
private TextCheckCell useTlsField;
private EditTextBoldCursor remarksField;
private ScrollView scrollView;
private LinearLayout linearLayout2;
private LinearLayout inputFieldsContainer;
private TextInfoPrivacyCell bottomCell;
private ActionBarMenuItem doneItem;
private SharedConfig.WsProxy currentProxyInfo;
private WsLoader.Bean currentBean;
private static final int done_button = 1;
public class TypeCell extends FrameLayout {
private TextView textView;
private ImageView checkImage;
private boolean needDivider;
public TypeCell(Context context) {
super(context);
setWillNotDraw(false);
textView = new TextView(context);
textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
textView.setLines(1);
textView.setMaxLines(1);
textView.setSingleLine(true);
textView.setEllipsize(TextUtils.TruncateAt.END);
textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL);
addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 23 + 48 : 21, 0, LocaleController.isRTL ? 21 : 23, 0));
checkImage = new ImageView(context);
checkImage.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_featuredStickers_addedIcon), PorterDuff.Mode.SRC_IN));
checkImage.setImageResource(R.drawable.sticker_added);
addView(checkImage, LayoutHelper.createFrame(19, 14, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL, 21, 0, 21, 0));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(50) + (needDivider ? 1 : 0), MeasureSpec.EXACTLY));
}
public void setValue(String name, boolean checked, boolean divider) {
textView.setText(name);
checkImage.setVisibility(checked ? VISIBLE : INVISIBLE);
needDivider = divider;
}
public void setTypeChecked(boolean value) {
checkImage.setVisibility(value ? VISIBLE : INVISIBLE);
}
@Override
protected void onDraw(Canvas canvas) {
if (needDivider) {
canvas.drawLine(0, getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight() - 1, Theme.dividerPaint);
}
}
}
public WsSettingsActivity() {
super();
currentBean = new WsLoader.Bean();
}
public WsSettingsActivity(SharedConfig.WsProxy proxyInfo) {
super();
currentProxyInfo = proxyInfo;
currentBean = proxyInfo.bean;
}
@Override
public void onResume() {
super.onResume();
AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid);
}
@Override
public View createView(Context context) {
actionBar.setTitle(LocaleController.getString("ProxyDetails", R.string.ProxyDetails));
actionBar.setBackButtonImage(R.drawable.ic_ab_back);
actionBar.setAllowOverlayTitle(false);
if (AndroidUtilities.isTablet()) {
actionBar.setOccupyStatusBar(false);
}
actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() {
@Override
public void onItemClick(int id) {
if (id == -1) {
finishFragment();
} else if (id == done_button) {
if (getParentActivity() == null) {
return;
}
if (StrUtil.isBlank(ipField.getText())) {
ipField.requestFocus();
AndroidUtilities.showKeyboard(ipField);
return;
}
if (StrUtil.isBlank(payloadField.getText())) {
payloadField.requestFocus();
AndroidUtilities.showKeyboard(payloadField);
return;
}
currentBean.setServer(ipField.getText().toString());
currentBean.setPayloadStr(payloadField.getText().toString());
currentBean.setTls(useTlsField.isChecked());
currentBean.setRemarks(remarksField.getText().toString());
if (currentProxyInfo == null) {
currentProxyInfo = new SharedConfig.WsProxy(currentBean);
SharedConfig.addProxy(currentProxyInfo);
SharedConfig.setCurrentProxy(currentProxyInfo);
} else {
currentProxyInfo.proxyCheckPingId = 0;
currentProxyInfo.availableCheckTime = 0;
currentProxyInfo.ping = 0;
SharedConfig.saveProxyList();
SharedConfig.setProxyEnable(false);
}
finishFragment();
}
}
});
doneItem = actionBar.createMenu().addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56));
doneItem.setContentDescription(LocaleController.getString("Done", R.string.Done));
fragmentView = new FrameLayout(context);
FrameLayout frameLayout = (FrameLayout) fragmentView;
fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray));
scrollView = new ScrollView(context);
scrollView.setFillViewport(true);
AndroidUtilities.setScrollViewEdgeEffectColor(scrollView, Theme.getColor(Theme.key_actionBarDefault));
frameLayout.addView(scrollView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
linearLayout2 = new LinearLayout(context);
linearLayout2.setOrientation(LinearLayout.VERTICAL);
scrollView.addView(linearLayout2, new ScrollView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
inputFieldsContainer = new LinearLayout(context);
inputFieldsContainer.setOrientation(LinearLayout.VERTICAL);
inputFieldsContainer.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// bring to front for transitions
inputFieldsContainer.setElevation(AndroidUtilities.dp(1f));
inputFieldsContainer.setOutlineProvider(null);
}
linearLayout2.addView(inputFieldsContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
inputFields = new EditTextBoldCursor[5];
for (int a = 0; a < 5; a++) {
FrameLayout container = new FrameLayout(context);
EditTextBoldCursor cursor = mkCursor();
inputFields[a] = cursor;
cursor.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI);
switch (a) {
case 0:
ipField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("UseProxyAddress", R.string.UseProxyAddress));
cursor.setText(currentBean.getServer());
break;
case 1:
payloadField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("WsPayload", R.string.WsPayload));
cursor.setText(currentBean.getPayloadStr());
break;
case 2:
remarksField = cursor;
cursor.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
cursor.setHintText(LocaleController.getString("ProxyRemarks", R.string.ProxyRemarks));
cursor.setText(currentBean.getRemarks());
break;
}
cursor.setSelection(cursor.length());
cursor.setPadding(0, 0, 0, 0);
container.addView(cursor, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 17, a == 0 ? 12 : 0, 17, 0));
}
inputFieldsContainer.addView((View) ipField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
inputFieldsContainer.addView((View) payloadField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
FrameLayout container = new FrameLayout(context);
useTlsField = new TextCheckCell(context);
useTlsField.setBackground(Theme.getSelectorDrawable(false));
useTlsField.setTextAndCheck(LocaleController.getString("VmessTls", R.string.VmessTls), currentBean.getTls(), false);
container.addView(useTlsField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 0));
useTlsField.setOnClickListener((v) -> useTlsField.setChecked(!useTlsField.isChecked()));
inputFieldsContainer.addView(container, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
inputFieldsContainer.addView((View) remarksField.getParent(), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 64));
bottomCell = new TextInfoPrivacyCell(context);
bottomCell.setBackground(Theme.getThemedDrawable(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow));
bottomCell.setText(LocaleController.getString("ProxyInfoWS", R.string.ProxyInfoWS));
linearLayout2.addView(bottomCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
return fragmentView;
}
EditTextBoldCursor mkCursor() {
EditTextBoldCursor cursor = new EditTextBoldCursor(getParentActivity());
cursor.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
cursor.setHintColor(Theme.getColor(Theme.key_windowBackgroundWhiteHintText));
cursor.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
cursor.setBackground(null);
cursor.setCursorColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
cursor.setCursorSize(AndroidUtilities.dp(20));
cursor.setCursorWidth(1.5f);
cursor.setSingleLine(true);
cursor.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL);
cursor.setHeaderHintColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueHeader));
cursor.setTransformHintToHeader(true);
cursor.setLineColors(Theme.getColor(Theme.key_windowBackgroundWhiteInputField), Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated), Theme.getColor(Theme.key_windowBackgroundWhiteRedText3));
return cursor;
}
@Override
public void onTransitionAnimationEnd(boolean isOpen, boolean backward) {
if (isOpen && !backward && currentProxyInfo == null) {
ipField.requestFocus();
AndroidUtilities.showKeyboard(ipField);
}
}
@Override
public ArrayList<ThemeDescription> getThemeDescriptions() {
final ThemeDescription.ThemeDescriptionDelegate delegate = () -> {
if (inputFields != null) {
for (int i = 0; i < inputFields.length; i++) {
inputFields[i].setLineColors(Theme.getColor(Theme.key_windowBackgroundWhiteInputField),
Theme.getColor(Theme.key_windowBackgroundWhiteInputFieldActivated),
Theme.getColor(Theme.key_windowBackgroundWhiteRedText3));
}
}
};
ArrayList<ThemeDescription> arrayList = new ArrayList<>();
arrayList.add(new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundGray));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_actionBarDefault));
arrayList.add(new ThemeDescription(scrollView, ThemeDescription.FLAG_LISTGLOWCOLOR, null, null, null, null, Theme.key_actionBarDefault));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_ITEMSCOLOR, null, null, null, null, Theme.key_actionBarDefaultIcon));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_TITLECOLOR, null, null, null, null, Theme.key_actionBarDefaultTitle));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SELECTORCOLOR, null, null, null, null, Theme.key_actionBarDefaultSelector));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SEARCH, null, null, null, null, Theme.key_actionBarDefaultSearch));
arrayList.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SEARCHPLACEHOLDER, null, null, null, null, Theme.key_actionBarDefaultSearchPlaceholder));
arrayList.add(new ThemeDescription(inputFieldsContainer, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundWhite));
arrayList.add(new ThemeDescription(linearLayout2, 0, new Class[]{View.class}, Theme.dividerPaint, null, null, Theme.key_divider));
arrayList.add(new ThemeDescription(null, 0, null, null, null, null, delegate, Theme.key_windowBackgroundWhiteBlueText4));
arrayList.add(new ThemeDescription(null, 0, null, null, null, null, delegate, Theme.key_windowBackgroundWhiteGrayText2));
if (inputFields != null) {
for (int a = 0; a < inputFields.length; a++) {
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_HINTTEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteHintText));
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_HINTTEXTCOLOR | ThemeDescription.FLAG_PROGRESSBAR, null, null, null, null, Theme.key_windowBackgroundWhiteBlueHeader));
arrayList.add(new ThemeDescription(inputFields[a], ThemeDescription.FLAG_CURSORCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(null, 0, null, null, null, delegate, Theme.key_windowBackgroundWhiteInputField));
arrayList.add(new ThemeDescription(null, 0, null, null, null, delegate, Theme.key_windowBackgroundWhiteInputFieldActivated));
arrayList.add(new ThemeDescription(null, 0, null, null, null, delegate, Theme.key_windowBackgroundWhiteRedText3));
}
} else {
arrayList.add(new ThemeDescription(null, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
arrayList.add(new ThemeDescription(null, ThemeDescription.FLAG_HINTTEXTCOLOR, null, null, null, null, Theme.key_windowBackgroundWhiteHintText));
}
arrayList.add(new ThemeDescription(bottomCell, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{TextInfoPrivacyCell.class}, null, null, null, Theme.key_windowBackgroundGrayShadow));
arrayList.add(new ThemeDescription(bottomCell, 0, new Class[]{TextInfoPrivacyCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText4));
arrayList.add(new ThemeDescription(bottomCell, ThemeDescription.FLAG_LINKCOLOR, new Class[]{TextInfoPrivacyCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteLinkText));
return arrayList;
}
}

View File

@ -1,91 +0,0 @@
package tw.nekomimi.nekogram.proxy.tcp2ws;
import org.telegram.messenger.FileLog;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class Tcp2wsServer extends Thread {
public final WsLoader.Bean bean;
public final int port;
public Tcp2wsServer(WsLoader.Bean bean, int port) {
this.bean = bean;
this.port = port;
}
public static final Map<String, Integer> mapper = Collections.unmodifiableMap(new HashMap<String, Integer>() {{
put("149.154.175.5", 1);
put("95.161.76.100", 2);
put("149.154.175.100", 3);
put("149.154.167.91", 4);
put("149.154.167.92", 4);
put("149.154.171.5", 5);
put("2001:b28:f23d:f001:0000:0000:0000:000a", 1);
put("2001:67c:4e8:f002:0000:0000:0000:000a", 2);
put("2001:b28:f23d:f003:0000:0000:0000:000a", 3);
put("2001:67c:4e8:f004:0000:0000:0000:000a", 4);
put("2001:b28:f23f:f005:0000:0000:0000:000a", 5);
put("149.154.161.144", 2);
put("149.154.167.", 2);
put("149.154.175.1", 3);
put("91.108.4.", 4);
put("149.154.164.", 4);
put("149.154.165.", 4);
put("149.154.166.", 4);
put("91.108.56.", 5);
put("2001:b28:f23d:f001:0000:0000:0000:000d", 1);
put("2001:67c:4e8:f002:0000:0000:0000:000d", 2);
put("2001:b28:f23d:f003:0000:0000:0000:000d", 3);
put("2001:67c:4e8:f004:0000:0000:0000:000d", 4);
put("2001:b28:f23f:f005:0000:0000:0000:000d", 5);
put("149.154.175.40", 6);
put("149.154.167.40", 7);
put("149.154.175.117", 8);
put("2001:b28:f23d:f001:0000:0000:0000:000e", 6);
put("2001:67c:4e8:f002:0000:0000:0000:000e", 7);
put("2001:b28:f23d:f003:0000:0000:0000:000e", 8);
}});
@Override
public void run() {
FileLog.d("SOCKS server started...");
try {
handleClients(port);
FileLog.d("SOCKS server stopped...");
} catch (Exception e) {
FileLog.d("SOCKS server crashed...");
FileLog.e(e);
interrupt();
}
}
protected void handleClients(int port) throws Exception {
final ServerSocket listenSocket = new ServerSocket(port);
listenSocket.setSoTimeout(2000);
FileLog.d("SOCKS server listening at port: " + listenSocket.getLocalPort());
while (isAlive() && !isInterrupted()) {
try {
final Socket clientSocket = listenSocket.accept();
FileLog.d("Connection from : " + clientSocket.getRemoteSocketAddress().toString());
new WsProxyHandler(clientSocket, bean).start();
} catch (InterruptedIOException e) {
// This exception is thrown when accept timeout is expired
} catch (Exception e) {
FileLog.e(e.getMessage(), e);
}
}
try {
listenSocket.close();
} catch (IOException e) {
FileLog.e(e);
}
}
}

View File

@ -1,73 +0,0 @@
package tw.nekomimi.nekogram.proxy.tcp2ws
import cn.hutool.core.codec.Base64
import cn.hutool.core.util.StrUtil
import okhttp3.Dns
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import tw.nekomimi.nekogram.NekoConfig
import java.net.InetAddress
class WsLoader {
lateinit var server: Tcp2wsServer
fun init(bean: Bean, port: Int) {
server = Tcp2wsServer(bean, port)
}
fun start() {
server.start()
}
fun stop() {
if (::server.isInitialized) {
server.interrupt()
}
}
companion object {
fun parse(url: String): Bean {
val lnk = url.replace("ws://", "http://")
.replace("wss://", "https://")
.toHttpUrlOrNull() ?: error("Invalid link")
val payloadStr = lnk.queryParameter("payload") ?: error("Missing payload")
val payload = Base64.decodeStr(payloadStr).split(",")
if (payload.size < 5) error("Invalid payload")
return Bean(
lnk.host,
payload,
lnk.isHttps,
lnk.fragment ?: ""
)
}
}
data class Bean(
var server: String = "",
var payload: List<String> = arrayListOf(),
var tls: Boolean = true,
var remarks: String = ""
) {
var payloadStr: String
get() = Base64.encodeUrlSafe(payload.joinToString(","))
set(value) {
payload = Base64.decodeStr(value).split(",")
}
override fun toString(): String {
val builder = HttpUrl.Builder()
.scheme("http")
.host(server)
.addQueryParameter("payload", payloadStr);
if (remarks.isNotBlank()) {
builder.fragment(remarks)
}
return builder.build().toString().replace("http://", if (tls) "wss://" else "ws://")
}
}
}

View File

@ -1,256 +0,0 @@
package tw.nekomimi.nekogram.proxy.tcp2ws;
import android.annotation.SuppressLint;
import com.neovisionaries.ws.client.ThreadType;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketAdapter;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFactory;
import com.neovisionaries.ws.client.WebSocketFrame;
import com.neovisionaries.ws.client.WebSocketListener;
import com.neovisionaries.ws.client.WebSocketState;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.common.value.qual.IntVal;
import org.telegram.messenger.FileLog;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocket;
import cn.hutool.http.ssl.AndroidSupportSSLFactory;
import cn.hutool.http.ssl.CustomProtocolsSSLFactory;
import tw.nekomimi.nekogram.NekoConfig;
import tw.nekomimi.nekogram.utils.DnsFactory;
public class WsProxyHandler extends Thread {
private InputStream clientInputStream = null;
private OutputStream clientOutputStream = null;
private final WsLoader.Bean bean;
private Socket clientSocket;
private WebSocket webSocket = null;
private final byte[] buffer = new byte[4096];
private String wsHost = "";
private final AtomicInteger wsStatus = new AtomicInteger(0);
private final static int STATUS_OPENED = 1;
private final static int STATUS_CLOSED = 2;
private final static int STATUS_FAILED = 3;
private final CountDownLatch connecting = new CountDownLatch(1);
public WsProxyHandler(Socket clientSocket, WsLoader.Bean bean) {
this.bean = bean;
this.clientSocket = clientSocket;
FileLog.d("ProxyHandler Created.");
}
@SuppressLint("DefaultLocale")
@Override
public void run() {
FileLog.d("Proxy to " + wsHost + "Started.");
try {
clientInputStream = clientSocket.getInputStream();
clientOutputStream = clientSocket.getOutputStream();
// Handle Socks5 HandShake
socks5Handshake();
FileLog.d("socks5 handshake and websocket connection done");
// Start read from client socket and send to websocket
this.clientSocket.setSoTimeout(1000);
while (clientSocket != null && webSocket != null && wsStatus.get() == STATUS_OPENED && !clientSocket.isClosed() && !clientSocket.isInputShutdown()) {
int readLen = 0;
try {
readLen = this.clientInputStream.read(buffer);
} catch (SocketTimeoutException ex) {
if (wsStatus.get() != STATUS_OPENED)
throw new Exception(String.format("[%s] timeout and ws closed", wsHost));
continue;
}
FileLog.d(String.format("[%s] read %d from local", wsHost, readLen));
if (readLen == -1) throw new Exception(String.format("[%s] socks closed", wsHost));
;
if (wsStatus.get() != STATUS_OPENED)
throw new Exception(String.format("[%s] ws closed when trying to write", wsHost));
;
this.webSocket.sendBinary(Arrays.copyOf(buffer, readLen));
}
} catch (SocketException se) {
if ("Socket closed".equals(se.getMessage())) {
FileLog.d("socket closed from ws when reading from client");
close();
} else {
FileLog.e(se);
close();
}
} catch (Exception e) {
FileLog.e(e);
close();
}
}
public void close() {
if (wsStatus.get() == STATUS_CLOSED)
return;
wsStatus.set(STATUS_CLOSED);
FileLog.d("ws handler closed");
try {
if (clientSocket != null)
clientSocket.close();
} catch (IOException e) {
// ignore
}
try {
if (webSocket != null) {
webSocket.sendClose();
}
} catch (Exception e) {
// ignore
}
clientSocket = null;
webSocket = null;
}
private void connectToServer(String wsHost) throws Exception {
this.wsHost = wsHost;
WebSocketFactory factory = new WebSocketFactory().setConnectionTimeout(5000);
webSocket = factory.createSocket((bean.getTls() ? "wss://" : "ws://") + wsHost + "/api");
webSocket.addListener(new WebSocketAdapter() {
@Override
public void onBinaryMessage(WebSocket websocket, byte[] binary) throws Exception {
WsProxyHandler.this.clientOutputStream.write(binary);
}
@Override
public void onError(WebSocket websocket, WebSocketException cause) throws Exception {
FileLog.e(cause);
wsStatus.set(STATUS_FAILED);
}
@Override
public void onConnectError(WebSocket websocket, WebSocketException exception) throws Exception {
FileLog.d(String.format("[%s] WS connect failed: %s", wsHost, exception.toString()));
wsStatus.set(STATUS_FAILED);
connecting.countDown();
}
@Override
public void onConnected(WebSocket websocket, Map<String, List<String>> headers) throws Exception {
FileLog.d(String.format("[%s] WS connected", wsHost));
wsStatus.set(STATUS_OPENED);
connecting.countDown();
}
});
webSocket.addProtocol("binary");
webSocket.connect();
}
private static final byte[] RESP_AUTH = new byte[]{0x05, 0x00};
private static final byte[] RESP_SUCCESS = new byte[]{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
private static final byte[] RESP_FAILED = new byte[]{0x05, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
private void socks5Handshake() throws Exception {
byte socksVersion = readOneByteFromClient();
if (socksVersion != 0x05) {
throw new Exception("Invalid socks version:" + socksVersion);
}
FileLog.d("Accepted socks5 requests.");
byte authMethodsLen = readOneByteFromClient();
boolean isNoAuthSupport = false;
for (int i = 0; i < authMethodsLen; i++) {
byte authMethod = readOneByteFromClient();
if (authMethod == 0x00)
isNoAuthSupport = true;
}
if (!isNoAuthSupport) throw new Exception("NO_AUTH is not supported from client.");
this.clientOutputStream.write(RESP_AUTH);
this.clientOutputStream.flush();
byte[] cmds = readBytesExactly(4);
// cmds[0] -> VER
// cmds[1] -> CMD
// cmds[2] -> RSV
// cmds[3] -> ADDR_TYPE
if (cmds[0] != 0x05 || cmds[1] != 0x01 || cmds[2] != 0x00)
throw new Exception("invalid socks5 cmds " + Arrays.toString(cmds));
int addrType = cmds[3];
String address;
if (addrType == 0x01) { // ipv4
address = InetAddress.getByAddress(readBytesExactly(4)).getHostAddress();
} else if (addrType == 0x04) { // ipv6
address = Inet6Address.getByAddress(readBytesExactly(16)).getHostAddress();
} else { // not supported: domain
throw new Exception("invalid addr type: " + addrType);
}
readBytesExactly(2); // read out port
String wsHost = getWsHost(address);
connectToServer(wsHost);
connecting.await();
if (wsStatus.get() == STATUS_OPENED) {
this.clientOutputStream.write(RESP_SUCCESS);
this.clientOutputStream.flush();
} else {
this.clientOutputStream.write(RESP_FAILED);
this.clientOutputStream.flush();
throw new Exception("websocket connect failed");
}
// just set status byte and ignore bnd.addr and bnd.port in RFC1928, since Telegram Android ignores it:
// proxyAuthState == 6 in tgnet/ConnectionSocket.cpp
}
private String getWsHost(String address) throws Exception {
Integer dcNumber = Tcp2wsServer.mapper.get(address);
for (int i = 1; dcNumber == null && i < 4; i++) {
dcNumber = Tcp2wsServer.mapper.get(address.substring(0, address.length() - i));
}
if (dcNumber == null)
throw new Exception("no matched dc: " + address);
if (dcNumber >= bean.getPayload().size())
throw new Exception("invalid dc number & payload: " + dcNumber);
String serverPrefix = bean.getPayload().get(dcNumber - 1);
String wsHost = serverPrefix + "." + this.bean.getServer();
FileLog.d("socks5 dest address: " + address + ", target ws host " + wsHost);
return wsHost;
}
private byte readOneByteFromClient() throws Exception {
return (byte) clientInputStream.read();
}
private byte[] readBytesExactly(int len) throws Exception {
byte[] ret = new byte[len];
int alreadyRead = 0;
while (alreadyRead < len) {
int read = this.clientInputStream.read(ret, alreadyRead, len - alreadyRead);
alreadyRead += read;
}
return ret;
}
}

View File

@ -1,690 +0,0 @@
@file:Suppress("UNCHECKED_CAST")
package tw.nekomimi.nekogram.utils
import android.Manifest
import android.app.Activity
import android.app.AlertDialog
import android.content.ClipboardManager
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.os.Build
import android.os.Environment
import android.util.Base64
import android.view.Gravity
import android.view.View
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.Toast
import androidx.core.view.setPadding
import com.github.shadowsocks.plugin.PluginOptions
import com.google.zxing.*
import com.google.zxing.common.GlobalHistogramBinarizer
import com.google.zxing.qrcode.QRCodeReader
import com.google.zxing.qrcode.QRCodeWriter
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import com.v2ray.ang.V2RayConfig
import com.v2ray.ang.V2RayConfig.SSR_PROTOCOL
import com.v2ray.ang.V2RayConfig.SS_PROTOCOL
import com.v2ray.ang.V2RayConfig.TROJAN_PROTOCOL
import com.v2ray.ang.V2RayConfig.VMESS1_PROTOCOL
import com.v2ray.ang.V2RayConfig.VMESS_PROTOCOL
import com.v2ray.ang.V2RayConfig.WSS_PROTOCOL
import com.v2ray.ang.V2RayConfig.WS_PROTOCOL
import com.v2ray.ang.dto.AngConfig
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.json.JSONArray
import org.json.JSONException
import org.telegram.messenger.*
import org.telegram.messenger.browser.Browser
import org.yaml.snakeyaml.Yaml
import tw.nekomimi.nekogram.ui.BottomBuilder
import tw.nekomimi.nekogram.proxy.ShadowsocksLoader
import tw.nekomimi.nekogram.proxy.ShadowsocksRLoader
import tw.nekomimi.nekogram.utils.AlertUtil.showToast
import java.io.File
import java.net.NetworkInterface
import java.util.*
import kotlin.collections.HashMap
object ProxyUtil {
@JvmStatic
fun isVPNEnabled(): Boolean {
val networkList = mutableListOf<String>()
runCatching {
Collections.list(NetworkInterface.getNetworkInterfaces()).forEach {
if (it.isUp) networkList.add(it.name)
}
}
return networkList.contains("tun0")
}
@JvmStatic
@JvmOverloads
fun parseProxies(text: String, tryDecode: Boolean = true): MutableList<String> {
if (tryDecode && !text.contains("proxies:")) {
try {
return parseProxies(String(Base64.decode(text, Base64.NO_PADDING)), false)
} catch (ignored: Exception) {
}
}
val proxies = mutableListOf<String>()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
try {
// sip008
val ssArray = JSONArray(text)
for (index in 0 until ssArray.length()) {
proxies.add(ShadowsocksLoader.Bean.parseJson(ssArray.getJSONObject(index)).toString())
}
return proxies
} catch (ignored: JSONException) {
}
if (text.contains("proxies:")) {
if (BuildVars.isMini) {
error(LocaleController.getString("MiniVersionAlert", R.string.MiniVersionAlert))
}
// clash
for (proxy in (Yaml().loadAs(text, Map::class.java)["proxies"] as List<Map<String, Any?>>)) {
val type = proxy["type"] as String
when (type) {
"ss" -> {
var pluginStr = ""
if (proxy.contains("plugin")) {
val opts = PluginOptions()
opts.id = proxy["plugin"] as String
opts.putAll(proxy["plugin-opts"] as Map<String, String?>)
pluginStr = opts.toString(false)
}
proxies.add(
ShadowsocksLoader.Bean(
proxy["server"] as String,
proxy["port"] as Int,
proxy["password"] as String,
proxy["cipher"] as String,
pluginStr,
proxy["name"] as String
).toString())
}
"vmess" -> {
val opts = AngConfig.VmessBean()
for (opt in proxy) {
when (opt.key) {
"name" -> opts.remarks = opt.value as String
"server" -> opts.address = opt.value as String
"port" -> opts.port = opt.value.toString().toInt()
"uuid" -> opts.id = opt.value as String
"alterId" -> opts.alterId = opt.value.toString().toInt()
"cipher" -> opts.security = opt.value as String
"network" -> opts.network = opt.value as String
"tls" -> opts.streamSecurity = if (opt.value?.toString() == "true") "tls" else opts.streamSecurity
"ws-path" -> opts.path = opt.value as String
"servername" -> opts.requestHost = opt.value as String
"h2-opts" -> for (h2Opt in (opt.value as Map<String, Any>)) {
when (h2Opt.key) {
"host" -> opts.requestHost = (h2Opt.value as List<String>).first()
"path" -> opts.path = h2Opt.value as String
}
}
"http-opts" -> for (httpOpt in (opt.value as Map<String, Any>)) {
when (httpOpt.key) {
"path" -> opts.path = (httpOpt.value as List<String>).first()
}
}
}
}
proxies.add(opts.toString())
}
"trojan" -> {
val opts = AngConfig.VmessBean()
opts.configType = V2RayConfig.EConfigType.Trojan
for (opt in proxy) {
when (opt.key) {
"name" -> opts.remarks = opt.value as String
"server" -> opts.address = opt.value as String
"port" -> opts.port = opt.value.toString().toInt()
"password" -> opts.id = opt.value as String
"sni" -> opts.requestHost = opt.value as String
}
}
proxies.add(opts.toString())
}
"ssr" -> {
val opts = ShadowsocksRLoader.Bean()
for (opt in proxy) {
when (opt.key) {
"name" -> opts.remarks = opt.value as String
"server" -> opts.host = opt.value as String
"port" -> opts.remotePort = opt.value.toString().toInt()
"cipher" -> opts.method = opt.value as String
"password" -> opts.password = opt.value as String
"obfs" -> opts.obfs = opt.value as String
"protocol" -> opts.protocol = opt.value as String
"obfs-param" -> opts.obfs_param = opt.value as String
"protocol-param" -> opts.protocol_param = opt.value as String
}
}
proxies.add(opts.toString())
}
}
}
return proxies
}
}
text.split('\n').map { it.split(" ") }.forEach {
it.forEach { line ->
if (line.startsWith("tg://proxy") ||
line.startsWith("tg://socks") ||
line.startsWith("https://t.me/proxy") ||
line.startsWith("https://t.me/socks") ||
line.startsWith(VMESS_PROTOCOL) ||
line.startsWith(VMESS1_PROTOCOL) ||
line.startsWith(SS_PROTOCOL) ||
line.startsWith(SSR_PROTOCOL) ||
line.startsWith(WS_PROTOCOL) ||
line.startsWith(WSS_PROTOCOL) ||
line.startsWith(TROJAN_PROTOCOL) /*||
line.startsWith(RB_PROTOCOL)*/) {
runCatching { proxies.add(SharedConfig.parseProxyInfo(line).toUrl()) }
}
}
}
if (proxies.isEmpty()) error("no proxy link found")
return proxies
}
@JvmStatic
fun importFromClipboard(ctx: Activity) {
var text = (ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager).primaryClip?.getItemAt(0)?.text?.toString()
val proxies = mutableListOf<SharedConfig.ProxyInfo>()
var error = false
text?.trim()?.split('\n')?.map { it.split(" ") }?.forEach {
it.forEach { line ->
if (line.startsWith("tg://proxy") ||
line.startsWith("tg://socks") ||
line.startsWith("https://t.me/proxy") ||
line.startsWith("https://t.me/socks") ||
line.startsWith(VMESS_PROTOCOL) ||
line.startsWith(VMESS1_PROTOCOL) ||
line.startsWith(SS_PROTOCOL) ||
line.startsWith(SSR_PROTOCOL) ||
line.startsWith(WS_PROTOCOL) ||
line.startsWith(WSS_PROTOCOL) ||
line.startsWith(TROJAN_PROTOCOL) /*||
line.startsWith(RB_PROTOCOL)*/) {
runCatching { proxies.add(SharedConfig.parseProxyInfo(line)) }.onFailure {
error = true
showToast(LocaleController.getString("BrokenLink", R.string.BrokenLink) + ": ${it.message ?: it.javaClass.simpleName}")
}
}
}
}
runCatching {
if (proxies.isNullOrEmpty() && !error) {
String(Base64.decode(text, Base64.NO_PADDING)).trim().split('\n').map { it.split(" ") }.forEach { str ->
str.forEach { line ->
if (line.startsWith("tg://proxy") ||
line.startsWith("tg://socks") ||
line.startsWith("https://t.me/proxy") ||
line.startsWith("https://t.me/socks") ||
line.startsWith(VMESS_PROTOCOL) ||
line.startsWith(VMESS1_PROTOCOL) ||
line.startsWith(SS_PROTOCOL) ||
line.startsWith(SSR_PROTOCOL) ||
line.startsWith(WS_PROTOCOL) ||
line.startsWith(WSS_PROTOCOL) ||
line.startsWith(TROJAN_PROTOCOL) /*||
line.startsWith(RB_PROTOCOL)*/) {
runCatching { proxies.add(SharedConfig.parseProxyInfo(line)) }.onFailure {
error = true
showToast(LocaleController.getString("BrokenLink", R.string.BrokenLink) + ": ${it.message ?: it.javaClass.simpleName}")
}
}
}
}
}
}
if (proxies.isNullOrEmpty()) {
if (!error) showToast(LocaleController.getString("BrokenLink", R.string.BrokenLink))
return
} else if (!error) {
AlertUtil.showSimpleAlert(ctx, LocaleController.getString("ImportedProxies", R.string.ImportedProxies) + "\n\n" + proxies.joinToString("\n") { it.title })
}
proxies.forEach {
SharedConfig.addProxy(it)
}
UIUtil.runOnUIThread {
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged)
}
}
@JvmStatic
fun importProxy(ctx: Context, link: String): Boolean {
runCatching {
if (link.startsWith(VMESS_PROTOCOL) || link.startsWith(VMESS1_PROTOCOL)) {
AndroidUtilities.showVmessAlert(ctx, SharedConfig.VmessProxy(link))
} else if (link.startsWith(TROJAN_PROTOCOL)) {
AndroidUtilities.showTrojanAlert(ctx, SharedConfig.VmessProxy(link))
} else if (link.startsWith(SS_PROTOCOL)) {
AndroidUtilities.showShadowsocksAlert(ctx, SharedConfig.ShadowsocksProxy(link))
} else if (link.startsWith(SSR_PROTOCOL)) {
AndroidUtilities.showShadowsocksRAlert(ctx, SharedConfig.ShadowsocksRProxy(link))
} else if (link.startsWith(WS_PROTOCOL) || link.startsWith(WSS_PROTOCOL)) {
AndroidUtilities.showWsAlert(ctx, SharedConfig.WsProxy(link))
} else {
val url = link.replace("tg://", "https://t.me/").toHttpUrlOrNull()!!
AndroidUtilities.showProxyAlert(ctx,
url.queryParameter("server") ?: return false,
url.queryParameter("port") ?: return false,
url.queryParameter("user"),
url.queryParameter("pass"),
url.queryParameter("secret"),
url.fragment)
}
return true
}.onFailure {
FileLog.e(it)
if (BuildVars.LOGS_ENABLED) {
AlertUtil.showSimpleAlert(ctx, it)
} else {
showToast("${LocaleController.getString("BrokenLink", R.string.BrokenLink)}: ${it.message}")
}
}
return false
}
@JvmStatic
fun importInBackground(link: String): SharedConfig.ProxyInfo {
val info = runCatching {
if (link.startsWith(VMESS_PROTOCOL) || link.startsWith(VMESS1_PROTOCOL)) {
SharedConfig.VmessProxy(link)
} else if (link.startsWith(SS_PROTOCOL)) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
error(LocaleController.getString("MinApi21Required", R.string.MinApi21Required))
}
SharedConfig.ShadowsocksProxy(link)
} else if (link.startsWith(SSR_PROTOCOL)) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
error(LocaleController.getString("MinApi21Required", R.string.MinApi21Required))
}
SharedConfig.ShadowsocksRProxy(link)
} else if (link.startsWith(WS_PROTOCOL) || link.startsWith(WSS_PROTOCOL)) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
error(LocaleController.getString("MinApi21Required", R.string.MinApi21Required))
}
SharedConfig.WsProxy(link)
} else {
SharedConfig.ProxyInfo.fromUrl(link)
}
}.getOrThrow()
if (!(SharedConfig.addProxy(info) === info)) {
error("already exists")
}
return info
}
@JvmStatic
fun shareProxy(ctx: Activity, info: SharedConfig.ProxyInfo, type: Int) {
val url = info.toUrl();
if (type == 1) {
AndroidUtilities.addToClipboard(url)
Toast.makeText(ctx, LocaleController.getString("LinkCopied", R.string.LinkCopied), Toast.LENGTH_LONG).show()
} else if (type == 0) {
val shareIntent = Intent(Intent.ACTION_SEND)
shareIntent.type = "text/plain"
shareIntent.putExtra(Intent.EXTRA_TEXT, url)
val chooserIntent = Intent.createChooser(shareIntent, LocaleController.getString("ShareLink", R.string.ShareLink))
chooserIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
ctx.startActivity(chooserIntent)
} else {
showQrDialog(ctx, url)
}
}
@JvmStatic
fun getOwnerActivity(ctx: Context): Activity {
if (ctx is Activity) return ctx
if (ctx is ContextWrapper) return getOwnerActivity(ctx.baseContext)
error("unable cast ${ctx.javaClass.name} to activity")
}
@JvmStatic
@JvmOverloads
fun showQrDialog(ctx: Context, text: String, icon: ((Int) -> Bitmap)? = null): AlertDialog {
val code = createQRCode(text, icon = icon)
ctx.setTheme(R.style.Theme_TMessages)
return AlertDialog.Builder(ctx).setView(LinearLayout(ctx).apply {
gravity = Gravity.CENTER
setBackgroundColor(Color.TRANSPARENT)
addView(LinearLayout(ctx).apply {
val root = this
gravity = Gravity.CENTER
setBackgroundColor(Color.WHITE)
setPadding(AndroidUtilities.dp(16f))
val width = AndroidUtilities.dp(260f)
addView(ImageView(ctx).apply {
setImageBitmap(code)
scaleType = ImageView.ScaleType.FIT_XY
setOnLongClickListener {
val builder = BottomBuilder(ctx)
builder.addItems(arrayOf(
LocaleController.getString("SaveToGallery", R.string.SaveToGallery),
LocaleController.getString("Cancel", R.string.Cancel)
), intArrayOf(
R.drawable.baseline_image_24,
R.drawable.baseline_cancel_24
)) { i, _, _ ->
if (i == 0) {
if (Build.VERSION.SDK_INT >= 23 && ctx.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
getOwnerActivity(ctx).requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 4)
return@addItems
}
val saveTo = File(Environment.getExternalStorageDirectory(), "${Environment.DIRECTORY_PICTURES}/share_${text.hashCode()}.jpg")
saveTo.parentFile?.mkdirs()
runCatching {
saveTo.createNewFile()
saveTo.outputStream().use {
loadBitmapFromView(root).compress(Bitmap.CompressFormat.JPEG, 100, it);
}
AndroidUtilities.addMediaToGallery(saveTo.path)
showToast(LocaleController.getString("PhotoSavedHint", R.string.PhotoSavedHint))
}.onFailure {
FileLog.e(it)
showToast(it)
}
}
}
builder.show()
return@setOnLongClickListener true
}
}, LinearLayout.LayoutParams(width, width))
}, LinearLayout.LayoutParams(-2, -2).apply {
gravity = Gravity.CENTER
})
}).create().apply {
show()
window?.setBackgroundDrawableResource(android.R.color.transparent)
}
}
private fun loadBitmapFromView(v: View): Bitmap {
val b = Bitmap.createBitmap(v.width, v.height, Bitmap.Config.ARGB_8888)
val c = Canvas(b)
v.layout(v.left, v.top, v.right, v.bottom)
v.draw(c)
return b
}
@JvmStatic
fun createQRCode(text: String, size: Int = 768, icon: ((Int) -> Bitmap)? = null): Bitmap {
return try {
val hints = HashMap<EncodeHintType, Any>()
hints[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.M
QRCodeWriter().encode(text, BarcodeFormat.QR_CODE, size, size, hints, null, null, icon)
} catch (e: WriterException) {
FileLog.e(e);
Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
}
}
val qrReader = QRCodeReader()
@JvmStatic
fun tryReadQR(ctx: Activity, bitmap: Bitmap) {
val intArray = IntArray(bitmap.width * bitmap.height)
bitmap.getPixels(intArray, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
val source = RGBLuminanceSource(bitmap.width, bitmap.height, intArray)
try {
val result = try {
qrReader.decode(BinaryBitmap(GlobalHistogramBinarizer(source)), mapOf(
DecodeHintType.TRY_HARDER to true
))
} catch (e: NotFoundException) {
qrReader.decode(BinaryBitmap(GlobalHistogramBinarizer(source.invert())), mapOf(
DecodeHintType.TRY_HARDER to true
))
}
showLinkAlert(ctx, result.text)
} catch (e: Throwable) {
showToast(LocaleController.getString("NoQrFound", R.string.NoQrFound))
}
}
@JvmStatic
@JvmOverloads
fun showLinkAlert(ctx: Activity, text: String, tryInternal: Boolean = true) {
val builder = BottomBuilder(ctx)
if (tryInternal) {
runCatching {
if (Browser.isInternalUrl(text, booleanArrayOf(false))) {
Browser.openUrl(ctx, text)
return
}
}
}
builder.addTitle(text)
builder.addItems(arrayOf(
LocaleController.getString("Open", R.string.Open),
LocaleController.getString("Copy", R.string.Copy),
LocaleController.getString("ShareQRCode", R.string.ShareQRCode)
), intArrayOf(
R.drawable.baseline_open_in_browser_24,
R.drawable.baseline_content_copy_24,
R.drawable.wallet_qr
)) { which, _, _ ->
when (which) {
0 -> Browser.openUrl(ctx, text)
1 -> {
AndroidUtilities.addToClipboard(text)
showToast(LocaleController.getString("LinkCopied", R.string.LinkCopied))
}
else -> showQrDialog(ctx, text)
}
}
builder.show()
}
}

View File

@ -0,0 +1,242 @@
@file:Suppress("UNCHECKED_CAST")
package tw.nekomimi.nekogram.utils
import android.Manifest
import android.app.Activity
import android.app.AlertDialog
import android.content.Context
import android.content.ContextWrapper
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.os.Build
import android.os.Environment
import android.view.Gravity
import android.view.View
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.core.view.setPadding
import com.google.zxing.*
import com.google.zxing.common.GlobalHistogramBinarizer
import com.google.zxing.qrcode.QRCodeReader
import com.google.zxing.qrcode.QRCodeWriter
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import org.telegram.messenger.*
import org.telegram.messenger.browser.Browser
import tw.nekomimi.nekogram.ui.BottomBuilder
import tw.nekomimi.nekogram.utils.AlertUtil.showToast
import java.io.File
import java.util.*
import kotlin.collections.HashMap
object QrUtil {
@JvmStatic
fun getOwnerActivity(ctx: Context): Activity {
if (ctx is Activity) return ctx
if (ctx is ContextWrapper) return getOwnerActivity(ctx.baseContext)
error("unable cast ${ctx.javaClass.name} to activity")
}
@JvmStatic
@JvmOverloads
fun showQrDialog(ctx: Context, text: String, icon: ((Int) -> Bitmap)? = null): AlertDialog {
val code = createQRCode(text, icon = icon)
ctx.setTheme(R.style.Theme_TMessages)
return AlertDialog.Builder(ctx).setView(LinearLayout(ctx).apply {
gravity = Gravity.CENTER
setBackgroundColor(Color.TRANSPARENT)
addView(LinearLayout(ctx).apply {
val root = this
gravity = Gravity.CENTER
setBackgroundColor(Color.WHITE)
setPadding(AndroidUtilities.dp(16f))
val width = AndroidUtilities.dp(260f)
addView(ImageView(ctx).apply {
setImageBitmap(code)
scaleType = ImageView.ScaleType.FIT_XY
setOnLongClickListener {
val builder = BottomBuilder(ctx)
builder.addItems(arrayOf(
LocaleController.getString("SaveToGallery", R.string.SaveToGallery),
LocaleController.getString("Cancel", R.string.Cancel)
), intArrayOf(
R.drawable.baseline_image_24,
R.drawable.baseline_cancel_24
)) { i, _, _ ->
if (i == 0) {
if (Build.VERSION.SDK_INT >= 23 && ctx.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
getOwnerActivity(ctx).requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 4)
return@addItems
}
val saveTo = File(Environment.getExternalStorageDirectory(), "${Environment.DIRECTORY_PICTURES}/share_${text.hashCode()}.jpg")
saveTo.parentFile?.mkdirs()
runCatching {
saveTo.createNewFile()
saveTo.outputStream().use {
loadBitmapFromView(root).compress(Bitmap.CompressFormat.JPEG, 100, it);
}
AndroidUtilities.addMediaToGallery(saveTo.path)
showToast(LocaleController.getString("PhotoSavedHint", R.string.PhotoSavedHint))
}.onFailure {
FileLog.e(it)
showToast(it)
}
}
}
builder.show()
return@setOnLongClickListener true
}
}, LinearLayout.LayoutParams(width, width))
}, LinearLayout.LayoutParams(-2, -2).apply {
gravity = Gravity.CENTER
})
}).create().apply {
show()
window?.setBackgroundDrawableResource(android.R.color.transparent)
}
}
private fun loadBitmapFromView(v: View): Bitmap {
val b = Bitmap.createBitmap(v.width, v.height, Bitmap.Config.ARGB_8888)
val c = Canvas(b)
v.layout(v.left, v.top, v.right, v.bottom)
v.draw(c)
return b
}
@JvmStatic
fun createQRCode(text: String, size: Int = 768, icon: ((Int) -> Bitmap)? = null): Bitmap {
return try {
val hints = HashMap<EncodeHintType, Any>()
hints[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.M
QRCodeWriter().encode(text, BarcodeFormat.QR_CODE, size, size, hints, null, null, icon)
} catch (e: WriterException) {
FileLog.e(e);
Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
}
}
val qrReader = QRCodeReader()
@JvmStatic
fun tryReadQR(ctx: Activity, bitmap: Bitmap) {
val intArray = IntArray(bitmap.width * bitmap.height)
bitmap.getPixels(intArray, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
val source = RGBLuminanceSource(bitmap.width, bitmap.height, intArray)
try {
val result = try {
qrReader.decode(BinaryBitmap(GlobalHistogramBinarizer(source)), mapOf(
DecodeHintType.TRY_HARDER to true
))
} catch (e: NotFoundException) {
qrReader.decode(BinaryBitmap(GlobalHistogramBinarizer(source.invert())), mapOf(
DecodeHintType.TRY_HARDER to true
))
}
showLinkAlert(ctx, result.text)
} catch (e: Throwable) {
showToast(LocaleController.getString("NoQrFound", R.string.NoQrFound))
}
}
@JvmStatic
@JvmOverloads
fun showLinkAlert(ctx: Activity, text: String, tryInternal: Boolean = true) {
val builder = BottomBuilder(ctx)
if (tryInternal) {
runCatching {
if (Browser.isInternalUrl(text, booleanArrayOf(false))) {
Browser.openUrl(ctx, text)
return
}
}
}
builder.addTitle(text)
builder.addItems(arrayOf(
LocaleController.getString("Open", R.string.Open),
LocaleController.getString("Copy", R.string.Copy),
LocaleController.getString("ShareQRCode", R.string.ShareQRCode)
), intArrayOf(
R.drawable.baseline_open_in_browser_24,
R.drawable.baseline_content_copy_24,
R.drawable.wallet_qr
)) { which, _, _ ->
when (which) {
0 -> Browser.openUrl(ctx, text)
1 -> {
AndroidUtilities.addToClipboard(text)
showToast(LocaleController.getString("LinkCopied", R.string.LinkCopied))
}
else -> showQrDialog(ctx, text)
}
}
builder.show()
}
}

View File

@ -7,6 +7,3 @@ source "bin/init/env.sh"
bin/init/libs/libvpx.sh
bin/init/libs/ffmpeg.sh
bin/init/libs/boringssl.sh
# Build v2ray-core
bin/libs/v2ray/build.sh

View File

@ -29,7 +29,3 @@ rm jni/boringssl/util/ar/testdata/mac/libsample.a
rm jni/boringssl/util/ar/testdata/linux/libsample.a
popd
rm -rf ssr-libev/src/main/jni/pcre/dist/testdata
rm -rf ssr-libev/src/main/jni/mbedtls/programs/fuzz/corpuses
rm -rf ssr-libev/src/main/jni/mbedtls/tests/data_files

View File

@ -1,9 +0,0 @@
#!/bin/bash
source "bin/init/env.sh"
git submodule update --init ss-rust/src/main/rust/shadowsocks-rust
rm -rf ss-rust/build/outputs/aar
./gradlew ss-rust:assembleRelease || exit 1
mkdir -p TMessagesProj/libs
cp ss-rust/build/outputs/aar/* TMessagesProj/libs

View File

@ -1,9 +0,0 @@
#!/bin/bash
source "bin/init/env.sh"
git submodule update --init 'ssr-libev/src/main/jni/*'
rm -rf ssr-libev/build/outputs/aar
./gradlew ssr-libev:assembleRelease || exit 1
mkdir -p TMessagesProj/libs
cp ssr-libev/build/outputs/aar/* TMessagesProj/libs

View File

@ -1,6 +1,3 @@
#!/bin/bash
bin/libs/v2ray.sh || exit 1
bin/libs/shadowsocks.sh || exit 1
bin/libs/ssr.sh || exit 1
bin/libs/native.sh || exit 1

View File

@ -1,4 +0,0 @@
#!/bin/bash
bin/libs/v2ray/init.sh
bin/libs/v2ray/build.sh

View File

@ -1,12 +0,0 @@
#!/usr/bin/env bash
source "bin/init/env.sh"
export GO111MOUDLE=on
export GO386=softfloat
cd "$PROJECT/v2ray"
gomobile init
gomobile bind -v -ldflags='-s -w' . || exit 1
mkdir -p "$PROJECT/TMessagesProj/libs"
/bin/cp -f libv2ray.aar "$PROJECT/TMessagesProj/libs"

View File

@ -1,11 +0,0 @@
#!/usr/bin/env bash
source "bin/init/env.sh"
export GO111MOUDLE=on
export PATH="$PATH:$(go env GOPATH)/bin"
cd $PROJECT
[ -f v2ray/go.mod ] || git submodule update --init v2ray
cd v2ray
git reset --hard && git clean -fdx
go mod download -x && go get -v golang.org/x/mobile/cmd/... || exit 1

1
ss-rust/.gitignore vendored
View File

@ -1 +0,0 @@
/build

View File

@ -1,77 +0,0 @@
import com.android.build.gradle.internal.tasks.factory.dependsOn
plugins {
id("com.android.library")
id("org.mozilla.rust-android-gradle.rust-android")
}
var targetAbi = ""
if (gradle.startParameter.taskNames.isNotEmpty()) {
if (gradle.startParameter.taskNames.size == 1) {
val targetTask = gradle.startParameter.taskNames[0].toLowerCase()
if (targetTask.contains("arm64")) {
targetAbi = "arm64"
} else if (targetTask.contains("arm")) {
targetAbi = "arm"
}
}
}
android {
ndkVersion = rootProject.extra.get("ndkVersion").toString()
compileSdk = 31
defaultConfig {
minSdk = 23
targetSdk = 31
}
buildToolsVersion = "31.0.0"
namespace = "io.nekohasekai.ss_rust"
if (targetAbi.isNotBlank()) splits.abi {
reset()
include(* when (targetAbi) {
"arm" -> arrayOf("armeabi-v7a")
"arm64" -> arrayOf("arm64-v8a")
else -> arrayOf("x86", "x86_64")
})
}
}
cargo {
module = "src/main/rust/shadowsocks-rust"
libname = "ss-local"
targets = when {
targetAbi.isBlank() -> listOf("arm", "arm64", "x86", "x86_64")
targetAbi == "arm" -> listOf("arm")
targetAbi == "arm64" -> listOf("arm64")
else -> listOf("arm", "arm64")
}
profile = findProperty("CARGO_PROFILE")?.toString() ?: "release"
extraCargoBuildArguments = listOf("--bin", "sslocal")
featureSpec.noDefaultBut(arrayOf(
"stream-cipher",
"logging",
"local-flow-stat",
"local-dns"))
exec = { spec, toolchain ->
spec.environment("RUST_ANDROID_GRADLE_LINKER_WRAPPER_PY", "$projectDir/$module/../linker-wrapper.py")
spec.environment("RUST_ANDROID_GRADLE_TARGET", "target/${toolchain.target}/$profile/lib$libname.so")
}
}
tasks.whenTaskAdded {
when (name) {
"mergeDebugJniLibFolders", "mergeReleaseJniLibFolders" -> dependsOn("cargoBuild")
}
}
tasks.register<Exec>("cargoClean") {
executable("cargo") // cargo.cargoCommand
args("clean")
workingDir("$projectDir/${cargo.module}")
}
tasks.clean.dependsOn("cargoClean")

View File

@ -1,3 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@ -1,18 +0,0 @@
from __future__ import absolute_import, print_function, unicode_literals
import os
import pipes
import shutil
import subprocess
import sys
args = [os.environ['RUST_ANDROID_GRADLE_CC'], os.environ['RUST_ANDROID_GRADLE_CC_LINK_ARG']] + sys.argv[1:]
# This only appears when the subprocess call fails, but it's helpful then.
printable_cmd = ' '.join(pipes.quote(arg) for arg in args)
print(printable_cmd)
code = subprocess.call(args)
if code == 0:
shutil.copyfile(sys.argv[sys.argv.index('-o') + 1], os.environ['RUST_ANDROID_GRADLE_TARGET'])
sys.exit(code)

@ -1 +0,0 @@
Subproject commit f805b5d3503e5ca0f85c22dabdeac3341618ec86

View File

@ -1 +0,0 @@
/build

View File

@ -1,55 +0,0 @@
plugins {
id 'com.android.library'
}
def targetAbi = ""
if (!gradle.startParameter.taskNames.isEmpty()) {
if (gradle.startParameter.taskNames.size == 1) {
def targetTask = gradle.startParameter.taskNames[0].toLowerCase()
if (targetTask.contains("arm64")) {
targetAbi = "arm64"
} else if (targetTask.contains("arm")) {
targetAbi = "arm"
}
} else {
targetAbi = "~"
}
}
android {
compileSdkVersion 30
buildToolsVersion '30.0.3'
ndkVersion rootProject.ext.ndkVersion
defaultConfig {
minSdkVersion 19
targetSdkVersion 30
externalNativeBuild {
ndkBuild {
if (!targetAbi.isBlank()) {
if (targetAbi == "arm64") {
abiFilters 'arm64-v8a'
} else if (targetAbi == "arm") {
abiFilters 'armeabi-v7a'
} else {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
} else {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
arguments "NDK_APPLICATION_MK:=src/main/jni/Application.mk", "APP_PLATFORM:=android-21", "--jobs=${Runtime.getRuntime().availableProcessors()}"
}
}
}
externalNativeBuild {
ndkBuild {
path 'src/main/jni/Android.mk'
}
}
namespace 'io.nekohasekai.ssr_libev'
}

View File

@ -1,3 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@ -1,293 +0,0 @@
# Copyright (C) 2009 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
LOCAL_PATH := $(call my-dir)
ROOT_PATH := $(LOCAL_PATH)
BUILD_SHARED_EXECUTABLE := $(LOCAL_PATH)/build-shared-executable.mk
########################################################
## libsodium
########################################################
include $(CLEAR_VARS)
SODIUM_SOURCE := \
crypto_aead/aes256gcm/aesni/aead_aes256gcm_aesni.c \
crypto_aead/chacha20poly1305/sodium/aead_chacha20poly1305.c \
crypto_aead/xchacha20poly1305/sodium/aead_xchacha20poly1305.c \
crypto_core/ed25519/ref10/ed25519_ref10.c \
crypto_core/hchacha20/core_hchacha20.c \
crypto_core/salsa/ref/core_salsa_ref.c \
crypto_generichash/blake2b/ref/blake2b-compress-ref.c \
crypto_generichash/blake2b/ref/blake2b-ref.c \
crypto_generichash/blake2b/ref/generichash_blake2b.c \
crypto_onetimeauth/poly1305/onetimeauth_poly1305.c \
crypto_onetimeauth/poly1305/donna/poly1305_donna.c \
crypto_pwhash/crypto_pwhash.c \
crypto_pwhash/argon2/argon2-core.c \
crypto_pwhash/argon2/argon2.c \
crypto_pwhash/argon2/argon2-encoding.c \
crypto_pwhash/argon2/argon2-fill-block-ref.c \
crypto_pwhash/argon2/blake2b-long.c \
crypto_pwhash/argon2/pwhash_argon2i.c \
crypto_scalarmult/curve25519/scalarmult_curve25519.c \
crypto_scalarmult/curve25519/ref10/x25519_ref10.c \
crypto_stream/chacha20/stream_chacha20.c \
crypto_stream/chacha20/ref/chacha20_ref.c \
crypto_stream/salsa20/stream_salsa20.c \
crypto_stream/salsa20/ref/salsa20_ref.c \
crypto_verify/sodium/verify.c \
randombytes/randombytes.c \
randombytes/sysrandom/randombytes_sysrandom.c \
sodium/core.c \
sodium/runtime.c \
sodium/utils.c \
sodium/version.c
LOCAL_MODULE := sodium
LOCAL_CFLAGS += -I$(LOCAL_PATH)/libsodium/src/libsodium/include \
-I$(LOCAL_PATH)/include \
-I$(LOCAL_PATH)/include/sodium \
-I$(LOCAL_PATH)/libsodium/src/libsodium/include/sodium \
-DPACKAGE_NAME=\"libsodium\" -DPACKAGE_TARNAME=\"libsodium\" \
-DPACKAGE_VERSION=\"1.0.15\" -DPACKAGE_STRING=\"libsodium-1.0.15\" \
-DPACKAGE_BUGREPORT=\"https://github.com/jedisct1/libsodium/issues\" \
-DPACKAGE_URL=\"https://github.com/jedisct1/libsodium\" \
-DPACKAGE=\"libsodium\" -DVERSION=\"1.0.15\" \
-DHAVE_PTHREAD=1 \
-DSTDC_HEADERS=1 \
-DHAVE_SYS_TYPES_H=1 \
-DHAVE_SYS_STAT_H=1 \
-DHAVE_STDLIB_H=1 \
-DHAVE_STRING_H=1 \
-DHAVE_MEMORY_H=1 \
-DHAVE_STRINGS_H=1 \
-DHAVE_INTTYPES_H=1 \
-DHAVE_STDINT_H=1 \
-DHAVE_UNISTD_H=1 \
-D__EXTENSIONS__=1 \
-D_ALL_SOURCE=1 \
-D_GNU_SOURCE=1 \
-D_POSIX_PTHREAD_SEMANTICS=1 \
-D_TANDEM_SOURCE=1 \
-DHAVE_DLFCN_H=1 \
-DLT_OBJDIR=\".libs/\" \
-DHAVE_SYS_MMAN_H=1 \
-DNATIVE_LITTLE_ENDIAN=1 \
-DASM_HIDE_SYMBOL=.hidden \
-DHAVE_WEAK_SYMBOLS=1 \
-DHAVE_ATOMIC_OPS=1 \
-DHAVE_ARC4RANDOM=1 \
-DHAVE_ARC4RANDOM_BUF=1 \
-DHAVE_MMAP=1 \
-DHAVE_MLOCK=1 \
-DHAVE_MADVISE=1 \
-DHAVE_MPROTECT=1 \
-DHAVE_NANOSLEEP=1 \
-DHAVE_POSIX_MEMALIGN=1 \
-DHAVE_GETPID=1 \
-DCONFIGURED=1
LOCAL_SRC_FILES := $(addprefix libsodium/src/libsodium/,$(SODIUM_SOURCE))
include $(BUILD_STATIC_LIBRARY)
########################################################
## libancillary
########################################################
include $(CLEAR_VARS)
ANCILLARY_SOURCE := fd_recv.c fd_send.c
LOCAL_MODULE := libancillary
LOCAL_CFLAGS += -I$(LOCAL_PATH)/libancillary
LOCAL_SRC_FILES := $(addprefix libancillary/, $(ANCILLARY_SOURCE))
include $(BUILD_STATIC_LIBRARY)
########################################################
## libipset
########################################################
include $(CLEAR_VARS)
bdd_src = bdd/assignments.c bdd/basics.c bdd/bdd-iterator.c bdd/expanded.c \
bdd/reachable.c bdd/read.c bdd/write.c
map_src = map/allocation.c map/inspection.c map/ipv4_map.c map/ipv6_map.c \
map/storage.c
set_src = set/allocation.c set/inspection.c set/ipv4_set.c set/ipv6_set.c \
set/iterator.c set/storage.c
IPSET_SOURCE := general.c $(bdd_src) $(map_src) $(set_src)
LOCAL_MODULE := libipset
LOCAL_CFLAGS += -I$(LOCAL_PATH)/shadowsocks-libev/libipset/include \
-I$(LOCAL_PATH)/shadowsocks-libev/libcork/include
LOCAL_SRC_FILES := $(addprefix shadowsocks-libev/libipset/,$(IPSET_SOURCE))
include $(BUILD_STATIC_LIBRARY)
########################################################
## libcork
########################################################
include $(CLEAR_VARS)
cli_src := cli/commands.c
core_src := core/allocator.c core/error.c core/gc.c \
core/hash.c core/ip-address.c core/mempool.c \
core/timestamp.c core/u128.c
ds_src := ds/array.c ds/bitset.c ds/buffer.c ds/dllist.c \
ds/file-stream.c ds/hash-table.c ds/managed-buffer.c \
ds/ring-buffer.c ds/slice.c
posix_src := posix/directory-walker.c posix/env.c posix/exec.c \
posix/files.c posix/process.c posix/subprocess.c
pthreads_src := pthreads/thread.c
CORK_SOURCE := $(cli_src) $(core_src) $(ds_src) $(posix_src) $(pthreads_src)
LOCAL_MODULE := libcork
LOCAL_CFLAGS += -I$(LOCAL_PATH)/shadowsocks-libev/libcork/include \
-DCORK_API=CORK_LOCAL
LOCAL_SRC_FILES := $(addprefix shadowsocks-libev/libcork/,$(CORK_SOURCE))
include $(BUILD_STATIC_LIBRARY)
########################################################
## libudns
########################################################
include $(CLEAR_VARS)
UDNS_SOURCES := udns_dn.c udns_dntosp.c udns_parse.c udns_resolver.c udns_init.c \
udns_misc.c udns_XtoX.c \
udns_rr_a.c udns_rr_ptr.c udns_rr_mx.c udns_rr_txt.c udns_bl.c \
udns_rr_srv.c udns_rr_naptr.c udns_codes.c udns_jran.c
LOCAL_MODULE := libudns
LOCAL_CFLAGS += -I$(LOCAL_PATH)/shadowsocks-libev/libudns \
-DHAVE_DECL_INET_NTOP
LOCAL_SRC_FILES := $(addprefix shadowsocks-libev/libudns/,$(UDNS_SOURCES))
include $(BUILD_STATIC_LIBRARY)
########################################################
## libev
########################################################
include $(CLEAR_VARS)
LOCAL_MODULE := libev
LOCAL_CFLAGS += -I$(LOCAL_PATH)/include/libev
LOCAL_SRC_FILES := \
shadowsocks-libev/libev/ev.c \
shadowsocks-libev/libev/event.c
include $(BUILD_STATIC_LIBRARY)
########################################################
## shadowsocks-libev local
########################################################
include $(CLEAR_VARS)
SHADOWSOCKS_SOURCES := local.c cache.c udprelay.c encrypt.c \
utils.c netutils.c json.c jconf.c acl.c http.c tls.c rule.c \
android.c
LOCAL_MODULE := ssr-local
LOCAL_SRC_FILES := $(addprefix shadowsocks-libev/src/, $(SHADOWSOCKS_SOURCES))
LOCAL_CFLAGS := -Wall -fno-strict-aliasing -DMODULE_LOCAL \
-DUSE_CRYPTO_MBEDTLS -DANDROID -DHAVE_CONFIG_H \
-DCONNECT_IN_PROGRESS=EINPROGRESS \
-I$(LOCAL_PATH)/include/shadowsocks-libev \
-I$(LOCAL_PATH)/include \
-I$(LOCAL_PATH)/libancillary \
-I$(LOCAL_PATH)/mbedtls/include \
-I$(LOCAL_PATH)/pcre \
-I$(LOCAL_PATH)/shadowsocks-libev/libudns \
-I$(LOCAL_PATH)/shadowsocks-libev/libcork/include \
-I$(LOCAL_PATH)/libsodium/src/libsodium/include \
-I$(LOCAL_PATH)/libsodium/src/libsodium/include/sodium \
-I$(LOCAL_PATH)/shadowsocks-libev/libipset/include \
-I$(LOCAL_PATH)/shadowsocks-libev/libev \
-I$(LOCAL_PATH)/shadowsocks-libev/src
LOCAL_STATIC_LIBRARIES := libev libmbedtls libipset libcork libudns \
libsodium libancillary libpcre
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_EXECUTABLE)
########################################################
## mbed TLS
########################################################
include $(CLEAR_VARS)
LOCAL_MODULE := mbedtls
LOCAL_C_INCLUDES := $(LOCAL_PATH)/mbedtls/include
MBEDTLS_SOURCES := $(wildcard $(LOCAL_PATH)/mbedtls/library/*.c)
LOCAL_SRC_FILES := $(MBEDTLS_SOURCES:$(LOCAL_PATH)/%=%)
include $(BUILD_STATIC_LIBRARY)
########################################################
## pcre
########################################################
include $(CLEAR_VARS)
LOCAL_MODULE := pcre
LOCAL_CFLAGS += -DHAVE_CONFIG_H
LOCAL_C_INCLUDES := $(LOCAL_PATH)/pcre/dist $(LOCAL_PATH)/pcre
libpcre_src_files := \
dist/pcre_byte_order.c \
dist/pcre_compile.c \
dist/pcre_config.c \
dist/pcre_dfa_exec.c \
dist/pcre_exec.c \
dist/pcre_fullinfo.c \
dist/pcre_get.c \
dist/pcre_globals.c \
dist/pcre_jit_compile.c \
dist/pcre_maketables.c \
dist/pcre_newline.c \
dist/pcre_ord2utf8.c \
dist/pcre_refcount.c \
dist/pcre_string_utils.c \
dist/pcre_study.c \
dist/pcre_tables.c \
dist/pcre_ucd.c \
dist/pcre_valid_utf8.c \
dist/pcre_version.c \
dist/pcre_xclass.c
LOCAL_SRC_FILES := $(addprefix pcre/, $(libpcre_src_files)) $(LOCAL_PATH)/patch/pcre/pcre_chartables.c
include $(BUILD_STATIC_LIBRARY)

View File

@ -1,4 +0,0 @@
APP_CFLAGS := -fdata-sections -ffunction-sections -fvisibility=hidden -fvisibility-inlines-hidden
APP_LDFLAGS := -Wl,--hash-style=both -Wl,-exclude-libs,ALL -Wl,--gc-sections
APP_THIN_ARCHIVE := true
APP_STL := c++_static

View File

@ -1,31 +0,0 @@
# Copyright (C) 2009 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# this file is included from Android.mk files to build a target-specific
# executable program
#
# Modified by @Mygod, based on:
# https://android.googlesource.com/platform/ndk/+/a355a4e/build/core/build-shared-library.mk
# https://android.googlesource.com/platform/ndk/+/a355a4e/build/core/build-executable.mk
LOCAL_BUILD_SCRIPT := BUILD_EXECUTABLE
LOCAL_MAKEFILE := $(local-makefile)
$(call check-defined-LOCAL_MODULE,$(LOCAL_BUILD_SCRIPT))
$(call check-LOCAL_MODULE,$(LOCAL_MAKEFILE))
$(call check-LOCAL_MODULE_FILENAME)
# we are building target objects
my := TARGET_
$(call handle-module-filename,lib,$(TARGET_SONAME_EXTENSION))
$(call handle-module-built)
LOCAL_MODULE_CLASS := EXECUTABLE
include $(BUILD_SYSTEM)/build-module.mk

View File

@ -1,129 +0,0 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have the `clock_gettime' function. */
/* #undef HAVE_CLOCK_GETTIME */
/* Define to 1 to use the syscall interface for clock_gettime */
#define HAVE_CLOCK_SYSCALL 1
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the `epoll_ctl' function. */
#define HAVE_EPOLL_CTL 1
/* Define to 1 if you have the `eventfd' function. */
#define HAVE_EVENTFD 1
/* Define to 1 if the floor function is available */
#define HAVE_FLOOR 1
/* Define to 1 if you have the `inotify_init' function. */
#define HAVE_INOTIFY_INIT 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `kqueue' function. */
/* #undef HAVE_KQUEUE */
/* Define to 1 if you have the `rt' library (-lrt). */
/* #undef HAVE_LIBRT */
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `nanosleep' function. */
#define HAVE_NANOSLEEP 1
/* Define to 1 if you have the `poll' function. */
#define HAVE_POLL 1
/* Define to 1 if you have the <poll.h> header file. */
#define HAVE_POLL_H 1
/* Define to 1 if you have the `port_create' function. */
/* #undef HAVE_PORT_CREATE */
/* Define to 1 if you have the <port.h> header file. */
/* #undef HAVE_PORT_H */
/* Define to 1 if you have the `select' function. */
#define HAVE_SELECT 1
/* Define to 1 if you have the `signalfd' function. */
#define HAVE_SIGNALFD 0
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/epoll.h> header file. */
#define HAVE_SYS_EPOLL_H 1
/* Define to 1 if you have the <sys/eventfd.h> header file. */
#define HAVE_SYS_EVENTFD_H 1
/* Define to 1 if you have the <sys/event.h> header file. */
/* #undef HAVE_SYS_EVENT_H */
/* Define to 1 if you have the <sys/inotify.h> header file. */
#define HAVE_SYS_INOTIFY_H 1
/* Define to 1 if you have the <sys/select.h> header file. */
#define HAVE_SYS_SELECT_H 1
/* Define to 1 if you have the <sys/signalfd.h> header file. */
#define HAVE_SYS_SIGNALFD_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#define LT_OBJDIR ".libs/"
/* Name of package */
#define PACKAGE "libev"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
#define PACKAGE_NAME ""
/* Define to the full name and version of this package. */
#define PACKAGE_STRING ""
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME ""
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION ""
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Version number of package */
#define VERSION "4.11"
#define DNDEBUG 1
#define HAVE_CONFIG_H 1

View File

@ -1,425 +0,0 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define if building universal (internal helper macro) */
/* #undef AC_APPLE_UNIVERSAL_BUILD */
/* errno for incomplete non-blocking connect(2) */
#define CONNECT_IN_PROGRESS EINPROGRESS
/* Override libev default fd conversion macro. */
/* #undef EV_FD_TO_WIN32_HANDLE */
/* Override libev default fd close macro. */
/* #undef EV_WIN32_CLOSE_FD */
/* Override libev default handle conversion macro. */
/* #undef EV_WIN32_HANDLE_TO_FD */
/* Reset max file descriptor size. */
/* #undef FD_SETSIZE */
/* Define to 1 if you have the <arpa/inet.h> header file. */
#define HAVE_ARPA_INET_H 1
/* Define to 1 if you have the `CCCryptorCreateWithMode' function. */
/* #undef HAVE_CCCRYPTORCREATEWITHMODE */
/* Define to 1 if you have the `clock_gettime' function. */
/* #undef HAVE_CLOCK_GETTIME */
/* Define to 1 to use the syscall interface for clock_gettime */
/* #undef HAVE_CLOCK_SYSCALL */
/* Define to 1 if you have the <CommonCrypto/CommonCrypto.h> header file. */
/* #undef HAVE_COMMONCRYPTO_COMMONCRYPTO_H */
/* Define to 1 if you have the declaration of `inet_ntop', and to 0 if you
don't. */
#define HAVE_DECL_INET_NTOP 1
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the `epoll_ctl' function. */
/* #undef HAVE_EPOLL_CTL */
/* Define to 1 if you have the `eventfd' function. */
/* #undef HAVE_EVENTFD */
/* Define to 1 if you have the `EVP_EncryptInit_ex' function. */
/* #undef HAVE_EVP_ENCRYPTINIT_EX */
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define to 1 if the floor function is available */
#define HAVE_FLOOR 1
/* Define to 1 if you have the `fork' function. */
#define HAVE_FORK 1
/* Define to 1 if you have the `getpwnam_r' function. */
#define HAVE_GETPWNAM_R 1
/* Define to 1 if you have the `inet_ntop' function. */
/* #undef HAVE_INET_NTOP */
/* Define to 1 if you have the `inotify_init' function. */
/* #undef HAVE_INOTIFY_INIT */
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Enable IPv6 support in libudns */
#define HAVE_IPv6 1
/* Define to 1 if you have the `kqueue' function. */
#define HAVE_KQUEUE 1
/* Define to 1 if you have the <langinfo.h> header file. */
#define HAVE_LANGINFO_H 1
/* Define to 1 if you have the `rt' library (-lrt). */
/* #undef HAVE_LIBRT */
/* Define to 1 if you have the `socket' library (-lsocket). */
/* #undef HAVE_LIBSOCKET */
/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define to 1 if you have the <linux/if.h> header file. */
/* #undef HAVE_LINUX_IF_H */
/* Define to 1 if you have the <linux/netfilter_ipv4.h> header file. */
/* #undef HAVE_LINUX_NETFILTER_IPV4_H */
/* Define to 1 if you have the <linux/netfilter_ipv6/ip6_tables.h> header
file. */
/* #undef HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H */
/* Define to 1 if you have the <locale.h> header file. */
#define HAVE_LOCALE_H 1
/* Define to 1 if you have the `malloc' function. */
#define HAVE_MALLOC 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `memset' function. */
#define HAVE_MEMSET 1
/* Define to 1 if you have the `nanosleep' function. */
#define HAVE_NANOSLEEP 1
/* Define to 1 if you have the <netdb.h> header file. */
#define HAVE_NETDB_H 1
/* Define to 1 if you have the <netinet/in.h> header file. */
#define HAVE_NETINET_IN_H 1
/* Define to 1 if you have the <net/if.h> header file. */
#define HAVE_NET_IF_H 1
/* Define to 1 if you have the <openssl/engine.h> header file. */
/* #undef HAVE_OPENSSL_ENGINE_H */
/* Define to 1 if you have the <openssl/err.h> header file. */
/* #undef HAVE_OPENSSL_ERR_H */
/* Define to 1 if you have the <openssl/evp.h> header file. */
/* #undef HAVE_OPENSSL_EVP_H */
/* Define to 1 if you have the <openssl/pem.h> header file. */
/* #undef HAVE_OPENSSL_PEM_H */
/* Define to 1 if you have the <openssl/rand.h> header file. */
/* #undef HAVE_OPENSSL_RAND_H */
/* Define to 1 if you have the <openssl/rsa.h> header file. */
/* #undef HAVE_OPENSSL_RSA_H */
/* Define to 1 if you have the <openssl/sha.h> header file. */
/* #undef HAVE_OPENSSL_SHA_H */
/* Define to 1 if you have the `poll' function. */
#define HAVE_POLL 1
/* Define to 1 if you have the <poll.h> header file. */
#define HAVE_POLL_H 1
/* Define to 1 if you have the `port_create' function. */
/* #undef HAVE_PORT_CREATE */
/* Define to 1 if you have the <port.h> header file. */
/* #undef HAVE_PORT_H */
/* Have PTHREAD_PRIO_INHERIT. */
#define HAVE_PTHREAD_PRIO_INHERIT 1
/* Define to 1 if you have the `RAND_pseudo_bytes' function. */
/* #undef HAVE_RAND_PSEUDO_BYTES */
/* Define to 1 if you have the 'select' function. */
#define HAVE_SELECT 1
/* Define to 1 if you have the `setresuid' function. */
/* #undef HAVE_SETRESUID */
/* Define to 1 if you have the `setreuid' function. */
#define HAVE_SETREUID 1
/* Define to 1 if you have the `setrlimit' function. */
#define HAVE_SETRLIMIT 1
/* Define to 1 if you have the `signalfd' function. */
/* #undef HAVE_SIGNALFD */
/* Define to 1 if you have the `socket' function. */
#define HAVE_SOCKET 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strerror' function. */
#define HAVE_STRERROR 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/epoll.h> header file. */
/* #undef HAVE_SYS_EPOLL_H */
/* Define to 1 if you have the <sys/eventfd.h> header file. */
/* #undef HAVE_SYS_EVENTFD_H */
/* Define to 1 if you have the <sys/event.h> header file. */
#define HAVE_SYS_EVENT_H 1
/* Define to 1 if you have the <sys/inotify.h> header file. */
/* #undef HAVE_SYS_INOTIFY_H */
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#define HAVE_SYS_IOCTL_H 1
/* Define to 1 if you have the <sys/select.h> header file. */
#define HAVE_SYS_SELECT_H 1
/* Define to 1 if you have the <sys/signalfd.h> header file. */
/* #undef HAVE_SYS_SIGNALFD_H */
/* Define to 1 if you have the <sys/socket.h> header file. */
#define HAVE_SYS_SOCKET_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
#define HAVE_SYS_WAIT_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the `vfork' function. */
#define HAVE_VFORK 1
/* Define to 1 if you have the <vfork.h> header file. */
/* #undef HAVE_VFORK_H */
/* Define to 1 if you have the <windows.h> header file. */
/* #undef HAVE_WINDOWS_H */
/* Define to 1 if you have the <winsock2.h> header file. */
/* #undef HAVE_WINSOCK2_H */
/* Define to 1 if `fork' works. */
#define HAVE_WORKING_FORK 1
/* Define to 1 if `vfork' works. */
#define HAVE_WORKING_VFORK 1
/* Define to 1 if you have the <ws2tcpip.h> header file. */
/* #undef HAVE_WS2TCPIP_H */
/* have zlib compression support */
/* #undef HAVE_ZLIB */
/* Define to 1 if you have the <zlib.h> header file. */
/* #undef HAVE_ZLIB_H */
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#define LT_OBJDIR ".libs/"
/* Define to 1 if assertions should be disabled. */
/* #undef NDEBUG */
/* Name of package */
#define PACKAGE "shadowsocks-libev"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "max.c.lv@gmail.com"
/* Define to the full name of this package. */
#define PACKAGE_NAME "shadowsocks-libev"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "shadowsocks-libev 2.4.8"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "shadowsocks-libev"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "2.4.8"
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
/* #undef PTHREAD_CREATE_JOINABLE */
/* Define as the return type of signal handlers (`int' or `void'). */
#define RETSIGTYPE void
/* Define to the type of arg 1 for `select'. */
#define SELECT_TYPE_ARG1 int
/* Define to the type of args 2, 3 and 4 for `select'. */
#define SELECT_TYPE_ARG234 (fd_set *)
/* Define to the type of arg 5 for `select'. */
#define SELECT_TYPE_ARG5 (struct timeval *)
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#define TIME_WITH_SYS_TIME 1
/* If the compiler supports a TLS storage class define it to that here */
#define TLS __thread
/* Use Apple CommonCrypto library */
/* #undef USE_CRYPTO_APPLECC */
/* Use mbed TLS library */
#define USE_CRYPTO_MBEDTLS 1
/* Use OpenSSL library */
/* #undef USE_CRYPTO_OPENSSL */
/* Use PolarSSL library */
/* #undef USE_CRYPTO_POLARSSL */
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# define _ALL_SOURCE 1
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# define _POSIX_PTHREAD_SEMANTICS 1
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# define _TANDEM_SOURCE 1
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# define __EXTENSIONS__ 1
#endif
/* Version number of package */
#define VERSION "2.4.8"
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
/* # undef WORDS_BIGENDIAN */
# endif
#endif
/* Define to 1 if on MINIX. */
/* #undef _MINIX */
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
/* #undef _POSIX_1_SOURCE */
/* Define to 1 if you need to in order for `stat' and other things to work. */
/* #undef _POSIX_SOURCE */
/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
#define below would cause a syntax error. */
/* #undef _UINT8_T */
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
/* #undef inline */
#endif
/* Define to `int' if <sys/types.h> does not define. */
/* #undef pid_t */
/* Define to the equivalent of the C99 'restrict' keyword, or to
nothing if this is not supported. Do not define if restrict is
supported directly. */
#define restrict __restrict
/* Work around a bug in Sun C++: it does not support _Restrict or
__restrict__, even though the corresponding Sun C compiler ends up with
"#define restrict _Restrict" or "#define restrict __restrict__" in the
previous line. Perhaps some future version of Sun C++ will work with
restrict; if so, hopefully it defines __RESTRICT like Sun C does. */
#if defined __SUNPRO_CC && !defined __RESTRICT
# define _Restrict
# define __restrict__
#endif
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */
/* Define to `int' if <sys/types.h> does not define. */
/* #undef ssize_t */
/* Define to the type of an unsigned integer type of width exactly 16 bits if
such a type exists and the standard includes do not define it. */
/* #undef uint16_t */
/* Define to the type of an unsigned integer type of width exactly 8 bits if
such a type exists and the standard includes do not define it. */
/* #undef uint8_t */
/* Define as `fork' if `vfork' does not work. */
/* #undef vfork */
/* Define to 1 if you have the <pcre.h> header file. */
#define HAVE_PCRE_H 1
/* Define to 1 if you have the <pcre/pcre.h> header file. */
/* #undef HAVE_PCRE_PCRE_H */

View File

@ -1,29 +0,0 @@
#ifndef sodium_version_H
#define sodium_version_H
#include "export.h"
#define SODIUM_VERSION_STRING "1.0.7"
#define SODIUM_LIBRARY_VERSION_MAJOR 9
#define SODIUM_LIBRARY_VERSION_MINOR 0
#ifdef __cplusplus
extern "C" {
#endif
SODIUM_EXPORT
const char *sodium_version_string(void);
SODIUM_EXPORT
int sodium_library_version_major(void);
SODIUM_EXPORT
int sodium_library_version_minor(void);
#ifdef __cplusplus
}
#endif
#endif

@ -1 +0,0 @@
Subproject commit 311e5d14f593f16c785bc6605220517eb1f21f6b

@ -1 +0,0 @@
Subproject commit 3b689a6ab443cb7b467c2cb6c8434d97fd807168

@ -1 +0,0 @@
Subproject commit d414c32a160a45725430d99b3c11904760ac8b9c

View File

@ -1,198 +0,0 @@
/*************************************************
* Perl-Compatible Regular Expressions *
*************************************************/
/* This file contains character tables that are used when no external tables
are passed to PCRE by the application that calls it. The tables are used only
for characters whose code values are less than 256.
This is a default version of the tables that assumes ASCII encoding. A program
called dftables (which is distributed with PCRE) can be used to build
alternative versions of this file. This is necessary if you are running in an
EBCDIC environment, or if you want to default to a different encoding, for
example ISO-8859-1. When dftables is run, it creates these tables in the
current locale. If PCRE is configured with --enable-rebuild-chartables, this
happens automatically.
The following #includes are present because without them gcc 4.x may remove the
array definition from the final binary if PCRE is built into a static library
and dead code stripping is activated. This leads to link errors. Pulling in the
header ensures that the array gets flagged as "someone outside this compilation
unit might reference this" and so it will always be supplied to the linker. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "pcre_internal.h"
const pcre_uint8 PRIV(default_tables)[] = {
/* This table is a lower casing table. */
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63,
64, 97, 98, 99,100,101,102,103,
104,105,106,107,108,109,110,111,
112,113,114,115,116,117,118,119,
120,121,122, 91, 92, 93, 94, 95,
96, 97, 98, 99,100,101,102,103,
104,105,106,107,108,109,110,111,
112,113,114,115,116,117,118,119,
120,121,122,123,124,125,126,127,
128,129,130,131,132,133,134,135,
136,137,138,139,140,141,142,143,
144,145,146,147,148,149,150,151,
152,153,154,155,156,157,158,159,
160,161,162,163,164,165,166,167,
168,169,170,171,172,173,174,175,
176,177,178,179,180,181,182,183,
184,185,186,187,188,189,190,191,
192,193,194,195,196,197,198,199,
200,201,202,203,204,205,206,207,
208,209,210,211,212,213,214,215,
216,217,218,219,220,221,222,223,
224,225,226,227,228,229,230,231,
232,233,234,235,236,237,238,239,
240,241,242,243,244,245,246,247,
248,249,250,251,252,253,254,255,
/* This table is a case flipping table. */
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63,
64, 97, 98, 99,100,101,102,103,
104,105,106,107,108,109,110,111,
112,113,114,115,116,117,118,119,
120,121,122, 91, 92, 93, 94, 95,
96, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90,123,124,125,126,127,
128,129,130,131,132,133,134,135,
136,137,138,139,140,141,142,143,
144,145,146,147,148,149,150,151,
152,153,154,155,156,157,158,159,
160,161,162,163,164,165,166,167,
168,169,170,171,172,173,174,175,
176,177,178,179,180,181,182,183,
184,185,186,187,188,189,190,191,
192,193,194,195,196,197,198,199,
200,201,202,203,204,205,206,207,
208,209,210,211,212,213,214,215,
216,217,218,219,220,221,222,223,
224,225,226,227,228,229,230,231,
232,233,234,235,236,237,238,239,
240,241,242,243,244,245,246,247,
248,249,250,251,252,253,254,255,
/* This table contains bit maps for various character classes. Each map is 32
bytes long and the bits run from the least significant end of each byte. The
classes that have their own maps are: space, xdigit, digit, upper, lower, word,
graph, print, punct, and cntrl. Other classes are built from combinations. */
0x00,0x3e,0x00,0x00,0x01,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
0x7e,0x00,0x00,0x00,0x7e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xfe,0xff,0xff,0x07,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x07,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
0xfe,0xff,0xff,0x87,0xfe,0xff,0xff,0x07,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xfe,0xff,0x00,0xfc,
0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x78,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
/* This table identifies various classes of character by individual bits:
0x01 white space character
0x02 letter
0x04 decimal digit
0x08 hexadecimal digit
0x10 alphanumeric or '_'
0x80 regular expression metacharacter or binary zero
*/
0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */
0x00,0x01,0x01,0x01,0x01,0x01,0x00,0x00, /* 8- 15 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */
0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00, /* - ' */
0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x00, /* ( - / */
0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */
0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x80, /* 8 - ? */
0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* @ - G */
0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* H - O */
0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* P - W */
0x12,0x12,0x12,0x80,0x80,0x00,0x80,0x10, /* X - _ */
0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* ` - g */
0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* h - o */
0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* p - w */
0x12,0x12,0x12,0x80,0x80,0x00,0x00,0x00, /* x -127 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */
/* End of pcre_chartables.c */

@ -1 +0,0 @@
Subproject commit 222bbf4b3fb8e13c21686803e47e31aa3e4ad130

@ -1 +0,0 @@
Subproject commit ca93436e5b1be02f9f4bfca79b8202c400161994

@ -1 +0,0 @@
Subproject commit 70921a02a860b0ca2df4069a609951bc4182c245

1
v2ray

@ -1 +0,0 @@
Subproject commit a697372e996000fa748f87b4c2bad4da038b5ddf