From ca419521efc2a9aa7d08b28af9dc0e4f2d162525 Mon Sep 17 00:00:00 2001 From: xtaodada Date: Fri, 16 Feb 2024 16:35:36 +0800 Subject: [PATCH] perf: Remove Extra Proxy --- .github/workflows/debug.yml | 140 -- .github/workflows/pr.yml | 141 -- .github/workflows/release.yml | 140 -- .../github/shadowsocks/plugin/NativePlugin.kt | 33 - .../plugin/NativePluginProvider.kt | 103 -- .../com/github/shadowsocks/plugin/NoPlugin.kt | 9 - .../github/shadowsocks/plugin/PathProvider.kt | 56 - .../com/github/shadowsocks/plugin/Plugin.kt | 41 - .../shadowsocks/plugin/PluginConfiguration.kt | 73 - .../shadowsocks/plugin/PluginContract.kt | 142 -- .../github/shadowsocks/plugin/PluginList.kt | 55 - .../shadowsocks/plugin/PluginManager.kt | 183 --- .../shadowsocks/plugin/PluginOptions.kt | 111 -- .../shadowsocks/plugin/ResolvedPlugin.kt | 55 - .../github/shadowsocks/utils/Commandline.kt | 159 -- .../com/github/shadowsocks/utils/Utils.kt | 136 -- .../main/java/com/v2ray/ang/V2RayConfig.kt | 70 - .../main/java/com/v2ray/ang/dto/AngConfig.kt | 82 - .../java/com/v2ray/ang/dto/V2rayConfig.kt | 139 -- .../java/com/v2ray/ang/dto/VmessQRCode.kt | 13 - .../com/v2ray/ang/util/V2rayConfigUtil.kt | 379 ----- .../telegram/messenger/AndroidUtilities.java | 775 +-------- .../org/telegram/messenger/MessageObject.java | 11 - .../messenger/MessagesController.java | 2 +- .../org/telegram/messenger/SharedConfig.java | 1385 +++-------------- .../telegram/tgnet/ConnectionsManager.java | 5 - .../java/org/telegram/ui/ChatActivity.java | 14 +- .../java/org/telegram/ui/LaunchActivity.java | 39 +- .../java/org/telegram/ui/ProfileActivity.java | 9 - .../org/telegram/ui/ProxyListActivity.java | 1023 +++--------- .../telegram/ui/ProxySettingsActivity.java | 158 +- .../tw/nekomimi/nekogram/database/Nitrites.kt | 4 - .../tw/nekomimi/nekogram/parts/ProxyChecks.kt | 187 --- .../tw/nekomimi/nekogram/parts/ProxyLoads.kt | 108 -- .../nekomimi/nekogram/parts/ProxySwitcher.kt | 108 -- .../nekogram/proxy/GuardedProcessPool.kt | 115 -- .../nekomimi/nekogram/proxy/ProxyManager.kt | 51 - .../nekogram/proxy/ShadowsocksLoader.kt | 290 ---- .../nekogram/proxy/ShadowsocksRLoader.kt | 242 --- .../proxy/ShadowsocksRSettingsActivity.java | 469 ------ .../proxy/ShadowsocksSettingsActivity.java | 569 ------- .../tw/nekomimi/nekogram/proxy/SubInfo.java | 147 -- .../tw/nekomimi/nekogram/proxy/SubManager.kt | 48 - .../nekogram/proxy/SubSettingsActivity.java | 347 ----- .../proxy/TrojanSettingsActivity.java | 378 ----- .../tw/nekomimi/nekogram/proxy/VmessLoader.kt | 442 ------ .../nekogram/proxy/VmessSettingsActivity.java | 505 ------ .../nekogram/proxy/WsSettingsActivity.java | 359 ----- .../nekogram/proxy/tcp2ws/Tcp2wsServer.java | 91 -- .../nekogram/proxy/tcp2ws/WsLoader.kt | 73 - .../nekogram/proxy/tcp2ws/WsProxyHandler.java | 256 --- .../nekomimi/nekogram/transtale/Translator.kt | 2 +- .../transtale/deepl/DeepLTranslatorRaw.java | 10 +- .../tw/nekomimi/nekogram/utils/ProxyUtil.kt | 445 +----- 54 files changed, 678 insertions(+), 10249 deletions(-) delete mode 100644 TMessagesProj/src/main/java/com/github/shadowsocks/plugin/NativePlugin.kt delete mode 100644 TMessagesProj/src/main/java/com/github/shadowsocks/plugin/NativePluginProvider.kt delete mode 100644 TMessagesProj/src/main/java/com/github/shadowsocks/plugin/NoPlugin.kt delete mode 100644 TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PathProvider.kt delete mode 100644 TMessagesProj/src/main/java/com/github/shadowsocks/plugin/Plugin.kt delete mode 100644 TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginConfiguration.kt delete mode 100644 TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginContract.kt delete mode 100644 TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginList.kt delete mode 100644 TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginManager.kt delete mode 100644 TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginOptions.kt delete mode 100644 TMessagesProj/src/main/java/com/github/shadowsocks/plugin/ResolvedPlugin.kt delete mode 100644 TMessagesProj/src/main/java/com/github/shadowsocks/utils/Commandline.kt delete mode 100644 TMessagesProj/src/main/java/com/github/shadowsocks/utils/Utils.kt delete mode 100644 TMessagesProj/src/main/java/com/v2ray/ang/V2RayConfig.kt delete mode 100644 TMessagesProj/src/main/java/com/v2ray/ang/dto/AngConfig.kt delete mode 100644 TMessagesProj/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt delete mode 100644 TMessagesProj/src/main/java/com/v2ray/ang/dto/VmessQRCode.kt delete mode 100644 TMessagesProj/src/main/java/com/v2ray/ang/util/V2rayConfigUtil.kt delete mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/parts/ProxyChecks.kt delete mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/parts/ProxyLoads.kt delete mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/parts/ProxySwitcher.kt delete mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/GuardedProcessPool.kt delete mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ProxyManager.kt delete mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ShadowsocksLoader.kt delete mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ShadowsocksRLoader.kt delete mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ShadowsocksRSettingsActivity.java delete mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ShadowsocksSettingsActivity.java delete mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/SubInfo.java delete mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/SubManager.kt delete mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/SubSettingsActivity.java delete mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/TrojanSettingsActivity.java delete mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/VmessLoader.kt delete mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/VmessSettingsActivity.java delete mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/WsSettingsActivity.java delete mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/tcp2ws/Tcp2wsServer.java delete mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/tcp2ws/WsLoader.kt delete mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/tcp2ws/WsProxyHandler.java diff --git a/.github/workflows/debug.yml b/.github/workflows/debug.yml index 12bfc4c80a..f3983eedaf 100644 --- a/.github/workflows/debug.yml +++ b/.github/workflows/debug.yml @@ -170,130 +170,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: | - sed -i 's/\/\///g' settings.gradle - 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: Set up JDK 17 - uses: actions/setup-java@v3 - if: steps.cache.outputs.cache-hit != 'true' - with: - java-version: '17' - distribution: 'temurin' - - name: Setup Android SDK Tools - uses: android-actions/setup-android@v3 - if: steps.cache.outputs.cache-hit != 'true' - - name: Install NDK - if: steps.cache.outputs.cache-hit != 'true' - run: | - echo "y" | 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: | - sed -i 's/\/\///g' settings.gradle - 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: Set up JDK 17 - uses: actions/setup-java@v3 - if: steps.cache.outputs.cache-hit != 'true' - with: - java-version: '17' - distribution: 'temurin' - - name: Setup Android SDK Tools - uses: android-actions/setup-android@v3 - if: steps.cache.outputs.cache-hit != 'true' - - name: Install NDK - if: steps.cache.outputs.cache-hit != 'true' - run: | - echo "y" | 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: | - sed -i 's/\/\///g' settings.gradle - 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: Set up JDK 17 - uses: actions/setup-java@v3 - if: steps.cache.outputs.cache-hit != 'true' - with: - java-version: '17' - distribution: 'temurin' - - name: Setup Android SDK Tools - uses: android-actions/setup-android@v3 - if: steps.cache.outputs.cache-hit != 'true' - - name: Install NDK - if: steps.cache.outputs.cache-hit != 'true' - run: | - echo "y" | 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: @@ -320,9 +201,6 @@ jobs: sed -i 's/\/\///g' settings.gradle 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: @@ -335,24 +213,6 @@ jobs: path: | TMessagesProj/src/main/libs key: ${{ hashFiles('TMessagesProj/jni/**', 'ffmpeg_status', 'boringssl_status') }}-arm64-v8a - - 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: Configure Gradle run: | sed -i -e "s/16384/6144/g" gradle.properties diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 068d624c68..d22bb625e4 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -168,134 +168,14 @@ 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: | - sed -i 's/\/\///g' settings.gradle - 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: Set up JDK 17 - uses: actions/setup-java@v3 - if: steps.cache.outputs.cache-hit != 'true' - with: - java-version: '17' - distribution: 'temurin' - - name: Setup Android SDK Tools - uses: android-actions/setup-android@v3 - if: steps.cache.outputs.cache-hit != 'true' - - name: Install NDK - if: steps.cache.outputs.cache-hit != 'true' - run: | - echo "y" | 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: | - sed -i 's/\/\///g' settings.gradle - 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: Set up JDK 17 - uses: actions/setup-java@v3 - if: steps.cache.outputs.cache-hit != 'true' - with: - java-version: '17' - distribution: 'temurin' - - name: Setup Android SDK Tools - uses: android-actions/setup-android@v3 - if: steps.cache.outputs.cache-hit != 'true' - - name: Install NDK - if: steps.cache.outputs.cache-hit != 'true' - run: | - echo "y" | 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: | - sed -i 's/\/\///g' settings.gradle - 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: Set up JDK 17 - uses: actions/setup-java@v3 - if: steps.cache.outputs.cache-hit != 'true' - with: - java-version: '17' - distribution: 'temurin' - - name: Setup Android SDK Tools - uses: android-actions/setup-android@v3 - if: steps.cache.outputs.cache-hit != 'true' - - name: Install NDK - if: steps.cache.outputs.cache-hit != 'true' - run: | - echo "y" | 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: -# - FullRelease - MiniRelease steps: - name: Checkout @@ -317,9 +197,6 @@ jobs: sed -i 's/\/\///g' settings.gradle 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: @@ -332,24 +209,6 @@ jobs: path: | TMessagesProj/src/main/libs key: ${{ hashFiles('TMessagesProj/jni/**', 'ffmpeg_status', 'boringssl_status') }}-arm64-v8a - - 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: Configure Gradle run: | sed -i -e "s/16384/6144/g" gradle.properties diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 003c7ff031..6c878b0587 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -173,130 +173,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: | - sed -i 's/\/\///g' settings.gradle - 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: Set up JDK 17 - uses: actions/setup-java@v3 - if: steps.cache.outputs.cache-hit != 'true' - with: - java-version: '17' - distribution: 'temurin' - - name: Setup Android SDK Tools - uses: android-actions/setup-android@v3 - if: steps.cache.outputs.cache-hit != 'true' - - name: Install NDK - if: steps.cache.outputs.cache-hit != 'true' - run: | - echo "y" | 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@v4 - 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: | - sed -i 's/\/\///g' settings.gradle - 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: Set up JDK 17 - uses: actions/setup-java@v3 - if: steps.cache.outputs.cache-hit != 'true' - with: - java-version: '17' - distribution: 'temurin' - - name: Setup Android SDK Tools - uses: android-actions/setup-android@v3 - if: steps.cache.outputs.cache-hit != 'true' - - name: Install NDK - if: steps.cache.outputs.cache-hit != 'true' - run: | - echo "y" | 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: | - sed -i 's/\/\///g' settings.gradle - 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: Set up JDK 17 - uses: actions/setup-java@v3 - if: steps.cache.outputs.cache-hit != 'true' - with: - java-version: '17' - distribution: 'temurin' - - name: Setup Android SDK Tools - uses: android-actions/setup-android@v3 - if: steps.cache.outputs.cache-hit != 'true' - - name: Install NDK - if: steps.cache.outputs.cache-hit != 'true' - run: | - echo "y" | 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: @@ -324,9 +205,6 @@ jobs: sed -i 's/\/\///g' settings.gradle 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: @@ -339,24 +217,6 @@ jobs: path: | TMessagesProj/src/main/libs key: ${{ hashFiles('TMessagesProj/jni/**', 'ffmpeg_status', 'boringssl_status') }}-arm64-v8a - - 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: Configure Gradle run: | sed -i -e "s/16384/6144/g" gradle.properties diff --git a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/NativePlugin.kt b/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/NativePlugin.kt deleted file mode 100644 index 55b7a99020..0000000000 --- a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/NativePlugin.kt +++ /dev/null @@ -1,33 +0,0 @@ -/******************************************************************************* - * * - * Copyright (C) 2017 by Max Lv * - * Copyright (C) 2017 by Mygod Studio * - * * - * 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 . * - * * - *******************************************************************************/ - -package com.github.shadowsocks.plugin - -import android.content.pm.ResolveInfo -import android.os.Build -import androidx.annotation.RequiresApi - -@RequiresApi(Build.VERSION_CODES.KITKAT) class NativePlugin(resolveInfo: ResolveInfo) : ResolvedPlugin(resolveInfo) { - init { - check(resolveInfo.providerInfo != null) - } - - override val componentInfo get() = resolveInfo.providerInfo!! -} diff --git a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/NativePluginProvider.kt b/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/NativePluginProvider.kt deleted file mode 100644 index b57b26799e..0000000000 --- a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/NativePluginProvider.kt +++ /dev/null @@ -1,103 +0,0 @@ -/******************************************************************************* - * * - * Copyright (C) 2017 by Max Lv * - * Copyright (C) 2017 by Mygod Studio * - * * - * 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 . * - * * - *******************************************************************************/ - -package com.github.shadowsocks.plugin - -import android.content.ContentProvider -import android.content.ContentValues -import android.database.Cursor -import android.database.MatrixCursor -import android.net.Uri -import android.os.Bundle -import android.os.ParcelFileDescriptor - -/** - * Base class for a native plugin provider. A native plugin provider offers read-only access to files that are required - * to run a plugin, such as binary files and other configuration files. To create a native plugin provider, extend this - * class, implement the abstract methods, and add it to your manifest like this: - * - *
<manifest>
- *    ...
- *    <application>
- *        ...
- *        <provider android:name="com.github.shadowsocks.$PLUGIN_ID.BinaryProvider"
- *                     android:authorities="com.github.shadowsocks.plugin.$PLUGIN_ID.BinaryProvider">
- *            <intent-filter>
- *                <category android:name="com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN" />
- *            </intent-filter>
- *        </provider>
- *        ...
- *    </application>
- *</manifest>
- */ -abstract class NativePluginProvider : ContentProvider() { - override fun getType(uri: Uri): String? = "application/x-elf" - - override fun onCreate(): Boolean = true - - /** - * Provide all files needed for native plugin. - * - * @param provider A helper object to use to add files. - */ - protected abstract fun populateFiles(provider: PathProvider) - - override fun query(uri: Uri, projection: Array?, selection: String?, selectionArgs: Array?, - sortOrder: String?): Cursor? { - check(selection == null && selectionArgs == null && sortOrder == null) - val result = MatrixCursor(projection) - populateFiles(PathProvider(uri, result)) - return result - } - - /** - * Returns executable entry absolute path. - * This is used for fast mode initialization where ss-local launches your native binary at the path given directly. - * In order for this to work, plugin app is encouraged to have the following in its AndroidManifest.xml: - * - android:installLocation="internalOnly" for - * - android:extractNativeLibs="true" for - * - * Default behavior is throwing UnsupportedOperationException. If you don't wish to use this feature, use the - * default behavior. - * - * @return Absolute path for executable entry. - */ - open fun getExecutable(): String = throw UnsupportedOperationException() - - abstract fun openFile(uri: Uri): ParcelFileDescriptor - override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor { - check(mode == "r") - return openFile(uri) - } - - override fun call(method: String, arg: String?, extras: Bundle?): Bundle? = when (method) { - PluginContract.METHOD_GET_EXECUTABLE -> Bundle().apply { putString(PluginContract.EXTRA_ENTRY, getExecutable()) } - else -> super.call(method, arg, extras) - } - - // Methods that should not be used - override fun insert(uri: Uri, values: ContentValues?): Uri? = throw UnsupportedOperationException() - - override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array?): Int = - throw UnsupportedOperationException() - - override fun delete(uri: Uri, selection: String?, selectionArgs: Array?): Int = - throw UnsupportedOperationException() -} diff --git a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/NoPlugin.kt b/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/NoPlugin.kt deleted file mode 100644 index 11f8091af7..0000000000 --- a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/NoPlugin.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.github.shadowsocks.plugin - -import org.telegram.messenger.LocaleController -import org.telegram.messenger.R - -object NoPlugin : Plugin() { - override val id: String get() = "" - override val label: CharSequence get() = LocaleController.getString("Disable", R.string.Disable) -} diff --git a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PathProvider.kt b/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PathProvider.kt deleted file mode 100644 index 4b18bb8ebe..0000000000 --- a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PathProvider.kt +++ /dev/null @@ -1,56 +0,0 @@ -/******************************************************************************* - * * - * Copyright (C) 2017 by Max Lv * - * Copyright (C) 2017 by Mygod Studio * - * * - * 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 . * - * * - *******************************************************************************/ - -package com.github.shadowsocks.plugin - -import android.database.MatrixCursor -import android.net.Uri -import android.os.Build -import androidx.annotation.RequiresApi -import java.io.File - -/** - * Helper class to provide relative paths of files to copy. - */ -class PathProvider internal constructor(baseUri: Uri, private val cursor: MatrixCursor) { - private val basePath = baseUri.path?.trim('/') ?: "" - - @RequiresApi(Build.VERSION_CODES.KITKAT) fun addPath(path: String, mode: Int = 0b110100100): PathProvider { - val trimmed = path.trim('/') - if (trimmed.startsWith(basePath)) cursor.newRow() - .add(PluginContract.COLUMN_PATH, trimmed) - .add(PluginContract.COLUMN_MODE, mode) - return this - } - @RequiresApi(Build.VERSION_CODES.KITKAT) fun addTo(file: File, to: String = "", mode: Int = 0b110100100): PathProvider { - var sub = to + file.name - if (basePath.startsWith(sub)) if (file.isDirectory) { - sub += '/' - file.listFiles()!!.forEach { addTo(it, sub, mode) } - } else addPath(sub, mode) - return this - } - fun addAt(file: File, at: String = "", mode: Int = 0b110100100): PathProvider { - if (basePath.startsWith(at)) { - if (file.isDirectory) file.listFiles()!!.forEach { addTo(it, at, mode) } else addPath(at, mode) - } - return this - } -} diff --git a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/Plugin.kt b/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/Plugin.kt deleted file mode 100644 index c805a62296..0000000000 --- a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/Plugin.kt +++ /dev/null @@ -1,41 +0,0 @@ -/******************************************************************************* - * * - * Copyright (C) 2017 by Max Lv * - * Copyright (C) 2017 by Mygod Studio * - * * - * 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 . * - * * - *******************************************************************************/ - -package com.github.shadowsocks.plugin - -import android.graphics.drawable.Drawable - -abstract class Plugin { - abstract val id: String - open val idAliases get() = emptyArray() - abstract val label: CharSequence - open val icon: Drawable? get() = null - open val defaultConfig: String? get() = null - open val packageName: String get() = "" - open val trusted: Boolean get() = true - open val directBootAware: Boolean get() = true - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - return id == (other as Plugin).id - } - override fun hashCode() = id.hashCode() -} diff --git a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginConfiguration.kt b/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginConfiguration.kt deleted file mode 100644 index 8435023593..0000000000 --- a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginConfiguration.kt +++ /dev/null @@ -1,73 +0,0 @@ -/******************************************************************************* - * * - * Copyright (C) 2017 by Max Lv * - * Copyright (C) 2017 by Mygod Studio * - * * - * 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 . * - * * - *******************************************************************************/ - -package com.github.shadowsocks.plugin - -import android.os.Build -import androidx.annotation.RequiresApi -import com.github.shadowsocks.utils.Commandline -import org.telegram.messenger.FileLog -import org.telegram.messenger.LocaleController -import org.telegram.messenger.R -import java.util.* -import kotlin.collections.HashMap - -@RequiresApi(Build.VERSION_CODES.LOLLIPOP) -class PluginConfiguration(val pluginsOptions: MutableMap, var selected: String) { - private constructor(plugins: List) : this( - HashMap(plugins.filter { it.id.isNotEmpty() }.associateBy { it.id }), - if (plugins.isEmpty()) "" else plugins[0].id) - - constructor(plugin: String) : this(plugin.split('\n').map { line -> - if (line.startsWith("kcptun ")) { - val opt = PluginOptions() - opt.id = "kcptun" - try { - val iterator = Commandline.translateCommandline(line).drop(1).iterator() - while (iterator.hasNext()) { - val option = iterator.next() - when { - option == "--nocomp" -> opt["nocomp"] = null - option.startsWith("--") -> opt[option.substring(2)] = iterator.next() - else -> throw IllegalArgumentException("Unknown kcptun parameter: $option") - } - } - } catch (exc: Exception) { - FileLog.e(exc) - } - opt - } else PluginOptions(line) - }) - - val selectedName get() = selected.takeIf { it.isNotBlank() } ?: LocaleController.getString("Disable", R.string.Disable) - - @JvmOverloads - fun getOptions( - id: String = selected, - defaultConfig: () -> String? = { PluginManager.fetchPlugins().lookup[id]?.defaultConfig } - ) = if (id.isEmpty()) PluginOptions() else pluginsOptions[id] ?: PluginOptions(id, defaultConfig()) - - override fun toString(): String { - val result = LinkedList() - for ((id, opt) in pluginsOptions) if (id == this.selected) result.addFirst(opt) else result.addLast(opt) - if (!pluginsOptions.contains(selected)) result.addFirst(getOptions()) - return result.joinToString("\n") { it.toString(false) } - } -} diff --git a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginContract.kt b/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginContract.kt deleted file mode 100644 index 07745d0a3d..0000000000 --- a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginContract.kt +++ /dev/null @@ -1,142 +0,0 @@ -/******************************************************************************* - * * - * Copyright (C) 2017 by Max Lv * - * Copyright (C) 2017 by Mygod Studio * - * * - * 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 . * - * * - *******************************************************************************/ - -package com.github.shadowsocks.plugin - -/** - * The contract between the plugin provider and host. Contains definitions for the supported actions, extras, etc. - * - * This class is written in Java to keep Java interoperability. - */ -object PluginContract { - /** - * ContentProvider Action: Used for NativePluginProvider. - * - * Constant Value: "com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN" - */ - const val ACTION_NATIVE_PLUGIN = "com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN" - - /** - * Activity Action: Used for ConfigurationActivity. - * - * Constant Value: "com.github.shadowsocks.plugin.ACTION_CONFIGURE" - */ - const val ACTION_CONFIGURE = "com.github.shadowsocks.plugin.ACTION_CONFIGURE" - /** - * Activity Action: Used for HelpActivity or HelpCallback. - * - * Constant Value: "com.github.shadowsocks.plugin.ACTION_HELP" - */ - const val ACTION_HELP = "com.github.shadowsocks.plugin.ACTION_HELP" - - /** - * The lookup key for a string that provides the plugin entry binary. - * - * Example: "/data/data/com.github.shadowsocks.plugin.obfs_local/lib/libobfs-local.so" - * - * Constant Value: "com.github.shadowsocks.plugin.EXTRA_ENTRY" - */ - const val EXTRA_ENTRY = "com.github.shadowsocks.plugin.EXTRA_ENTRY" - /** - * The lookup key for a string that provides the options as a string. - * - * Example: "obfs=http;obfs-host=www.baidu.com" - * - * Constant Value: "com.github.shadowsocks.plugin.EXTRA_OPTIONS" - */ - const val EXTRA_OPTIONS = "com.github.shadowsocks.plugin.EXTRA_OPTIONS" - /** - * The lookup key for a CharSequence that provides user relevant help message. - * - * Example: "obfs=|tls> Enable obfuscating: HTTP or TLS (Experimental). - * obfs-host= Hostname for obfuscating (Experimental)." - * - * Constant Value: "com.github.shadowsocks.plugin.EXTRA_HELP_MESSAGE" - */ - const val EXTRA_HELP_MESSAGE = "com.github.shadowsocks.plugin.EXTRA_HELP_MESSAGE" - - /** - * The metadata key to retrieve plugin id. Required for plugins. - * - * Constant Value: "com.github.shadowsocks.plugin.id" - */ - const val METADATA_KEY_ID = "com.github.shadowsocks.plugin.id" - /** - * The metadata key to retrieve plugin id aliases. - * Can be a string (representing one alias) or a resource to a string or string array. - * - * Constant Value: "com.github.shadowsocks.plugin.id.aliases" - */ - const val METADATA_KEY_ID_ALIASES = "com.github.shadowsocks.plugin.id.aliases" - /** - * The metadata key to retrieve default configuration. Default value is empty. - * - * Constant Value: "com.github.shadowsocks.plugin.default_config" - */ - const val METADATA_KEY_DEFAULT_CONFIG = "com.github.shadowsocks.plugin.default_config" - /** - * The metadata key to retrieve executable path to your native binary. - * This path should be relative to your application's nativeLibraryDir. - * - * If this is set, the host app will prefer this value and (probably) not launch your app at all (aka faster mode). - * In order for this to work, plugin app is encouraged to have the following in its AndroidManifest.xml: - * - android:installLocation="internalOnly" for - * - android:extractNativeLibs="true" for - * - * Do not use this if you plan to do some setup work before giving away your binary path, - * or your native binary is not at a fixed location relative to your application's nativeLibraryDir. - * - * Since plugin lib: 1.3.0 - * - * Constant Value: "com.github.shadowsocks.plugin.executable_path" - */ - const val METADATA_KEY_EXECUTABLE_PATH = "com.github.shadowsocks.plugin.executable_path" - - const val METHOD_GET_EXECUTABLE = "shadowsocks:getExecutable" - - /** ConfigurationActivity result: fallback to manual edit mode. */ - const val RESULT_FALLBACK = 1 - - /** - * Relative to the file to be copied. This column is required. - * - * Example: "kcptun", "doc/help.txt" - * - * Type: String - */ - const val COLUMN_PATH = "path" - /** - * File mode bits. Default value is 644 in octal. - * - * Example: 0b110100100 (for 755 in octal) - * - * Type: Int or String (deprecated) - */ - const val COLUMN_MODE = "mode" - - /** - * The scheme for general plugin actions. - */ - const val SCHEME = "plugin" - /** - * The authority for general plugin actions. - */ - const val AUTHORITY = "com.github.shadowsocks" -} diff --git a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginList.kt b/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginList.kt deleted file mode 100644 index 196102e22f..0000000000 --- a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginList.kt +++ /dev/null @@ -1,55 +0,0 @@ -/******************************************************************************* - * * - * Copyright (C) 2020 by Max Lv * - * Copyright (C) 2020 by Mygod Studio * - * * - * 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 . * - * * - *******************************************************************************/ - -package com.github.shadowsocks.plugin - -import android.content.Intent -import android.content.pm.PackageManager -import android.os.Build -import androidx.annotation.RequiresApi -import org.telegram.messenger.ApplicationLoader -import org.telegram.messenger.LocaleController -import org.telegram.messenger.R - -@RequiresApi(Build.VERSION_CODES.KITKAT) class PluginList : ArrayList() { - init { - add(NoPlugin) - addAll(ApplicationLoader.applicationContext.packageManager.queryIntentContentProviders( - Intent(PluginContract.ACTION_NATIVE_PLUGIN), PackageManager.GET_META_DATA) - .map { NativePlugin(it) }) - } - - val lookup = mutableMapOf().apply { - for (plugin in this@PluginList) { - fun check(old: Plugin?) = check(old == null || old === plugin) { LocaleController.formatString("SSPluginConflictingName",R.string.SSPluginConflictingName,plugin.id) } - check(put(plugin.id, plugin)) - } - } - - val lookupNames get() = lookup.values.map { - if (it.label.isNotBlank() && it.id.isNotBlank()) { - "${it.label} (${it.id})" - } else if (it.label.isNotBlank()) { - it.label - } else if (it.id.isNotBlank()) { - it.id - } else it.packageName - }.map { it.takeIf { it.isNotBlank() } ?: LocaleController.getString("Disable", R.string.Disable) }.toTypedArray() -} diff --git a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginManager.kt b/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginManager.kt deleted file mode 100644 index dcff2e58d3..0000000000 --- a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginManager.kt +++ /dev/null @@ -1,183 +0,0 @@ -/******************************************************************************* - * * - * Copyright (C) 2017 by Max Lv * - * Copyright (C) 2017 by Mygod Studio * - * * - * 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 . * - * * - *******************************************************************************/ - -package com.github.shadowsocks.plugin - -import android.annotation.SuppressLint -import android.content.BroadcastReceiver -import android.content.ContentResolver -import android.content.Intent -import android.content.pm.ComponentInfo -import android.content.pm.PackageManager -import android.content.pm.ProviderInfo -import android.database.Cursor -import android.net.Uri -import android.os.Build -import android.os.Bundle -import android.system.Os -import androidx.annotation.RequiresApi -import com.github.shadowsocks.utils.listenForPackageChanges -import org.telegram.messenger.ApplicationLoader -import org.telegram.messenger.FileLog -import java.io.File -import java.io.FileNotFoundException - -@RequiresApi(Build.VERSION_CODES.LOLLIPOP) -object PluginManager { - - val app get() = ApplicationLoader.applicationContext - - fun bundleOf(pair: Pair) = Bundle().apply { putString(pair.first, pair.second) } - - class PluginNotFoundException(plugin: String) : FileNotFoundException(plugin) { - } - - private var receiver: BroadcastReceiver? = null - private var cachedPlugins: PluginList? = null - - @JvmStatic - fun fetchPlugins() = synchronized(this) { - if (receiver == null) receiver = ApplicationLoader.applicationContext.listenForPackageChanges { - synchronized(this) { - receiver = null - cachedPlugins = null - } - } - if (cachedPlugins == null) cachedPlugins = PluginList() - cachedPlugins!! - } - - private fun buildUri(id: String) = Uri.Builder() - .scheme(PluginContract.SCHEME) - .authority(PluginContract.AUTHORITY) - .path("/$id") - .build() - - @JvmStatic - fun buildIntent(id: String, action: String): Intent = Intent(action, buildUri(id)) - - // the following parts are meant to be used by :bg - @Throws(Throwable::class) - fun init(configuration: PluginConfiguration): Pair? { - if (configuration.selected.isEmpty()) return null - var throwable: Throwable? = null - - try { - val result = initNative(configuration) - if (result != null) return result - } catch (t: Throwable) { - if (throwable == null) throwable = t else FileLog.e(t) - } - - // add other plugin types here - - throw throwable ?: PluginNotFoundException(configuration.selected) - } - - private fun initNative(configuration: PluginConfiguration): Pair? { - var flags = PackageManager.GET_META_DATA - if (Build.VERSION.SDK_INT >= 24) { - flags = flags or PackageManager.MATCH_DIRECT_BOOT_UNAWARE or PackageManager.MATCH_DIRECT_BOOT_AWARE - } - val providers = app.packageManager.queryIntentContentProviders( - Intent(PluginContract.ACTION_NATIVE_PLUGIN, buildUri(configuration.selected)), flags) - if (providers.isEmpty()) return null - val provider = providers.single().providerInfo - val options = configuration.getOptions { provider.loadString(PluginContract.METADATA_KEY_DEFAULT_CONFIG) } - var failure: Throwable? = null - try { - initNativeFaster(provider)?.also { return it to options } - } catch (t: Throwable) { - FileLog.w("Initializing native plugin faster mode failed") - failure = t - } - - val uri = Uri.Builder().apply { - scheme(ContentResolver.SCHEME_CONTENT) - authority(provider.authority) - }.build() - try { - return initNativeFast(app.contentResolver, options, uri)?.let { it to options } - } catch (t: Throwable) { - FileLog.w("Initializing native plugin fast mode failed") - failure?.also { t.addSuppressed(it) } - failure = t - } - - try { - return initNativeSlow(app.contentResolver, options, uri)?.let { it to options } - } catch (t: Throwable) { - failure?.also { t.addSuppressed(it) } - throw t - } - } - - private fun initNativeFaster(provider: ProviderInfo): String? { - return provider.loadString(PluginContract.METADATA_KEY_EXECUTABLE_PATH)?.let { relativePath -> - File(provider.applicationInfo.nativeLibraryDir).resolve(relativePath).apply { - check(canExecute()) - }.absolutePath - } - } - - private fun initNativeFast(cr: ContentResolver, options: PluginOptions, uri: Uri): String? { - return cr.call(uri, PluginContract.METHOD_GET_EXECUTABLE, null, - bundleOf(PluginContract.EXTRA_OPTIONS to options.id))?.getString(PluginContract.EXTRA_ENTRY)?.also { - check(File(it).canExecute()) - } - } - - @SuppressLint("Recycle") - private fun initNativeSlow(cr: ContentResolver, options: PluginOptions, uri: Uri): String? { - var initialized = false - fun entryNotFound(): Nothing = throw IndexOutOfBoundsException("Plugin entry binary not found") - val pluginDir = File(app.noBackupFilesDir, "plugin") - (cr.query(uri, arrayOf(PluginContract.COLUMN_PATH, PluginContract.COLUMN_MODE), null, null, null) - ?: return null).use { cursor -> - if (!cursor.moveToFirst()) entryNotFound() - pluginDir.deleteRecursively() - if (!pluginDir.mkdirs()) throw FileNotFoundException("Unable to create plugin directory") - val pluginDirPath = pluginDir.absolutePath + '/' - do { - val path = cursor.getString(0) - val file = File(pluginDir, path) - check(file.absolutePath.startsWith(pluginDirPath)) - cr.openInputStream(uri.buildUpon().path(path).build())!!.use { inStream -> - file.outputStream().use { outStream -> inStream.copyTo(outStream) } - } - Os.chmod(file.absolutePath, when (cursor.getType(1)) { - Cursor.FIELD_TYPE_INTEGER -> cursor.getInt(1) - Cursor.FIELD_TYPE_STRING -> cursor.getString(1).toInt(8) - else -> throw IllegalArgumentException("File mode should be of type int") - }) - if (path == options.id) initialized = true - } while (cursor.moveToNext()) - } - if (!initialized) entryNotFound() - return File(pluginDir, options.id).absolutePath - } - - fun ComponentInfo.loadString(key: String) = when (val value = metaData.get(key)) { - is String -> value - is Int -> app.packageManager.getResourcesForApplication(applicationInfo).getString(value) - null -> null - else -> error("meta-data $key has invalid type ${value.javaClass}") - } -} diff --git a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginOptions.kt b/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginOptions.kt deleted file mode 100644 index 990db19657..0000000000 --- a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/PluginOptions.kt +++ /dev/null @@ -1,111 +0,0 @@ -/******************************************************************************* - * * - * Copyright (C) 2017 by Max Lv * - * Copyright (C) 2017 by Mygod Studio * - * * - * 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 . * - * * - *******************************************************************************/ - -package com.github.shadowsocks.plugin - -import android.os.Build -import androidx.annotation.RequiresApi -import java.util.* - -/** - * Helper class for processing plugin options. - * - * Based on: https://github.com/apache/ant/blob/588ce1f/src/main/org/apache/tools/ant/types/Commandline.java - */ -@RequiresApi(Build.VERSION_CODES.LOLLIPOP) -class PluginOptions : HashMap { - var id = "" - - constructor() : super() - constructor(initialCapacity: Int) : super(initialCapacity) - constructor(initialCapacity: Int, loadFactor: Float) : super(initialCapacity, loadFactor) - - private constructor(options: String?, parseId: Boolean) : this() { - @Suppress("NAME_SHADOWING") - var parseId = parseId - if (options.isNullOrEmpty()) return - check(options.all { !it.isISOControl() }) { "No control characters allowed." } - val tokenizer = StringTokenizer("$options;", "\\=;", true) - val current = StringBuilder() - var key: String? = null - while (tokenizer.hasMoreTokens()) when (val nextToken = tokenizer.nextToken()) { - "\\" -> current.append(tokenizer.nextToken()) - "=" -> if (key == null) { - key = current.toString() - current.setLength(0) - } else current.append(nextToken) - ";" -> { - if (key != null) { - put(key, current.toString()) - key = null - } else if (current.isNotEmpty()) - if (parseId) id = current.toString() else put(current.toString(), null) - current.setLength(0) - parseId = false - } - else -> current.append(nextToken) - } - } - - constructor(options: String?) : this(options, true) - constructor(id: String, options: String?) : this(options, false) { - this.id = id - } - - /** - * Put but if value is null or default, the entry is deleted. - * - * @return Old value before put. - */ - fun putWithDefault(key: String, value: String?, default: String? = null) = - if (value == null || value == default) remove(key) else put(key, value) - - private fun append(result: StringBuilder, str: String) = str.indices.map { str[it] }.forEach { - when (it) { - '\\', '=', ';' -> { - result.append('\\') // intentionally no break - result.append(it) - } - else -> result.append(it) - } - } - - fun toString(trimId: Boolean): String { - val result = StringBuilder() - if (!trimId) if (id.isEmpty()) return "" else append(result, id) - for ((key, value) in entries) { - if (result.isNotEmpty()) result.append(';') - append(result, key) - if (value != null) { - result.append('=') - append(result, value) - } - } - return result.toString() - } - - override fun toString(): String = toString(true) - - override fun equals(other: Any?): Boolean { - if (this === other) return true - return javaClass == other?.javaClass && super.equals(other) && id == (other as PluginOptions).id - } - override fun hashCode(): Int = Objects.hash(super.hashCode(), id) -} diff --git a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/ResolvedPlugin.kt b/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/ResolvedPlugin.kt deleted file mode 100644 index cc88fc1e56..0000000000 --- a/TMessagesProj/src/main/java/com/github/shadowsocks/plugin/ResolvedPlugin.kt +++ /dev/null @@ -1,55 +0,0 @@ -/******************************************************************************* - * * - * Copyright (C) 2017 by Max Lv * - * Copyright (C) 2017 by Mygod Studio * - * * - * 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 . * - * * - *******************************************************************************/ - -package com.github.shadowsocks.plugin - -import android.content.pm.ComponentInfo -import android.content.pm.ResolveInfo -import android.graphics.drawable.Drawable -import android.os.Build -import androidx.annotation.RequiresApi -import com.github.shadowsocks.plugin.PluginManager.app -import com.github.shadowsocks.plugin.PluginManager.loadString - -@RequiresApi(Build.VERSION_CODES.LOLLIPOP) -abstract class ResolvedPlugin(protected val resolveInfo: ResolveInfo) : Plugin() { - protected abstract val componentInfo: ComponentInfo - - override val id by lazy { componentInfo.loadString(PluginContract.METADATA_KEY_ID)!! } - override val idAliases: Array by lazy { - when (val value = componentInfo.metaData.get(PluginContract.METADATA_KEY_ID_ALIASES)) { - is String -> arrayOf(value) - is Int -> app.packageManager.getResourcesForApplication(componentInfo.applicationInfo).run { - when (getResourceTypeName(value)) { - "string" -> arrayOf(getString(value)) - else -> getStringArray(value) - } - } - null -> emptyArray() - else -> error("unknown type for plugin meta-data idAliases") - } - } - override val label: CharSequence get() = resolveInfo.loadLabel(app.packageManager) - override val icon: Drawable get() = resolveInfo.loadIcon(app.packageManager) - override val defaultConfig by lazy { componentInfo.loadString(PluginContract.METADATA_KEY_DEFAULT_CONFIG) } - override val packageName: String get() = componentInfo.packageName - override val trusted = true - override val directBootAware get() = Build.VERSION.SDK_INT < 24 || componentInfo.directBootAware -} diff --git a/TMessagesProj/src/main/java/com/github/shadowsocks/utils/Commandline.kt b/TMessagesProj/src/main/java/com/github/shadowsocks/utils/Commandline.kt deleted file mode 100644 index 71a02c7936..0000000000 --- a/TMessagesProj/src/main/java/com/github/shadowsocks/utils/Commandline.kt +++ /dev/null @@ -1,159 +0,0 @@ -/******************************************************************************* - * * - * Copyright (C) 2017 by Max Lv * - * Copyright (C) 2017 by Mygod Studio * - * * - * 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 . * - * * - *******************************************************************************/ - -package com.github.shadowsocks.utils - -import java.util.* - -/** - * Commandline objects help handling command lines specifying processes to - * execute. - * - * The class can be used to define a command line as nested elements or as a - * helper to define a command line by an application. - * - * - * ` - *

- *   

- *     

- *     

- *     

- *   


- *


-` * - * - * Based on: https://github.com/apache/ant/blob/588ce1f/src/main/org/apache/tools/ant/types/Commandline.java - * - * Adds support for escape character '\'. - */ -object Commandline { - - /** - * Quote the parts of the given array in way that makes them - * usable as command line arguments. - * @param args the list of arguments to quote. - * @return empty string for null or no command, else every argument split - * by spaces and quoted by quoting rules. - */ - fun toString(args: Iterable?): String { - // empty path return empty string - args ?: return "" - // path containing one or more elements - val result = StringBuilder() - for (arg in args) { - if (result.isNotEmpty()) result.append(' ') - arg.indices.map { arg[it] }.forEach { - when (it) { - ' ', '\\', '"', '\'' -> { - result.append('\\') // intentionally no break - result.append(it) - } - else -> result.append(it) - } - } - } - return result.toString() - } - - /** - * Quote the parts of the given array in way that makes them - * usable as command line arguments. - * @param args the list of arguments to quote. - * @return empty string for null or no command, else every argument split - * by spaces and quoted by quoting rules. - */ - fun toString(args: Array) = toString(args.asIterable()) // thanks to Java, arrays aren't iterable - - /** - * Crack a command line. - * @param toProcess the command line to process. - * @return the command line broken into strings. - * An empty or null toProcess parameter results in a zero sized array. - */ - fun translateCommandline(toProcess: String?): Array { - if (toProcess == null || toProcess.isEmpty()) { - //no command? no string - return arrayOf() - } - // parse with a simple finite state machine - - val normal = 0 - val inQuote = 1 - val inDoubleQuote = 2 - var state = normal - val tok = StringTokenizer(toProcess, "\\\"\' ", true) - val result = ArrayList() - val current = StringBuilder() - var lastTokenHasBeenQuoted = false - var lastTokenIsSlash = false - - while (tok.hasMoreTokens()) { - val nextTok = tok.nextToken() - when (state) { - inQuote -> if ("\'" == nextTok) { - lastTokenHasBeenQuoted = true - state = normal - } else current.append(nextTok) - inDoubleQuote -> when (nextTok) { - "\"" -> if (lastTokenIsSlash) { - current.append(nextTok) - lastTokenIsSlash = false - } else { - lastTokenHasBeenQuoted = true - state = normal - } - "\\" -> lastTokenIsSlash = if (lastTokenIsSlash) { - current.append(nextTok) - false - } else true - else -> { - if (lastTokenIsSlash) { - current.append("\\") // unescaped - lastTokenIsSlash = false - } - current.append(nextTok) - } - } - else -> { - when { - lastTokenIsSlash -> { - current.append(nextTok) - lastTokenIsSlash = false - } - "\\" == nextTok -> lastTokenIsSlash = true - "\'" == nextTok -> state = inQuote - "\"" == nextTok -> state = inDoubleQuote - " " == nextTok -> if (lastTokenHasBeenQuoted || current.isNotEmpty()) { - result.add(current.toString()) - current.setLength(0) - } - else -> current.append(nextTok) - } - lastTokenHasBeenQuoted = false - } - } - } - if (lastTokenHasBeenQuoted || current.isNotEmpty()) result.add(current.toString()) - require(state != inQuote && state != inDoubleQuote) { "unbalanced quotes in $toProcess" } - require(!lastTokenIsSlash) { "escape character following nothing in $toProcess" } - return result.toTypedArray() - } -} diff --git a/TMessagesProj/src/main/java/com/github/shadowsocks/utils/Utils.kt b/TMessagesProj/src/main/java/com/github/shadowsocks/utils/Utils.kt deleted file mode 100644 index a959509886..0000000000 --- a/TMessagesProj/src/main/java/com/github/shadowsocks/utils/Utils.kt +++ /dev/null @@ -1,136 +0,0 @@ -/******************************************************************************* - * * - * Copyright (C) 2018 by Max Lv * - * Copyright (C) 2018 by Mygod Studio * - * * - * 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 . * - * * - *******************************************************************************/ - -package com.github.shadowsocks.utils - -import android.annotation.SuppressLint -import android.content.* -import android.content.pm.PackageInfo -import android.content.res.Resources -import android.graphics.BitmapFactory -import android.graphics.ImageDecoder -import android.net.Uri -import android.os.Build -import android.system.Os -import android.system.OsConstants -import android.util.TypedValue -import androidx.annotation.AttrRes -import androidx.annotation.RequiresApi -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch -import kotlinx.coroutines.suspendCancellableCoroutine -import org.telegram.messenger.FileLog -import java.io.FileDescriptor -import java.net.HttpURLConnection -import java.net.InetAddress -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException - -fun Iterable.forEachTry(action: (T) -> Unit) { - var result: Exception? = null - for (element in this) try { - action(element) - } catch (e: Exception) { - if (result == null) result = e else result.addSuppressed(e) - } - if (result != null) { - FileLog.e(result) - throw result - } -} - -val Throwable.readableMessage get() = localizedMessage ?: javaClass.name - -/** - * https://android.googlesource.com/platform/prebuilts/runtime/+/94fec32/appcompat/hiddenapi-light-greylist.txt#9466 - */ -private val getInt = FileDescriptor::class.java.getDeclaredMethod("getInt$") -val FileDescriptor.int get() = getInt.invoke(this) as Int - -private val parseNumericAddress by lazy @SuppressLint("SoonBlockedPrivateApi") { - InetAddress::class.java.getDeclaredMethod("parseNumericAddress", String::class.java).apply { - isAccessible = true - } -} - -/** - * A slightly more performant variant of parseNumericAddress. - * - * Bug in Android 9.0 and lower: https://issuetracker.google.com/issues/123456213 - */ -@RequiresApi(Build.VERSION_CODES.LOLLIPOP) fun String?.parseNumericAddress(): InetAddress? = Os.inet_pton(OsConstants.AF_INET, this) - ?: Os.inet_pton(OsConstants.AF_INET6, this)?.let { - if (Build.VERSION.SDK_INT >= 29) it else parseNumericAddress.invoke(null, this) as InetAddress - } - -suspend fun HttpURLConnection.useCancellable(block: suspend HttpURLConnection.() -> T): T { - return suspendCancellableCoroutine { cont -> - cont.invokeOnCancellation { - if (Build.VERSION.SDK_INT >= 26) disconnect() else GlobalScope.launch(Dispatchers.IO) { disconnect() } - } - GlobalScope.launch(Dispatchers.IO) { - try { - cont.resume(block()) - } catch (e: Throwable) { - cont.resumeWithException(e) - } - } - } -} - -fun parsePort(str: String?, default: Int, min: Int = 1025): Int { - val value = str?.toIntOrNull() ?: default - return if (value < min || value > 65535) default else value -} - -fun broadcastReceiver(callback: (Context, Intent) -> Unit): BroadcastReceiver = object : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) = callback(context, intent) -} - -fun Context.listenForPackageChanges(onetime: Boolean = true, callback: () -> Unit) = object : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - callback() - if (onetime) context.unregisterReceiver(this) - } -}.apply { - registerReceiver(this, IntentFilter().apply { - addAction(Intent.ACTION_PACKAGE_ADDED) - addAction(Intent.ACTION_PACKAGE_REMOVED) - addDataScheme("package") - }) -} - -fun ContentResolver.openBitmap(uri: Uri) = - if (Build.VERSION.SDK_INT >= 28) ImageDecoder.decodeBitmap(ImageDecoder.createSource(this, uri)) - else BitmapFactory.decodeStream(openInputStream(uri)) - -val PackageInfo.signaturesCompat - get() = - if (Build.VERSION.SDK_INT >= 28) signingInfo.apkContentsSigners else @Suppress("DEPRECATION") signatures - -/** - * Based on: https://stackoverflow.com/a/26348729/2245107 - */ -fun Resources.Theme.resolveResourceId(@AttrRes resId: Int): Int { - val typedValue = TypedValue() - if (!resolveAttribute(resId, typedValue, true)) throw Resources.NotFoundException() - return typedValue.resourceId -} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/com/v2ray/ang/V2RayConfig.kt b/TMessagesProj/src/main/java/com/v2ray/ang/V2RayConfig.kt deleted file mode 100644 index 39b57eafcf..0000000000 --- a/TMessagesProj/src/main/java/com/v2ray/ang/V2RayConfig.kt +++ /dev/null @@ -1,70 +0,0 @@ -package com.v2ray.ang - -/** - * - * App Config Const - */ -object V2RayConfig { - const val ANG_PACKAGE = "com.v2ray.ang" - const val ANG_CONFIG = "ang_config" - const val PREF_CURR_CONFIG = "pref_v2ray_config" - const val PREF_CURR_CONFIG_GUID = "pref_v2ray_config_guid" - const val PREF_CURR_CONFIG_NAME = "pref_v2ray_config_name" - const val PREF_CURR_CONFIG_DOMAIN = "pref_v2ray_config_domain" - const val PREF_INAPP_BUY_IS_PREMIUM = "pref_inapp_buy_is_premium" - const val VMESS_PROTOCOL: String = "vmess://" - const val VMESS1_PROTOCOL = "vmess1://" - const val SS_PROTOCOL: String = "ss://" - const val SSR_PROTOCOL: String = "ssr://" - const val TROJAN_PROTOCOL: String = "trojan://" - const val WS_PROTOCOL: String = "ws://" - const val WSS_PROTOCOL: String = "wss://" - - const val SOCKS_PROTOCOL: String = "socks://" - const val BROADCAST_ACTION_SERVICE = "com.v2ray.ang.action.service" - const val BROADCAST_ACTION_ACTIVITY = "com.v2ray.ang.action.activity" - const val BROADCAST_ACTION_WIDGET_CLICK = "com.v2ray.ang.action.widget.click" - - const val TASKER_EXTRA_BUNDLE = "com.twofortyfouram.locale.intent.extra.BUNDLE" - const val TASKER_EXTRA_STRING_BLURB = "com.twofortyfouram.locale.intent.extra.BLURB" - const val TASKER_EXTRA_BUNDLE_SWITCH = "tasker_extra_bundle_switch" - const val TASKER_EXTRA_BUNDLE_GUID = "tasker_extra_bundle_guid" - const val TASKER_DEFAULT_GUID = "Default" - - const val PREF_V2RAY_ROUTING_AGENT = "pref_v2ray_routing_agent" - const val PREF_V2RAY_ROUTING_DIRECT = "pref_v2ray_routing_direct" - const val PREF_V2RAY_ROUTING_BLOCKED = "pref_v2ray_routing_blocked" - const val TAG_AGENT = "proxy" - const val TAG_DIRECT = "direct" - const val TAG_BLOCKED = "block" - - const val androidpackagenamelistUrl = "https://raw.githubusercontent.com/2dust/androidpackagenamelist/master/proxy.txt" - const val v2rayCustomRoutingListUrl = "https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/" - const val v2rayNGIssues = "https://github.com/2dust/v2rayNG/issues" - const val promotionUrl = "https://1.2345345.xyz/ads.html" - - const val DNS_AGENT = "1.1.1.1" - const val DNS_DIRECT = "223.5.5.5" - - const val MSG_REGISTER_CLIENT = 1 - const val MSG_STATE_RUNNING = 11 - const val MSG_STATE_NOT_RUNNING = 12 - const val MSG_UNREGISTER_CLIENT = 2 - const val MSG_STATE_START = 3 - const val MSG_STATE_START_SUCCESS = 31 - const val MSG_STATE_START_FAILURE = 32 - const val MSG_STATE_STOP = 4 - const val MSG_STATE_STOP_SUCCESS = 41 - const val MSG_STATE_RESTART = 5 - - object EConfigType { - - @JvmField - val Vmess = 1 - - @JvmField - val Trojan = 2 - - } - -} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/com/v2ray/ang/dto/AngConfig.kt b/TMessagesProj/src/main/java/com/v2ray/ang/dto/AngConfig.kt deleted file mode 100644 index 46aeeaba0c..0000000000 --- a/TMessagesProj/src/main/java/com/v2ray/ang/dto/AngConfig.kt +++ /dev/null @@ -1,82 +0,0 @@ -package com.v2ray.ang.dto - -import cn.hutool.core.codec.Base64 -import com.google.gson.Gson -import com.v2ray.ang.V2RayConfig -import com.v2ray.ang.V2RayConfig.TROJAN_PROTOCOL -import com.v2ray.ang.V2RayConfig.VMESS_PROTOCOL -import com.v2ray.ang.util.Utils - -data class AngConfig( - var index: Int, - var vmess: ArrayList, - var subItem: ArrayList -) { - data class VmessBean(var guid: String = "123456", - var address: String = "", - var port: Int = 443, - var id: String = "", - var alterId: Int = 0, - var security: String = "auto", - var network: String = "tcp", - var remarks: String = "", - var headerType: String = "none", - var requestHost: String = "", - var path: String = "", - var streamSecurity: String = "", - var configType: Int = 1, - var configVersion: Int = 2, - var testResult: String = "") { - - override fun equals(other: Any?): Boolean { - return super.equals(other) || (other is VmessBean && - address == other.address && - port == other.port && - id == other.id && - network == other.network && - headerType == other.headerType && - requestHost == other.requestHost && - path == other.path) - } - - override fun toString(): String { - - if (configType == V2RayConfig.EConfigType.Vmess) { - - val vmessQRCode = VmessQRCode() - - vmessQRCode.v = configVersion.toString() - vmessQRCode.ps = remarks - vmessQRCode.add = address - vmessQRCode.port = port.toString() - vmessQRCode.id = id - vmessQRCode.aid = alterId.toString() - vmessQRCode.net = network - vmessQRCode.type = headerType - vmessQRCode.host = requestHost - vmessQRCode.path = path - vmessQRCode.tls = streamSecurity - - return VMESS_PROTOCOL + Base64.encode(Gson().toJson(vmessQRCode)) - - } else if (configType == V2RayConfig.EConfigType.Trojan) { - - val params = if (requestHost.isNotBlank()) "?sni=" + Utils.urlEncode(requestHost) else "" - val remark = if (remarks.isNotBlank()) "#" + Utils.urlEncode(remarks) else "" - - return TROJAN_PROTOCOL + Utils.urlEncode(id) + "@" + address + ":" + port + params + remark - - } else { - - error("invalid vmess bean type") - - } - - } - - } - - data class SubItemBean(var id: String = "", - var remarks: String = "", - var url: String = "") -} diff --git a/TMessagesProj/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt b/TMessagesProj/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt deleted file mode 100644 index 756df2b213..0000000000 --- a/TMessagesProj/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt +++ /dev/null @@ -1,139 +0,0 @@ -package com.v2ray.ang.dto - -data class V2rayConfig( - val stats: Any?=null, - val log: LogBean, - val policy: PolicyBean, - val inbounds: ArrayList, - var outbounds: ArrayList, - var dns: DnsBean, - val routing: RoutingBean) { - - data class LogBean(val access: String, - val error: String, - val loglevel: String) - - data class InboundBean( - var tag: String, - var port: Int, - var protocol: String, - var listen: String?=null, - val settings: InSettingsBean, - val sniffing: SniffingBean?) { - - data class InSettingsBean(val auth: String? = null, - val udp: Boolean? = null, - val userLevel: Int? =null, - val address: String? = null, - val port: Int? = null, - val network: String? = null) - - data class SniffingBean(var enabled: Boolean, - val destOverride: List) - } - - data class OutboundBean(val tag: String, - var protocol: String, - var settings: OutSettingsBean?, - var streamSettings: StreamSettingsBean?, - var mux: MuxBean?) { - - data class OutSettingsBean(var vnext: List?, - var servers: List?) { - - data class VnextBean(var address: String, - var port: Int, - var users: List) { - - data class UsersBean(var id: String, - var alterId: Int, - var security: String, - var level: Int) - } - - data class ServersBean(var address: String, - var password: String, - var port: Int, - var email: String) - - } - - data class StreamSettingsBean(var network: String, - var security: String, - var tcpSettings: TcpsettingsBean?, - var kcpsettings: KcpsettingsBean?, - var wssettings: WssettingsBean?, - var httpsettings: HttpsettingsBean?, - var tlssettings: TlssettingsBean?, - var quicsettings: QuicsettingBean? - ) { - - data class TcpsettingsBean(var connectionReuse: Boolean = true, - var header: HeaderBean = HeaderBean()) { - data class HeaderBean(var type: String = "none", - var request: Any? = null, - var response: Any? = null) - } - - data class KcpsettingsBean(var mtu: Int = 1350, - var tti: Int = 20, - var uplinkCapacity: Int = 12, - var downlinkCapacity: Int = 100, - var congestion: Boolean = false, - var readBufferSize: Int = 1, - var writeBufferSize: Int = 1, - var header: HeaderBean = HeaderBean()) { - data class HeaderBean(var type: String = "none") - } - - data class WssettingsBean(var connectionReuse: Boolean = true, - var path: String = "", - var headers: HeadersBean = HeadersBean()) { - data class HeadersBean(var Host: String = "") - } - - data class HttpsettingsBean(var host: List = ArrayList(), var path: String = "") - - data class TlssettingsBean(var serverName: String = "", - var allowInsecure: Boolean = false, - var allowInsecureCiphers: Boolean = false) - - data class QuicsettingBean(var security: String = "none", - var key: String = "", - var header: HeaderBean = HeaderBean()) { - data class HeaderBean(var type: String = "none") - } - } - - data class MuxBean(var enabled: Boolean) - } - - //data class DnsBean(var servers: List) - data class DnsBean(var servers: List?=null, - var hosts: Map?=null - ) { - data class ServersBean(var address: String = "", - var port: Int = 0, - var domains: List?) - } - - data class RoutingBean(var domainStrategy: String, - var rules: ArrayList) { - - data class RulesBean(var type: String = "", - var ip: ArrayList? = null, - var domain: ArrayList? = null, - var outboundTag: String = "", - var port: String? = null, - var inboundTag: ArrayList? = null) - } - - data class PolicyBean(var levels: Map, - var system: Any?=null) { - data class LevelBean( - var handshake: Int? = null, - var connIdle: Int? = null, - var uplinkOnly: Int? = null, - var downlinkOnly: Int? = null) - } -} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/com/v2ray/ang/dto/VmessQRCode.kt b/TMessagesProj/src/main/java/com/v2ray/ang/dto/VmessQRCode.kt deleted file mode 100644 index 30618017b1..0000000000 --- a/TMessagesProj/src/main/java/com/v2ray/ang/dto/VmessQRCode.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.v2ray.ang.dto - -data class VmessQRCode(var v: String = "", - var ps: String = "", - var add: String = "", - var port: String = "", - var id: String = "", - var aid: String = "", - var net: String = "", - var type: String = "", - var host: String = "", - var path: String = "", - var tls: String = "") \ No newline at end of file diff --git a/TMessagesProj/src/main/java/com/v2ray/ang/util/V2rayConfigUtil.kt b/TMessagesProj/src/main/java/com/v2ray/ang/util/V2rayConfigUtil.kt deleted file mode 100644 index 21ab95180e..0000000000 --- a/TMessagesProj/src/main/java/com/v2ray/ang/util/V2rayConfigUtil.kt +++ /dev/null @@ -1,379 +0,0 @@ -package com.v2ray.ang.util - -import android.text.TextUtils -import com.google.gson.Gson -import com.google.gson.GsonBuilder -import com.google.gson.JsonArray -import com.google.gson.JsonObject -import com.v2ray.ang.V2RayConfig -import com.v2ray.ang.dto.AngConfig.VmessBean -import com.v2ray.ang.dto.V2rayConfig -import com.v2ray.ang.dto.V2rayConfig.OutboundBean.OutSettingsBean -import com.v2ray.ang.dto.V2rayConfig.OutboundBean.StreamSettingsBean.TlssettingsBean -import org.json.JSONArray -import org.json.JSONException -import org.json.JSONObject - -object V2rayConfigUtil { - private val requestObj: JsonObject by lazy { - Gson().fromJson("""{"version":"1.1","method":"GET","path":["/"],"headers":{"User-Agent":["Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36","Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46"],"Accept-Encoding":["gzip, deflate"],"Connection":["keep-alive"],"Pragma":"no-cache"}}""", JsonObject::class.java) - } - -// private val responseObj: JSONObject by lazy { -// JSONObject("""{"version":"1.1","status":"200","reason":"OK","headers":{"Content-Type":["application/octet-stream","video/mpeg"],"Transfer-Encoding":["chunked"],"Connection":["keep-alive"],"Pragma":"no-cache"}}""") -// } - - data class Result(var status: Boolean, var content: String) - - @JvmStatic - var currDomain: String = "" - - /** - * 生成v2ray的客户端配置文件 - */ - @JvmStatic - fun getV2rayConfig(vmess: VmessBean, port: Int): Result { - val result = Result(false, "") - try { - //取得默认配置 - val assets = Utils.readTextFromAssets("v2ray_config.json") - if (TextUtils.isEmpty(assets)) { - return result - } - - //转成Json - val v2rayConfig = Gson().fromJson(assets, V2rayConfig::class.java) ?: return result -// if (v2rayConfig == null) { -// return result -// } - - inbounds(vmess, v2rayConfig, port) - - outbounds(vmess, v2rayConfig) - - routing(vmess, v2rayConfig) - - val finalConfig = GsonBuilder().setPrettyPrinting().create().toJson(v2rayConfig) - - result.status = true - result.content = finalConfig - return result - - } catch (e: Exception) { - e.printStackTrace() - return result - } - } - - /** - * - */ - private fun inbounds(vmess: VmessBean, v2rayConfig: V2rayConfig, port: Int): Boolean { - try { - v2rayConfig.inbounds.forEach { curInbound -> - curInbound.listen = "127.0.0.1" - } - v2rayConfig.inbounds[0].port = port -// val socksPort = Utils.parseInt(app.defaultDPreference.getPrefString(SettingsActivity.PREF_SOCKS_PORT, "10808")) -// val lanconnPort = Utils.parseInt(app.defaultDPreference.getPrefString(SettingsActivity.PREF_HTTP_PORT, "")) - -// if (socksPort > 0) { -// v2rayConfig.inbounds[0].port = socksPort -// } -// if (lanconnPort > 0) { -// val httpCopy = v2rayConfig.inbounds[0].copy() -// httpCopy.port = lanconnPort -// httpCopy.protocol = "http" -// v2rayConfig.inbounds.add(httpCopy) -// } - v2rayConfig.inbounds[0].sniffing?.enabled = false - - } catch (e: Exception) { - e.printStackTrace() - return false - } - return true - } - - /** - * vmess协议服务器配置 - */ - private fun outbounds(vmess: VmessBean, v2rayConfig: V2rayConfig): Boolean { - try { - val outbound = v2rayConfig.outbounds[0] - - when (vmess.configType) { - V2RayConfig.EConfigType.Vmess -> { - outbound.settings?.servers = null - - val vnext = v2rayConfig.outbounds[0].settings?.vnext?.get(0) - vnext?.address = vmess.address - vnext?.port = vmess.port - val user = vnext?.users?.get(0) - user?.id = vmess.id - user?.alterId = vmess.alterId - user?.security = vmess.security - user?.level = 8 - - //Mux - val muxEnabled = false//app.defaultDPreference.getPrefBoolean(SettingsActivity.PREF_MUX_ENABLED, false) - outbound.mux?.enabled = muxEnabled - - //远程服务器底层传输配置 - outbound.streamSettings = boundStreamSettings(vmess) - - outbound.protocol = "vmess" - } - V2RayConfig.EConfigType.Trojan -> { - - outbound.streamSettings = V2rayConfig.OutboundBean.StreamSettingsBean( - "tcp", - "tls", null,null,null,null, - TlssettingsBean(vmess.requestHost), null) - - outbound.settings?.vnext = null - - outbound.settings = OutSettingsBean(null, listOf(OutSettingsBean.ServersBean( - vmess.address, - vmess.id, - vmess.port, - "user@neko.gram" - ))) - - //Mux - outbound.mux?.enabled = false - - outbound.protocol = "trojan" - - } - else -> { - } - } - - var serverDomain: String - if (Utils.isIpv6Address(vmess.address)) { - serverDomain = String.format("[%s]:%s", vmess.address, vmess.port) - } else { - serverDomain = String.format("%s:%s", vmess.address, vmess.port) - } - currDomain = serverDomain - } catch (e: Exception) { - e.printStackTrace() - return false - } - return true - } - - /** - * 远程服务器底层传输配置 - */ - private fun boundStreamSettings(vmess: VmessBean): V2rayConfig.OutboundBean.StreamSettingsBean { - val streamSettings = V2rayConfig.OutboundBean.StreamSettingsBean("", "", null, null, null, null, null, null) - try { - //远程服务器底层传输配置 - streamSettings.network = vmess.network - streamSettings.security = vmess.streamSecurity - - //streamSettings - when (streamSettings.network) { - "kcp" -> { - val kcpsettings = V2rayConfig.OutboundBean.StreamSettingsBean.KcpsettingsBean() - kcpsettings.mtu = 1350 - kcpsettings.tti = 50 - kcpsettings.uplinkCapacity = 12 - kcpsettings.downlinkCapacity = 100 - kcpsettings.congestion = false - kcpsettings.readBufferSize = 1 - kcpsettings.writeBufferSize = 1 - kcpsettings.header = V2rayConfig.OutboundBean.StreamSettingsBean.KcpsettingsBean.HeaderBean() - kcpsettings.header.type = vmess.headerType - streamSettings.kcpsettings = kcpsettings - } - "ws" -> { - val wssettings = V2rayConfig.OutboundBean.StreamSettingsBean.WssettingsBean() - wssettings.connectionReuse = true - val host = vmess.requestHost.trim() - val path = vmess.path.trim() - - if (!TextUtils.isEmpty(host)) { - wssettings.headers = V2rayConfig.OutboundBean.StreamSettingsBean.WssettingsBean.HeadersBean() - wssettings.headers.Host = host - } - if (!TextUtils.isEmpty(path)) { - wssettings.path = path - } - streamSettings.wssettings = wssettings - - val tlssettings = TlssettingsBean() - tlssettings.allowInsecure = true - if (!TextUtils.isEmpty(host)) { - tlssettings.serverName = host - } - streamSettings.tlssettings = tlssettings - } - "h2" -> { - val httpsettings = V2rayConfig.OutboundBean.StreamSettingsBean.HttpsettingsBean() - val host = vmess.requestHost.trim() - val path = vmess.path.trim() - - if (!TextUtils.isEmpty(host)) { - httpsettings.host = host.split(",").map { it.trim() } - } - httpsettings.path = path - streamSettings.httpsettings = httpsettings - - val tlssettings = TlssettingsBean() - tlssettings.allowInsecure = true - streamSettings.tlssettings = tlssettings - } - "quic" -> { - val quicsettings = V2rayConfig.OutboundBean.StreamSettingsBean.QuicsettingBean() - val host = vmess.requestHost.trim() - val path = vmess.path.trim() - - quicsettings.security = host - quicsettings.key = path - - quicsettings.header = V2rayConfig.OutboundBean.StreamSettingsBean.QuicsettingBean.HeaderBean() - quicsettings.header.type = vmess.headerType - - streamSettings.quicsettings = quicsettings - } - else -> { - //tcp带http伪装 - if (vmess.headerType == "http") { - val tcpSettings = V2rayConfig.OutboundBean.StreamSettingsBean.TcpsettingsBean() - tcpSettings.connectionReuse = true - tcpSettings.header = V2rayConfig.OutboundBean.StreamSettingsBean.TcpsettingsBean.HeaderBean() - tcpSettings.header.type = vmess.headerType - -// if (requestObj.has("headers") -// || requestObj.optJSONObject("headers").has("Pragma")) { -// val arrHost = ArrayList() -// vmess.requestHost -// .split(",") -// .forEach { -// arrHost.add(it) -// } -// requestObj.optJSONObject("headers") -// .put("Host", arrHost) -// -// } - if (!TextUtils.isEmpty(vmess.requestHost)) { - val arrHost = ArrayList() - vmess.requestHost - .split(",") - .forEach { - arrHost.add("\"$it\"") - } - requestObj.getAsJsonObject("headers") - .add("Host", Gson().fromJson(arrHost.toString(), JsonArray::class.java)) - } - if (!TextUtils.isEmpty(vmess.path)) { - val arrPath = ArrayList() - vmess.path - .split(",") - .forEach { - arrPath.add("\"$it\"") - } - requestObj.add("path", Gson().fromJson(arrPath.toString(), JsonArray::class.java)) - } - tcpSettings.header.request = requestObj - //tcpSettings.header.response = responseObj - streamSettings.tcpSettings = tcpSettings - } - } - } - } catch (e: Exception) { - e.printStackTrace() - return streamSettings - } - return streamSettings - } - - /** - * routing - */ - private fun routing(vmess: VmessBean, v2rayConfig: V2rayConfig) { - - v2rayConfig.routing.domainStrategy = "IPIfNonMatch" - - } - - /** - * is valid config - */ - fun isValidConfig(conf: String): Boolean { - try { - val jObj = JSONObject(conf) - var hasBound = false - //hasBound = (jObj.has("outbounds") and jObj.has("inbounds")) or (jObj.has("outbound") and jObj.has("inbound")) - hasBound = (jObj.has("outbounds")) or (jObj.has("outbound")) - return hasBound - } catch (e: JSONException) { - return false - } - } - - private fun parseDomainName(jsonConfig: String): String { - try { - val jObj = JSONObject(jsonConfig) - var domainName: String - if (jObj.has("outbound")) { - domainName = parseDomainName(jObj.optJSONObject("outbound")) - if (!TextUtils.isEmpty(domainName)) { - return domainName - } - } - if (jObj.has("outbounds")) { - for (i in 0..(jObj.optJSONArray("outbounds").length() - 1)) { - domainName = parseDomainName(jObj.optJSONArray("outbounds").getJSONObject(i)) - if (!TextUtils.isEmpty(domainName)) { - return domainName - } - } - } - if (jObj.has("outboundDetour")) { - for (i in 0..(jObj.optJSONArray("outboundDetour").length() - 1)) { - domainName = parseDomainName(jObj.optJSONArray("outboundDetour").getJSONObject(i)) - if (!TextUtils.isEmpty(domainName)) { - return domainName - } - } - } - } catch (e: Exception) { - e.printStackTrace() - } - return "" - } - - private fun parseDomainName(outbound: JSONObject): String { - try { - if (outbound.has("settings")) { - var vnext: JSONArray? - if (outbound.optJSONObject("settings").has("vnext")) { - // vmess - vnext = outbound.optJSONObject("settings").optJSONArray("vnext") - } else if (outbound.optJSONObject("settings").has("servers")) { - // shadowsocks or socks - vnext = outbound.optJSONObject("settings").optJSONArray("servers") - } else { - return "" - } - for (i in 0..(vnext.length() - 1)) { - val item = vnext.getJSONObject(i) - val address = item.getString("address") - val port = item.getString("port") - if (Utils.isIpv6Address(address)) { - return String.format("[%s]:%s", address, port) - } else { - return String.format("%s:%s", address, port) - } - } - } - } catch (e: Exception) { - e.printStackTrace() - } - return "" - } -} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java index f593671e4b..ea86ad1109 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java @@ -208,24 +208,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import cn.hutool.core.util.StrUtil; -import kotlin.Unit; -import tw.nekomimi.nekogram.ui.BottomBuilder; import tw.nekomimi.nekogram.NekoConfig; -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; -import static com.v2ray.ang.V2RayConfig.SS_PROTOCOL; -import static com.v2ray.ang.V2RayConfig.TROJAN_PROTOCOL; -import static com.v2ray.ang.V2RayConfig.VMESS1_PROTOCOL; -import static com.v2ray.ang.V2RayConfig.VMESS_PROTOCOL; -import static com.v2ray.ang.V2RayConfig.WSS_PROTOCOL; -import static com.v2ray.ang.V2RayConfig.WS_PROTOCOL; public class AndroidUtilities { public final static int LIGHT_STATUS_BAR_OVERLAY = 0x0f000000, DARK_STATUS_BAR_OVERLAY = 0x33000000; @@ -948,34 +933,6 @@ private static void gatherLinks(ArrayList links, Spannable s, Pattern return true; }; - public static boolean addProxyLinks(Spannable text) { - if (text == null) return false; - final URLSpan[] old = text.getSpans(0, text.length(), URLSpan.class); - for (int i = old.length - 1; i >= 0; i--) { - String url = old[i].getURL(); - if (url.startsWith("vmess") || url.startsWith("ss")) { - text.removeSpan(old[i]); - } - } - final ArrayList links = new ArrayList<>(); - gatherLinks(links, text, LinkifyPort.PROXY_PATTERN, new String[]{VMESS_PROTOCOL, VMESS1_PROTOCOL, SS_PROTOCOL, SSR_PROTOCOL, TROJAN_PROTOCOL, WS_PROTOCOL, WSS_PROTOCOL,/*, RB_PROTOCOL*/}, sUrlMatchFilter, false); - pruneOverlaps(links); - if (links.size() == 0) { - return false; - } - for (int a = 0, N = links.size(); a < N; a++) { - LinkSpec link = links.get(a); - URLSpan[] oldSpans = text.getSpans(link.start, link.end, URLSpan.class); - if (oldSpans != null && oldSpans.length > 0) { - for (int b = 0; b < oldSpans.length; b++) { - text.removeSpan(oldSpans[b]); - } - } - text.setSpan(new URLSpan(link.url), link.start, link.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } - return true; - } - public static boolean addLinks(Spannable text, int mask) { return addLinks(text, mask, false); } @@ -3990,27 +3947,68 @@ public static boolean handleProxyIntent(Activity activity, Intent intent) { 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; } @@ -4030,7 +4028,7 @@ public static boolean shouldEnableAnimation() { return true; } - public static void showProxyAlert(Context activity, final String address, final String port, final String user, final String password, final String secret, final String remarks) { + public static void showProxyAlert(Activity activity, final String address, final String port, final String user, final String password, final String secret) { BottomSheet.Builder builder = new BottomSheet.Builder(activity); final Runnable dismissRunnable = builder.getDismissRunnable(); @@ -4136,640 +4134,42 @@ protected void onDetachedFromWindow() { 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) -> { - - 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.addProxy(info); - - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged); - - dismissRunnable.run(); - - }); - 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.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(); - int 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(); - int 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(); - int 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); - } 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 == 6) { - - RequestTimeDelegate callback = new RequestTimeDelegate() { - @Override - public void run(long time) { - int c = count.getAndIncrement(); - int 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 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); + info = new SharedConfig.ProxyInfo(address, p, user, password, ""); } 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(); - int 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); - } - - }); - + editor.remove("proxy_pass"); + editor.remove("proxy_user"); + editor.putString("proxy_secret", secret); + info = new SharedConfig.ProxyInfo(address, p, "", "", secret); } - } + editor.commit(); - 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); + SharedConfig.currentProxy = 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(); @@ -4789,17 +4189,6 @@ public void run(long time) { 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(); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java index 108d799b0a..fd08947a4d 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -5675,12 +5675,6 @@ public void generateCaption() { addUrlsByPattern(isOutOwner(), caption, true, 0, 0, true); } - try { - AndroidUtilities.addProxyLinks((Spannable) caption); - } catch (Exception e) { - FileLog.e(e); - } - addEntitiesToText(caption, useManualParse); if (isVideo()) { addUrlsByPattern(isOutOwner(), caption, true, 3, (int) getDuration(), false); @@ -6450,11 +6444,6 @@ private boolean applyEntities() { // } // } } - try { - AndroidUtilities.addProxyLinks((Spannable) messageText); - } catch (Throwable e) { - FileLog.e(e); - } if (isYouTubeVideo()) { addUrlsByPattern(isOutOwner(), messageText, false, 3, Integer.MAX_VALUE, false); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index 5034a5faca..4e707211a9 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -8972,7 +8972,7 @@ private void checkPromoInfoInternal(boolean reset) { TLRPC.TL_help_promoData res = (TLRPC.TL_help_promoData) response; SharedConfig.ProxyInfo proxy = SharedConfig.currentProxy; - if (res.proxy && (NekoConfig.hideProxySponsorChannel.Bool() || (proxy != null && proxy.subId == 1L))) { + if (res.proxy && (NekoConfig.hideProxySponsorChannel.Bool())) { nextPromoInfoCheckTime = getConnectionsManager().getCurrentTime() + 60 * 60; noDialog = true; } else { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java index 7238948662..721d0fea11 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java @@ -28,10 +28,6 @@ import androidx.annotation.RequiresApi; import androidx.core.content.pm.ShortcutManagerCompat; -import com.v2ray.ang.V2RayConfig; -import com.v2ray.ang.dto.AngConfig; -import com.v2ray.ang.util.Utils; - import org.apache.commons.lang3.StringUtils; import org.dizitart.no2.objects.filters.ObjectFilters; import org.json.JSONArray; @@ -69,23 +65,12 @@ import cn.hutool.core.util.StrUtil; import okhttp3.HttpUrl; import tw.nekomimi.nekogram.NekoConfig; -import tw.nekomimi.nekogram.proxy.ProxyManager; -import tw.nekomimi.nekogram.proxy.ShadowsocksLoader; -import tw.nekomimi.nekogram.proxy.ShadowsocksRLoader; -import tw.nekomimi.nekogram.proxy.VmessLoader; -import tw.nekomimi.nekogram.proxy.tcp2ws.WsLoader; -import tw.nekomimi.nekogram.proxy.SubInfo; -import tw.nekomimi.nekogram.proxy.SubManager; import tw.nekomimi.nekogram.utils.AlertUtil; import tw.nekomimi.nekogram.utils.EnvUtil; import tw.nekomimi.nekogram.utils.FileUtil; import tw.nekomimi.nekogram.utils.UIUtil; import xyz.nextalone.nagram.NaConfig; -import static com.v2ray.ang.V2RayConfig.SSR_PROTOCOL; -import static com.v2ray.ang.V2RayConfig.SS_PROTOCOL; -import static com.v2ray.ang.V2RayConfig.WSS_PROTOCOL; -import static com.v2ray.ang.V2RayConfig.WS_PROTOCOL; import java.util.List; import java.util.Locale; @@ -296,951 +281,160 @@ private static boolean isWhitelisted(MediaCodecInfo codecInfo) { public static boolean bigCameraForRound; public static boolean useSurfaceInStories; public static boolean photoViewerBlur = true; - public static boolean payByInvoice; - public static int stealthModeSendMessageConfirm = 2; - private static int lastLocalId = -210000; - - public static String storageCacheDir; - - private static String passportConfigJson = ""; - private static HashMap passportConfigMap; - public static int passportConfigHash; - - private static boolean configLoaded; - private static final Object sync = new Object(); - private static final Object localIdSync = new Object(); - -// public static int saveToGalleryFlags; - public static int mapPreviewType = 2; - public static boolean chatBubbles = Build.VERSION.SDK_INT >= 30; - public static boolean raiseToSpeak = false; - public static boolean raiseToListen = true; - public static boolean nextMediaTap = true; - public static boolean recordViaSco = false; - public static boolean customTabs = true; - public static boolean directShare = true; - public static boolean inappCamera = true; - public static boolean roundCamera16to9 = true; - public static boolean noSoundHintShowed = false; - public static boolean streamMedia = true; - public static boolean streamAllVideo = false; - public static boolean streamMkv = false; - public static boolean saveStreamMedia = true; - public static boolean pauseMusicOnRecord = false; - public static boolean pauseMusicOnMedia = false; - public static boolean noiseSupression; - public static final boolean noStatusBar = true; - public static boolean debugWebView; - public static boolean sortContactsByName; - public static boolean sortFilesByName; - public static boolean shuffleMusic; - public static boolean playOrderReversed; - public static boolean hasCameraCache; - public static boolean showNotificationsForAllAccounts = true; - public static int repeatMode; - public static boolean allowBigEmoji; - public static int fontSize = 12; - public static boolean fontSizeIsDefault; - public static int bubbleRadius = 3; - public static int ivFontSize = 12; - public static boolean proxyRotationEnabled; - public static int proxyRotationTimeout; - public static int messageSeenHintCount; - public static int emojiInteractionsHintCount; - public static int dayNightThemeSwitchHintCount; - public static int callEncryptionHintDisplayedCount; - - public static TLRPC.TL_help_appUpdate pendingAppUpdate; - public static int pendingAppUpdateBuildVersion; - public static long lastUpdateCheckTime; - - public static boolean hasEmailLogin; - - @PerformanceClass - private static int devicePerformanceClass; - @PerformanceClass - private static int overrideDevicePerformanceClass; - - public static boolean drawDialogIcons; - public static boolean useThreeLinesLayout; - public static boolean archiveHidden; - - private static int chatSwipeAction; - - public static int distanceSystemType; - public static int mediaColumnsCount = 3; - public static int storiesColumnsCount = 3; - public static int fastScrollHintCount = 3; - public static boolean dontAskManageStorage; - public static boolean multipleReactionsPromoShowed; - - public static boolean translateChats = true; - - public static CopyOnWriteArraySet activeAccounts; - public static int loginingAccount = -1; - - public static boolean isFloatingDebugActive; - public static LiteMode liteMode; - - private static final int[] LOW_SOC = { - -1775228513, // EXYNOS 850 - 802464304, // EXYNOS 7872 - 802464333, // EXYNOS 7880 - 802464302, // EXYNOS 7870 - 2067362118, // MSM8953 - 2067362060, // MSM8937 - 2067362084, // MSM8940 - 2067362241, // MSM8992 - 2067362117, // MSM8952 - 2067361998, // MSM8917 - -1853602818 // SDM439 - }; - - static { - loadConfig(); - } - - public static class ProxyInfo implements Comparable { - - public int group; - - public String address; - public int port; - public String username; - public String password; - public String secret; - - public long proxyCheckPingId; - public long ping; - public boolean checking; - public boolean available; - public long availableCheckTime; - - @Override - public int compareTo(ProxyInfo info) { - - if (available && !info.available) { - return -1; - } else if (!available && info.available) { - return 1; - } else if (available && info.available) { - return (int) (ping - info.ping); - } else { - return hashCode() + "".compareTo(info.hashCode() + ""); - } - - } - - public long subId; - - public ProxyInfo() { - address = ""; - password = ""; - username = ""; - secret = ""; - } - - public ProxyInfo(String address, int port, String username, String password, String secret) { - this.address = address; - this.port = port; - this.username = username; - this.password = password; - this.secret = secret; - if (this.address == null) { - this.address = ""; - } - if (this.password == null) { - this.password = ""; - } - if (this.username == null) { - this.username = ""; - } - if (this.secret == null) { - this.secret = ""; - } - } - - public String getAddress() { - - return address + ":" + port; - - } - - public String getType() { - - if (!StrUtil.isBlank(secret)) { - - return "MTProto"; - - } else { - - return "Socks5"; - - } - - } - - public String getTitle() { - - StringBuilder builder = new StringBuilder(); - - builder.append("[ "); - - if (subId != 0L) { - - try { - - builder.append(SubManager.getSubList().find(ObjectFilters.eq("id", subId)).firstOrDefault().displayName()); - - } catch (Exception e) { - - builder.append("Unknown"); - - } - - } else { - - builder.append(getType()); - - } - - builder.append(" ] "); - - if (StrUtil.isBlank(getRemarks())) { - - builder.append(getAddress()); - - } else { - - builder.append(getRemarks()); - - } - - return builder.toString(); - - } - - private String remarks; - - public String getRemarks() { - - return remarks; - - } - - public void setRemarks(String remarks) { - this.remarks = remarks; - if (StrUtil.isBlank(remarks)) { - this.remarks = null; - } - } - - public String toUrl() { - - HttpUrl.Builder builder = HttpUrl.parse(StrUtil.isBlank(secret) ? - "https://t.me/socks" : "https://t.me/proxy").newBuilder() - .addQueryParameter("server", address) - .addQueryParameter("port", port + ""); - - if (!StrUtil.isBlank(secret)) { - - builder.addQueryParameter("secret", secret); - - } else { - - builder.addQueryParameter("user", username) - .addQueryParameter("pass", password); - - } - - if (!StrUtil.isBlank(remarks)) { - - builder.fragment(Utils.INSTANCE.urlEncode(remarks)); - - } - - return builder.toString(); - - } - - public static ProxyInfo fromUrl(String url) { - - Uri lnk = Uri.parse(url); - - if (lnk == null) throw new IllegalArgumentException(url); - - ProxyInfo info = new ProxyInfo(lnk.getQueryParameter("server"), - Utilities.parseInt(lnk.getQueryParameter("port")), - lnk.getQueryParameter("user"), - lnk.getQueryParameter("pass"), - lnk.getQueryParameter("secret")); - - if (StrUtil.isNotBlank(lnk.getFragment())) { - - info.setRemarks(lnk.getFragment()); - - } - - return info; - - } - - public JSONObject toJsonInternal() throws JSONException { - - JSONObject obj = new JSONObject(); - - if (!StrUtil.isBlank(remarks)) { - obj.put("remarks", remarks); - } - - if (group != 0) { - obj.put("group", group); - } - - obj.put("address", address); - obj.put("port", port); - if (StrUtil.isBlank(secret)) { - obj.put("type", "socks5"); - if (!username.isEmpty()) { - obj.put("username", username); - } - if (!password.isEmpty()) { - obj.put("password", password); - } - } else { - obj.put("type", "mtproto"); - obj.put("secret", secret); - } - - return obj; - - } - - public static ProxyInfo fromJson(JSONObject obj) { - - ProxyInfo info; - - switch (obj.optString("type", "null")) { - - case "socks5": { - - info = new ProxyInfo(); - - info.group = obj.optInt("group", 0); - info.address = obj.optString("address", ""); - info.port = obj.optInt("port", 443); - info.username = obj.optString("username", ""); - info.password = obj.optString("password", ""); - - info.remarks = obj.optString("remarks"); - - if (StrUtil.isBlank(info.remarks)) info.remarks = null; - - info.group = obj.optInt("group", 0); - - break; - - } - - case "mtproto": { - - info = new ProxyInfo(); - - info.address = obj.optString("address", ""); - info.port = obj.optInt("port", 443); - info.secret = obj.optString("secret", ""); - - info.remarks = obj.optString("remarks"); - - if (StrUtil.isBlank(info.remarks)) info.remarks = null; - - info.group = obj.optInt("group", 0); - - break; - - } - - case "vmess": { - - info = new VmessProxy(obj.optString("link")); - - break; - - } - - case "shadowsocks": { - - info = new ShadowsocksProxy(obj.optString("link")); - - break; - - } - - case "shadowsocksr": { - - info = new ShadowsocksRProxy(obj.optString("link")); - - break; - - } - - case "ws": { - - info = new WsProxy(obj.optString("link")); - - break; - - } - - default: { - - throw new IllegalStateException("invalid proxy type " + obj.optString("type", "null")); - - } - - } - - return info; - - } - - @Override - public int hashCode() { - - return (address + port + username + password + secret).hashCode(); - - } - - @Override - public boolean equals(@Nullable Object obj) { - return super.equals(obj) || (obj instanceof ProxyInfo && hashCode() == obj.hashCode()); - } - - public String getLink() { - StringBuilder url = new StringBuilder(!TextUtils.isEmpty(secret) ? "https://t.me/proxy?" : "https://t.me/socks?"); - try { - url.append("server=").append(URLEncoder.encode(address, "UTF-8")).append("&").append("port=").append(port); - if (!TextUtils.isEmpty(username)) { - url.append("&user=").append(URLEncoder.encode(username, "UTF-8")); - } - if (!TextUtils.isEmpty(password)) { - url.append("&pass=").append(URLEncoder.encode(password, "UTF-8")); - } - if (!TextUtils.isEmpty(secret)) { - url.append("&secret=").append(URLEncoder.encode(secret, "UTF-8")); - } - } catch (UnsupportedEncodingException ignored) {} - return url.toString(); - } - } - - public abstract static class ExternalSocks5Proxy extends ProxyInfo { - - public ExternalSocks5Proxy() { - - address = "127.0.0.1"; - username = ""; - password = ""; - secret = ""; - - } - - public abstract boolean isStarted(); - - public abstract void start(); - - public abstract void stop(); - - @Override - public abstract String getAddress(); - - @Override - public abstract String toUrl(); - - @Override - public abstract String getRemarks(); - - @Override - public abstract void setRemarks(String remarks); - - @Override - public abstract String getType(); - - @Override - public abstract JSONObject toJsonInternal() throws JSONException; - - } - - public static class VmessProxy extends ExternalSocks5Proxy { - - public AngConfig.VmessBean bean; - public VmessLoader loader; - - { - - if (BuildVars.isMini) { - - throw new RuntimeException(LocaleController.getString("MiniVersionAlert", R.string.MiniVersionAlert)); - - } - - } - - public VmessProxy(String vmessLink) { - - this(VmessLoader.parseVmessLink(vmessLink)); - - } - - public VmessProxy(AngConfig.VmessBean bean) { - - this.bean = bean; - - } - - @Override - public String getAddress() { - return bean.getAddress() + ":" + bean.getPort(); - } - - @Override - public boolean isStarted() { - - return loader != null; - - } - - @Override - public void start() { - - if (loader != null) return; - - VmessLoader loader = new VmessLoader(); - - try { - - loader.initConfig(bean); - - port = loader.start(); - - this.loader = loader; - - if (SharedConfig.proxyEnabled && SharedConfig.currentProxy == this) { - - ConnectionsManager.setProxySettings(true, address, port, username, password, secret); - - } - - } catch (Exception e) { - - FileLog.e(e); - - AlertUtil.showToast(e.getMessage() == null ? e.getClass().getSimpleName() : e.getMessage()); - - } - - } - - @Override - public void stop() { - - if (loader != null) { - - VmessLoader loader = this.loader; - - loader.stop(); - - this.loader = null; - - } - - } - - @Override - public String toUrl() { - return bean.toString(); - } - - @Override - public String getRemarks() { - return bean.getRemarks(); - } - - @Override - public void setRemarks(String remarks) { - bean.setRemarks(remarks); - } - - @Override - public String getType() { - - if (bean.getConfigType() == V2RayConfig.EConfigType.Trojan) { - - return "Trojan"; - - } else { - - return "Vmess"; - - } - - } - - @Override - public JSONObject toJsonInternal() throws JSONException { - - JSONObject obj = new JSONObject(); - obj.put("type", "vmess"); - obj.put("link", toUrl()); - return obj; - - } - - @Override - public int hashCode() { - return (bean.getAddress() + bean.getPort() + bean.getId() + bean.getNetwork() + bean.getPath()).hashCode(); - } - - @Override - public boolean equals(@Nullable Object obj) { - return super.equals(obj) || (obj instanceof VmessProxy && bean.equals(((VmessProxy) obj).bean)); - } - - } - - public static class ShadowsocksProxy extends ExternalSocks5Proxy { - - public ShadowsocksLoader.Bean bean; - public ShadowsocksLoader loader; - - public ShadowsocksProxy(String ssLink) { - - this(ShadowsocksLoader.Bean.Companion.parse(ssLink)); - - } - - public ShadowsocksProxy(ShadowsocksLoader.Bean bean) { - - this.bean = bean; - - if (BuildVars.isMini) { - - throw new RuntimeException(LocaleController.getString("MiniVersionAlert", R.string.MiniVersionAlert)); - - } - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - - throw new RuntimeException(LocaleController.getString("MinApi21Required", R.string.MinApi21Required)); - - } - - } - - @Override - public String getAddress() { - return bean.getHost() + ":" + bean.getRemotePort(); - } - - @Override - public boolean isStarted() { - - return loader != null; - - } - - @Override - public void start() { - - if (loader != null) return; - - port = ProxyManager.mkPort(); - ShadowsocksLoader loader = new ShadowsocksLoader(); - loader.initConfig(bean, port); - - loader.start(); - - this.loader = loader; - - if (SharedConfig.proxyEnabled && SharedConfig.currentProxy == this) { - - ConnectionsManager.setProxySettings(true, address, port, username, password, secret); - - } - - } - - @Override - public void stop() { - - if (loader != null) { - - FileLog.d(getTitle() + " stopped"); - - ShadowsocksLoader loader = this.loader; - - loader.stop(); - - this.loader = null; - - } - - } - - @Override - public String toUrl() { - return bean.toString(); - } - - - @Override - public String getRemarks() { - return bean.getRemarks(); - } - - @Override - public void setRemarks(String remarks) { - bean.setRemarks(remarks); - } - - @Override - public String getType() { - return "SS"; - } - - @Override - public JSONObject toJsonInternal() throws JSONException { - - JSONObject obj = new JSONObject(); - obj.put("type", "shadowsocks"); - obj.put("link", toUrl()); - return obj; - - } - - @Override - public int hashCode() { - - return (bean.getHost() + bean.getRemotePort() + bean.getMethod()).hashCode(); - - } - - @Override - public boolean equals(@Nullable Object obj) { - return super.equals(obj) || (obj instanceof ShadowsocksProxy && bean.equals(((ShadowsocksProxy) obj).bean)); - } - - } - - public static class ShadowsocksRProxy extends ExternalSocks5Proxy { - - public ShadowsocksRLoader.Bean bean; - public ShadowsocksRLoader loader; - - public ShadowsocksRProxy(String ssLink) { - - this(ShadowsocksRLoader.Bean.Companion.parse(ssLink)); - - } - - public ShadowsocksRProxy(ShadowsocksRLoader.Bean bean) { - - this.bean = bean; - - if (BuildVars.isMini) { - - throw new RuntimeException(LocaleController.getString("MiniVersionAlert", R.string.MiniVersionAlert)); - - } - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - - throw new RuntimeException(LocaleController.getString("MinApi21Required", R.string.MinApi21Required)); - - } - - } - - @Override - public String getAddress() { - return bean.getHost() + ":" + bean.getRemotePort(); - } - - @Override - public boolean isStarted() { - - return loader != null; - - } - - @Override - public void start() { - - if (loader != null) return; - - port = ProxyManager.mkPort(); - ShadowsocksRLoader loader = new ShadowsocksRLoader(); - loader.initConfig(bean, port); - - loader.start(); - - this.loader = loader; - - if (SharedConfig.proxyEnabled && SharedConfig.currentProxy == this) { - - ConnectionsManager.setProxySettings(true, address, port, username, password, secret); - - } - - } - - @Override - public void stop() { - - if (loader != null) { - - ShadowsocksRLoader loader = this.loader; - - this.loader = null; + public static boolean payByInvoice; + public static int stealthModeSendMessageConfirm = 2; + private static int lastLocalId = -210000; - loader.stop(); + public static String storageCacheDir; - } + private static String passportConfigJson = ""; + private static HashMap passportConfigMap; + public static int passportConfigHash; - } + private static boolean configLoaded; + private static final Object sync = new Object(); + private static final Object localIdSync = new Object(); - @Override - public String toUrl() { - return bean.toString(); - } +// public static int saveToGalleryFlags; + public static int mapPreviewType = 2; + public static boolean chatBubbles = Build.VERSION.SDK_INT >= 30; + public static boolean raiseToSpeak = false; + public static boolean raiseToListen = true; + public static boolean nextMediaTap = true; + public static boolean recordViaSco = false; + public static boolean customTabs = true; + public static boolean directShare = true; + public static boolean inappCamera = true; + public static boolean roundCamera16to9 = true; + public static boolean noSoundHintShowed = false; + public static boolean streamMedia = true; + public static boolean streamAllVideo = false; + public static boolean streamMkv = false; + public static boolean saveStreamMedia = true; + public static boolean pauseMusicOnRecord = false; + public static boolean pauseMusicOnMedia = false; + public static boolean noiseSupression; + public static final boolean noStatusBar = true; + public static boolean debugWebView; + public static boolean sortContactsByName; + public static boolean sortFilesByName; + public static boolean shuffleMusic; + public static boolean playOrderReversed; + public static boolean hasCameraCache; + public static boolean showNotificationsForAllAccounts = true; + public static int repeatMode; + public static boolean allowBigEmoji; + public static int fontSize = 12; + public static boolean fontSizeIsDefault; + public static int bubbleRadius = 3; + public static int ivFontSize = 12; + public static boolean proxyRotationEnabled; + public static int proxyRotationTimeout; + public static int messageSeenHintCount; + public static int emojiInteractionsHintCount; + public static int dayNightThemeSwitchHintCount; + public static int callEncryptionHintDisplayedCount; - @Override - public String getRemarks() { - return bean.getRemarks(); - } + public static TLRPC.TL_help_appUpdate pendingAppUpdate; + public static int pendingAppUpdateBuildVersion; + public static long lastUpdateCheckTime; - @Override - public void setRemarks(String remarks) { - bean.setRemarks(remarks); - } + public static boolean hasEmailLogin; - @Override - public String getType() { - return "SSR"; - } + @PerformanceClass + private static int devicePerformanceClass; + @PerformanceClass + private static int overrideDevicePerformanceClass; - @Override - public JSONObject toJsonInternal() throws JSONException { + public static boolean drawDialogIcons; + public static boolean useThreeLinesLayout; + public static boolean archiveHidden; - JSONObject obj = new JSONObject(); - obj.put("type", "shadowsocksr"); - obj.put("link", toUrl()); - return obj; + private static int chatSwipeAction; - } + public static int distanceSystemType; + public static int mediaColumnsCount = 3; + public static int storiesColumnsCount = 3; + public static int fastScrollHintCount = 3; + public static boolean dontAskManageStorage; + public static boolean multipleReactionsPromoShowed; - @Override - public int hashCode() { + public static boolean translateChats = true; - return (bean.getHost() + bean.getRemotePort() + bean.getMethod() + bean.getProtocol() + bean.getProtocol_param() + bean.getObfs() + bean.getObfs_param()).hashCode(); + public static CopyOnWriteArraySet activeAccounts; + public static int loginingAccount = -1; - } + public static boolean isFloatingDebugActive; + public static LiteMode liteMode; - @Override - public boolean equals(@Nullable Object obj) { - return super.equals(obj) || (obj instanceof ShadowsocksRProxy && bean.equals(((ShadowsocksRProxy) obj).bean)); - } + private static final int[] LOW_SOC = { + -1775228513, // EXYNOS 850 + 802464304, // EXYNOS 7872 + 802464333, // EXYNOS 7880 + 802464302, // EXYNOS 7870 + 2067362118, // MSM8953 + 2067362060, // MSM8937 + 2067362084, // MSM8940 + 2067362241, // MSM8992 + 2067362117, // MSM8952 + 2067361998, // MSM8917 + -1853602818 // SDM439 + }; + static { + loadConfig(); } - public static class WsProxy extends ExternalSocks5Proxy { + public static class ProxyInfo { - public WsLoader.Bean bean; - public WsLoader loader; + public String address; + public int port; + public String username; + public String password; + public String secret; - public WsProxy(String url) { - this(WsLoader.Companion.parse(url)); - } + public long proxyCheckPingId; + public long ping; + public boolean checking; + public boolean available; + public long availableCheckTime; - public WsProxy(WsLoader.Bean bean) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - throw new RuntimeException(LocaleController.getString("MinApi21Required", R.string.MinApi21Required)); + public ProxyInfo(String address, int port, String username, String password, String secret) { + this.address = address; + this.port = port; + this.username = username; + this.password = password; + this.secret = secret; + if (this.address == null) { + this.address = ""; } - - this.bean = bean; - } - - @Override - public boolean isStarted() { - return loader != null; - } - - @Override - public void start() { - if (loader != null) return; - synchronized (this) { - loader = new WsLoader(); - port = ProxyManager.mkPort(); - loader.init(bean, port); - loader.start(); - if (SharedConfig.proxyEnabled && SharedConfig.currentProxy == this) { - ConnectionsManager.setProxySettings(true, address, port, username, password, secret); - } + if (this.password == null) { + this.password = ""; + } + if (this.username == null) { + this.username = ""; + } + if (this.secret == null) { + this.secret = ""; } } - @Override - public void stop() { - if (loader == null) return; - ConnectionsManager.setProxySettings(false, address, port, username, password, secret); - UIUtil.runOnIoDispatcher(() -> { - synchronized (this) { - if (loader == null) - return; - loader.stop(); - loader = null; + public String getLink() { + StringBuilder url = new StringBuilder(!TextUtils.isEmpty(secret) ? "https://t.me/proxy?" : "https://t.me/socks?"); + try { + url.append("server=").append(URLEncoder.encode(address, "UTF-8")).append("&").append("port=").append(port); + if (!TextUtils.isEmpty(username)) { + url.append("&user=").append(URLEncoder.encode(username, "UTF-8")); } - }); - } - - @Override - public String getAddress() { - return bean.getServer(); - } - - @Override - public String toUrl() { - return bean.toString(); - } - - @Override - public String getRemarks() { - return bean.getRemarks(); - } - - @Override - public void setRemarks(String remarks) { - bean.setRemarks(remarks); - } - - @Override - public String getType() { - return "WS"; - } - - @Override - public int hashCode() { - return bean.hashCode(); - } - - @Override - public JSONObject toJsonInternal() throws JSONException { - JSONObject obj = new JSONObject(); - obj.put("type", "ws"); - obj.put("link", toUrl()); - return obj; + if (!TextUtils.isEmpty(password)) { + url.append("&pass=").append(URLEncoder.encode(password, "UTF-8")); + } + if (!TextUtils.isEmpty(secret)) { + url.append("&secret=").append(URLEncoder.encode(secret, "UTF-8")); + } + } catch (UnsupportedEncodingException ignored) {} + return url.toString(); } - } public static LinkedList proxyList = new LinkedList<>(); @@ -1263,21 +457,6 @@ public static LinkedList getProxyList() { private static boolean proxyListLoaded; public static ProxyInfo currentProxy; - public static Proxy getActiveSocks5Proxy() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) - return null; - // https://stackoverflow.com/questions/36205896/how-to-use-httpurlconnection-over-socks-proxy-on-android - // Android did not support socks proxy natively(using HURL) on devices previous than Marshmallow - // Hutool use HttpURLConnection too - if (!(currentProxy instanceof ExternalSocks5Proxy) || currentProxy instanceof WsProxy) - return null; - final ExternalSocks5Proxy proxy = (ExternalSocks5Proxy) currentProxy; - if (!proxy.isStarted()) - return null; - FileLog.w("Return socks5 proxy: " + currentProxy.toString() + " port:" + currentProxy.port); - return new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(currentProxy.address, currentProxy.port)); - } - public static void saveConfig() { synchronized (sync) { try { @@ -2257,39 +1436,10 @@ public static void setProxyEnable(boolean enable) { preferences.edit().putBoolean("proxy_enabled", enable).commit(); - ProxyInfo info = currentProxy; - - if (info == null) { - - info = new ProxyInfo(); - - } - - ProxyInfo finalInfo = info; + ProxyInfo finalInfo = currentProxy; UIUtil.runOnIoDispatcher(() -> { - try { - - if (enable && finalInfo instanceof ExternalSocks5Proxy) { - - ((ExternalSocks5Proxy) finalInfo).start(); - - } else if (!enable && finalInfo instanceof ExternalSocks5Proxy) { - - ((ExternalSocks5Proxy) finalInfo).stop(); - - } - - } catch (Exception e) { - - FileLog.e(e); - AlertUtil.showToast(e); - - return; - - } - ConnectionsManager.setProxySettings(enable, finalInfo.address, finalInfo.port, finalInfo.username, finalInfo.password, finalInfo.secret); UIUtil.runOnUIThread(() -> NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged)); @@ -2299,13 +1449,7 @@ public static void setProxyEnable(boolean enable) { } public static void setCurrentProxy(@Nullable ProxyInfo info) { - - if (currentProxy instanceof ExternalSocks5Proxy && !currentProxy.equals(info)) { - ((ExternalSocks5Proxy) currentProxy).stop(); - } - currentProxy = info; - MessagesController.getGlobalMainSettings().edit() .putInt("current_proxy", info == null ? 0 : info.hashCode()) .apply(); @@ -2314,152 +1458,74 @@ public static void setCurrentProxy(@Nullable ProxyInfo info) { } - public static void reloadProxyList() { - proxyListLoaded = false; - loadProxyList(); - - if (proxyEnabled && currentProxy == null) { - setProxyEnable(false); - } - - } - public static void loadProxyList() { if (proxyListLoaded) { return; } - - if (!proxyList.isEmpty()) { - for (ProxyInfo proxyInfo : getProxyList()) { - if (proxyInfo instanceof ExternalSocks5Proxy) { - ((ExternalSocks5Proxy) proxyInfo).stop(); - } - } - } + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + String proxyAddress = preferences.getString("proxy_ip", ""); + String proxyUsername = preferences.getString("proxy_user", ""); + String proxyPassword = preferences.getString("proxy_pass", ""); + String proxySecret = preferences.getString("proxy_secret", ""); + int proxyPort = preferences.getInt("proxy_port", 1080); proxyListLoaded = true; proxyList.clear(); currentProxy = null; - - int current = MessagesController.getGlobalMainSettings().getInt("current_proxy", 0); - - for (SubInfo subInfo : SubManager.getSubList().find()) { - if (!subInfo.enable) continue; - - for (String proxy : subInfo.proxies) { - try { - ProxyInfo info = parseProxyInfo(proxy); - info.subId = subInfo.id; - if (info.hashCode() == current) { - currentProxy = info; - if (info instanceof ExternalSocks5Proxy) { - UIUtil.runOnIoDispatcher(() -> { - try { - ((ExternalSocks5Proxy) info).start(); - } catch (Exception e) { - FileLog.e(e); - AlertUtil.showToast(e); - } - }); + String list = preferences.getString("proxy_list", null); + if (!TextUtils.isEmpty(list)) { + byte[] bytes = Base64.decode(list, Base64.DEFAULT); + SerializedData data = new SerializedData(bytes); + int count = data.readInt32(false); + if (count == -1) { // V2 or newer + int version = data.readByte(false); + + if (version == PROXY_SCHEMA_V2) { + count = data.readInt32(false); + + for (int i = 0; i < count; i++) { + ProxyInfo info = new ProxyInfo( + data.readString(false), + data.readInt32(false), + data.readString(false), + data.readString(false), + data.readString(false)); + + info.ping = data.readInt64(false); + info.availableCheckTime = data.readInt64(false); + + proxyList.add(0, info); + if (currentProxy == null && !TextUtils.isEmpty(proxyAddress)) { + if (proxyAddress.equals(info.address) && proxyPort == info.port && proxyUsername.equals(info.username) && proxyPassword.equals(info.password)) { + currentProxy = info; + } } } - proxyList.add(info); - } catch (Exception e) { - FileLog.d("load sub proxy failed: " + e); + } else { + FileLog.e("Unknown proxy schema version: " + version); } - } - } - - File proxyListFile = new File(ApplicationLoader.applicationContext.getFilesDir().getParentFile(), "nekox/proxy_list.json"); - boolean error = false; - if (proxyListFile.isFile()) { - try { - JSONArray proxyArray = new JSONArray(FileUtil.readUtf8String(proxyListFile)); - for (int a = 0; a < proxyArray.length(); a++) { - JSONObject proxyObj = proxyArray.getJSONObject(a); - ProxyInfo info; - try { - info = ProxyInfo.fromJson(proxyObj); - } catch (Exception ex) { - FileLog.d("load proxy failed: " + ex); - error = true; - continue; - } + } else { + for (int a = 0; a < count; a++) { + ProxyInfo info = new ProxyInfo( + data.readString(false), + data.readInt32(false), + data.readString(false), + data.readString(false), + data.readString(false)); proxyList.add(0, info); - if (info.hashCode() == current) { - currentProxy = info; - if (info instanceof ExternalSocks5Proxy) { - UIUtil.runOnIoDispatcher(() -> { - try { - ((ExternalSocks5Proxy) info).start(); - } catch (Exception e) { - FileLog.e(e); - AlertUtil.showToast(e); - } - }); + if (currentProxy == null && !TextUtils.isEmpty(proxyAddress)) { + if (proxyAddress.equals(info.address) && proxyPort == info.port && proxyUsername.equals(info.username) && proxyPassword.equals(info.password)) { + currentProxy = info; } } } - } catch (Exception ex) { - FileLog.d("invalid proxy list json format" + ex); } + data.cleanup(); } - - if (error) saveProxyList(); - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); - boolean proxyEnabledValue = preferences.getBoolean("proxy_enabled", false); - if (proxyEnabledValue && currentProxy == null) proxyEnabledValue = false; - proxyEnabled = proxyEnabledValue; - } - - public static ProxyInfo parseProxyInfo(String url) throws InvalidProxyException { - if (url.startsWith(V2RayConfig.VMESS_PROTOCOL) || url.startsWith(V2RayConfig.VMESS1_PROTOCOL) || url.startsWith(V2RayConfig.TROJAN_PROTOCOL)) { - try { - return new VmessProxy(url); - } catch (Exception ex) { - throw new InvalidProxyException(ex); - } - } else if (url.startsWith(SS_PROTOCOL)) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - throw new InvalidProxyException("shadowsocks requires min api 21"); - } - try { - return new ShadowsocksProxy(url); - } catch (Exception ex) { - throw new InvalidProxyException(ex); - } - } else if (url.startsWith(SSR_PROTOCOL)) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - throw new InvalidProxyException("shadowsocksR requires min api 21"); - } - try { - return new ShadowsocksRProxy(url); - } catch (Exception ex) { - throw new InvalidProxyException(ex); - } - } else if (url.startsWith(WS_PROTOCOL) || url.startsWith(WSS_PROTOCOL)) { - try { - return new WsProxy(url); - } catch (Exception ex) { - throw new InvalidProxyException(ex); - } - }/* else if (url.startsWith(RB_PROTOCOL)) { - try { - return new RelayBatonProxy(url); - } catch (Exception ex) { - throw new InvalidProxyException(ex); - } - } */ - - if (url.startsWith("tg:proxy") || - url.startsWith("tg://proxy") || - url.startsWith("tg:socks") || - url.startsWith("tg://socks") || - url.startsWith("https://t.me/proxy") || - url.startsWith("https://t.me/socks")) { - return ProxyInfo.fromUrl(url); + if (currentProxy == null && !TextUtils.isEmpty(proxyAddress)) { + ProxyInfo info = currentProxy = new ProxyInfo(proxyAddress, proxyPort, proxyUsername, proxyPassword, proxySecret); + proxyList.add(0, info); } - throw new InvalidProxyException(); } public static class InvalidProxyException extends Exception { @@ -2480,44 +1546,49 @@ public InvalidProxyException(Throwable cause) { } public static void saveProxyList() { - UIUtil.runOnIoDispatcher(() -> { - - JSONArray proxyArray = new JSONArray(); - - for (ProxyInfo info : getProxyList()) { - try { - JSONObject obj = info.toJsonInternal(); - if (info.subId != 0L) { - continue; - } - proxyArray.put(obj); - } catch (Exception e) { - FileLog.e(e); - } + List infoToSerialize = new ArrayList<>(proxyList); + Collections.sort(infoToSerialize, (o1, o2) -> { + long bias1 = SharedConfig.currentProxy == o1 ? -200000 : 0; + if (!o1.available) { + bias1 += 100000; } - - File proxyListFile = new File(ApplicationLoader.applicationContext.getFilesDir().getParentFile(), "nekox/proxy_list.json"); - - try { - FileUtil.writeUtf8String(proxyArray.toString(), proxyListFile); - } catch (Exception e) { - FileLog.e(e); + long bias2 = SharedConfig.currentProxy == o2 ? -200000 : 0; + if (!o2.available) { + bias2 += 100000; } - + return Long.compare(o1.ping + bias1, o2.ping + bias2); }); + SerializedData serializedData = new SerializedData(); + serializedData.writeInt32(-1); + serializedData.writeByte(PROXY_CURRENT_SCHEMA_VERSION); + int count = infoToSerialize.size(); + serializedData.writeInt32(count); + for (int a = count - 1; a >= 0; a--) { + ProxyInfo info = infoToSerialize.get(a); + serializedData.writeString(info.address != null ? info.address : ""); + serializedData.writeInt32(info.port); + serializedData.writeString(info.username != null ? info.username : ""); + serializedData.writeString(info.password != null ? info.password : ""); + serializedData.writeString(info.secret != null ? info.secret : ""); + + serializedData.writeInt64(info.ping); + serializedData.writeInt64(info.availableCheckTime); + } + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + preferences.edit().putString("proxy_list", Base64.encodeToString(serializedData.toByteArray(), Base64.NO_WRAP)).apply(); + serializedData.cleanup(); } public static ProxyInfo addProxy(ProxyInfo proxyInfo) { - synchronized (sync) { - int count = proxyList.size(); - for (int a = 0; a < count; a++) { - ProxyInfo info = proxyList.get(a); - if (info.equals(proxyInfo)) { - return info; - } + loadProxyList(); + int count = proxyList.size(); + for (int a = 0; a < count; a++) { + ProxyInfo info = proxyList.get(a); + if (proxyInfo.address.equals(info.address) && proxyInfo.port == info.port && proxyInfo.username.equals(info.username) && proxyInfo.password.equals(info.password) && proxyInfo.secret.equals(info.secret)) { + return info; } - proxyList.add(proxyInfo); } + proxyList.add(0, proxyInfo); saveProxyList(); return proxyInfo; } @@ -2527,25 +1598,25 @@ public static boolean isProxyEnabled() { } public static void deleteProxy(ProxyInfo proxyInfo) { - if (currentProxy == proxyInfo) { currentProxy = null; - if (proxyEnabled) { - setProxyEnable(false); + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + boolean enabled = preferences.getBoolean("proxy_enabled", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString("proxy_ip", ""); + editor.putString("proxy_pass", ""); + editor.putString("proxy_user", ""); + editor.putString("proxy_secret", ""); + editor.putInt("proxy_port", 1080); + editor.putBoolean("proxy_enabled", false); + editor.putBoolean("proxy_enabled_calls", false); + editor.apply(); + if (enabled) { + ConnectionsManager.setProxySettings(false, "", 0, "", "", ""); } } proxyList.remove(proxyInfo); - if (proxyInfo.subId != 0) { - SubInfo sub = SubManager.getSubList().find(ObjectFilters.eq("id", proxyInfo.subId)).firstOrDefault(); - try { - if (sub.proxies.remove(proxyInfo.toUrl())) { - SubManager.getSubList().update(sub); - } - } catch (UnsupportedOperationException ignored) { - } - } else { - saveProxyList(); - } + saveProxyList(); } public static void deleteAllProxy() { diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java b/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java index 5f00677df6..3378abec95 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java @@ -63,7 +63,6 @@ import cn.hutool.core.util.StrUtil; import tw.nekomimi.nekogram.NekoConfig; -import tw.nekomimi.nekogram.parts.ProxySwitcher; import tw.nekomimi.nekogram.utils.DnsFactory; import tw.nekomimi.nekogram.ErrorDatabase; @@ -500,9 +499,6 @@ public void init(int version, int layer, int apiId, String deviceModel, String s 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(); @@ -656,7 +652,6 @@ public static void onConnectionStateChanged(final int state, final int currentAc try { AndroidUtilities.runOnUIThread(() -> { getInstance(currentAccount).connectionState = state; - ProxySwitcher.didReceivedNotification(state); AccountInstance.getInstance(currentAccount).getNotificationCenter().postNotificationName(NotificationCenter.didUpdateConnectionState); }); } catch (Exception e) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 9fe6c1bba6..03d87d9a30 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -29560,12 +29560,7 @@ private void processSelectedOption(int option) { AlertUtil.showConfirm(getParentActivity(), LocaleController.getString("ImportProxyList", R.string.ImportProxyList), R.drawable.menu_secret, LocaleController.getString("Import", R.string.Import), - false, () -> { - String status = ProxyListActivity.processProxyListFile(getParentActivity(), finalLocFile1); - if (!StrUtil.isBlank(status)) { - presentFragment(new ProxyListActivity(status)); - } - }); + false, () -> {}); } else if (locFile.getName().toLowerCase().endsWith(".nekox-stickers.json")) { @@ -35013,12 +35008,7 @@ public void didPressImage(ChatMessageCell cell, float x, float y) { AlertUtil.showConfirm(getParentActivity(), LocaleController.getString("ImportProxyList", R.string.ImportProxyList), R.drawable.menu_secret, LocaleController.getString("Import", R.string.Import), - false, () -> { - String status = ProxyListActivity.processProxyListFile(getParentActivity(), finalLocFile); - if (!StrUtil.isBlank(status)) { - presentFragment(new ProxyListActivity(status)); - } - }); + false, () -> {}); } else if (message.getDocumentName().toLowerCase().endsWith(".nekox-stickers.json")) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index f3bd8333ef..71ec9d0bd5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -82,8 +82,6 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.v2ray.ang.V2RayConfig; - //import com.google.android.gms.common.api.Status; import com.google.common.primitives.Longs; //import com.google.firebase.appindexing.Action; @@ -229,8 +227,6 @@ 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.MonetHelper; import tw.nekomimi.nekogram.utils.ProxyUtil; @@ -382,12 +378,7 @@ protected void onCreate(Bundle savedInstanceState) { Uri uri = intent.getData(); if (uri != null) { String url = uri.toString().toLowerCase(); - isProxy = url.startsWith("tg:proxy") || url.startsWith("tg://proxy") || url.startsWith("tg:socks") || url.startsWith("tg://socks") || - url.startsWith(V2RayConfig.VMESS_PROTOCOL) || - url.startsWith(V2RayConfig.VMESS1_PROTOCOL) || - url.startsWith(V2RayConfig.SS_PROTOCOL) || - url.startsWith(V2RayConfig.SSR_PROTOCOL) || - url.startsWith(V2RayConfig.TROJAN_PROTOCOL); + isProxy = url.startsWith("tg:proxy") || url.startsWith("tg://proxy") || url.startsWith("tg:socks") || url.startsWith("tg://socks"); } } } @@ -998,21 +989,21 @@ public void onPreviewOpenAnimationEnd() { } MediaController.getInstance().setBaseActivity(this, true); - UIUtil.runOnIoDispatcher(() -> { +// 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); +// 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); //FileLog.d("UI create time = " + (SystemClock.elapsedRealtime() - ApplicationLoader.startTime)); // ApplicationLoader.startAppCenter(this); if (updateLayout != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index 1d9837bde1..51aba77490 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -283,7 +283,6 @@ import cn.hutool.core.util.RuntimeUtil; import cn.hutool.core.util.StrUtil; import kotlin.Unit; -import libv2ray.Libv2ray; import tw.nekomimi.nekogram.BackButtonMenuRecent; import tw.nekomimi.nekogram.helpers.SettingsHelper; import tw.nekomimi.nekogram.helpers.SettingsSearchResult; @@ -3881,14 +3880,6 @@ public void openExceptions() { 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.msg_copy, (it) -> { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProxyListActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProxyListActivity.java index 8beff0d152..f240d1703a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProxyListActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProxyListActivity.java @@ -8,26 +8,19 @@ package org.telegram.ui; -import android.Manifest; -import android.annotation.SuppressLint; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.app.Dialog; import android.content.Context; -import android.content.Intent; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; -import android.content.pm.PackageManager; import android.graphics.Canvas; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Build; import android.os.SystemClock; -import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; @@ -37,17 +30,6 @@ import android.widget.ImageView; import android.widget.TextView; -import androidx.annotation.NonNull; -import androidx.core.content.FileProvider; -import androidx.recyclerview.widget.DefaultItemAnimator; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.ListAdapter; -import androidx.recyclerview.widget.RecyclerView; - -import com.v2ray.ang.V2RayConfig; - -import org.json.JSONArray; -import org.json.JSONObject; import androidx.annotation.NonNull; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.ItemTouchHelper; @@ -55,19 +37,13 @@ import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ApplicationLoader; -import org.telegram.messenger.BuildConfig; -import org.telegram.messenger.BuildVars; import org.telegram.messenger.DownloadController; -import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.ProxyRotationController; import org.telegram.messenger.R; -import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.SharedConfig; -import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.ConnectionsManager; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; @@ -88,44 +64,10 @@ import org.telegram.ui.Components.NumberTextView; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.SlideChooseView; -import org.telegram.ui.Components.URLSpanNoUnderline; -import java.io.File; -import java.io.IOException; import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedList; import java.util.Collections; import java.util.List; -import java.util.Map; -import java.util.TreeSet; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import cn.hutool.core.thread.ThreadUtil; -import cn.hutool.core.util.StrUtil; -import kotlin.Unit; -import okhttp3.HttpUrl; -import tw.nekomimi.nekogram.ui.BottomBuilder; -import tw.nekomimi.nekogram.proxy.ShadowsocksRSettingsActivity; -import tw.nekomimi.nekogram.proxy.ShadowsocksSettingsActivity; -import tw.nekomimi.nekogram.proxy.SubSettingsActivity; -import tw.nekomimi.nekogram.proxy.TrojanSettingsActivity; -import tw.nekomimi.nekogram.proxy.VmessSettingsActivity; -import tw.nekomimi.nekogram.proxy.WsSettingsActivity; -import tw.nekomimi.nekogram.parts.ProxyChecksKt; -import tw.nekomimi.nekogram.proxy.SubInfo; -import tw.nekomimi.nekogram.proxy.SubManager; -import tw.nekomimi.nekogram.utils.AlertUtil; -import tw.nekomimi.nekogram.utils.FileUtil; -import tw.nekomimi.nekogram.utils.ProxyUtil; -import tw.nekomimi.nekogram.utils.UIUtil; -import tw.nekomimi.nekogram.NekoConfig; public class ProxyListActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { private final static boolean IS_PROXY_ROTATION_AVAILABLE = true; @@ -144,7 +86,6 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente private int rowCount; private int useProxyRow; - private int enablePublicProxyRow; private int useProxyShadowRow; private int connectionsHeaderRow; private int proxyStartRow; @@ -167,8 +108,6 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente private List proxyList = new ArrayList<>(); private boolean wasCheckedAllList; - private ActionBarMenuItem otherItem; - public class TextDetailProxyCell extends FrameLayout { private TextView textView; @@ -182,7 +121,6 @@ public class TextDetailProxyCell extends FrameLayout { private boolean isSelectionEnabled; private int color; - private Pattern urlPattern; public TextDetailProxyCell(Context context) { super(context); @@ -214,28 +152,7 @@ public TextDetailProxyCell(Context context) { checkImageView.setScaleType(ImageView.ScaleType.CENTER); checkImageView.setContentDescription(LocaleController.getString("Edit", R.string.Edit)); addView(checkImageView, LayoutHelper.createFrame(48, 48, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP, 8, 8, 8, 0)); - checkImageView.setOnClickListener(v -> { - SharedConfig.ProxyInfo info = currentInfo; - if (info instanceof SharedConfig.VmessProxy) { - if (((SharedConfig.VmessProxy) info).bean.getConfigType() == V2RayConfig.EConfigType.Trojan) { - presentFragment(new TrojanSettingsActivity((SharedConfig.VmessProxy) info)); - } else { - presentFragment(new VmessSettingsActivity((SharedConfig.VmessProxy) info)); - } - } else if (info instanceof SharedConfig.ShadowsocksProxy) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - presentFragment(new ShadowsocksSettingsActivity((SharedConfig.ShadowsocksProxy) info)); - } - } else if (info instanceof SharedConfig.ShadowsocksRProxy) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - presentFragment(new ShadowsocksRSettingsActivity((SharedConfig.ShadowsocksRProxy) info)); - } - } else if (info instanceof SharedConfig.WsProxy) { - presentFragment(new WsSettingsActivity((SharedConfig.WsProxy) info)); - } else { - presentFragment(new ProxySettingsActivity(info)); - } - }); + checkImageView.setOnClickListener(v -> presentFragment(new ProxySettingsActivity(currentInfo))); checkBox = new CheckBox2(context, 21); checkBox.setColor(Theme.key_checkbox, Theme.key_radioBackground, Theme.key_checkboxCheck); @@ -251,40 +168,8 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(64) + 1, MeasureSpec.EXACTLY)); } - @SuppressLint("SetTextI18n") public void setProxy(SharedConfig.ProxyInfo proxyInfo) { - - String title = proxyInfo.getTitle(); - - SpannableStringBuilder stringBuilder = null; - try { - if (urlPattern == null) { - urlPattern = Pattern.compile("@[a-zA-Z\\d_]{1,32}"); - } - Matcher matcher = urlPattern.matcher(title); - while (matcher.find()) { - if (stringBuilder == null) { - stringBuilder = new SpannableStringBuilder(title); - textView.setMovementMethod(new AndroidUtilities.LinkMovementMethodMy()); - } - int start = matcher.start(); - int end = matcher.end(); - if (title.charAt(start) != '@') { - start++; - } - URLSpanNoUnderline url = new URLSpanNoUnderline(title.subSequence(start + 1, end).toString()) { - @Override - public void onClick(View widget) { - MessagesController.getInstance(currentAccount).openByUserName(getURL(), ProxyListActivity.this, 1); - } - }; - stringBuilder.setSpan(url, start, end, 0); - } - } catch (Exception e) { - FileLog.e(e); - } - - textView.setText(stringBuilder == null ? title : stringBuilder); + textView.setText(proxyInfo.address + ":" + proxyInfo.port); currentInfo = proxyInfo; } @@ -325,9 +210,8 @@ public void updateStatus() { valueTextView.setTag(colorKey); valueTextView.setTextColor(color); if (checkDrawable != null) { - checkDrawable.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); + checkDrawable.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY)); } - } public void setSelectionEnabled(boolean enabled, boolean animated) { @@ -411,7 +295,7 @@ public void setChecked(boolean checked) { checkDrawable = getResources().getDrawable(R.drawable.proxy_check).mutate(); } if (checkDrawable != null) { - checkDrawable.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); + checkDrawable.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY)); } if (LocaleController.isRTL) { valueTextView.setCompoundDrawablesWithIntrinsicBounds(null, null, checkDrawable, null); @@ -435,23 +319,15 @@ protected void onAttachedToWindow() { @Override protected void onDraw(Canvas canvas) { - 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 ProxyListActivity() { - } - - private String alert; - - public ProxyListActivity(String alert) { - this.alert = alert; - } - @Override public boolean onFragmentCreate() { super.onFragmentCreate(); + SharedConfig.loadProxyList(); currentConnectionState = ConnectionsManager.getInstance(currentAccount).getConnectionState(); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.proxyChangedByRotation); @@ -460,7 +336,7 @@ public boolean onFragmentCreate() { NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.didUpdateConnectionState); final SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - useProxySettings = SharedConfig.proxyEnabled; + useProxySettings = preferences.getBoolean("proxy_enabled", false) && !SharedConfig.proxyList.isEmpty(); useProxyForCalls = preferences.getBoolean("proxy_enabled_calls", false); updateRows(true); @@ -475,149 +351,6 @@ public void onFragmentDestroy() { NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.proxySettingsChanged); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.proxyCheckDone); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.didUpdateConnectionState); - - if (currentCheck != null) currentCheck.shutdownNow(); - - } - - private int menu_add = 1; - private int menu_add_input_socks = 2; - private int menu_add_input_telegram = 3; - private int menu_add_input_vmess = 4; - private int menu_add_input_ss = 7; - private int menu_add_input_ssr = 8; - private int menu_add_input_ws = 9; - private int menu_add_input_rb = 17; - - private int menu_add_import_from_clipboard = 5; - private int menu_add_scan_qr = 6; - private int menu_other = 9; - private int menu_retest_ping = 10; - private int menu_reorder_by_ping = 11; - private int menu_export_json = 12; - private int menu_import_json = 13; - private int menu_delete_all = 14; - private int menu_delete_unavailable = 15; - private int menu_sub = 16; - - public void processProxyList(ArrayList files) { - - for (String proxyListFilePath : files) { - - File proxyListFile = new File(proxyListFilePath); - - processProxyListFile(getParentActivity(), proxyListFile); - - } - - } - - public static String processProxyListFile(Context ctx, File proxyListFile) { - - try { - - if (proxyListFile.length() > 2 * 1024 * 1024L) { - - throw new IllegalArgumentException("file too large."); - - } - - JSONObject proxyRootObject = new JSONObject(FileUtil.readUtf8String(proxyListFile)); - - int version = proxyRootObject.optInt("nekox_proxy_list_version", 1); - - if (version == 1) { - - if (proxyRootObject.isNull("proxies")) { - - throw new IllegalArgumentException("proxies array not found."); - - } - - JSONArray proxyArray = proxyRootObject.getJSONArray("proxies"); - - if (proxyArray.length() == 0) { - - throw new IllegalArgumentException("Empty proxy list."); - - } - - LinkedList imported = new LinkedList<>(); - LinkedHashMap errors = new LinkedHashMap<>(); - - for (int index = 0; index < proxyArray.length(); index++) { - - String proxyUrl = proxyArray.getString(index); - - try { - - imported.add(ProxyUtil.importInBackground(proxyUrl).getTitle()); - - } catch (Exception ex) { - - errors.put(proxyUrl.length() < 15 ? proxyUrl : (proxyUrl.substring(0, 15) + "..."), ex.getMessage()); - - } - - } - - StringBuilder status = new StringBuilder(); - - if (!imported.isEmpty()) { - - status.append(LocaleController.getString("ImportedProxies", R.string.ImportedProxies)); - - for (String success : imported) { - - status.append("\n").append(success); - - } - - - if (!errors.isEmpty()) { - - status.append("\n\n"); - - } - - } - - if (!errors.isEmpty()) { - - status.append(LocaleController.getString("ErrorsInImport", R.string.ErrorsInImport)); - - for (Map.Entry error : errors.entrySet()) { - - status.append("\n").append(error.getKey()).append(": ").append(error.getValue()); - - } - - } - - if (imported.isEmpty()) { - - AlertUtil.showSimpleAlert(ctx, status.toString()); - - } else { - - return status.toString(); - - } - - } else { - - throw new IllegalArgumentException("invalid proxy list version " + version + "."); - - } - - } catch (Exception e) { - - AlertUtil.showSimpleAlert(ctx, LocaleController.getString("InvalidProxyFile", R.string.InvalidProxyFile) + proxyListFile.getPath() + "\n\n" + e.getMessage()); - - } - - return null; - } @Override @@ -634,176 +367,10 @@ public View createView(Context context) { public void onItemClick(int id) { if (id == -1) { finishFragment(); - } else if (id == menu_retest_ping) { - checkProxyList(true); - } else if (id == menu_reorder_by_ping) { - SharedConfig.proxyList = new LinkedList<>(new TreeSet<>(SharedConfig.getProxyList())); - SharedConfig.saveProxyList(); - updateRows(true); - } else if (id == menu_export_json) { - File cacheFile = new File(ApplicationLoader.applicationContext.getExternalCacheDir(), "Proxy-List-" + new Date().toLocaleString() + ".nekox.json"); - - try { - - JSONObject listRoot = new JSONObject(); - - listRoot.put("nekox_proxy_list_version", 1); - - JSONArray proxyArray = new JSONArray(); - - for (SharedConfig.ProxyInfo info : SharedConfig.getProxyList()) { - - if (info.subId <= 1) { - - continue; - - } - - proxyArray.put(info.toUrl()); - - } - - if (proxyArray.length() == 0) { - AlertUtil.showSimpleAlert(getParentActivity(), LocaleController.getString("NoProxy", R.string.NoProxy)); - return; - } - - listRoot.put("proxies", proxyArray); - - FileUtil.writeUtf8String(listRoot.toString(4), cacheFile); - } catch (Exception e) { - return; - } - Intent intent = new Intent(Intent.ACTION_SEND); - intent.setType("*/*"); - if (Build.VERSION.SDK_INT >= 24) { - try { - intent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(getParentActivity(), BuildConfig.APPLICATION_ID + ".provider", cacheFile)); - intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - } catch (Exception ignore) { - intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(cacheFile)); - } - } else { - intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(cacheFile)); - } - getParentActivity().startActivityForResult(Intent.createChooser(intent, LocaleController.getString("ShareFile", R.string.ShareFile)), 500); - } else if (id == menu_import_json) { - try { - if (Build.VERSION.SDK_INT >= 23 && getParentActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { - - getParentActivity().requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 4); - return; - } - } catch (Throwable ignore) { - } - DocumentSelectActivity fragment = new DocumentSelectActivity(false); - fragment.setMaxSelectedFiles(-1); - fragment.setAllowPhoto(false); - fragment.setDelegate(new DocumentSelectActivity.DocumentSelectActivityDelegate() { - - @Override - public void didSelectFiles(DocumentSelectActivity activity, ArrayList files, String caption, boolean notify, int scheduleDate) { - activity.finishFragment(); - processProxyList(files); - } - - @Override - public void didSelectPhotos(ArrayList photos, boolean notify, int scheduleDate) { - } - - @Override - public void startDocumentSelectActivity() { - } - }); - presentFragment(fragment); - } else if (id == menu_delete_all) { - AlertUtil.showConfirm(getParentActivity(), - LocaleController.getString("DeleteAllServer", R.string.DeleteAllServer), - R.drawable.msg_delete, LocaleController.getString("Delete", R.string.Delete), - true, () -> { - SharedConfig.deleteAllProxy(); - updateRows(true); - }); - } else if (id == menu_delete_unavailable) { - AlertUtil.showConfirm(getParentActivity(), - LocaleController.getString("DeleteUnavailableServer", R.string.DeleteUnavailableServer), - R.drawable.msg_delete, LocaleController.getString("Delete", R.string.Delete), - true, () -> { - deleteUnavailableProxy(); - }); - } else if (id == menu_sub) { - showSubDialog(); } } }); - ActionBarMenu menu = actionBar.createMenu(); - - ActionBarMenuItem addItem = menu.addItem(menu_add, R.drawable.add); - - addItem.addSubItem(menu_add_import_from_clipboard, LocaleController.getString("ImportProxyFromClipboard", R.string.ImportProxyFromClipboard)).setOnClickListener((v) -> { - - ProxyUtil.importFromClipboard(getParentActivity()); - - }); - - addItem.addSubItem(menu_add_scan_qr, LocaleController.getString("ScanQRCode", R.string.ScanQRCode)).setOnClickListener((v) -> { - - if (Build.VERSION.SDK_INT >= 23) { - if (getParentActivity().checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { - getParentActivity().requestPermissions(new String[]{Manifest.permission.CAMERA}, 22); - return; - } - } - - CameraScanActivity.showAsSheet(this, new CameraScanActivity.CameraScanActivityDelegate() { - - @Override - public void didFindQr(String text) { - - try { - HttpUrl.parse(text); - Browser.openUrl(getParentActivity(), text); - return; - } catch (Exception ignored) { - } - - AlertUtil.showCopyAlert(getParentActivity(), text); - - } - - }); - - }); - - addItem.addSubItem(menu_add_input_socks, LocaleController.getString("AddProxySocks5", R.string.AddProxySocks5)).setOnClickListener((v) -> presentFragment(new ProxySettingsActivity(0))); - addItem.addSubItem(menu_add_input_telegram, LocaleController.getString("AddProxyTelegram", R.string.AddProxyTelegram)).setOnClickListener((v) -> presentFragment(new ProxySettingsActivity(1))); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - addItem.addSubItem(menu_add_input_ws, LocaleController.getString("AddProxyWs", R.string.AddProxyWs)).setOnClickListener((v) -> presentFragment(new WsSettingsActivity())); - } - - if (!BuildVars.isMini) { - - addItem.addSubItem(menu_add_input_vmess, LocaleController.getString("AddProxyVmess", R.string.AddProxyVmess)).setOnClickListener((v) -> presentFragment(new VmessSettingsActivity())); - addItem.addSubItem(menu_add_input_vmess, LocaleController.getString("AddProxyVmess", R.string.AddProxyTrojan)).setOnClickListener((v) -> presentFragment(new TrojanSettingsActivity())); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - addItem.addSubItem(menu_add_input_ss, LocaleController.getString("AddProxySS", R.string.AddProxySS)).setOnClickListener((v) -> presentFragment(new ShadowsocksSettingsActivity())); - addItem.addSubItem(menu_add_input_ssr, LocaleController.getString("AddProxySSR", R.string.AddProxySSR)).setOnClickListener((v) -> presentFragment(new ShadowsocksRSettingsActivity())); - } - // addItem.addSubItem(menu_add_input_rb, LocaleController.getString("AddProxyRB", R.string.AddProxyRB)).setOnClickListener((v) -> presentFragment(new RelayBatonSettingsActivity())); - - } - - menu.addItem(menu_sub, R.drawable.msg_list); - - otherItem = menu.addItem(menu_other, R.drawable.ic_ab_other); - otherItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); - otherItem.addSubItem(menu_retest_ping, LocaleController.getString("RetestPing", R.string.RetestPing)); - otherItem.addSubItem(menu_reorder_by_ping, LocaleController.getString("ReorderByPing", R.string.ReorderByPing)); - otherItem.addSubItem(menu_delete_all, LocaleController.getString("DeleteAllServer", R.string.DeleteAllServer)); - otherItem.addSubItem(menu_delete_unavailable, LocaleController.getString("DeleteUnavailableServer", R.string.DeleteUnavailableServer)); - listAdapter = new ListAdapter(context); fragmentView = new FrameLayout(context); @@ -826,55 +393,56 @@ protected void dispatchDraw(Canvas canvas) { listView.setOnItemClickListener((view, position) -> { if (position == useProxyRow) { if (SharedConfig.currentProxy == null) { - if (!SharedConfig.proxyList.isEmpty()) { - SharedConfig.setCurrentProxy(SharedConfig.proxyList.get(0)); + if (!proxyList.isEmpty()) { + SharedConfig.currentProxy = proxyList.get(0); + + if (!useProxySettings) { + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit(); + editor.putString("proxy_ip", SharedConfig.currentProxy.address); + editor.putString("proxy_pass", SharedConfig.currentProxy.password); + editor.putString("proxy_user", SharedConfig.currentProxy.username); + editor.putInt("proxy_port", SharedConfig.currentProxy.port); + editor.putString("proxy_secret", SharedConfig.currentProxy.secret); + editor.commit(); + } } else { - addProxy(); + presentFragment(new ProxySettingsActivity()); return; } } - useProxySettings = !useProxySettings; updateRows(true); + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + TextCheckCell textCheckCell = (TextCheckCell) view; textCheckCell.setChecked(useProxySettings); + if (!useProxySettings) { + RecyclerListView.Holder holder = (RecyclerListView.Holder) listView.findViewHolderForAdapterPosition(callsRow); + if (holder != null) { + textCheckCell = (TextCheckCell) holder.itemView; + textCheckCell.setChecked(false); + } + useProxyForCalls = false; + } + + SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit(); + editor.putBoolean("proxy_enabled", useProxySettings); + editor.commit(); + ConnectionsManager.setProxySettings(useProxySettings, SharedConfig.currentProxy.address, SharedConfig.currentProxy.port, SharedConfig.currentProxy.username, SharedConfig.currentProxy.password, SharedConfig.currentProxy.secret); NotificationCenter.getGlobalInstance().removeObserver(ProxyListActivity.this, NotificationCenter.proxySettingsChanged); - SharedConfig.setProxyEnable(useProxySettings); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged); NotificationCenter.getGlobalInstance().addObserver(ProxyListActivity.this, NotificationCenter.proxySettingsChanged); - updateRows(true); - } else if (position == enablePublicProxyRow) { - final boolean enabled = NekoConfig.enablePublicProxy.toggleConfigBool(); - TextCheckCell cell = (TextCheckCell) view; - cell.setChecked(enabled); - UIUtil.runOnIoDispatcher(() -> { - SharedPreferences pref = MessagesController.getGlobalMainSettings(); - for (SubInfo subInfo : SubManager.getSubList().find()) { - if (subInfo.id != SubManager.publicProxySubID) continue; - subInfo.enable = enabled; - if (enabled) { - try { - subInfo.proxies = subInfo.reloadProxies(); - subInfo.lastFetch = System.currentTimeMillis(); - } catch (Exception ignored) { - } - } - SubManager.getSubList().update(subInfo, true); - break; + for (int a = proxyStartRow; a < proxyEndRow; a++) { + RecyclerListView.Holder holder = (RecyclerListView.Holder) listView.findViewHolderForAdapterPosition(a); + if (holder != null) { + TextDetailProxyCell cell = (TextDetailProxyCell) holder.itemView; + cell.updateStatus(); } - // clear proxy id - useProxySettings = false; - SharedConfig.setCurrentProxy(null); - // reload list & UI - AndroidUtilities.runOnUIThread(() -> { - SharedConfig.reloadProxyList(); - updateRows(true); - }); - }); - - updateRows(true); + } } else if (position == rotationRow) { SharedConfig.proxyRotationEnabled = !SharedConfig.proxyRotationEnabled; TextCheckCell textCheckCell = (TextCheckCell) view; @@ -888,7 +456,7 @@ protected void dispatchDraw(Canvas canvas) { textCheckCell.setChecked(useProxyForCalls); SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit(); editor.putBoolean("proxy_enabled_calls", useProxyForCalls); - editor.apply(); + editor.commit(); } else if (position >= proxyStartRow && position < proxyEndRow) { if (!selectedItems.isEmpty()) { listAdapter.toggleSelected(position); @@ -896,90 +464,151 @@ protected void dispatchDraw(Canvas canvas) { } SharedConfig.ProxyInfo info = proxyList.get(position - proxyStartRow); useProxySettings = true; - SharedConfig.setCurrentProxy(info); - updateRows(true); + SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit(); + editor.putString("proxy_ip", info.address); + editor.putString("proxy_pass", info.password); + editor.putString("proxy_user", info.username); + editor.putInt("proxy_port", info.port); + editor.putString("proxy_secret", info.secret); + editor.putBoolean("proxy_enabled", useProxySettings); + if (!info.secret.isEmpty()) { + useProxyForCalls = false; + editor.putBoolean("proxy_enabled_calls", false); + } + editor.commit(); + SharedConfig.currentProxy = info; + for (int a = proxyStartRow; a < proxyEndRow; a++) { + RecyclerListView.Holder holder = (RecyclerListView.Holder) listView.findViewHolderForAdapterPosition(a); + if (holder != null) { + TextDetailProxyCell cell = (TextDetailProxyCell) holder.itemView; + cell.setChecked(cell.currentInfo == info); + cell.updateStatus(); + } + } + updateRows(false); RecyclerListView.Holder holder = (RecyclerListView.Holder) listView.findViewHolderForAdapterPosition(useProxyRow); if (holder != null) { TextCheckCell textCheckCell = (TextCheckCell) holder.itemView; textCheckCell.setChecked(true); } + ConnectionsManager.setProxySettings(useProxySettings, SharedConfig.currentProxy.address, SharedConfig.currentProxy.port, SharedConfig.currentProxy.username, SharedConfig.currentProxy.password, SharedConfig.currentProxy.secret); + } else if (position == proxyAddRow) { + presentFragment(new ProxySettingsActivity()); + } else if (position == deleteAllRow) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.getString(R.string.DeleteAllProxiesConfirm)); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setTitle(LocaleController.getString(R.string.DeleteProxyTitle)); + builder.setPositiveButton(LocaleController.getString(R.string.Delete), (dialog, which) -> { + for (SharedConfig.ProxyInfo info : proxyList) { + SharedConfig.deleteProxy(info); + } + useProxyForCalls = false; + useProxySettings = false; + NotificationCenter.getGlobalInstance().removeObserver(ProxyListActivity.this, NotificationCenter.proxySettingsChanged); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged); + NotificationCenter.getGlobalInstance().addObserver(ProxyListActivity.this, NotificationCenter.proxySettingsChanged); + updateRows(true); + if (listAdapter != null) { + listAdapter.notifyItemChanged(useProxyRow, ListAdapter.PAYLOAD_CHECKED_CHANGED); + listAdapter.notifyItemChanged(callsRow, ListAdapter.PAYLOAD_CHECKED_CHANGED); + listAdapter.clearSelected(); + } + }); + AlertDialog dialog = builder.create(); + showDialog(dialog); + TextView button = (TextView) dialog.getButton(DialogInterface.BUTTON_POSITIVE); + if (button != null) { + button.setTextColor(Theme.getColor(Theme.key_text_RedBold)); + } } }); listView.setOnItemLongClickListener((view, position) -> { if (position >= proxyStartRow && position < proxyEndRow) { - final SharedConfig.ProxyInfo info = proxyList.get(position - proxyStartRow); - BottomBuilder builder = new BottomBuilder(context); - builder.addItems(new String[]{ - - info.subId == 1 ? null : LocaleController.getString("EditProxy", R.string.EditProxy), - info.subId == 1 && info instanceof SharedConfig.WsProxy ? null : LocaleController.getString("ShareProxy", R.string.ShareProxy), - info.subId == 1 && info instanceof SharedConfig.WsProxy ? null : LocaleController.getString("ShareQRCode", R.string.ShareQRCode), - info.subId == 1 && info instanceof SharedConfig.WsProxy ? null : LocaleController.getString("CopyLink", R.string.CopyLink), - info.subId == 1 ? null : LocaleController.getString("ProxyDelete", R.string.ProxyDelete), - LocaleController.getString("Cancel", R.string.Cancel) - - }, new int[]{ - - R.drawable.group_edit, - R.drawable.msg_share, - R.drawable.wallet_qr, - R.drawable.msg_link, - R.drawable.msg_delete, - R.drawable.msg_cancel - - }, (i, text, cell) -> { - - if (i == 0) { - if (info instanceof SharedConfig.VmessProxy) { - if (((SharedConfig.VmessProxy) info).bean.getConfigType() == V2RayConfig.EConfigType.Trojan) { - presentFragment(new TrojanSettingsActivity((SharedConfig.VmessProxy) info)); - } else { - presentFragment(new VmessSettingsActivity((SharedConfig.VmessProxy) info)); + listAdapter.toggleSelected(position); + return true; + } + return false; + }); + + ActionBarMenu actionMode = actionBar.createActionMode(); + selectedCountTextView = new NumberTextView(actionMode.getContext()); + selectedCountTextView.setTextSize(18); + selectedCountTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + selectedCountTextView.setTextColor(Theme.getColor(Theme.key_actionBarActionModeDefaultIcon)); + actionMode.addView(selectedCountTextView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 72, 0, 0, 0)); + selectedCountTextView.setOnTouchListener((v, event) -> true); + + shareMenuItem = actionMode.addItemWithWidth(MENU_SHARE, R.drawable.msg_share, AndroidUtilities.dp(54)); + deleteMenuItem = actionMode.addItemWithWidth(MENU_DELETE, R.drawable.msg_delete, AndroidUtilities.dp(54)); + + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + switch (id) { + case -1: + if (selectedItems.isEmpty()) { + finishFragment(); + } else { + listAdapter.clearSelected(); + } + break; + case MENU_DELETE: + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.getString(selectedItems.size() > 1 ? R.string.DeleteProxyMultiConfirm : R.string.DeleteProxyConfirm)); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setTitle(LocaleController.getString(R.string.DeleteProxyTitle)); + builder.setPositiveButton(LocaleController.getString(R.string.Delete), (dialog, which) -> { + for (SharedConfig.ProxyInfo info : selectedItems) { + SharedConfig.deleteProxy(info); } - } else if (info instanceof SharedConfig.ShadowsocksProxy) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - presentFragment(new ShadowsocksSettingsActivity((SharedConfig.ShadowsocksProxy) info)); + if (SharedConfig.currentProxy == null) { + useProxyForCalls = false; + useProxySettings = false; } - } else if (info instanceof SharedConfig.ShadowsocksRProxy) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - presentFragment(new ShadowsocksRSettingsActivity((SharedConfig.ShadowsocksRProxy) info)); + NotificationCenter.getGlobalInstance().removeObserver(ProxyListActivity.this, NotificationCenter.proxySettingsChanged); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged); + NotificationCenter.getGlobalInstance().addObserver(ProxyListActivity.this, NotificationCenter.proxySettingsChanged); + updateRows(true); + if (listAdapter != null) { + if (SharedConfig.currentProxy == null) { + listAdapter.notifyItemChanged(useProxyRow, ListAdapter.PAYLOAD_CHECKED_CHANGED); + listAdapter.notifyItemChanged(callsRow, ListAdapter.PAYLOAD_CHECKED_CHANGED); + } + listAdapter.clearSelected(); } - } else if (info instanceof SharedConfig.WsProxy) { - presentFragment(new WsSettingsActivity((SharedConfig.WsProxy) info)); - } else { - presentFragment(new ProxySettingsActivity(info)); + }); + AlertDialog dialog = builder.create(); + showDialog(dialog); + TextView button = (TextView) dialog.getButton(DialogInterface.BUTTON_POSITIVE); + if (button != null) { + button.setTextColor(Theme.getColor(Theme.key_text_RedBold)); } - } else if (i == 1) { - ProxyUtil.shareProxy(getParentActivity(), info, 0); - } else if (i == 2) { - ProxyUtil.shareProxy(getParentActivity(), info, 2); - } else if (i == 3) { - ProxyUtil.shareProxy(getParentActivity(), info, 1); - } else if (i == 4) { - AlertUtil.showConfirm(getParentActivity(), - LocaleController.getString("DeleteProxy", R.string.DeleteProxy), - R.drawable.msg_delete, LocaleController.getString("Delete", R.string.Delete), - true, () -> { - - SharedConfig.deleteProxy(info); - if (SharedConfig.currentProxy == null) { - SharedConfig.setProxyEnable(false); - } - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged); - }); - } - return Unit.INSTANCE; - }); - showDialog(builder.create()); - return true; + break; + case MENU_SHARE: + StringBuilder links = new StringBuilder(); + for (SharedConfig.ProxyInfo info : selectedItems) { + if (links.length() > 0) { + links.append("\n\n"); + } + links.append(info.getLink()); + } + + Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setType("text/plain"); + shareIntent.putExtra(Intent.EXTRA_TEXT, links.toString()); + Intent chooserIntent = Intent.createChooser(shareIntent, LocaleController.getString(selectedItems.size() > 1 ? R.string.ShareLinks : R.string.ShareLink)); + chooserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(chooserIntent); + + if (listAdapter != null) { + listAdapter.clearSelected(); + } + break; + } } - return false; }); - if (alert != null) { - AlertUtil.showSimpleAlert(context, alert); - alert = null; - } return fragmentView; } @@ -992,73 +621,7 @@ public boolean onBackPressed() { return true; } - @SuppressLint("NewApi") - private void addProxy() { - BottomBuilder builder = new BottomBuilder(getParentActivity()); - builder.addItems(new String[]{ - - LocaleController.getString("AddProxySocks5", R.string.AddProxySocks5), - LocaleController.getString("AddProxyTelegram", R.string.AddProxyTelegram), - LocaleController.getString("AddProxyWs", R.string.AddProxyWs), - BuildVars.isMini ? null : LocaleController.getString("AddProxyVmess", R.string.AddProxyVmess), - BuildVars.isMini ? null : LocaleController.getString("AddProxyTrojan", R.string.AddProxyTrojan), - BuildVars.isMini || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP ? null : LocaleController.getString("AddProxySS", R.string.AddProxySS), - BuildVars.isMini || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP ? null : LocaleController.getString("AddProxySSR", R.string.AddProxySSR), - LocaleController.getString("ImportProxyFromClipboard", R.string.ImportProxyFromClipboard), - LocaleController.getString("ScanQRCode", R.string.ScanQRCode) - - }, null, (i, t, c) -> { - - if (i == 0) { - presentFragment(new ProxySettingsActivity(0)); - } else if (i == 1) { - presentFragment(new ProxySettingsActivity(1)); - } else if (i == 2) { - presentFragment(new WsSettingsActivity()); - } else if (i == 3) { - presentFragment(new VmessSettingsActivity()); - } else if (i == 4) { - presentFragment(new TrojanSettingsActivity()); - } else if (i == 5) { - presentFragment(new ShadowsocksSettingsActivity()); - } else if (i == 6) { - presentFragment(new ShadowsocksRSettingsActivity()); - } else if (i == 7) { - ProxyUtil.importFromClipboard(getParentActivity()); - } else { - - if (Build.VERSION.SDK_INT >= 23) { - if (getParentActivity().checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { - getParentActivity().requestPermissions(new String[]{Manifest.permission.CAMERA}, 22); - return Unit.INSTANCE; - } - } - - CameraScanActivity.showAsSheet(this, new CameraScanActivity.CameraScanActivityDelegate() { - - @Override - public void didFindQr(String text) { - - try { - HttpUrl.parse(text); - Browser.openUrl(getParentActivity(), text); - return; - } catch (Exception ignored) { - } - - AlertUtil.showCopyAlert(getParentActivity(), text); - - } - - }); - } - return Unit.INSTANCE; - }); - builder.show(); - } - private void updateRows(boolean notify) { - proxyList = SharedConfig.getProxyList(); rowCount = 0; useProxyRow = rowCount++; if (useProxySettings && SharedConfig.currentProxy != null && SharedConfig.proxyList.size() > 1 && IS_PROXY_ROTATION_AVAILABLE) { @@ -1114,7 +677,6 @@ private void updateRows(boolean notify) { }); } - enablePublicProxyRow = rowCount++; if (!proxyList.isEmpty()) { proxyStartRow = rowCount; rowCount += proxyList.size(); @@ -1129,21 +691,17 @@ private void updateRows(boolean notify) { boolean change = callsRow == -1; callsRow = rowCount++; callsDetailRow = rowCount++; - UIUtil.runOnUIThread(() -> { - if (!notify && change) { - listAdapter.notifyItemChanged(proxyShadowRow); - listAdapter.notifyItemRangeInserted(proxyShadowRow + 1, 2); - } - }); + if (!notify && change) { + listAdapter.notifyItemChanged(proxyShadowRow); + listAdapter.notifyItemRangeInserted(proxyShadowRow + 1, 2); + } } else { boolean change = callsRow != -1; callsRow = -1; callsDetailRow = -1; if (!notify && change) { - UIUtil.runOnUIThread(() -> { - listAdapter.notifyItemChanged(proxyShadowRow); - listAdapter.notifyItemRangeRemoved(proxyShadowRow + 1, 2); - }); + listAdapter.notifyItemChanged(proxyShadowRow); + listAdapter.notifyItemRangeRemoved(proxyShadowRow + 1, 2); } } if (proxyList.size() >= 10) { @@ -1151,179 +709,32 @@ private void updateRows(boolean notify) { } else { deleteAllRow = -1; } - checkProxyList(false); + checkProxyList(); if (notify && listAdapter != null) { - UIUtil.runOnUIThread(() -> { - try { - listView.clearAnimation(); - listView.getRecycledViewPool().clear(); - listAdapter.notifyDataSetChanged(); - } catch (Exception e) { - FileLog.e(e); - } - }); - } - } - - private ExecutorService currentCheck; - - private void checkProxyList(boolean force) { - if (currentCheck == null) { - currentCheck = Executors.newFixedThreadPool(3); - } - ProxyChecksKt.checkProxyList(this, force, currentCheck); - } - - private void deleteUnavailableProxy() { - for (SharedConfig.ProxyInfo info : SharedConfig.getProxyList()) { - if (info.subId != 0) continue; - checkSingleProxy(info, 1, () -> { - deleteUnavailableProxy(info); - }); - } - } - - private void deleteUnavailableProxy(SharedConfig.ProxyInfo proxyInfo) { - if (!proxyInfo.available) { - SharedConfig.deleteProxy(proxyInfo); - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxyCheckDone); + listAdapter.notifyDataSetChanged(); } } - public void checkSingleProxy(SharedConfig.ProxyInfo proxyInfo, int repeat, Runnable callback) { - - if (SharedConfig.activeAccounts.isEmpty() && proxyInfo instanceof SharedConfig.WsProxy) { - proxyInfo.availableCheckTime = SystemClock.elapsedRealtime(); - proxyInfo.checking = false; - proxyInfo.available = false; - proxyInfo.ping = 0; - callback.run(); - return; - } - - UIUtil.runOnIoDispatcher(() -> { - if (proxyInfo instanceof SharedConfig.ExternalSocks5Proxy && !((SharedConfig.ExternalSocks5Proxy) proxyInfo).isStarted()) { - try { - ((SharedConfig.ExternalSocks5Proxy) proxyInfo).start(); - } catch (Exception e) { - FileLog.e(e); - AlertUtil.showToast(e); - } - ThreadUtil.sleep(233L); + private void checkProxyList() { + for (int a = 0, count = proxyList.size(); a < count; a++) { + final SharedConfig.ProxyInfo proxyInfo = proxyList.get(a); + if (proxyInfo.checking || SystemClock.elapsedRealtime() - proxyInfo.availableCheckTime < 2 * 60 * 1000) { + continue; } + proxyInfo.checking = true; proxyInfo.proxyCheckPingId = ConnectionsManager.getInstance(currentAccount).checkProxy(proxyInfo.address, proxyInfo.port, proxyInfo.username, proxyInfo.password, proxyInfo.secret, time -> AndroidUtilities.runOnUIThread(() -> { + proxyInfo.availableCheckTime = SystemClock.elapsedRealtime(); + proxyInfo.checking = false; if (time == -1) { - if (repeat > 0) { - checkSingleProxy(proxyInfo, repeat - 1, callback); - } else { - proxyInfo.availableCheckTime = SystemClock.elapsedRealtime(); - proxyInfo.checking = false; - proxyInfo.available = false; - proxyInfo.ping = 0; - if (proxyInfo instanceof SharedConfig.ExternalSocks5Proxy && proxyInfo != SharedConfig.currentProxy) { - ((SharedConfig.ExternalSocks5Proxy) proxyInfo).stop(); - } - if (callback != null) { - UIUtil.runOnUIThread(callback); - } - } + proxyInfo.available = false; + proxyInfo.ping = 0; } else { - proxyInfo.availableCheckTime = SystemClock.elapsedRealtime(); - proxyInfo.checking = false; proxyInfo.ping = time; proxyInfo.available = true; - if (proxyInfo instanceof SharedConfig.ExternalSocks5Proxy && proxyInfo != SharedConfig.currentProxy) { - ((SharedConfig.ExternalSocks5Proxy) proxyInfo).stop(); - } - if (callback != null) { - UIUtil.runOnUIThread(callback); - } } + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxyCheckDone, proxyInfo); })); - }); - } - - private void showSubDialog() { - BottomBuilder builder = new BottomBuilder(getParentActivity()); - builder.addTitle(LocaleController.getString("ProxySubscription", R.string.ProxySubscription)); - HashMap toChange = new HashMap<>(); - for (SubInfo sub : SubManager.getSubList().find()) { - TextCheckCell subItem = builder.addCheckItem(sub.name, sub.enable, true, (it, target) -> { - if (target == sub.enable) { - toChange.remove(sub); - } else { - toChange.put(sub, target); - } - return Unit.INSTANCE; - }); - - subItem.setOnLongClickListener((it) -> { - if (sub.internal) return false; - builder.dismiss(); - presentFragment(new SubSettingsActivity(sub)); - return true; - }); - } - - builder.addButton(LocaleController.getString("Add", R.string.Add), false, true, (it) -> { - presentFragment(new SubSettingsActivity()); - return Unit.INSTANCE; - }); - - String updateStr = LocaleController.getString("Update", R.string.Update); - updateStr = updateStr.toLowerCase(); - updateStr = StrUtil.upperFirst(updateStr); - - builder.addButton(updateStr, (it) -> { - AlertDialog pro = AlertUtil.showProgress(getParentActivity(), LocaleController.getString("SubscriptionUpdating", R.string.SubscriptionUpdating)); - AtomicBoolean canceled = new AtomicBoolean(); - pro.setOnCancelListener((__) -> { - canceled.set(true); - }); - pro.show(); - - UIUtil.runOnIoDispatcher(() -> { - for (SubInfo subInfo : SubManager.getSubList().find()) { - if (!subInfo.enable) continue; - try { - subInfo.proxies = subInfo.reloadProxies(); - subInfo.lastFetch = System.currentTimeMillis(); - } catch (IOException allTriesFailed) { - if (canceled.get()) return; - AlertUtil.showSimpleAlert(getParentActivity(), "All tries failed: " + allTriesFailed.toString().trim()); - continue; - } - SubManager.getSubList().update(subInfo, true); - if (canceled.get()) return; - } - SharedConfig.reloadProxyList(); - updateRows(true); - UIUtil.runOnUIThread(pro::dismiss); - }); - return Unit.INSTANCE; - }); - - builder.addButton(LocaleController.getString("OK", R.string.OK), (it) -> { - if (!toChange.isEmpty()) { - AlertDialog pro = AlertUtil.showProgress(getParentActivity()); - pro.setCanCancel(false); - pro.show(); - - UIUtil.runOnIoDispatcher(() -> { - for (Map.Entry toChangeE : toChange.entrySet()) { - toChangeE.getKey().enable = toChangeE.getValue(); - SubManager.getSubList().update(toChangeE.getKey(), true); - } - SharedConfig.reloadProxyList(); - UIUtil.runOnUIThread(() -> updateRows(true)); - ThreadUtil.sleep(233L); - UIUtil.runOnUIThread(pro::dismiss); - }); - } - return Unit.INSTANCE; - }); - builder.show(); } @Override @@ -1334,7 +745,9 @@ protected void onDialogDismiss(Dialog dialog) { @Override public void onResume() { super.onResume(); - updateRows(true); + if (listAdapter != null) { + listAdapter.notifyDataSetChanged(); + } } @Override @@ -1360,7 +773,7 @@ public void didReceivedNotification(int id, int account, Object... args) { int idx = proxyList.indexOf(SharedConfig.currentProxy); if (idx >= 0) { RecyclerListView.Holder holder = (RecyclerListView.Holder) listView.findViewHolderForAdapterPosition(idx + proxyStartRow); - if (holder != null && holder.itemView instanceof TextDetailProxyCell) { + if (holder != null) { TextDetailProxyCell cell = (TextDetailProxyCell) holder.itemView; cell.updateStatus(); } @@ -1373,17 +786,13 @@ public void didReceivedNotification(int id, int account, Object... args) { } } else if (id == NotificationCenter.proxyCheckDone) { if (listView != null) { - if (args.length == 0) { - updateRows(true); - } else { - SharedConfig.ProxyInfo proxyInfo = (SharedConfig.ProxyInfo) args[0]; - int idx = proxyList.indexOf(proxyInfo); - if (idx >= 0) { - RecyclerListView.Holder holder = (RecyclerListView.Holder) listView.findViewHolderForAdapterPosition(idx + proxyStartRow); - if (holder != null && holder.itemView instanceof TextDetailProxyCell) { - TextDetailProxyCell cell = (TextDetailProxyCell) holder.itemView; - cell.updateStatus(); - } + SharedConfig.ProxyInfo proxyInfo = (SharedConfig.ProxyInfo) args[0]; + int idx = proxyList.indexOf(proxyInfo); + if (idx >= 0) { + RecyclerListView.Holder holder = (RecyclerListView.Holder) listView.findViewHolderForAdapterPosition(idx + proxyStartRow); + if (holder != null) { + TextDetailProxyCell cell = (TextDetailProxyCell) holder.itemView; + cell.updateStatus(); } } @@ -1502,8 +911,6 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { checkCell.setTextAndCheck(LocaleController.getString("UseProxySettings", R.string.UseProxySettings), useProxySettings, rotationRow != -1); } else if (position == callsRow) { checkCell.setTextAndCheck(LocaleController.getString("UseProxyForCalls", R.string.UseProxyForCalls), useProxyForCalls, false); - } else if (position == enablePublicProxyRow) { - checkCell.setTextAndCheck(LocaleController.getString("enablePublicProxy", R.string.enablePublicProxy), NekoConfig.enablePublicProxy.Bool(), false); } else if (position == rotationRow) { checkCell.setTextAndCheck(LocaleController.getString(R.string.UseProxyRotation), SharedConfig.proxyRotationEnabled, true); } @@ -1522,12 +929,11 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } case VIEW_TYPE_PROXY_DETAIL: { TextDetailProxyCell cell = (TextDetailProxyCell) holder.itemView; - try { - SharedConfig.ProxyInfo info = proxyList.get(position - proxyStartRow); - cell.setProxy(info); - cell.setChecked(SharedConfig.currentProxy == info); - } catch (IndexOutOfBoundsException e) { - } + SharedConfig.ProxyInfo info = proxyList.get(position - proxyStartRow); + cell.setProxy(info); + cell.setChecked(SharedConfig.currentProxy == info); + cell.setItemSelected(selectedItems.contains(proxyList.get(position - proxyStartRow)), false); + cell.setSelectionEnabled(!selectedItems.isEmpty(), false); break; } case VIEW_TYPE_SLIDE_CHOOSER: { @@ -1566,8 +972,6 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi checkCell.setChecked(useProxySettings); } else if (position == callsRow) { checkCell.setChecked(useProxyForCalls); - } else if (position == enablePublicProxyRow) { - checkCell.setChecked(NekoConfig.enablePublicProxy.Bool()); } else if (position == rotationRow) { checkCell.setChecked(SharedConfig.proxyRotationEnabled); } @@ -1586,8 +990,6 @@ public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { checkCell.setChecked(useProxySettings); } else if (position == callsRow) { checkCell.setChecked(useProxyForCalls); - } else if (position == enablePublicProxyRow) { - checkCell.setChecked(NekoConfig.enablePublicProxy.Bool()); } else if (position == rotationRow) { checkCell.setChecked(SharedConfig.proxyRotationEnabled); } @@ -1597,7 +999,7 @@ public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { int position = holder.getAdapterPosition(); - return position == useProxyRow || position == rotationRow || position == callsRow || position == enablePublicProxyRow || position == deleteAllRow || position >= proxyStartRow && position < proxyEndRow; + return position == useProxyRow || position == rotationRow || position == callsRow || position == proxyAddRow || position == deleteAllRow || position >= proxyStartRow && position < proxyEndRow; } @Override @@ -1644,8 +1046,8 @@ public long getItemId(int position) { return -1; } else if (position == proxyShadowRow) { return -2; -// } else if (position == proxyAddRow) { -// return -3; + } else if (position == proxyAddRow) { + return -3; } else if (position == useProxyRow) { return -4; } else if (position == callsRow) { @@ -1673,7 +1075,7 @@ public int getItemViewType(int position) { return VIEW_TYPE_SHADOW; } else if (position == proxyAddRow || position == deleteAllRow) { return VIEW_TYPE_TEXT_SETTING; - } else if (position == useProxyRow || position == rotationRow || position == callsRow || position == enablePublicProxyRow) { + } else if (position == useProxyRow || position == rotationRow || position == callsRow) { return VIEW_TYPE_TEXT_CHECK; } else if (position == connectionsHeaderRow) { return VIEW_TYPE_HEADER; @@ -1685,7 +1087,6 @@ public int getItemViewType(int position) { return VIEW_TYPE_INFO; } } - } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProxySettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProxySettingsActivity.java index 0ab2fe2e6f..f965adb9e0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProxySettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProxySettingsActivity.java @@ -12,7 +12,6 @@ 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.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.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 TypeCell(Context context) { 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 void setTypeChecked(boolean value) { @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 void onItemClick(int id) { } 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 void onItemClick(int id) { 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 void onItemClick(int id) { 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 void onItemClick(int id) { 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 void onItemClick(int id) { } 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 void afterTextChanged(Editable s) { 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 void afterTextChanged(Editable s) { 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.getThemedDrawableByKey(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 void afterTextChanged(Editable s) { 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 @@ private void setShareDoneEnabled(boolean enabled, boolean animated) { 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 @@ private void setShareDoneEnabled(boolean enabled, boolean animated) { 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 void onTransitionResume(Transition transition) { ((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 void onTransitionAnimationEnd(boolean isOpen, boolean backward) { @Override public ArrayList 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 ArrayList getThemeDescriptions() { 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 ArrayList getThemeDescriptions() { 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)); diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/database/Nitrites.kt b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/database/Nitrites.kt index 85c27cda01..7d97607002 100644 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/database/Nitrites.kt +++ b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/database/Nitrites.kt @@ -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 @@ -23,9 +22,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 } diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/parts/ProxyChecks.kt b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/parts/ProxyChecks.kt deleted file mode 100644 index 2d80673010..0000000000 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/parts/ProxyChecks.kt +++ /dev/null @@ -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 - - } - - } - - } - -} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/parts/ProxyLoads.kt b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/parts/ProxyLoads.kt deleted file mode 100644 index 403b49eacb..0000000000 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/parts/ProxyLoads.kt +++ /dev/null @@ -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, exceptions: MutableMap): List { - 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, exceptions: MutableMap): List { - - return runBlocking { - - suspendCoroutine { - - val ret = AtomicBoolean() - val cl = AtomicInteger(urls.size) - var defer: List? = 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) - } - } - } - } - } - } - } -} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/parts/ProxySwitcher.kt b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/parts/ProxySwitcher.kt deleted file mode 100644 index 8d11c207eb..0000000000 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/parts/ProxySwitcher.kt +++ /dev/null @@ -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() - - 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 - - } - - } - - } - -} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/GuardedProcessPool.kt b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/GuardedProcessPool.kt deleted file mode 100644 index f7e25f3db1..0000000000 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/GuardedProcessPool.kt +++ /dev/null @@ -1,115 +0,0 @@ -/******************************************************************************* - * * - * Copyright (C) 2017 by Max Lv * - * Copyright (C) 2017 by Mygod Studio * - * * - * 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 . * - * * - *******************************************************************************/ - -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) { - 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() - 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, 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() } } - } -} diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ProxyManager.kt b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ProxyManager.kt deleted file mode 100644 index 4a3a3e6ebe..0000000000 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ProxyManager.kt +++ /dev/null @@ -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 - - } - -} diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ShadowsocksLoader.kt b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ShadowsocksLoader.kt deleted file mode 100644 index a06c10272f..0000000000 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ShadowsocksLoader.kt +++ /dev/null @@ -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() - 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" - - ) - - } - -} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ShadowsocksRLoader.kt b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ShadowsocksRLoader.kt deleted file mode 100644 index ca7f15714b..0000000000 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ShadowsocksRLoader.kt +++ /dev/null @@ -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() - 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" - ) - - } - -} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ShadowsocksRSettingsActivity.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ShadowsocksRSettingsActivity.java deleted file mode 100644 index a120d6e050..0000000000 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ShadowsocksRSettingsActivity.java +++ /dev/null @@ -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 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 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; - } -} diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ShadowsocksSettingsActivity.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ShadowsocksSettingsActivity.java deleted file mode 100644 index 0f8a57a9ae..0000000000 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/ShadowsocksSettingsActivity.java +++ /dev/null @@ -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 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 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; - } -} diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/SubInfo.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/SubInfo.java deleted file mode 100644 index 93a53263c5..0000000000 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/SubInfo.java +++ /dev/null @@ -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 urls = new LinkedList<>(); - public List 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 reloadProxies() throws IOException { - - HashMap exceptions = new HashMap<>(); - - try { - if (id == SubManager.publicProxySubID) { - if (!NekoConfig.enablePublicProxy.Bool()) - return new ArrayList<>(); - List 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 exceptions) { - this.exceptions = exceptions; - } - - public HashMap exceptions; - - @NonNull - @Override - public String toString() { - - StringBuilder errors = new StringBuilder(); - - for (Map.Entry 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) document.get("urls"); - proxies = (List) document.get("proxies"); - - lastFetch = document.get("lastFetch", Long.class); - enable = document.get("enable", Boolean.class); - internal = document.get("internal", Boolean.class); - - } - -} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/SubManager.kt b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/SubManager.kt deleted file mode 100644 index 7c39a04dbe..0000000000 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/SubManager.kt +++ /dev/null @@ -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) - - } - - } - -} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/SubSettingsActivity.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/SubSettingsActivity.java deleted file mode 100644 index 4bb79cdb3e..0000000000 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/SubSettingsActivity.java +++ /dev/null @@ -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.msg_delete, 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.msg_delete, 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 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 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; - } -} diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/TrojanSettingsActivity.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/TrojanSettingsActivity.java deleted file mode 100644 index b42d7a93f3..0000000000 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/TrojanSettingsActivity.java +++ /dev/null @@ -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 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 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; - } -} diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/VmessLoader.kt b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/VmessLoader.kt deleted file mode 100644 index a86bcebbc0..0000000000 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/VmessLoader.kt +++ /dev/null @@ -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 - } - } - -} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/VmessSettingsActivity.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/VmessSettingsActivity.java deleted file mode 100644 index 755cab4722..0000000000 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/VmessSettingsActivity.java +++ /dev/null @@ -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 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 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; - } -} diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/WsSettingsActivity.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/WsSettingsActivity.java deleted file mode 100644 index f755aacab3..0000000000 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/WsSettingsActivity.java +++ /dev/null @@ -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 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 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; - } -} diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/tcp2ws/Tcp2wsServer.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/tcp2ws/Tcp2wsServer.java deleted file mode 100644 index 938e05b1c2..0000000000 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/tcp2ws/Tcp2wsServer.java +++ /dev/null @@ -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 mapper = Collections.unmodifiableMap(new HashMap() {{ - 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); - } - } -} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/tcp2ws/WsLoader.kt b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/tcp2ws/WsLoader.kt deleted file mode 100644 index 1503ea6486..0000000000 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/tcp2ws/WsLoader.kt +++ /dev/null @@ -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 = 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://") - } - } - -} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/tcp2ws/WsProxyHandler.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/tcp2ws/WsProxyHandler.java deleted file mode 100644 index bb08c8b967..0000000000 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/proxy/tcp2ws/WsProxyHandler.java +++ /dev/null @@ -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> 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; - } - -} diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/transtale/Translator.kt b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/transtale/Translator.kt index aa4479197c..8fb114eda6 100644 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/transtale/Translator.kt +++ b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/transtale/Translator.kt @@ -19,7 +19,7 @@ import tw.nekomimi.nekogram.utils.receiveLazy import java.util.* fun T.applyProxy(): T { - SharedConfig.getActiveSocks5Proxy()?.let { setProxy(it) } +// SharedConfig.getActiveSocks5Proxy()?.let { setProxy(it) } return this } diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/transtale/deepl/DeepLTranslatorRaw.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/transtale/deepl/DeepLTranslatorRaw.java index 23055568f8..8a0fbcc6d5 100644 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/transtale/deepl/DeepLTranslatorRaw.java +++ b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/transtale/deepl/DeepLTranslatorRaw.java @@ -181,11 +181,11 @@ private String request(String url, String body) throws IOException { InputStream httpConnectionStream = null; URL downloadUrl = new URL(url); HttpURLConnection httpConnection; - final Proxy proxy = SharedConfig.getActiveSocks5Proxy(); - if (proxy != null) - httpConnection = (HttpURLConnection) downloadUrl.openConnection(proxy); - else - httpConnection = (HttpURLConnection) downloadUrl.openConnection(); +// final Proxy proxy = SharedConfig.getActiveSocks5Proxy(); +// if (proxy != null) +// httpConnection = (HttpURLConnection) downloadUrl.openConnection(proxy); +// else + httpConnection = (HttpURLConnection) downloadUrl.openConnection(); httpConnection.addRequestProperty("Connection", "keep-alive"); httpConnection.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4147.105 Safari/537.36"); httpConnection.addRequestProperty("Content-Type", "application/json"); diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/utils/ProxyUtil.kt b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/utils/ProxyUtil.kt index c64d154901..360ac29e85 100644 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/utils/ProxyUtil.kt +++ b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/utils/ProxyUtil.kt @@ -5,10 +5,8 @@ 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 @@ -19,40 +17,33 @@ import android.net.NetworkCapabilities import android.net.NetworkRequest 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.BarcodeFormat +import com.google.zxing.BinaryBitmap +import com.google.zxing.DecodeHintType +import com.google.zxing.EncodeHintType +import com.google.zxing.NotFoundException +import com.google.zxing.RGBLuminanceSource +import com.google.zxing.WriterException 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.AndroidUtilities +import org.telegram.messenger.ApplicationLoader +import org.telegram.messenger.FileLog +import org.telegram.messenger.LocaleController +import org.telegram.messenger.NotificationCenter +import org.telegram.messenger.R +import org.telegram.messenger.SharedConfig import org.telegram.messenger.browser.Browser -import org.yaml.snakeyaml.Yaml -import tw.nekomimi.nekogram.proxy.ShadowsocksLoader -import tw.nekomimi.nekogram.proxy.ShadowsocksRLoader import tw.nekomimi.nekogram.ui.BottomBuilder import tw.nekomimi.nekogram.utils.AlertUtil.showToast import java.io.File -import java.util.* object ProxyUtil { @@ -108,414 +99,6 @@ object ProxyUtil { } } - @JvmStatic - @JvmOverloads - fun parseProxies(text: String, tryDecode: Boolean = true): MutableList { - - if (tryDecode && !text.contains("proxies:")) { - try { - return parseProxies(String(Base64.decode(text, Base64.NO_PADDING)), false) - } catch (ignored: Exception) { - } - } - - val proxies = mutableListOf() - - 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>)) { - 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) - 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)) { - when (h2Opt.key) { - "host" -> opts.requestHost = (h2Opt.value as List).first() - "path" -> opts.path = h2Opt.value as String - } - } - "http-opts" -> for (httpOpt in (opt.value as Map)) { - when (httpOpt.key) { - "path" -> opts.path = (httpOpt.value as List).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() - - 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 {