Compare commits

115 Commits
v2.9 ... v3.5

Author SHA1 Message Date
KOWX712
058ac8dfdc v3.5 release 2025-02-23 18:06:34 +08:00
KOWX712
735444d8a3 misc: simplify download function 2025-02-23 16:04:28 +08:00
KOWX712
6a806ac588 fix: deselect unnecessary app 2025-02-23 16:01:18 +08:00
Re*Index. (ot_inc)
3ffe75a1f3 Fixed ja-JP.json (#20) 2025-02-22 22:48:27 +08:00
KOWX712
4fdc057162 misc: update more-exclude.json 2025-02-22 22:03:59 +08:00
KOWX712
b7b5c2c1f0 misc: unify button styling 2025-02-22 22:03:32 +08:00
KOWX712
ddeb13c5e2 misc: function to check advanced mode 2025-02-22 22:03:32 +08:00
KOWX712
410629fad5 opt: move unnecessary list download to JS 2025-02-22 22:03:32 +08:00
KOWX712
7424ed325a opt: move valid kb download operation to JS 2025-02-22 22:03:32 +08:00
KOWX712
f1128cd55b opt: partially move update operation to JS
- move fetch update.json operation to JS
- move changelog download to JS
2025-02-22 22:03:32 +08:00
Bladius2024
e5dcc62fdf feat: add Polish Translation 2025-02-22 02:11:56 +08:00
KOWX712
ee169eb2cd opt: ui border sizing 2025-02-21 17:44:33 +08:00
KOWX712
a9d6833342 opt: uninstall button 2025-02-21 03:34:30 +08:00
KOWX712
a8e388d4cf opt: boot hash window ui 2025-02-21 03:18:57 +08:00
KOWX712
09f6f522de opt: simplify ripple effect class 2025-02-21 02:29:42 +08:00
KOWX712
f2483efc6e deps: update markdown parser
update to marked v15.0.7
2025-02-21 02:06:03 +08:00
KOWX712
6ed4df7d9c misc: rename file 2025-02-21 02:06:03 +08:00
KOWX712
ac4ff62cce opt: ui 2025-02-21 02:06:03 +08:00
KOWX712
b6c81362fe show prompt on fetching security patch date 2025-02-20 18:30:46 +08:00
KOWX712
5f70249003 script opt 2025-02-20 00:17:55 +08:00
KOWX712
16f1cde2d7 fix Failed to fetch app list on vanilla rom
#17
2025-02-20 00:01:05 +08:00
KOWX712
96ea764aa0 Update .extra 2025-02-19 21:23:42 +08:00
KOWX712
c44a101776 option to fetch a security patch date 2025-02-18 19:21:55 +08:00
KOWX712
581d81d5dd reflect recent update 2025-02-17 15:37:15 +08:00
KOWX712
d0882dfa57 use advanced config for security patch 2025-02-16 18:05:02 +08:00
KOWX712
3050ecf84c v3.4 release 2025-02-15 21:15:15 +08:00
KOWX712
83cd9a0ac8 Set status bars theme based on device theme in MMRL 2025-02-15 21:14:09 +08:00
KOWX712
bf8fdb8419 remove FileSystemAPI request on MMRL 2025-02-15 21:14:09 +08:00
KOWX712
edfe2986e7 display security patch option on tricky store v1.2.1+ only 2025-02-15 21:14:09 +08:00
KOWX712
473bd64770 fix wrong changelog
fix wrong version changelog displayed  on minor update (vX.X.X)
2025-02-13 21:58:43 +08:00
KOWX712
68ed991d98 optimize input experience 2025-02-13 17:22:13 +08:00
KOWX712
553df593ae module name 2025-02-13 16:39:33 +08:00
KOWX712
dfc6726e10 light theme input box color 2025-02-13 12:54:21 +08:00
KOWX712
5a66cba009 revert some translation 2025-02-13 12:54:21 +08:00
KOWX712
f8dfe50a0c optimize input experience 2025-02-13 12:54:21 +08:00
KOWX712
24c00f124d uncheck advanced mode on auto 2025-02-13 12:54:21 +08:00
KOWX712
5e3836f41f Function to handle security patch operation 2025-02-13 12:54:21 +08:00
KOWX712
41b434f2bb function to handle kb operation 2025-02-13 12:54:21 +08:00
Berk Mirsat
5441eb0830 update Turkish translation (#16) 2025-02-13 00:52:20 +08:00
KOWX712
046af031d8 complete read value logic 2025-02-11 21:21:11 +08:00
KOWX712
4977695022 fix wrong formatted output 2025-02-11 20:31:39 +08:00
KOWX712
0427153ea6 apply immediately
no need to reboot to apply
2025-02-11 20:02:41 +08:00
KOWX712
2980bda649 update error prompt 2025-02-11 19:34:56 +08:00
KOWX712
0821e88fdc update layout 2025-02-11 19:29:50 +08:00
KOWX712
25ecc49a77 fix abnormal checkbox size 2025-02-11 18:41:33 +08:00
KOWX712
42f0b6df77 revert cubic-bezier animaiton 2025-02-11 18:40:21 +08:00
KOWX712
006ca27100 custom checkbox style 2025-02-11 18:29:38 +08:00
KOWX712
f36f5bf7db touch up 2025-02-11 18:07:01 +08:00
KOWX712
41430b4386 allow save empty 2025-02-11 17:44:58 +08:00
KOWX712
6ee2b65b75 spacing format 2025-02-11 17:44:58 +08:00
KOWX712
1a50c322d9 add animation 2025-02-11 17:13:15 +08:00
KOWX712
83469179e6 config in webui 2025-02-11 16:41:12 +08:00
KOWX712
d534185d48 security patch custom config 2025-02-11 12:59:54 +08:00
KOWX712
7324d92aeb add mmrl check and guide 2025-02-11 03:44:47 +08:00
KOWX712
6cd29416ec request api on mmrl 33045+ 2025-02-11 01:58:40 +08:00
KOWX712
39c303e04e clickable current path
click folder name on path to go to the folder
2025-02-10 00:00:03 +08:00
KOWX712
8d67689d76 import custom keybox 2025-02-09 02:11:16 +08:00
KOWX712
2886b7e742 check ksu next on installation 2025-02-08 21:40:02 +08:00
KOWX712
2447312286 validate security patch date 2025-02-08 16:29:27 +08:00
KOWX712
895b3ff1bd v3.3.1 release 2025-02-08 13:23:33 +08:00
KOWX712
e18871754f change security patch logic
check if security patch is older than one year
2025-02-08 13:20:05 +08:00
KOWX712
a4c08ba08c v3.3 release
changelog: fix typo
2025-02-07 14:48:41 +08:00
KOWX712
66e048d5a1 update with tricky store 1.2.1 2025-02-07 14:48:41 +08:00
KOWX712
b81d95d31f script opt 2025-02-07 14:48:41 +08:00
KOWX712
bb7573f5dd add denylist to target on boot
choose "Select from DenyList" in WebUI once to enable this feature
2025-02-06 22:32:36 +08:00
KOWX712
ccffd2eaed update username 2025-02-05 22:23:44 +08:00
KOWX712
d9c1cdc11d Update README.md 2025-02-05 14:57:01 +08:00
KOWX712
e1f9c8904a Update .extra 2025-02-05 14:49:43 +08:00
KOWX712
3b98a88c77 typo 2025-02-02 13:03:36 +08:00
KOWX712
0b8dcd4503 v3.2 release 2025-02-02 13:00:56 +08:00
KOWX712
913118ac60 handle vendor patch
set `ro.vendor.build.security_patch` same with `ro.build.version.security_patch`
2025-02-02 12:49:20 +08:00
KOWX712
cb4276643a add android and com.android.vending by default
make compatible with latest pif inject a4086509f9
https://github.com/5ec1cff/TrickyStore/pull/83
2025-02-01 11:51:32 +08:00
Berk Mirsat
0087575117 A13 check package name (#13) 2025-01-29 18:30:15 +08:00
KOWX712
5f01b4fed1 Update .extra 2025-01-29 13:44:10 +07:00
berkmirsat
1f7a4c174b add Turkish translation 2025-01-29 06:36:17 +07:00
KOWX712
19f6b156f6 wait for next 2025-01-23 07:35:29 +08:00
KOWX712
63874eeb8b Update README.md 2025-01-22 23:58:29 +08:00
KOWX712
2c5082acbc check json format on pull request 2025-01-19 22:23:02 +08:00
Re*Index. (ot_inc)
1cb810405a Update ja-JP.json 2025-01-19 18:59:40 +08:00
KOWX712
142dfdbe81 fix gsf app name missing 2025-01-19 16:29:13 +08:00
KOWX712
5ef6293924 v3.1 release 2025-01-19 15:38:22 +08:00
KOWX712
a6b35e8d85 fix update issue 2025-01-19 15:38:22 +08:00
KOWX712
51747f261e complete additional system app
complete aa7147d115 (#10)
2025-01-19 14:41:10 +08:00
ChiseWaguri
aa7147d115 Add Play Store and Service Framework for A13+ checks 2025-01-19 11:07:13 +08:00
KOWX712
5e9463d8d2 update to marked v15.0.6 2025-01-17 03:29:32 +08:00
KOWX712
d1313d743c Update .extra
Update .extra
2025-01-16 03:43:58 +08:00
KOWX712
2542e1a18a Backup before replacing kb on uninstallation 2025-01-15 22:36:39 +08:00
KOWX712
aa0837ec49 backup before putting a new kb
#8
2025-01-15 22:11:23 +08:00
KOWX712
684b38afef prevent deletion if tricky store add webui/action in future 2025-01-15 02:14:51 +08:00
KOWX712
e348fbdd6f Update .gitattributes 2025-01-13 00:35:49 +08:00
KOWX712
bb167b760d update zh language name 2025-01-10 03:38:10 +08:00
KOWX712
8909a73b59 opt code
- ensure auto install use latest ksuwebui standalone.
2025-01-09 01:33:07 +08:00
KOWX712
d8848fe5c3 fix multiple gms
fix multiple gms on device without gms as system app.
2025-01-06 18:24:25 +08:00
KOWX712
2d2cdd7672 fix multiple eventlistener for ripple effect 2025-01-04 15:13:03 +08:00
KOWX712
c1818b6ba2 remove ripple effect on mode menu 2025-01-03 14:47:58 +08:00
KOWX712
c69337501a update Chinese translation 2025-01-03 14:44:33 +08:00
KOWX712
12a39ce60a Complete markdown support
- Update markdown parser to v15.0.5
- Add credit to markedjs/marked
- UI adjust
2025-01-03 11:41:07 +08:00
KOWX712
ec330a4b0b Add markdown support in changelog 2025-01-02 17:16:10 +08:00
KOWX712
7e2c185c5c Update README.md 2025-01-02 12:27:37 +08:00
KOWX712
f641f388ad opt menu touch effect 2025-01-02 01:26:42 +08:00
KOWX712
f7aee9dc34 remove lite from update 2025-01-01 10:08:34 +08:00
KOWX712
c19b93ffa3 v3.0 Happy New Year 2025 2025-01-01 09:38:47 +08:00
KOWX712
2dc69abea4 change button color 2025-01-01 09:38:12 +08:00
KOWX712
75ff61e4d2 fix missing animation 2024-12-31 20:21:56 +08:00
KOWX712
bb3b0abb30 adjust update menu UI 2024-12-31 18:21:52 +08:00
KOWX712
502e6f6ea6 change update method 2024-12-31 17:02:04 +08:00
KOWX712
1d5428e683 Fix save button animation 2024-12-30 09:38:37 +08:00
KOWX712
fe64f37361 UI adjust + optimize
- adjust about page appearance
- change mode menu shape to round
- enlarge on selected mode
- improve color recognition algorithm
- code optimize
2024-12-30 03:06:28 +08:00
KOWX712
24548025fe Update A-template.json 2024-12-29 03:52:27 +08:00
KOWX712
d3885966b2 fix wrong error toast 2024-12-29 03:36:31 +08:00
KOWX712
ae32ccf973 Final touchup
- UI adjust: color, placement, size

#7
2024-12-29 03:08:34 +08:00
KOWX712
77a6e06631 Support ! and ? mode in WebUI
- Long press to open mode menu
- Show toast on error log

#7
2024-12-29 02:39:49 +08:00
KOWX712
940d809ac5 complete animation
- adjust position of prompt and save button on MMRL
- complete ripple animation
- new checkbox animation
2024-12-28 14:54:38 +08:00
KOWX712
1861e43a81 Simplify logic, add Material Design ripple effect 2024-12-26 20:52:01 +08:00
KOWX712
10c02a6924 Add trigger on pull request 2024-12-26 01:19:03 +08:00
47 changed files with 3183 additions and 617 deletions

2
.extra

File diff suppressed because one or more lines are too long

4
.gitattributes vendored
View File

@@ -3,7 +3,9 @@
*.prop text eol=lf
*.md text eol=lf
*.xml text eol=lf
*.json text eol=lf
.extra text eol=lf
META-INF/** text eol=lf
# Denote all files that are truly binary and should not be modified.
common/addon/**/tools/** binary
module/bin/**/** binary

View File

@@ -6,6 +6,9 @@ on:
- main
paths:
- 'module/**'
pull_request:
paths:
- 'module/**'
workflow_dispatch:
jobs:
@@ -18,17 +21,20 @@ jobs:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 2
fetch-depth: 0
fetch-tags: true
- name: Extract Module Info
id: extract_info
run: |
MODULE_VERSION=$(grep -oP '^version=\K.*' module/module.prop)
BUILD_COUNT=$((1000 + ${{ github.run_number }}))
ARTIFACT_NAME="TrickyAddonModule-${MODULE_VERSION}-canary-${BUILD_COUNT}"
MODULE_VERSION=$(grep '^version=' module/module.prop | sed 's/version=//')
COMMIT_NUM=$(git rev-list --count HEAD)
BUILD_COUNT=${{ github.run_number }}
ARTIFACT_NAME="TrickyAddonModule-${MODULE_VERSION}-${COMMIT_NUM}${BUILD_COUNT}-canary"
sed -i "s/^version=.*/& (${COMMIT_NUM}${BUILD_COUNT}-canary)/" module/module.prop
echo "MODULE_VERSION=${MODULE_VERSION}" >> $GITHUB_ENV
echo "ARTIFACT_NAME=${ARTIFACT_NAME}" >> $GITHUB_ENV
echo "VERSION=${MODULE_VERSION}" >> $GITHUB_ENV
- name: Upload Artifact
uses: actions/upload-artifact@v4
@@ -40,12 +46,16 @@ jobs:
- name: Check if valid to release
id: check_tag
run: |
VERSION=$(grep '^version=' module/module.prop | sed 's/version=//')
git fetch --tags
if git tag | grep -qx "^$VERSION"; then
if [ "${{ github.event_name }}" = "pull_request" ]; then
echo "version_tag_exists=true" >> $GITHUB_OUTPUT
else
echo "version_tag_exists=false" >> $GITHUB_OUTPUT
git fetch --tags
VERSION=${{ env.VERSION }}
if git tag | grep -qx "^${VERSION}"; then
echo "version_tag_exists=true" >> $GITHUB_OUTPUT
else
echo "version_tag_exists=false" >> $GITHUB_OUTPUT
fi
fi
release:
@@ -87,13 +97,12 @@ jobs:
FILES="TrickyAddonModule-${VERSION}.zip"
else
PRERELEASE=false
FORMATTED_RELEASE_NOTES=$(echo -e "### Tricky Addon module\n$RELEASE_NOTES\n---\n### Tricky Addon Lite - script only\n- Check on [changelog](https://github.com/KOWX712/Tricky-Addon-Update-Target-List/tree/main/lite-script_only#tricky-addon-lite-update-target-list-script)")
FILES="TrickyAddonModule-${VERSION}.zip,TrickyAddonLite_ScriptOnly_Extract-${VERSION}.zip"
FORMATTED_RELEASE_NOTES=$(echo -e "### Tricky Addon module\n$RELEASE_NOTES\n")
FILES="TrickyAddonModule-${VERSION}.zip"
fi
echo "CURRENT_TAG=$CURRENT_TAG" >> $GITHUB_ENV
echo "ZIP_NAME=TrickyAddonModule-${VERSION}.zip" >> $GITHUB_ENV
echo "LITE_SCRIPT_ONLY_ZIP_NAME=TrickyAddonLite_ScriptOnly_Extract-${VERSION}.zip" >> $GITHUB_ENV
echo "RELEASE_NOTES<<EOF" >> $GITHUB_ENV
echo "$FORMATTED_RELEASE_NOTES" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
@@ -105,12 +114,6 @@ jobs:
cd module && zip -r "../${{ env.ZIP_NAME }}" ./*
echo "Created zip file: ${{ env.ZIP_NAME }}"
- name: Compress lite-script_only folder
if: ${{ env.PRERELEASE == 'false' }}
run: |
cd lite-script_only && zip -r "../${{ env.LITE_SCRIPT_ONLY_ZIP_NAME }}" ./*
echo "Created zip file: ${{ env.LITE_SCRIPT_ONLY_ZIP_NAME }}"
- name: Create release
uses: softprops/action-gh-release@v2
env:

31
.github/workflows/json-lint.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: pr_jsonlint
on:
pull_request:
paths:
- 'module/webui/locales/*.json'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install JSON linter
run: npm install -g jsonlint
- name: Lint JSON files
run: |
for file in $(find module/webui/locales -name "*.json"); do
echo "Checking $file"
if ! jsonlint "$file"; then
echo "Error in $file"
exit 1
fi
done

View File

@@ -16,28 +16,31 @@ Configure Tricky Store target.txt with KSU WebUI.
### Magisk
- Action button to open WebUI
- Support KSUWebUIStandalone and latest MMRL
- Automatic install [KSUWebUIStandalone](https://github.com/5ec1cff/KsuWebUIStandalone) if none of them are installed.
- Support [KSUWebUIStandalone](https://github.com/5ec1cff/KsuWebUIStandalone) and [MMRL](https://github.com/MMRLApp/MMRL)
- Automatic KSUWebUIStandalone install if none of them are installed.
### What Can This Module Do
| Feature | Status |
|:---|:---:|
| Configure target.txt with app name display | ✅ |
| Select apps from Magisk DenyList (optional) | ✅ |
| Deselect [unnecessary apps](https://github.com/KOWX712/Tricky-Addon-Update-Target-List/blob/main/more-excldue.json) (optional) | ✅ |
| Set verifiedBootHash (optional) | ✅ |
| Provide AOSP Keybox (optional) | ✅ |
| Valid Keybox (not guaranteed) | ❌ |
| Shamiko Whitelist switch ([Why?](https://github.com/rushizgithub/shamiko?tab=readme-ov-file#whitelist)) | ❌ |
| Add `!` or `?` to the target ([Not needed](https://github.com/5ec1cff/TrickyStore/releases/tag/1.1.0)) | ❌ |
| Periodically update target and add new apps | ❌ |
| Add system apps (GMS added by default) | ❌ |
| Feature | Status |
| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----: |
| Configure target.txt with app name display | ✅ |
| Long press to choose `!` or `?` mode for the app. [Auto](https://github.com/5ec1cff/TrickyStore/releases/tag/1.1.0)<br>Use this only when the app cannot work without this. | ✅ |
| Select apps from Magisk DenyList `optional` | ✅ |
| Deselect [unnecessary apps](https://github.com/KOWX712/Tricky-Addon-Update-Target-List/blob/main/more-exclude.json) `optional` | ✅ |
| Set verifiedBootHash `optional` | ✅ |
| Auto config [security patch](https://github.com/5ec1cff/TrickyStore?tab=readme-ov-file#customize-security-patch-level-121), customizable in WebUI | ✅ |
| Provide AOSP Keybox `optional` | ✅ |
| Import custom Keybox from device storage | ✅ |
| Valid Keybox `not guaranteed` | ❌ |
| Shamiko Whitelist switch. [Why?](https://github.com/rushizgithub/shamiko?tab=readme-ov-file#whitelist) | ❌ |
| Periodically add all app to target.txt | ❌ |
| Add system apps `GMS added by default` | ❌ |
## Localization
- Read [Translation Guide](https://github.com/KOWX712/Tricky-Addon-Update-Target-List/blob/main/module/webui/locales/A-translate.md)
## Acknowledgement
- [j-hc/zygisk-detach](https://github.com/j-hc/zygisk-detach) - KSU WebUI template
- [markedjs/marked](https://github.com/markedjs/marked) - Markdown Support
## Links
[![release](https://custom-icon-badges.demolab.com/badge/-Download-F25278?style=for-the-badge&logo=download&logoColor=white)](https://github.com/KOWX712/Tricky-Addon-Update-Target-List/releases)

View File

@@ -8,12 +8,58 @@ GitHub release: [Tricky Addon: Update Target List](https://github.com/KOWX712/Tr
Telegram channel: [KOW's Little World](https://t.me/kowchannel)
## Changelog
### v3.5
- **Script:** Set `system=prop` in auto config.
- **WebUI:** Option to fetch secuirty patch date.
- **WebUI:** Fixed `Failed to fetch app list` issue in vanilla rom.
- **WebUI:** Added Polish translation (#18, @Bladius2024)
- **WebUI:** Update Japanese translation (#20, @reindex-ot)
- **WebUI:** Minor UI improvements.
### v3.4
- **WebUI:** Allow import custom keybox from device storage.
- **WebUI:** Allow custom config security patch in WebUI, save empty to disable auto config.
- **WebUI:** Update Turkish translation (#16, @berkmirsatk)
- **WebUI:** Fix wrong changelog version displayed in update changelog.
- **MMRL:** Display a guide to enable the JavaScript API in MMRL. Directly request API permission on v33045+
- More minor improvements
### v3.3.1
- Fixed security patch logic, use pif.json to get security patch date.
- No auto config `security_patch.txt` for security patch lesser than one year.
### v3.3
- Support auto config `security_patch.txt` for Tricky Store v1.2.1 or higher.
- No longer need to add `!` to Play Store for devices that have security patch older than one year to get strong integrity in new A13+ check.
- **Magisk:** automatically add apps from DenyList to `target.txt` on boot. To enable this feature, click "Select from DenyList" once in WebUI after update.
### v3.2
- Add `android` and `com.android.vending` by default.
- Handle `ro.vendor.build.security_patch` if the value is different.
- Updated Japanese translation (#11, @reindex-ot)
- Added Turkish translation (@berkmirsatk)
### v3.1
- Added `com.google.android.gsf` and `com.android.vending` into WebUI app list. (#10, @ChiseWaguri)
- Fixed multiple instances of GMS appeared in the app list when GMS isn't a system app.
- Added auto backup `keybox.xml` to `keybox.xml.bak` before replacing it.
- Minor animation improvements and code optimizations.
- [Markdown support](https://github.com/markedjs/marked) for future update changelog in WebUI.
### v3.0
- Animation improvement: new checkbox animation, new touch ripple animation, and more.
- Adjust save button and prompt position in MMRL.
- Long press on app to select `!` and `?` mode, use this only when the app cannot work without this.
- Display gms in app list.
- Show module version in header.
- Rewrite update method, you can now update module directly in WebUI.
### v2.9
- Preserve `!` and `?` during update target in WebUi.
- Preserve `!` and `?` during update target in WebUI.
- Optimized scripts, thanks to @backslashxx.
- Fixed freeze in weak connection.
- Added Spanish, thanks to @Keinta15.
- Removed rescriction on installation but module will still be removed if tricky store is not found after reboot.
- Removed restriction on installation but module will still be removed if Tricky Store is not found after reboot.
### v2.8
- Fixed all KSUWebUIStandalone freeze issue, removed visible option.
@@ -31,7 +77,7 @@ Telegram channel: [KOW's Little World](https://t.me/kowchannel)
- Press any position of app card to select/deselct.
### v2.6
- Invisible module, intergrate action button & webui on tricky store card. You can stil use visible option if you found any issue with invisble module. Thanks for idea from @backslashxx.
- Invisible module, integrate action button & WebUI on Tricky Store card. You can still use visible option if you found any issue with invisible module. Thanks for idea from @backslashxx.
- To uninstall invisble module, scroll down to the bottom of WebUI and press Uninstall WebUI.
- Add update prompt if found new version in webui, and show module if found an update. (invisible)
- Reduced WebUI loading time

View File

@@ -1,4 +1,4 @@
## Tricky Addon Lite: Update Target List Script
## Tricky Addon Lite: Update Target List Script (EOL)
- Script only, **NOT Module**
- Run with root priviledge
- Recommend to run with MT manager

View File

@@ -21,6 +21,8 @@ me.garfieldhan.apatch.next"
ADDITION="
com.google.android.gms
com.google.android.gsf
com.android.vending
io.github.vvb2060.keyattestation
io.github.vvb2060.mahoshojo
icu.nullptr.nativetest"

View File

@@ -3,70 +3,58 @@
###########################################
MODPATH="/data/adb/modules/.TA_utl"
COMPATH="$MODPATH/common"
ORG_PATH="$PATH"
TMP_DIR="$MODPATH/common/tmp"
SCRIPT_DIR="/data/adb/tricky_store"
URL="https://github.com/5ec1cff/KsuWebUIStandalone/releases/download/v1.0/KsuWebUI-1.0-34-release.apk"
APK_DIR="$COMPATH/tmp"
BBPATH="/data/adb/magisk/busybox \
/data/adb/ksu/bin/busybox \
/data/adb/ap/bin/busybox \
/data/adb/modules/busybox-ndk/system/*/busybox"
APK_PATH="$TMP_DIR/base.apk"
check_wget() {
for path in $BBPATH; do
[ -f "$path" ] && BUSYBOX="$path" && break
done
if ! command -v wget >/dev/null || grep -q "wget-curl" "$(command -v wget)"; then
if [ -n "$BUSYBOX" ]; then
wget() { "$BUSYBOX" wget "$@"; }
else
exit 1
fi
manual_download() {
echo "$1"
sleep 3
am start -a android.intent.action.VIEW -d "https://github.com/5ec1cff/KsuWebUIStandalone/releases"
exit 1
}
download() {
PATH=/data/adb/magisk:/data/data/com.termux/files/usr/bin:$PATH
if command -v curl >/dev/null 2>&1; then
timeout 10 curl -Ls "$1"
else
timeout 10 busybox wget --no-check-certificate -qO- "$1"
fi
PATH="$ORG_PATH"
}
get_webui() {
echo "- Downloading the WebUI APK..."
check_wget
if ! wget --no-check-certificate -P "$APK_DIR" "$URL"; then
echo "! Error: APK download failed."
exit 1
fi
echo "- Download complete."
APK_PATH=$(find "$APK_DIR" -type f -name "*.apk" | head -n 1)
if [ -z "$APK_PATH" ]; then
echo "! Error: No APK file found in $APK_DIR."
exit 1
fi
echo "- Downloading KSU WebUI Standalone..."
API="https://api.github.com/repos/5ec1cff/KsuWebUIStandalone/releases/latest"
ping -c 1 -w 5 raw.githubusercontent.com &>/dev/null || manual_download "! Error: Unable to connect to raw.githubusercontent.com, please download manually."
URL=$(download "$API" | grep -o '"browser_download_url": "[^"]*"' | cut -d '"' -f 4) || manual_download "! Error: Unable to get latest version, please download manually."
download "$URL" > "$APK_PATH" || manual_download "! Error: APK download failed, please download manually."
echo "- Installing..."
if ! pm install -r "$APK_PATH" >/dev/null 2>&1; then
echo "! Error: APK installation failed."
pm install -r "$APK_PATH" || {
rm -f "$APK_PATH"
exit 1
fi
manual_download "! Error: APK installation failed, please download manually.."
}
echo "- Done."
rm -f "$APK_PATH"
echo "- Launching..."
if ! am start -n "io.github.a13e300.ksuwebui/.WebUIActivity" -e id "tricky_store"; then
echo "! Error: WebUI launch failed."
exit 1
fi
echo "- Application launched successfully."
echo "- Launching WebUI..."
am start -n "io.github.a13e300.ksuwebui/.WebUIActivity" -e id "tricky_store"
}
# Lunch KSUWebUI standalone or MMRL, install KSUWebUI standalone if both are not installed
if pm list packages | grep -q "io.github.a13e300.ksuwebui"; then
# Launch KSUWebUI standalone or MMRL, install KSUWebUI standalone if both are not installed
if pm path io.github.a13e300.ksuwebui >/dev/null 2>&1; then
echo "- Launching WebUI in KSUWebUIStandalone..."
am start -n "io.github.a13e300.ksuwebui/.WebUIActivity" -e id "tricky_store"
elif pm list packages | grep -q "com.dergoogler.mmrl"; then
elif pm path com.dergoogler.mmrl >/dev/null 2>&1; then
echo "- Launching WebUI in MMRL WebUI..."
am start -n "com.dergoogler.mmrl/.ui.activity.webui.WebUIActivity" -e MOD_ID "tricky_store"
else
echo "- Installing KSU WebUI..."
echo "! No WebUI app found"
get_webui
fi
echo "- WebUI launched successfully."

View File

@@ -1,9 +1,14 @@
#!/bin/sh
PATH=/data/adb/ap/bin:/data/adb/ksu/bin:/data/adb/magisk:/data/data/com.termux/files/usr/bin:$PATH
MODPATH=${0%/*}
ORG_PATH="$PATH"
SKIPLIST="$MODPATH/tmp/skiplist"
OUTPUT="$MODPATH/tmp/exclude-list"
KBOUTPUT="$MODPATH/tmp/.extra"
if [ "$MODPATH" = "/data/adb/modules/.TA_utl/common" ]; then
MODDIR="/data/adb/modules/.TA_utl"
MAGISK="true"
else
MODDIR="/data/adb/modules/TA_utl"
fi
aapt() { "$MODPATH/aapt" "$@"; }
@@ -11,56 +16,42 @@ aapt() { "$MODPATH/aapt" "$@"; }
# wget = low pref, no ssl.
# curl, has ssl on android, we use it if found
download() {
PATH=/data/adb/ap/bin:/data/adb/ksu/bin:/data/adb/magisk:/data/data/com.termux/files/usr/bin:$PATH
if command -v curl >/dev/null 2>&1; then
timeout 3 curl -s "$1"
timeout 10 curl -Ls "$1"
else
timeout 3 busybox wget --no-check-certificate -qO - "$1"
timeout 10 busybox wget --no-check-certificate -qO- "$1"
fi
}
get_kb() {
download "https://raw.githubusercontent.com/KOWX712/Tricky-Addon-Update-Target-List/main/.extra" > "$KBOUTPUT"
[ -s "$KBOUTPUT" ] || rm -f "$KBOUTPUT"
PATH="$ORG_PATH"
}
get_xposed() {
pm list packages -3 | cut -d':' -f2 | grep -vxF -f "$SKIPLIST" | grep -vxF -f "$OUTPUT" | while read -r PACKAGE; do
pm list packages -3 | cut -d':' -f2 | grep -vxF -f "$SKIPLIST" | while read -r PACKAGE; do
APK_PATH=$(pm path "$PACKAGE" | grep "base.apk" | cut -d':' -f2 | tr -d '\r')
if [ -n "$APK_PATH" ]; then
if aapt dump xmltree "$APK_PATH" AndroidManifest.xml 2>/dev/null | grep -qE "xposed.category|xposeddescription"; then
echo "$PACKAGE" >>"$OUTPUT"
echo "$PACKAGE"
fi
fi
done
}
get_unnecessary() {
if [ ! -s "$OUTPUT" ] || [ ! -f "$OUTPUT" ]; then
download "https://raw.githubusercontent.com/KOWX712/Tricky-Addon-Update-Target-List/main/more-exclude.json" 2>/dev/null | grep -o '"package-name": *"[^"]*"' | awk -F'"' '{print $4}' >"$OUTPUT"
fi
get_xposed
}
check_update() {
if [ -d "$MODPATH/update" ]; then
JSON=$(download "https://raw.githubusercontent.com/KOWX712/Tricky-Addon-Update-Target-List/main/update.json") || exit 1
REMOTE_VERSION=$(echo "$JSON" | grep -o '"versionCode": *[0-9]*' | awk -F: '{print $2}' | tr -d ' ')
LOCAL_VERSION=$(grep -o 'versionCode=[0-9]*' "$MODPATH/update/module.prop" | awk -F= '{print $2}')
if [ "$REMOTE_VERSION" -gt "$LOCAL_VERSION" ]; then
if [ "$MODPATH" = "/data/adb/modules/.TA_utl/common" ]; then
[ -d "/data/adb/modules/TA_utl" ] && rm -rf "/data/adb/modules/TA_utl"
cp -rf "$MODPATH/update" "/data/adb/modules/TA_utl"
else
cp -f "$MODPATH/update/module.prop" "/data/adb/modules/TA_utl/module.prop"
fi
echo "update"
[ -f "$MODDIR/disable" ] && rm -f "$MODDIR/disable"
LOCAL_VERSION=$(grep '^versionCode=' "$MODPATH/update/module.prop" | awk -F= '{print $2}')
if [ "$REMOTE_VERSION" -gt "$LOCAL_VERSION" ] && [ ! -f "/data/adb/modules/TA_utl/update" ]; then
if [ "$MAGISK" = "true" ]; then
[ -d "/data/adb/modules/TA_utl" ] && rm -rf "/data/adb/modules/TA_utl"
cp -rf "$MODPATH/update" "/data/adb/modules/TA_utl"
else
cp -f "$MODPATH/update/module.prop" "/data/adb/modules/TA_utl/module.prop"
fi
echo "update"
fi
}
uninstall() {
if [ "$MODPATH" = "/data/adb/modules/.TA_utl/common" ]; then
[ -d "/data/adb/modules/TA_utl" ] && rm -rf "/data/adb/modules/TA_utl"
if [ "$MAGISK" = "true" ]; then
cp -rf "$MODPATH/update" "/data/adb/modules/TA_utl"
else
cp -f "$MODPATH/update/module.prop" "/data/adb/modules/TA_utl/module.prop"
@@ -68,21 +59,78 @@ uninstall() {
touch "/data/adb/modules/TA_utl/remove"
}
get_update() {
download "$ZIP_URL" > "$MODPATH/tmp/module.zip"
[ -s "$MODPATH/tmp/module.zip" ] || exit 1
}
install_update() {
if command -v magisk >/dev/null 2>&1; then
magisk --install-module "$MODPATH/tmp/module.zip"
elif command -v apd >/dev/null 2>&1; then
apd module install "$MODPATH/tmp/module.zip"
elif command -v ksud >/dev/null 2>&1; then
ksud module install "$MODPATH/tmp/module.zip"
else
exit 1
fi
rm -f "$MODPATH/tmp/module.zip"
rm -f "$MODPATH/tmp/changelog.md"
rm -f "$MODPATH/tmp/version"
}
release_note() {
awk -v header="### $VERSION" '
$0 == header {
print;
found = 1;
next
}
found && /^###/ { exit }
found { print }
' "$MODPATH/tmp/changelog.md"
}
set_security_patch() {
# Find pif.json
[ -f "/data/adb/modules/playintegrityfix/pif.json" ] && PIF="/data/adb/modules/playintegrityfix/pif.json"
[ -f "/data/adb/pif.json" ] && PIF="/data/adb/pif.json"
[ -f "/data/adb/modules/playintegrityfix/custom.pif.json" ] && PIF="/data/adb/modules/playintegrityfix/custom.pif.json"
security_patch=$(grep '"SECURITY_PATCH"' "$PIF" | sed 's/.*: "//; s/".*//')
[ -z "$security_patch" ] && security_patch=$(getprop ro.build.version.security_patch) # Fallback
formatted_security_patch=$(echo "$security_patch" | sed 's/-//g')
security_patch_after_1y=$(echo "$formatted_security_patch + 10000" | bc)
TODAY=$(date +%Y%m%d)
if [ -n "$formatted_security_patch" ] && [ "$TODAY" -lt "$security_patch_after_1y" ]; then
TS_version=$(grep "versionCode=" "/data/adb/modules/tricky_store/module.prop" | cut -d'=' -f2)
if [ "$TS_version" -lt 158 ]; then
resetprop ro.vendor.build.security_patch "$security_patch"
resetprop ro.build.version.security_patch "$security_patch"
else
SECURITY_PATCH_FILE="/data/adb/tricky_store/security_patch.txt"
printf "system=prop\nboot=%s\nvendor=%s\n" "$security_patch" "$security_patch" > "$SECURITY_PATCH_FILE"
chmod 644 "$SECURITY_PATCH_FILE"
fi
else
echo "not set"
fi
}
get_latest_security_patch() {
security_patch=$(download "https://source.android.com/docs/security/bulletin/pixel" | grep -o "<td>[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}</td>" | head -n 1 | sed 's/<td>\(.*\)<\/td>/\1/')
[ -n "$security_patch" ] && echo "$security_patch" || exit 1
}
case "$1" in
--kb)
get_kb
exit
;;
--unnecessary)
get_unnecessary
exit
;;
--xposed)
get_xposed
exit
;;
--update)
--check-update)
REMOTE_VERSION="$2"
check_update
exit
;;
@@ -90,4 +138,26 @@ case "$1" in
uninstall
exit
;;
--get-update)
ZIP_URL="$2"
get_update
exit
;;
--install-update)
install_update
exit
;;
--release-note)
VERSION="$2"
release_note
exit
;;
--security-patch)
set_security_patch
exit
;;
--get-security-patch)
get_latest_security_patch
exit
;;
esac

View File

@@ -8,19 +8,23 @@ MODID=`grep_prop id $TMPDIR/module.prop`
NEW_MODID=".TA_utl"
kb="$COMPATH/.default"
ui_print " ";
ui_print " "
if [ "$APATCH" ]; then
ui_print "- APatch:$APATCH_VER$APATCH_VER_CODE"
ACTION=false
elif [ "$KSU" ]; then
ui_print "- KSU:$KSU_KERNEL_VER_CODE$KSU_VER_CODE"
if [ "$KSU_NEXT" ]; then
ui_print "- KernelSU Next:$KSU_KERNEL_VER_CODE$KSU_VER_CODE"
else
ui_print "- KernelSU:$KSU_KERNEL_VER_CODE$KSU_VER_CODE"
fi
ACTION=false
elif [ "$MAGISK_VER_CODE" ]; then
ui_print "- Magisk:$MAGISK_VER$MAGISK_VER_CODE"
else
ui_print " ";
ui_print "! recovery is not supported";
abort " ";
ui_print " "
ui_print "! recovery is not supported"
abort " "
fi
[ -d "$TS" ] || ui_print "! Warning: Tricky store module not found"
@@ -32,7 +36,7 @@ initialize
ui_print "- Finalizing..."
find_config
migrate_old_boot_hash
migrate_config
rm -f "$MODPATH/install_func.sh"

View File

@@ -31,10 +31,19 @@ find_config() {
[ -d "$CONFIG_DIR" ] && rm -rf "$CONFIG_DIR"
}
migrate_old_boot_hash() {
migrate_config() {
# Migrate boot_hash
if [ ! -f "/data/adb/boot_hash" ]; then
mv "$COMPATH/boot_hash" "/data/adb/boot_hash"
else
rm -f "$COMPATH/boot_hash"
fi
# Migrate security_patch config*
if [ ! -s "/data/adb/security_patch" ]; then
echo "#Tricky Addon security patch auto config" > "/data/adb/security_patch"
fi
if ! grep -q "^auto_config=" "/data/adb/security_patch"; then
echo "auto_config=1" >> "/data/adb/security_patch"
fi
}

View File

@@ -1,7 +1,7 @@
id=TA_utl
name=Tricky Addon - Update Target List
version=v2.9
versionCode=290
version=v3.5
versionCode=350
author=KOWX712
description=A WebUI to conifgure tricky store target.txt
updateJson=https://raw.githubusercontent.com/KOWX712/Tricky-Addon-Update-Target-List/main/update.json

View File

@@ -15,5 +15,5 @@ if [ ! -d "$TS" ] || [ -f "$TS/remove" ]; then
fi
fi
rm -f "$TS/action.sh"
rm -rf "$TS/webroot"
[ -L "$TS/webroot" ] && rm -f "$TS/webroot"
[ -L "$TS/action.sh" ] && rm -f "$TS/action.sh"

View File

@@ -1,17 +1,39 @@
MODPATH=${0%/*}
HIDE_DIR="/data/adb/modules/.TA_utl"
TS="/data/adb/modules/tricky_store"
SCRIPT_DIR="/data/adb/tricky_store"
TSPA="/data/adb/modules/tsupport-advance"
aapt() { "$MODPATH/common/aapt" "$@"; }
add_denylist_to_target() {
exclamation_target=$(grep '!' "/data/adb/tricky_store/target.txt" | sed 's/!$//')
question_target=$(grep '?' "/data/adb/tricky_store/target.txt" | sed 's/?$//')
target=$(sed 's/[!?]$//' /data/adb/tricky_store/target.txt)
denylist=$(magisk --denylist ls 2>/dev/null | awk -F'|' '{print $1}' | grep -v "isolated")
printf "%s\n" "$target" "$denylist" | sort -u > "/data/adb/tricky_store/target.txt"
for target in $exclamation_target; do
sed -i "s/^$target$/$target!/" "/data/adb/tricky_store/target.txt"
done
for target in $question_target; do
sed -i "s/^$target$/$target?/" "/data/adb/tricky_store/target.txt"
done
}
# Spoof security patch
if grep -q "^auto_config=1" "/data/adb/security_patch"; then
sh "$MODPATH/common/get_extra.sh" --security-patch
fi
# Reset verified Boot Hash
hash_value=$(grep -v '^#' "/data/adb/boot_hash" | tr -d '[:space:]')
if [ -n "$hash_value" ]; then
resetprop -n ro.boot.vbmeta.digest "$hash_value"
fi
# Disable TSupport-A auto update target to prevent overwrite
if [ -d "$TSPA" ]; then
touch "/storage/emulated/0/stop-tspa-auto-target"
@@ -19,21 +41,32 @@ elif [ ! -d "$TSPA" ] && [ -f "/storage/emulated/0/stop-tspa-auto-target" ]; the
rm -f "/storage/emulated/0/stop-tspa-auto-target"
fi
# Hide module
# Magisk operation
if [ -f "$MODPATH/action.sh" ]; then
if [[ "$MODPATH" != "$HIDE_DIR" ]]; then
# Hide module from Magisk manager
if [ "$MODPATH" != "$HIDE_DIR" ]; then
rm -rf "$HIDE_DIR"
mv "$MODPATH" "$HIDE_DIR"
fi
MODPATH="$HIDE_DIR"
elif [ -d "$HIDE_DIR" ]; then
rm -rf "$HIDE_DIR"
# Add target from denylist
# To trigger this, choose "Select from DenyList" in WebUI once
[ -f "/data/adb/tricky_store/target_from_denylist" ] && add_denylist_to_target
else
[ -d "$HIDE_DIR" ] && rm -rf "$HIDE_DIR"
fi
# Hide module from APatch, KernelSU, KSUWebUIStandalone, MMRL
rm -f "$MODPATH/module.prop"
# Symlink tricky store
[ -f "$MODPATH/action.sh" ] && ln -s "$MODPATH/action.sh" "$TS/action.sh"
ln -s "$MODPATH/webui" "$TS/webroot"
if [ -f "$MODPATH/action.sh" ] && [ ! -f "$TS/action.sh" ] && [ ! -L "$TS/action.sh" ]; then
ln -s "$MODPATH/action.sh" "$TS/action.sh"
fi
if [ ! -d "$TS/webroot" ] && [ ! -L "$TS/webroot" ]; then
ln -s "$MODPATH/webui" "$TS/webroot"
fi
# Optimization
OUTPUT_APP="$MODPATH/common/tmp/applist"
@@ -43,18 +76,36 @@ until [ "$(getprop sys.boot_completed)" = "1" ]; do
sleep 1
done
# Create temporary directory
mkdir -p "$MODPATH/common/tmp"
# Additional system apps
SYSTEM_APP="com.google.android.gms|com.google.android.gsf|com.android.vending"
# Initialize cache files to save app list and skip list
echo "# This file is generated from service.sh to speed up load time" > "$OUTPUT_APP"
echo "# This file is generated from service.sh to speed up load time" > "$OUTPUT_SKIP"
pm list packages -3 </dev/null 2>&1 | cat | awk -F: '{print $2}' | while read -r PACKAGE; do
APK_PATH=$(pm path "$PACKAGE" </dev/null 2>&1 | cat | grep "base.apk" | awk -F: '{print $2}' | tr -d '\r')
# Get list of third party apps and specific system apps, then cache app name
# Check Xposed module
{
pm list packages -3 2>/dev/null
pm list package -s | grep -E "$SYSTEM_APP" 2>/dev/null || true
} | awk -F: '{print $2}' | while read -r PACKAGE; do
# Get APK path for the package
APK_PATH=$(pm path "$PACKAGE" 2>/dev/null | grep "base.apk" | awk -F: '{print $2}' | tr -d '\r')
[ -z "$APK_PATH" ] && APK_PATH=$(pm path "$PACKAGE" 2>/dev/null | grep ".apk" | awk -F: '{print $2}' | tr -d '\r')
if [ -n "$APK_PATH" ]; then
APP_NAME=$(aapt dump badging "$APK_PATH" </dev/null 2>&1 | cat | grep "application-label:" | sed "s/application-label://g; s/'//g")
# Extract app name and save package info
APP_NAME=$(aapt dump badging "$APK_PATH" 2>/dev/null | grep "application-label:" | sed "s/application-label://g; s/'//g")
echo "app-name: $APP_NAME, package-name: $PACKAGE" >> "$OUTPUT_APP"
else
echo "app-name: Unknown App package-name: $PACKAGE" >> "$OUTPUT_APP"
fi
if ! aapt dump xmltree "$APK_PATH" AndroidManifest.xml </dev/null 2>&1 | cat | grep -qE "xposed.category|xposeddescription"; then
# Check if app is Xposed module and add to skip list if not
if ! aapt dump xmltree "$APK_PATH" AndroidManifest.xml 2>/dev/null | grep -qE "xposed.category|xposeddescription"; then
echo "$PACKAGE" >> "$OUTPUT_SKIP"
fi
done

View File

@@ -10,8 +10,11 @@ fi
# Remove residue and restore aosp keybox.
rm -rf "/data/adb/modules/.TA_utl"
rm -f "/data/adb/boot_hash"
rm -f "/data/adb/security_patch"
rm -f "/data/adb/tricky_store/target_from_denylist"
if [ -d "$TS" ]; then
rm -f "$TS/action.sh"
rm -rf "$TS/webroot"
[ -L "$TS/webroot" ] && rm -f "$TS/webroot"
[ -L "$TS/action.sh" ] && rm -f "$TS/action.sh"
fi
mv -f "$SCRIPT_DIR/keybox.xml" "$SCRIPT_DIR/keybox.xml.bak"
xxd -r -p "$MODPATH/common/.default" | base64 -d > "$SCRIPT_DIR/keybox.xml"

View File

@@ -5,21 +5,27 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title data-i18n="title">TrickyAddon</title>
<link rel="stylesheet" type="text/css" href="/mmrl/insets.css" />
<link rel="stylesheet" href="styles/global.css" type="text/css">
<link rel="stylesheet" href="styles/about.css" type="text/css">
<link rel="stylesheet" href="styles/applist.css" type="text/css">
<link rel="stylesheet" href="styles/boot-hash.css" type="text/css">
<link rel="stylesheet" href="styles/boot_hash.css" type="text/css">
<link rel="stylesheet" href="styles/header.css" type="text/css">
<link rel="stylesheet" href="styles/search_menu.css" type="text/css">
<link rel="stylesheet" type="text/css" href="/mmrl/insets.css" />
<link rel="stylesheet" href="styles/security_patch.css" type="text/css">
<script type="module" crossorigin src="scripts/main.js"></script>
<script type="module" crossorigin src="scripts/about.js"></script>
<script type="module" crossorigin src="scripts/help.js"></script>
<script type="module" crossorigin src="scripts/boot_hash.js"></script>
<script type="module" crossorigin src="scripts/security_patch.js"></script>
<script src="scripts/marked.min.js"></script>
</head>
<body>
<!-- Header -->
<div class="header-block"></div>
<div class="header">
<div id="title" data-i18n="header.title"></div>
<div id="title" data-i18n="header.title"></div><span id="module-version"></span>
<button id="help-button" class="help-button">
<svg xmlns="http://www.w3.org/2000/svg" height="21px" viewBox="0 -1060 960 990" width="21px" fill="#6E6E6E"><path d="M478-240q21 0 35.5-14.5T528-290q0-21-14.5-35.5T478-340q-21 0-35.5 14.5T428-290q0 21 14.5 35.5T478-240Zm-36-154h74q0-33 7.5-52t42.5-52q26-26 41-49.5t15-56.5q0-56-41-86t-97-30q-57 0-92.5 30T342-618l66 26q5-18 22.5-39t53.5-21q32 0 48 17.5t16 38.5q0 20-12 37.5T506-526q-44 39-54 59t-10 73Zm38 314q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z" /></svg>
</button>
@@ -29,7 +35,7 @@
<div class="language-dropdown">
<button class="language-button">
<i class="language-icon">
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px"><path d="M480-80q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-155.5t86-127Q252-817 325-848.5T480-880q83 0 155.5 31.5t127 86q54.5 54.5 86 127T880-480q0 82-31.5 155t-86 127.5q-54.5 54.5-127 86T480-80Zm0-82q26-36 45-75t31-83H404q12 44 31 83t45 75Zm-104-16q-18-33-31.5-68.5T322-320H204q29 50 72.5 87t99.5 55Zm208 0q56-18 99.5-55t72.5-87H638q-9 38-22.5 73.5T584-178ZM170-400h136q-3-20-4.5-39.5T300-480q0-21 1.5-40.5T306-560H170q-5 20-7.5 39.5T160-480q0 21 2.5 40.5T170-400Zm216 0h188q3-20 4.5-39.5T580-480q0-21-1.5-40.5T574-560H386q-3 20-4.5 39.5T380-480q0 21 1.5 40.5T386-400Zm268 0h136q5-20 7.5-39.5T800-480q0-21-2.5-40.5T790-560H654q3 20 4.5 39.5T660-480q0 21-1.5 40.5T654-400Zm-16-240h118q-29-50-72.5-87T584-782q18 33 31.5 68.5T638-640Zm-234 0h152q-12-44-31-83t-45-75q-26 36-45 75t-31 83Zm-200 0h118q9-38 22.5-73.5T376-782q-56 18-99.5 55T204-640Z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" height="22px" viewBox="0 -960 960 960" width="22px"><path d="M480-80q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 31.5-155.5t86-127Q252-817 325-848.5T480-880q83 0 155.5 31.5t127 86q54.5 54.5 86 127T880-480q0 82-31.5 155t-86 127.5q-54.5 54.5-127 86T480-80Zm0-82q26-36 45-75t31-83H404q12 44 31 83t45 75Zm-104-16q-18-33-31.5-68.5T322-320H204q29 50 72.5 87t99.5 55Zm208 0q56-18 99.5-55t72.5-87H638q-9 38-22.5 73.5T584-178ZM170-400h136q-3-20-4.5-39.5T300-480q0-21 1.5-40.5T306-560H170q-5 20-7.5 39.5T160-480q0 21 2.5 40.5T170-400Zm216 0h188q3-20 4.5-39.5T580-480q0-21-1.5-40.5T574-560H386q-3 20-4.5 39.5T380-480q0 21 1.5 40.5T386-400Zm268 0h136q5-20 7.5-39.5T800-480q0-21-2.5-40.5T790-560H654q3 20 4.5 39.5T660-480q0 21-1.5 40.5T654-400Zm-16-240h118q-29-50-72.5-87T584-782q18 33 31.5 68.5T638-640Zm-234 0h152q-12-44-31-83t-45-75q-26 36-45 75t-31 83Zm-200 0h118q9-38 22.5-73.5T376-782q-56 18-99.5 55T204-640Z"/></svg>
</i>
</button>
<div class="language-menu"></div>
@@ -45,12 +51,12 @@
<!-- Floating Button Element -->
<div class="floating-card">
<button class="floating-btn" id="save" data-i18n="functional_button.save_and_update_button"></button>
<button class="floating-btn ripple-element" id="save" data-i18n="functional_button.save_and_update_button"></button>
</div>
<!-- Menu Options -->
<div class="search-menu-container">
<div class="search-card">
<div class="search-card ripple-element">
<span class="search-icon">
<svg xmlns="http://www.w3.org/2000/svg" height="19px" viewBox="0 -960 960 960" width="24px" fill="#6E6E6E"><path d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z" /></svg>
</span>
@@ -59,22 +65,24 @@
</div>
<div class="menu">
<input type="checkbox" id="menu-toggle" class="menu-toggle">
<label for="menu-toggle" id="menu-button">
<label for="menu-toggle" class="menu-button ripple-element" id="menu-button">
<i class="menu-icon">
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -1060 960 960" width="24px"><path d="M120-240v-80h720v80H120Zm0-200v-80h720v80H120Zm0-200v-80h720v80H120Z"/></svg>
</i>
</label>
<div id="menu-options" class="menu-options">
<ul>
<li id="refresh" data-i18n="menu.refresh"></li>
<li id="select-all" data-i18n="menu.select_all"></li>
<li id="deselect-all" data-i18n="menu.deselect_all"></li>
<li id="select-denylist" data-i18n="menu.select_denylist"></li>
<li id="deselect-unnecessary" data-i18n="menu.deselect_unnecessary"></li>
<li id="aospkb" data-i18n="menu.set_aosp_keybox"></li>
<li id="extrakb" data-i18n="menu.set_valid_keybox"></li>
<li id="boot-hash" data-i18n="menu.set_verified_boot_hash"></li>
<li id="about" data-i18n="menu.about"></li>
<li class="ripple-element" id="refresh" data-i18n="menu.refresh"></li>
<li class="ripple-element" id="select-all" data-i18n="menu.select_all"></li>
<li class="ripple-element" id="deselect-all" data-i18n="menu.deselect_all"></li>
<li class="ripple-element" id="select-denylist" data-i18n="menu.select_denylist"></li>
<li class="ripple-element" id="deselect-unnecessary" data-i18n="menu.deselect_unnecessary"></li>
<li class="ripple-element" id="aospkb" data-i18n="menu.set_aosp_keybox"></li>
<li class="ripple-element" id="validkb" data-i18n="menu.set_valid_keybox"></li>
<li class="ripple-element" id="customkb" data-i18n="menu.set_custom_keybox"></li>
<li class="ripple-element" id="boot-hash" data-i18n="menu.set_verified_boot_hash"></li>
<li class="ripple-element" id="security-patch" data-i18n="menu.set_security_patch"></li>
<li class="ripple-element" id="about" data-i18n="menu.about"></li>
</ul>
</div>
</div>
@@ -83,16 +91,50 @@
<!-- Applist Display -->
<div id="apps-list"></div>
<div class="update-card" id="update-card">
<p id="update-available" data-i18n="update_banner.update_available"></p>
<p id="redirect-to-release" data-i18n="update_banner.redirect_to_release"></p>
<div class="update-card ripple-element" id="update-card">
<p id="update-available" data-i18n="update.update_available"></p>
<p id="redirect-to-release" data-i18n="update.redirect_to_release"></p>
</div>
<div class="mode-overlay"></div>
<template id="app-template">
<div class="card-box">
<div class="card">
<div class="card ripple-element" id="card">
<div class="content" data-package="">
<div class="mode">
<label class="mode-switch" id="normal">
<input type="radio" class="mode-input" id="normal-mode">
<i class="mode-icon">
<div class="status-indicator ripple-element" id="normal-indicator">
<svg xmlns="http://www.w3.org/2000/svg" height="30px" viewBox="0 -960 960 960" width="30px" fill="#ffffff"><path d="M480-480Zm0 280q-116 0-198-82t-82-198q0-116 82-198t198-82q116 0 198 82t82 198q0 116-82 198t-198 82Zm0-80q83 0 141.5-58.5T680-480q0-83-58.5-141.5T480-680q-83 0-141.5 58.5T280-480q0 83 58.5 141.5T480-280Z"/></svg>
</div>
</i>
</label>
<label class="mode-switch" id="generate">
<input type="radio" class="mode-input" id="generate-mode">
<i class="mode-icon">
<div class="status-indicator ripple-element" id="generate-indicator">
<svg xmlns="http://www.w3.org/2000/svg" height="18px" viewBox="0 -960 960 960" width="18px" fill="#ffffff"><path d="M480-120q-33 0-56.5-23.5T400-200q0-33 23.5-56.5T480-280q33 0 56.5 23.5T560-200q0 33-23.5 56.5T480-120Zm-80-240v-480h160v480H400Z"/></svg>
</div>
</i>
</label>
<label class="mode-switch" id="hack">
<input type="radio" class="mode-input" id="hack-mode">
<i class="mode-icon">
<div class="status-indicator ripple-element" id="hack-indicator">
<svg xmlns="http://www.w3.org/2000/svg" height="19px" viewBox="0 -960 960 960" width="19px" fill="#ffffff"><path d="M424-320q0-81 14.5-116.5T500-514q41-36 62.5-62.5T584-637q0-41-27.5-68T480-732q-51 0-77.5 31T365-638l-103-44q21-64 77-111t141-47q105 0 161.5 58.5T698-641q0 50-21.5 85.5T609-475q-49 47-59.5 71.5T539-320H424Zm56 240q-33 0-56.5-23.5T400-160q0-33 23.5-56.5T480-240q33 0 56.5 23.5T560-160q0 33-23.5 56.5T480-80Z"/></svg>
</div>
</i>
</label>
</div>
<p class="name"></p>
<input type="checkbox" class="checkbox">
<div class="checkbox-wrapper">
<input type="checkbox" class="checkbox" id="checkbox1" disabled />
<label for="checkbox1" class="custom-checkbox">
<span class="tick-symbol">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -3 26 26" width="16px" height="16px" fill="#fff"><path d="M 22.566406 4.730469 L 20.773438 3.511719 C 20.277344 3.175781 19.597656 3.304688 19.265625 3.796875 L 10.476563 16.757813 L 6.4375 12.71875 C 6.015625 12.296875 5.328125 12.296875 4.90625 12.71875 L 3.371094 14.253906 C 2.949219 14.675781 2.949219 15.363281 3.371094 15.789063 L 9.582031 22 C 9.929688 22.347656 10.476563 22.613281 10.96875 22.613281 C 11.460938 22.613281 11.957031 22.304688 12.277344 21.839844 L 22.855469 6.234375 C 23.191406 5.742188 23.0625 5.066406 22.566406 4.730469 Z"/></svg>
</span>
</label>
</div>
</div>
</div>
</div>
@@ -147,6 +189,20 @@
</ul>
</li>
<br>
<li id="set_custom_keybox">
<strong data-i18n="help.set_custom_keybox"></strong>
<ul>
<li data-i18n="help.set_custom_keybox_description"></li>
</ul>
</li>
<br>
<li id="set_security_patch">
<strong data-i18n="help.set_security_patch"></strong>
<ul>
<li data-i18n="help.set_security_patch_description"></li>
</ul>
</li>
<br>
<li id="set_verified_boot_hash">
<strong data-i18n="help.set_verified_boot_hash"></strong>
<ul>
@@ -162,10 +218,9 @@
<!-- BootHash Input Overlay -->
<div id="boot-hash-overlay" class="boot-hash-overlay"></div>
<div id="boot-hash-card" class="boot-hash-card">
<textarea id="boot-hash-input" class="input-box" placeholder="Paste your verified Boot Hash here" data-i18n="reset_vbmeta.boot_hash_input_placeholder"></textarea>
<div class="button-container">
<button id="boot-hash-save-button" class="boot-hash-save-button" data-i18n="reset_vbmeta.boot_hash_save_button"></button>
</div>
<div class="boot-hash-title" data-i18n="boot_hash.title"></div>
<textarea id="boot-hash-input" class="boot-hash-input" placeholder="Paste your verified Boot Hash here" data-i18n="boot_hash.input_placeholder" oninput="window.trimInput(this)"></textarea>
<button id="boot-hash-save-button" class="boot-hash-save-button ripple-element" data-i18n="boot_hash.save_button"></button>
</div>
<!-- About Overlay -->
@@ -181,11 +236,11 @@
<br>
<p>
<div class="link">
<i class="link-icon" id="telegram" aria-hidden="true">
<i class="link-icon ripple-element" id="telegram" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 0 496 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M248 8C111 8 0 119 0 256S111 504 248 504 496 393 496 256 385 8 248 8zM363 176.7c-3.7 39.2-19.9 134.4-28.1 178.3-3.5 18.6-10.3 24.8-16.9 25.4-14.4 1.3-25.3-9.5-39.3-18.7-21.8-14.3-34.2-23.2-55.3-37.2-24.5-16.1-8.6-25 5.3-39.5 3.7-3.8 67.1-61.5 68.3-66.7 .2-.7 .3-3.1-1.2-4.4s-3.6-.8-5.1-.5q-3.3 .7-104.6 69.1-14.8 10.2-26.9 9.9c-8.9-.2-25.9-5-38.6-9.1-15.5-5-27.9-7.7-26.8-16.3q.8-6.7 18.5-13.7 108.4-47.2 144.6-62.3c68.9-28.6 83.2-33.6 92.5-33.8 2.1 0 6.6 .5 9.6 2.9a10.5 10.5 0 0 1 3.5 6.7A43.8 43.8 0 0 1 363 176.7z"/></svg>
<span id="link-text" data-i18n="about.telegram_channel"></span>
</i>
<i class="link-icon" id="github" aria-hidden="true">
<i class="link-icon ripple-element" id="github" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 0 496 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3 .3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5 .3-6.2 2.3zm44.2-1.7c-2.9 .7-4.9 2.6-4.6 4.9 .3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3 .7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3 .3 2.9 2.3 3.9 1.6 1 3.6 .7 4.3-.7 .7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3 .7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3 .7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
<span id="link-text" data-i18n="about.github"></span>
</i>
@@ -194,14 +249,93 @@
<br>
<p id="acknowledgment" data-i18n="about.acknowledgment"></p>
<p>j-hc/zygisk-detach: WebUI template</p>
<p>markedjs/marked: Markdown Support</p>
</div>
</div>
</div>
<!-- Update Overlay -->
<div class="update-overlay">
<div class="update-menu">
<button class="close-update">&#x2715;</button>
<div class="update-content">
<h1 data-i18n="update.changelog"></h1>
<div class="changelog"></div>
<div class="update-button-container">
<button class="install ripple-element" data-i18n="update.install"></button>
<button class="reboot ripple-element" data-i18n="update.reboot"></button>
</div>
</div>
</div>
</div>
<!-- MMRL Permission Request Overlay -->
<div id="permission-popup" class="permission-popup hidden">
<div class="permission-content">
<h2 id="permission-title">Please allow JavaScript API in MMRL settings</h2>
<div class="permission-steps">
<p>1. Settings</p>
<p>2. Security</p>
<p>3. Allow JavaScript API</p>
<p>4. Tricky Store</p>
<p>5. Enable Allow Advanced KernelSU API</p>
</div>
</div>
</div>
<!-- Security Patch Overlay -->
<div id="security-patch-overlay" class="security-patch-overlay"></div>
<div id="security-patch-card" class="security-patch-card">
<div class="security-patch-header" data-i18n="security_patch.title"></div>
<div class="security-patch-content">
<div id="normal-mode-inputs" class="normal-mode-inputs">
<div class="input-group">
<label id="security_patch-all">All</label>
<input type="text" id="all-patch" placeholder="20250101" maxlength="8" autocapitalize="none">
</div>
</div>
<div id="advanced-mode-inputs" class="advanced-mode-inputs hidden">
<div class="input-group">
<label id="security_patch-system">System</label>
<input type="text" id="system-patch" placeholder="202501" maxlength="6" autocapitalize="none">
</div>
<div class="input-group">
<label id="security_patch-boot">Boot</label>
<input type="text" id="boot-patch" placeholder="2025-01-01" autocapitalize="none" oninput="formatDate(this, 'boot')" maxlength="10">
</div>
<div class="input-group">
<label id="security_patch-vendor">Vendor</label>
<input type="text" id="vendor-patch" placeholder="2025-01-01" autocapitalize="none" oninput="formatDate(this, 'vendor')" maxlength="10">
</div>
</div>
<div class="advanced-toggle">
<input type="checkbox" class="checkbox" id="advanced-mode" />
<label for="advanced-mode" class="custom-checkbox">
<span class="tick-symbol">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -3 26 26" width="16px" height="16px" fill="#fff">
<path d="M 22.566406 4.730469 L 20.773438 3.511719 C 20.277344 3.175781 19.597656 3.304688 19.265625 3.796875 L 10.476563 16.757813 L 6.4375 12.71875 C 6.015625 12.296875 5.328125 12.296875 4.90625 12.71875 L 3.371094 14.253906 C 2.949219 14.675781 2.949219 15.363281 3.371094 15.789063 L 9.582031 22 C 9.929688 22.347656 10.476563 22.613281 10.96875 22.613281 C 11.460938 22.613281 11.957031 22.304688 12.277344 21.839844 L 22.855469 6.234375 C 23.191406 5.742188 23.0625 5.066406 22.566406 4.730469 Z"/>
</svg>
</span>
</label>
<label for="advanced-mode" data-i18n="security_patch.advanced_mode"></label>
</div>
<div>
<button id="get-patch" class="get-button ripple-element" data-i18n="security_patch.get_date"></button>
<div class="button-container">
<button id="auto-config" class="auto-button ripple-element" data-i18n="security_patch.auto"></button>
<button id="save-patch" class="save-button ripple-element" data-i18n="security_patch.save"></button>
</div>
</div>
</div>
</div>
<!-- Footer -->
<div class="footer">
<div class="uninstall-container hidden-uninstall">
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#FFFFFF"><path d="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z" /></svg>
<div class="uninstall-container ripple-element hidden-uninstall">
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#FF3636"><path d="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z" /></svg>
<span data-i18n="functional_button.uninstall_webui"></span>
</div>
</div>

View File

@@ -1,7 +1,7 @@
{
"language": "English",
"header": {
"title": "Tricky Addon - Update Target List"
"title": "Tricky Addon"
},
"help": {
"help_instructions": "Instructions",
@@ -14,15 +14,22 @@
"select_denylist": "Select From DenyList",
"select_denylist_description": "Available in Magisk only, select apps that are in the DenyList. Recommended.",
"deselect_unnecessary": "Deselect Unnecessary",
"deselect_unnecessary_description": "Unnecessary category: Xposed module, root manager, root-related apps, and general apps that never check bootloader status. This option requires an Internet connection.",
"deselect_unnecessary_description": "Unnecessary category: Xposed module, root manager, root-related apps, and general apps that never check bootloader status. This option requires Internet connection.",
"set_keybox": "Set AOSP & Valid Keybox",
"set_keybox_description": "Replace tricky store keybox.xml. AOSP keybox will be replaced if there's no more valid keybox. Valid keybox option requires Internet connection.",
"set_custom_keybox": "Set Custom Keybox",
"set_custom_keybox_description": "Import keybox from your device storage. Only support xml file.",
"set_security_patch": "Set Security Patch",
"set_security_patch_description": "Set custom security patch spoof. Auto config will use security patch from PIF module, enabled by default. Leave blank and save to disable auto config.",
"set_verified_boot_hash": "Set Verified Boot Hash",
"set_verified_boot_hash_description": "Get verifiedBootHash value from Key Attestation Demo. Fix abnormal boot state by resetting ro.boot.vbmeta.digest."
},
"update_banner": {
"update": {
"update_available": "A new version is ready",
"redirect_to_release": "tap to download the latest version"
"redirect_to_release": "tap to download the latest version",
"changelog": "Changelog",
"install": "Install",
"reboot": "Reboot"
},
"search_bar": {
"search_placeholder": "Search"
@@ -42,12 +49,15 @@
"deselect_unnecessary": "Deselect Unnecessary",
"set_aosp_keybox": "Set AOSP Keybox",
"set_valid_keybox": "Set Valid Keybox",
"set_custom_keybox": "Set Custom Keybox",
"set_verified_boot_hash": "Set Verified Boot Hash",
"set_security_patch": "Set Security Patch",
"about": "About"
},
"reset_vbmeta": {
"boot_hash_input_placeholder": "Paste your verified Boot Hash here",
"boot_hash_save_button": "Save"
"boot_hash": {
"title": "Boot Hash",
"input_placeholder": "Paste your verified Boot Hash here",
"save_button": "Save"
},
"about": {
"module_name_line1": "Tricky Addon",
@@ -70,6 +80,36 @@
"save_error": "Failed to save config",
"uninstall_prompt": "WebUI will be removed after reboot",
"uninstall_failed": "Failed to uninstall WebUI",
"new_update": "A new update is available!"
"new_update": "A new update is available!",
"downloading": "Downloading new update...",
"downloaded": "Download completed",
"download_fail": "Fail to download update",
"installing": "Installing update...",
"installed": "Installed successfully, reboot now.",
"install_fail": "Fail to install, please update manual",
"rebooting": "Rebooting...",
"reboot_fail": "Fail to reboot, please reboot manually",
"custom_key_set": "Custom keybox set successfully",
"custom_key_set_error": "Failed to set custom keybox",
"no_file_selected": "No file selected"
},
"security_patch": {
"title": "Security Patch",
"advanced_mode": "Advanced",
"get_date": "Get Security Patch Date",
"auto": "Auto",
"save": "Save",
"fetching": "Fetching...",
"fetched": "Done",
"get_failed": "Failed to fetch security patch date",
"auto_success": "Auto config enabled successfully",
"auto_failed": "Failed to enable auto config",
"save_success": "Security patch saved successfully",
"save_failed": "Failed to save security patch",
"value_empty": "Security patch configuration is disabled",
"invalid_all": "Invalid format",
"invalid_boot": "Invalid boot format",
"invalid_system": "Invalid system format",
"invalid_vendor": "Invalid vendor format"
}
}

View File

@@ -1,7 +1,7 @@
{
"language": "English",
"header": {
"title": "Tricky Addon - Update Target List"
"title": "Tricky Addon"
},
"help": {
"help_instructions": "Instructions",
@@ -14,15 +14,22 @@
"select_denylist": "Select From DenyList",
"select_denylist_description": "Available in Magisk only, select apps that are in the DenyList. Recommended.",
"deselect_unnecessary": "Deselect Unnecessary",
"deselect_unnecessary_description": "Unnecessary category: Xposed module, root manager, root-related apps, and general apps that never check bootloader status. This option requires an Internet connection.",
"deselect_unnecessary_description": "Unnecessary category: Xposed module, root manager, root-related apps, and general apps that never check bootloader status. This option requires Internet connection.",
"set_keybox": "Set AOSP & Valid Keybox",
"set_keybox_description": "Replace tricky store keybox.xml. AOSP keybox will be replaced if there's no more valid keybox. Valid keybox option requires Internet connection.",
"set_custom_keybox": "Set Custom Keybox",
"set_custom_keybox_description": "Import keybox from your device storage. Only support xml file.",
"set_security_patch": "Set Security Patch",
"set_security_patch_description": "Set custom security patch spoof. Auto config will use security patch from PIF module, enabled by default. Leave blank and save to disable auto config.",
"set_verified_boot_hash": "Set Verified Boot Hash",
"set_verified_boot_hash_description": "Get verifiedBootHash value from Key Attestation Demo. Fix abnormal boot state by resetting ro.boot.vbmeta.digest."
},
"update_banner": {
"update": {
"update_available": "A new version is ready",
"redirect_to_release": "tap to download the latest version"
"redirect_to_release": "tap to download the latest version",
"changelog": "Changelog",
"install": "Install",
"reboot": "Reboot"
},
"search_bar": {
"search_placeholder": "Search"
@@ -42,12 +49,15 @@
"deselect_unnecessary": "Deselect Unnecessary",
"set_aosp_keybox": "Set AOSP Keybox",
"set_valid_keybox": "Set Valid Keybox",
"set_custom_keybox": "Set Custom Keybox",
"set_verified_boot_hash": "Set Verified Boot Hash",
"set_security_patch": "Set Security Patch",
"about": "About"
},
"reset_vbmeta": {
"boot_hash_input_placeholder": "Paste your verified Boot Hash here",
"boot_hash_save_button": "Save"
"boot_hash": {
"title": "Boot Hash",
"input_placeholder": "Paste your verified Boot Hash here",
"save_button": "Save"
},
"about": {
"module_name_line1": "Tricky Addon",
@@ -70,6 +80,36 @@
"save_error": "Failed to save config",
"uninstall_prompt": "WebUI will be removed after reboot",
"uninstall_failed": "Failed to uninstall WebUI",
"new_update": "A new update is available!"
"new_update": "A new update is available!",
"downloading": "Downloading new update...",
"downloaded": "Download completed",
"download_fail": "Fail to download update",
"installing": "Installing update...",
"installed": "Installed successfully, reboot now.",
"install_fail": "Fail to install, please update manual",
"rebooting": "Rebooting...",
"reboot_fail": "Fail to reboot, please reboot manually",
"custom_key_set": "Custom keybox set successfully",
"custom_key_set_error": "Failed to set custom keybox",
"no_file_selected": "No file selected"
},
"security_patch": {
"title": "Security Patch",
"advanced_mode": "Advanced",
"get_date": "Get Security Patch Date",
"auto": "Auto",
"save": "Save",
"fetching": "Fetching...",
"fetched": "Done",
"get_failed": "Failed to fetch security patch date",
"auto_success": "Auto config enabled successfully",
"auto_failed": "Failed to enable auto config",
"save_success": "Security patch saved successfully",
"save_failed": "Failed to save security patch",
"value_empty": "Security patch configuration is disabled",
"invalid_all": "Invalid format",
"invalid_boot": "Invalid boot format",
"invalid_system": "Invalid system format",
"invalid_vendor": "Invalid vendor format"
}
}

View File

@@ -1,7 +1,7 @@
{
"language": "Español",
"header": {
"title": "Tricky Addon - Update Target List"
"title": "Tricky Addon"
},
"help": {
"help_instructions": "Instrucciones",
@@ -17,12 +17,19 @@
"deselect_unnecessary_description": "Categorías innecesarias: módulos Xposed, gestores de root, aplicaciones relacionadas con root y aplicaciones generales que nunca verifican el estado del bootloader. Esta opción requiere conexión a Internet.",
"set_keybox": "Configurar AOSP y Keybox Válido",
"set_keybox_description": "Reemplazar el archivo keybox.xml de Tricky Store. El AOSP Keybox será reemplazado si no hay un keybox válido. Esta opción requiere conexión a Internet.",
"set_custom_keybox": "Establecer Keybox Personalizado",
"set_custom_keybox_description": "Importar keybox desde el almacenamiento de tu dispositivo. Solo soporta archivos xml.",
"set_security_patch": "Configurar Parche de Seguridad",
"set_security_patch_description": "Configurar parche de seguridad personalizado. La configuración automática usará el parche de seguridad de PIF, habilitado por defecto. Deja en blanco y guarda para deshabilitar la configuración automática.",
"set_verified_boot_hash": "Configurar Boot Hash Verificado",
"set_verified_boot_hash_description": "Obtén el valor de verifiedBootHash del Key Attestation Demo. Corrige un estado de arranque anormal reiniciando ro.boot.vbmeta.digest."
},
"update_banner": {
"update": {
"update_available": "Una nueva versión está lista",
"redirect_to_release": "toca para descargar la última versión"
"redirect_to_release": "toca para descargar la última versión",
"changelog": "Registro de cambios",
"install": "Instalar",
"reboot": "Reiniciar"
},
"search_bar": {
"search_placeholder": "Buscar"
@@ -42,16 +49,19 @@
"deselect_unnecessary": "Deseleccionar innecesarios",
"set_aosp_keybox": "Configurar AOSP Keybox",
"set_valid_keybox": "Configurar Keybox Válido",
"set_custom_keybox": "Establecer Keybox Personalizado",
"set_security_patch": "Configurar Parche de Seguridad",
"set_verified_boot_hash": "Configurar Boot Hash Verificado",
"about": "Acerca de"
},
"reset_vbmeta": {
"boot_hash_input_placeholder": "Pega aquí tu Boot Hash verificado",
"boot_hash_save_button": "Guardar"
"boot_hash": {
"title": "Boot Hash",
"input_placeholder": "Pega aquí tu Boot Hash verificado",
"save_button": "Guardar"
},
"about": {
"module_name_line1": "Tricky Addon",
"module_name_line2": "Update Target List",
"module_name_line2": "Actualizar Lista de Objetivos",
"by": "por",
"telegram_channel": "Canal de Telegram",
"github": "GitHub",
@@ -70,6 +80,36 @@
"save_error": "Error al guardar la configuración",
"uninstall_prompt": "El WebUI se eliminará después de reiniciar",
"uninstall_failed": "Error al desinstalar el WebUI",
"new_update": "¡Una nueva actualización está disponible!"
"new_update": "¡Una nueva actualización está disponible!",
"downloading": "Descargando nueva actualización...",
"downloaded": "Descarga completada",
"download_fail": "Error al descargar la actualización",
"installing": "Instalando actualización...",
"installed": "Instalado con éxito, reinicia ahora.",
"install_fail": "Error al instalar, actualiza manualmente",
"rebooting": "Reiniciando...",
"reboot_fail": "Error al reiniciar, reinicia manualmente",
"custom_key_set": "Keybox personalizado establecido con éxito",
"custom_key_set_error": "Error al establecer el keybox personalizado",
"no_file_selected": "Ningún archivo seleccionado"
},
"security_patch": {
"title": "Parche de Seguridad",
"advanced_mode": "Avanzado",
"get_date": "Obtener Fecha del Parche de Seguridad",
"auto": "Automático",
"save": "Guardar",
"fetching": "Obteniendo...",
"fetched": "Completado",
"get_failed": "Error al obtener la fecha del parche de seguridad",
"auto_success": "Configuración automática habilitada con éxito",
"auto_failed": "Error al habilitar la configuración automática",
"save_success": "Parche de seguridad guardado con éxito",
"save_failed": "Error al guardar el parche de seguridad",
"value_empty": "La configuración del parche de seguridad está deshabilitada",
"invalid_all": "Formato inválido",
"invalid_boot": "Formato de boot inválido",
"invalid_system": "Formato de system inválido",
"invalid_vendor": "Formato de vendor inválido"
}
}

View File

@@ -1,7 +1,7 @@
{
"language": "日本語",
"header": {
"title": "Tricky Addon - Update Target List"
"title": "Tricky Addon"
},
"help": {
"help_instructions": "使い方",
@@ -17,12 +17,19 @@
"deselect_unnecessary_description": "不要なカテゴリー: Xposed モジュール、root マネージャー、root 関連アプリ、Bootloader の状態を確認しない一般的なアプリです。このオプションはインターネット接続が必要です。",
"set_keybox": "AOSP と 有効な Keybox",
"set_keybox_description": "Tricky Store の keybox.xml を置き換えます。有効な Keybox がなくなった場合は、AOSP Keybox に置き換えられます。インターネット接続が必要です。",
"set_custom_keybox": "カスタム Keybox を設定",
"set_custom_keybox_description": "デバイスのストレージからカスタム Keybox ファイルをインポートします。xml ファイルのみ対応。",
"set_security_patch": "セキュリティパッチを設定",
"set_security_patch_description": "カスタムセキュリティパッチの設定。自動設定は PIF モジュールのセキュリティパッチを使用します。空白のまま保存すると自動設定を無効にします。",
"set_verified_boot_hash": "確認付きブートハッシュを設定",
"set_verified_boot_hash_description": "Key Attestation Demo から確認付きブートハッシュの値を取得します。ro.boot.vbmeta.digest をリセットして異常なブート状態を修正します。"
},
"update_banner": {
"update": {
"update_available": "新しいバージョンの準備完了",
"redirect_to_release": "タップで最新のバージョンをダウンロード"
"redirect_to_release": "タップで最新のバージョンをダウンロード",
"changelog": "変更履歴",
"install": "インストール",
"reboot": "再起動"
},
"search_bar": {
"search_placeholder": "検索"
@@ -42,16 +49,19 @@
"deselect_unnecessary": "不要な選択を解除",
"set_aosp_keybox": "AOSP Keybox を設定",
"set_valid_keybox": "有効な Keybox を設定",
"set_custom_keybox": "カスタム Keybox を設定",
"set_verified_boot_hash": "確認付きブートハッシュを設定",
"set_security_patch": "セキュリティパッチを設定",
"about": "このアドオンについて"
},
"reset_vbmeta": {
"boot_hash_input_placeholder": "確認付きブートハッシュをここに貼り付け",
"boot_hash_save_button": "保存"
"boot_hash": {
"title": "ブートハッシュ",
"input_placeholder": "確認付きブートハッシュをここに貼り付け",
"save_button": "保存"
},
"about": {
"module_name_line1": "Tricky Addon",
"module_name_line2": "Update Target List",
"module_name_line2": "ターゲットリストを更新",
"by": "開発者: ",
"telegram_channel": "Telegram チャンネル",
"github": "GitHub",
@@ -70,6 +80,36 @@
"save_error": "設定の保存に失敗しました。",
"uninstall_prompt": "WebUI は再起動後に削除されます。",
"uninstall_failed": "WebUI のアンインストールに失敗しました。",
"new_update": "新しいバージョンがあります!"
"new_update": "新しいバージョンがあります!",
"downloading": "新しい更新をダウンロード中...",
"downloaded": "ダウンロードが完了しました",
"download_fail": "更新のダウンロードに失敗しました",
"installing": "更新をインストール中...",
"installed": "正常にインストールされました。再起動してください。",
"install_fail": "インストールに失敗しました。手動で更新してください。",
"rebooting": "再起動中...",
"reboot_fail": "再起動に失敗しました。手動で再起動してください。",
"custom_key_set": "カスタム Keybox の設定に成功しました",
"custom_key_set_error": "カスタム Keybox の設定に失敗しました",
"no_file_selected": "ファイルが選択されていません"
},
"security_patch": {
"title": "セキュリティパッチ",
"advanced_mode": "高度",
"get_date": "セキュリティパッチの日付を取得",
"auto": "自動",
"save": "保存",
"fetching": "取得中...",
"fetched": "完了",
"get_failed": "セキュリティパッチの日付を取得できませんでした",
"auto_success": "自動設定が有効化されました",
"auto_failed": "自動設定が有効化できませんでした",
"save_success": "セキュリティパッチが正常に保存されました",
"save_failed": "セキュリティパッチの保存に失敗しました",
"value_empty": "セキュリティパッチの設定は無効です",
"invalid_all": "無効な形式です",
"invalid_boot": "無効な boot 形式です",
"invalid_system": "無効な system 形式です",
"invalid_vendor": "無効な vendor 形式です"
}
}
}

View File

@@ -0,0 +1,115 @@
{
"language": "Polski",
"header": {
"title": "Tricky Addon"
},
"help": {
"help_instructions": "Instrukcja",
"save_and_update": "Zapisz",
"save_and_update_description": "Zapisz bieżącą konfigurację do target.txt.",
"refresh": "Odśwież",
"refresh_description": "Odśwież listę aplikacji i listę wykluczeń.",
"select_deselect": "Zaznacz i odznacz wszystko",
"select_description": "Zaznacz lub odznacz wszystkie aplikacje w bieżącym interfejsie.",
"select_denylist": "Wybierz z listy odrzuconych",
"select_denylist_description": "Dostępne tylko w Magisk, wybrane aplikacje, które są na DenyList. Zalecane.",
"deselect_unnecessary": "Odznacz niepotrzebne",
"deselect_unnecessary_description": "Kategoria niepotrzebna: moduł Xposed, menedżer root, aplikacje związane z rootem i ogólne aplikacje, które nigdy nie sprawdzają stanu bootloadera. Ta opcja wymaga połączenia internetowego.",
"set_keybox": "Ustaw AOSP i prawidłowy klucz",
"set_keybox_description": "Zastąp tricky store keybox.xml. Klucz AOSP zostanie zastąpiony, jeśli nie będzie już prawidłowego klucza. Opcja pobrania prawidłowego klucza wymaga połączenia internetowego.",
"set_custom_keybox": "Ustaw niestandardowy klucz",
"set_custom_keybox_description": "Importuj klucz z pamięci urządzenia. Obsługuje tylko pliki xml.",
"set_security_patch": "Ustaw poprawkę bezpieczeństwa",
"set_security_patch_description": "Ustaw niestandardową poprawkę bezpieczeństwa. Automatyczna konfiguracja użyje poprawki bezpieczeństwa z modułu PIF, domyślnie włączonego. Pozostaw puste i zapisz, aby wyłączyć automatyczną konfigurację.",
"set_verified_boot_hash": "Ustaw zweryfikowany skrót rozruchowy",
"set_verified_boot_hash_description": "Pobierz wartość verifiedBootHash z Key Attestation Demo. Napraw nieprawidłowy stan rozruchu, resetując ro.boot.vbmeta.digest."
},
"update": {
"update_available": "Nowa wersja jest gotowa",
"redirect_to_release": "dotknij, aby pobrać najnowszą wersję",
"changelog": "Dziennik zmian",
"install": "Zainstaluj",
"reboot": "Odśwież"
},
"search_bar": {
"search_placeholder": "Szukaj"
},
"functional_button": {
"save_and_update_button": "Zapisz",
"uninstall_webui": "Odinstaluj WebUI"
},
"loading": {
"loading": "Ładowanie..."
},
"menu": {
"refresh": "Odśwież ",
"select_all": "Zaznacz wszystko",
"deselect_all": "Odznacz wszystko",
"select_denylist": "Wybierz z listy odrzuconych",
"deselect_unnecessary": "Odznacz niepotrzebne",
"set_aosp_keybox": "Ustaw klucz AOSP",
"set_valid_keybox": "Ustaw ważny klucz",
"set_custom_keybox": "Ustaw niestandardowy klucz ",
"set_verified_boot_hash": "Ustaw zweryfikowany skrót rozruchowy",
"set_security_patch": "Ustaw poprawkę bezpieczeństwa",
"about": "O"
},
"boot_hash": {
"title": "Hash rozruchu",
"input_placeholder": "Wklej tutaj zweryfikowany skrót rozruchowy",
"save_button": "Zapisz"
},
"about": {
"module_name_line1": "Tricky Addon",
"module_name_line2": "Aktualizacja listy celów",
"by": "wydany przez:",
"telegram_channel": "Kanał Telegram",
"github": "GitHub",
"disclaimer": "Ten moduł nie jest częścią modułu Tricky Store. NIE zgłaszaj żadnych problemów do Tricky Store, jeśli je napotkasz.",
"acknowledgment": "Podziękowania dla:"
},
"prompt": {
"no_internet": "Sprawdź swoje połączenie internetowe",
"aosp_key_set": "Klucz AOSP ustawiony pomyślnie",
"key_set_error": "Nie udało się zaktualizować klucza",
"valid_key_set": "Prawidłowy klucz został pomyślnie ustawiony",
"no_valid_fallback": "Nie znaleziono prawidłowego klucza. Zastąpiono kluczem AOSP.",
"boot_hash_set": "Zweryfikowano skrót rozruchowy, który został pomyślnie zapisany",
"boot_hash_set_error": "Nie udało się zaktualizować zweryfikowanego skrótu rozruchowego",
"saved_target": "Konfiguracja zapisana w pliku target.txt",
"save_error": "Nie udało się zapisać konfiguracji",
"uninstall_prompt": "WebUI zostanie usunięty po ponownym uruchomieniu",
"uninstall_failed": "Nie udało się odinstalować WebUI",
"new_update": "Dostępna jest nowa aktualizacja!",
"downloading": "Pobieranie nowej aktualizacji...",
"downloaded": "Pobieranie ukończone",
"download_fail": "Nie udało się pobrać aktualizacji",
"installing": "Instalowanie aktualizacji...",
"installed": "Instalacja przebiegła pomyślnie, uruchom ponownie.",
"install_fail": "Nie udało się zainstalować, zaktualizuj instrukcję",
"rebooting": "Ponowne uruchomienie...",
"reboot_fail": "Nie udało się ponownie uruchomić, proszę ponownie uruchomić ręcznie",
"custom_key_set": "Niestandardowe klucz został pomyślnie ustawiony",
"custom_key_set_error": "Nie udało się ustawić niestandardowego klucza",
"no_file_selected": "Nie wybrano pliku"
},
"security_patch": {
"title": "Poprawka bezpieczeństwa",
"advanced_mode": "Zaawansowany",
"get_date": "Pobierz datę poprawki zabezpieczeń",
"auto": "Automatyczny",
"save": "Zapisz",
"fetching": "Pobieranie...",
"fetched": "Zrobione",
"get_failed": "Nie udało się pobrać daty poprawki zabezpieczeń",
"auto_success": "Konfiguracja automatyczna włączona pomyślnie",
"auto_failed": "Nie udało się włączyć automatycznej konfiguracji",
"save_success": "Poprawka zabezpieczeń została pomyślnie zapisana",
"save_failed": "Nie udało się zapisać poprawki zabezpieczeń",
"value_empty": "Konfiguracja poprawki zabezpieczeń jest wyłączona",
"invalid_all": "Nieprawidłowy format",
"invalid_boot": "Nieprawidłowy format rozruchu",
"invalid_system": "Nieprawidłowy format systemu",
"invalid_vendor": "Nieprawidłowy format dostawcy"
}
}

View File

@@ -1,7 +1,7 @@
{
"language": "Русский",
"header": {
"title": "Tricky Addon - Обновить список целей"
"title": "Tricky Addon"
},
"help": {
"help_instructions": "Инструкции",
@@ -17,12 +17,19 @@
"deselect_unnecessary_description": "Ненужные категории: модули Xposed, менеджеры root, приложения, связанные с root, и общие приложения, которые никогда не проверяют статус загрузчика. Этот параметр требует подключения к интернету.",
"set_keybox": "Установить AOSP и действующий Keybox",
"set_keybox_description": "Замените tricky store keybox.xml. AOSP keybox будет заменен, если не будет найден действующий keybox. Опция с действующим keybox требует подключения к интернету.",
"set_custom_keybox": "Установить пользовательский Keybox",
"set_custom_keybox_description": "Импортируйте файл keybox из вашего устройства в хранилище. Поддерживаются только xml файлы.",
"set_security_patch": "Установить Security Patch",
"set_security_patch_description": "Установите пользовательский патч безопасности. Автоматическая настройка будет использовать патч безопасности из модуля PIF, включен по умолчанию. Оставьте пустым и сохраните, чтобы отключить автоматическую настройку.",
"set_verified_boot_hash": "Установить Verified Boot Hash",
"set_verified_boot_hash_description": "Получите значение verifiedBootHash из Key Attestation Demo. Исправьте аномальное состояние загрузки, сбросив ro.boot.vbmeta.digest."
},
"update_banner": {
"update": {
"update_available": "Доступна новая версия",
"redirect_to_release": "нажмите, чтобы скачать последнюю версию"
"redirect_to_release": "нажмите, чтобы скачать последнюю версию",
"changelog": "Список изменений",
"install": "Установить",
"reboot": "Перезагрузить"
},
"search_bar": {
"search_placeholder": "Поиск"
@@ -42,12 +49,15 @@
"deselect_unnecessary": "Отменить выбор ненужных",
"set_aosp_keybox": "Установить AOSP Keybox",
"set_valid_keybox": "Установить действующий Keybox",
"set_custom_keybox": "Установить пользовательский Keybox",
"set_security_patch": "Установить Security Patch",
"set_verified_boot_hash": "Установить Verified Boot Hash",
"about": "О программе"
},
"reset_vbmeta": {
"boot_hash_input_placeholder": "Вставьте свой проверенный Boot Hash сюда",
"boot_hash_save_button": "Сохранить"
"boot_hash": {
"title": "Boot Hash",
"input_placeholder": "Вставьте свой проверенный Boot Hash сюда",
"save_button": "Сохранить"
},
"about": {
"module_name_line1": "Tricky Addon",
@@ -70,6 +80,36 @@
"save_error": "Не удалось сохранить конфигурацию",
"uninstall_prompt": "WebUI будет удален после перезагрузки",
"uninstall_failed": "Не удалось удалить WebUI",
"new_update": "Доступно новое обновление!"
"new_update": "Доступно новое обновление!",
"downloading": "Загрузка нового обновления...",
"downloaded": "Загрузка завершена",
"download_fail": "Не удалось загрузить обновление",
"installing": "Установка обновления...",
"installed": "Успешно установлено, перезагрузите устройство.",
"install_fail": "Не удалось установить, обновите вручную",
"rebooting": "Перезагрузка...",
"reboot_fail": "Не удалось перезагрузить, перезагрузите вручную",
"custom_key_set": "Пользовательский keybox успешно установлен",
"custom_key_set_error": "Не удалось установить пользовательский keybox",
"no_file_selected": "Файл не выбран"
},
"security_patch": {
"title": "Патч безопасности",
"advanced_mode": "Расширенный",
"get_date": "Получить дату патча безопасности",
"auto": "Авто",
"save": "Сохранить",
"fetching": "Получение...",
"fetched": "Готово",
"get_failed": "Не удалось получить дату патча безопасности",
"auto_success": "Автоматическая конфигурация успешно включена",
"auto_failed": "Не удалось включить автоматическую конфигурацию",
"save_success": "Патч безопасности успешно сохранен",
"save_failed": "Не удалось сохранить патч безопасности",
"value_empty": "Конфигурация патча безопасности отключена",
"invalid_all": "Неверный формат",
"invalid_boot": "Неверный формат boot",
"invalid_system": "Неверный формат system",
"invalid_vendor": "Неверный формат vendor"
}
}

View File

@@ -1,7 +1,7 @@
{
"language": "Tagalog",
"header": {
"title": "Tricky Addon - I-update ang Target List"
"title": "Tricky Addon"
},
"help": {
"help_instructions": "Mga Tagubilin",
@@ -16,13 +16,20 @@
"deselect_unnecessary": "Huwag Pumili ng Hindi Kinakailangan",
"deselect_unnecessary_description": "Hindi kinakailangang kategorya: Xposed module, root manager, root-related apps, at mga karaniwang apps na hindi kailanman nire-refresh ang bootloader status. Nangangailangan ng koneksyon sa internet.",
"set_keybox": "I-set ang AOSP at Valid Keybox",
"set_keybox_description": "Palitan ang tricky store keybox.xml. Palitan ang AOSP keybox kung walang valid keybox. Nangangailangan ng koneksyon sa internet ang valid keybox option.",
"set_keybox_description": "Palitan ang tricky store keybox. Palitan ang AOSP keybox kung walang valid keybox. Nangangailangan ng koneksyon sa internet ang valid keybox option.",
"set_custom_keybox": "I-set ang Custom Keybox",
"set_custom_keybox_description": "Mag-import ng custom keybox mula sa iyong device storage. Sumusuporta lamang ng xml file.",
"set_security_patch": "I-set ang Security Patch",
"set_security_patch_description": "I-set ang custom security patch. Ang auto config ay mag-use ng security patch mula sa PIF module, default enabled. I-leave blank at i-save para i-disable ang auto config.",
"set_verified_boot_hash": "I-set ang Verified Boot Hash",
"set_verified_boot_hash_description": "Kunin ang verifiedBootHash mula sa Key Attestation Demo. Ayusin ang abnormal na boot state sa pamamagitan ng pag-reset ng ro.boot.vbmeta.digest."
},
"update_banner": {
"update": {
"update_available": "Handa na ang bagong bersyon",
"redirect_to_release": "i-tap para i-download ang pinakabagong bersyon"
"redirect_to_release": "i-tap para i-download ang pinakabagong bersyon",
"changelog": "Mga Pagbabago",
"install": "I-install",
"reboot": "I-reboot"
},
"search_bar": {
"search_placeholder": "Maghanap"
@@ -42,12 +49,15 @@
"deselect_unnecessary": "Huwag Pumili ng Hindi Kinakailangan",
"set_aosp_keybox": "I-set ang AOSP Keybox",
"set_valid_keybox": "I-set ang Valid Keybox",
"set_custom_keybox": "I-set ang Custom Keybox",
"set_verified_boot_hash": "I-set ang Verified Boot Hash",
"set_security_patch": "I-set ang Security Patch",
"about": "Tungkol"
},
"reset_vbmeta": {
"boot_hash_input_placeholder": "I-paste ang iyong verified Boot Hash dito",
"boot_hash_save_button": "I-save"
"boot_hash": {
"title": "Boot Hash",
"input_placeholder": "I-paste ang iyong verified Boot Hash dito",
"save_button": "I-save"
},
"about": {
"module_name_line1": "Tricky Addon",
@@ -70,6 +80,36 @@
"save_error": "Nabigong i-save ang config",
"uninstall_prompt": "Mawawala ang WebUI pagkatapos ng reboot",
"uninstall_failed": "Nabigong i-uninstall ang WebUI",
"new_update": "May bagong update na available!"
"new_update": "May bagong update na available!",
"downloading": "Nagda-download ng bagong update...",
"downloaded": "Natapos ang pag-download",
"download_fail": "Nabigo ang pag-download ng update",
"installing": "Nag-i-install ng update...",
"installed": "Matagumpay na na-install, mag-reboot na ngayon.",
"install_fail": "Nabigo ang pag-install, pakisubukang mag-update nang manu-mano",
"rebooting": "Nag-re-reboot...",
"reboot_fail": "Nabigo ang pag-reboot, pakisubukang mag-reboot nang manu-mano",
"custom_key_set": "Matagumpay na na-set ang Custom Keybox",
"custom_key_set_error": "Nabigong i-set ang Custom Keybox",
"no_file_selected": "Walang napiling file"
},
"security_patch": {
"title": "Security Patch",
"advanced_mode": "Advanced",
"get_date": "Kunin ang Petsa ng Security Patch",
"auto": "Auto",
"save": "I-save",
"fetching": "Kumukuha...",
"fetched": "Tapos na",
"get_failed": "Hindi makuha ang petsa ng security patch",
"auto_success": "Matagumpay na na-enable ang auto config",
"auto_failed": "Nabigong i-enable ang auto config",
"save_success": "Matagumpay na na-save ang security patch",
"save_failed": "Nabigong i-save ang security patch",
"value_empty": "Naka-disable ang configuration ng security patch",
"invalid_all": "Invalid format",
"invalid_boot": "Invalid boot format",
"invalid_system": "Invalid system format",
"invalid_vendor": "Invalid vendor format"
}
}

View File

@@ -0,0 +1,115 @@
{
"language": "Türkçe",
"header": {
"title": "Tricky Addon"
},
"help": {
"help_instructions": "Talimatlar",
"save_and_update": "Kaydet",
"save_and_update_description": "Mevcut yapılandırmayı target.txt dosyasına kaydet.",
"refresh": "Yenile",
"refresh_description": "Uygulama ve hariç tutma listesini yenile.",
"select_deselect": "Tümünü Seç & Seçimi Kaldır",
"select_description": "Mevcut arayüzdeki tüm uygulamaları seç veya seçimini kaldır.",
"select_denylist": "Reddetme Listesinden Seç",
"select_denylist_description": "Yalnızca Magisk'te mevcut, Reddetme Listesindeki uygulamaları seç. Tavsiye edilir.",
"deselect_unnecessary": "Gereksizleri Seçme",
"deselect_unnecessary_description": "Gereksiz kategori: Xposed modülü, root yöneticisi, root ile ilgili uygulamalar ve asla bootloader durumunu kontrol etmeyen genel uygulamalar. Bu seçenek internet bağlantısı gerektirir.",
"set_keybox": "AOSP & Geçerli Keybox Ayarla",
"set_keybox_description": "Tricky Store'daki keybox.xml dosyasını değiştirir. Eğer geçerli bir keybox yoksa AOSP keybox ile değiştirilecektir. Geçerli keybox seçeneği internet bağlantısı gerektirir.",
"set_custom_keybox": "Özel Keybox Ayarla",
"set_custom_keybox_description": "Cihaz depolamasından bir keybox dosyasını içe aktarın. Sadece xml dosyaları desteklenir.",
"set_security_patch": "Güvenlik Yaması Ayarla",
"set_security_patch_description": "Özel güvenlik yamasını ayarlayın. Otomatik yapılandırma PIF modülünün güvenlik yamasını kullanacaktır. Boş bırakın ve kaydedin ki otomatik yapılandırma devre dışı bırakılsın.",
"set_verified_boot_hash": "Doğrulanmış Boot Hash Ayarla",
"set_verified_boot_hash_description": "Key Attestation Demo'dan verifiedBootHash değerini alın. Abnormal boot durumunu ro.boot.vbmeta.digest'i sıfırlayarak düzeltin."
},
"update": {
"update_available": "Yeni bir sürüm hazır",
"redirect_to_release": "Son sürümü indirmek için dokunun",
"changelog": "Değişiklik Günlüğü",
"install": "Yükle",
"reboot": "Yeniden Başlat"
},
"search_bar": {
"search_placeholder": "Ara"
},
"functional_button": {
"save_and_update_button": "Kaydet",
"uninstall_webui": "WebUI'ı Kaldır"
},
"loading": {
"loading": "Yükleniyor..."
},
"menu": {
"refresh": "Yenile",
"select_all": "Tümünü Seç",
"deselect_all": "Tüm Seçimleri Kaldır",
"select_denylist": "Reddetme Listesinden Seç",
"deselect_unnecessary": "Gereksizleri Seçme",
"set_aosp_keybox": "AOSP Keybox Ayarla",
"set_valid_keybox": "Geçerli Keybox Ayarla",
"set_custom_keybox": "Özel Keybox Ayarla",
"set_security_patch": "Güvenlik Yaması Ayarla",
"set_verified_boot_hash": "Doğrulanmış Boot Hash Ayarla",
"about": "Hakkında"
},
"boot_hash": {
"title": "Boot Hash",
"input_placeholder": "Doğrulanmış Boot Hash'inizi buraya yapıştırın",
"save_button": "Kaydet"
},
"about": {
"module_name_line1": "Tricky Addon",
"module_name_line2": "Target List'i Güncelle",
"by": "tarafından",
"telegram_channel": "Telegram Kanalı",
"github": "GitHub",
"disclaimer": "Bu modül, Tricky Store modülünün bir parçası değildir. Herhangi bir sorun yaşarsanız, lütfen bunu Tricky Store'a rapor etmeyin.",
"acknowledgment": "Teşekkürler"
},
"prompt": {
"no_internet": "Lütfen internet bağlantınızı kontrol edin",
"aosp_key_set": "AOSP keybox başarıyla ayarlandı",
"key_set_error": "Keybox güncellenemedi",
"valid_key_set": "Geçerli keybox başarıyla ayarlandı",
"no_valid_fallback": "Geçerli keybox bulunamadı, AOSP keybox ile değiştirildi.",
"boot_hash_set": "Doğrulanmış Boot Hash başarıyla kaydedildi",
"boot_hash_set_error": "Doğrulanmış Boot Hash güncellenemedi",
"saved_target": "Yapılandırma target.txt dosyasına kaydedildi",
"save_error": "Yapılandırma kaydedilemedi",
"uninstall_prompt": "WebUI yeniden başlatma sonrasında kaldırılacak",
"uninstall_failed": "WebUI kaldırılamadı",
"new_update": "Yeni bir güncelleme mevcut!",
"downloading": "Yeni güncelleme indiriliyor...",
"downloaded": "İndirme tamamlandı",
"download_fail": "Güncelleme indirilemedi",
"installing": "Güncelleme yükleniyor...",
"installed": "Başarıyla yüklendi, şimdi yeniden başlatın.",
"install_fail": "Yükleme başarısız oldu, lütfen manuel olarak güncelleyin",
"rebooting": "Yeniden başlatılıyor...",
"reboot_fail": "Yeniden başlatma başarısız, lütfen manuel olarak yeniden başlatın",
"custom_key_set": "Özel keybox başarıyla ayarlandı",
"custom_key_set_error": "Özel keybox ayarlanamadı",
"no_file_selected": "Dosya seçilmedi"
},
"security_patch": {
"title": "Güvenlik Yaması",
"advanced_mode": "Gelişmiş",
"get_date": "Güvenlik Yaması Tarihini Al",
"auto": "Otomatik",
"save": "Kaydet",
"fetching": "Alınıyor...",
"fetched": "Tamamlandı",
"get_failed": "Güvenlik yaması tarihi alınamadı",
"auto_success": "Otomatik yapılandırma başarıyla etkinleştirildi",
"auto_failed": "Otomatik yapılandırma etkinleştirilemedi",
"save_success": "Güvenlik yaması başarıyla kaydedildi",
"save_failed": "Güvenlik yaması kaydedilemedi",
"value_empty": "Güvenlik yaması yapılandırması devre dışı bırakıldı",
"invalid_all": "Geçersiz format",
"invalid_boot": "Geçersiz boot formatı",
"invalid_system": "Geçersiz system formatı",
"invalid_vendor": "Geçersiz vendor formatı"
}
}

View File

@@ -1,7 +1,7 @@
{
"language": "中文(简体)",
"language": "简体中文",
"header": {
"title": "TS插件 - 更新目标列表"
"title": "TS 插件"
},
"help": {
"help_instructions": "使用指南",
@@ -17,12 +17,19 @@
"deselect_unnecessary_description": "非必要分类Xposed 模块、root 管理器、与 root 相关的应用,以及从不检查 bootloader 状态的通用应用。此功能需连网使用。",
"set_keybox": "设置 AOSP & 有效密钥",
"set_keybox_description": "替换 Tricky Store 的密钥keybox.xml。如果没有有效密钥将替换为 AOSP 密钥。有效密钥选项需连网使用。",
"set_custom_keybox": "设置自定义密钥",
"set_custom_keybox_description": "从设备存储导入自定义密钥。仅支持 xml 文件。",
"set_security_patch": "设置安全补丁",
"set_security_patch_description": "设置自定义安全补丁。自动配置将使用 PIF 模块的安全补丁,默认启用。留空保存则禁用自动配置。",
"set_verified_boot_hash": "设置哈希值",
"set_verified_boot_hash_description": "从 Key Attestation Demo 获取 verifiedBootHash哈希值。通过重置 ro.boot.vbmeta.digest 修复异常 boot 状态。"
},
"update_banner": {
"update": {
"update_available": "发现新的版本",
"redirect_to_release": "点击跳转 GitHub 下载最新版本"
"redirect_to_release": "点击下载最新版本",
"changelog": "更新日志",
"install": "安装",
"reboot": "重启"
},
"search_bar": {
"search_placeholder": "搜索"
@@ -42,12 +49,15 @@
"deselect_unnecessary": "取消选择非必应用",
"set_aosp_keybox": "设置 AOSP 密钥",
"set_valid_keybox": "设置有效密钥",
"set_custom_keybox": "设置自定义密钥",
"set_security_patch": "设置安全补丁",
"set_verified_boot_hash": "设置哈希值",
"about": "关于"
},
"reset_vbmeta": {
"boot_hash_input_placeholder": "在此粘贴您的哈希值",
"boot_hash_save_button": "保存"
"boot_hash": {
"title": "哈希值",
"input_placeholder": "在此粘贴您的哈希值",
"save_button": "保存"
},
"about": {
"module_name_line1": "TS插件",
@@ -70,6 +80,36 @@
"save_error": "保存配置失败",
"uninstall_prompt": "WebUI 将在重启后被移除",
"uninstall_failed": "卸载 WebUI 失败",
"new_update": "发现新的版本!"
"new_update": "发现新的版本!",
"downloading": "正在下载...",
"downloaded": "下载完成",
"download_fail": "下载失败",
"installing": "正常安装...",
"installed": "安装完成,重启生效",
"install_fail": "安装失败,请手动更新",
"rebooting": "正在重启...",
"reboot_fail": "重启失败,请手动重启",
"custom_key_set": "成功设置自定义密钥",
"custom_key_set_error": "设置自定义密钥失败",
"no_file_selected": "未选择文件"
},
"security_patch": {
"title": "安全补丁",
"advanced_mode": "高级",
"get_date": "获取安全补丁日期",
"auto": "自动",
"save": "保存",
"fetching": "获取中...",
"fetched": "完成",
"get_failed": "获取安全补丁日期失败",
"auto_success": "自动配置成功启用",
"auto_failed": "无法启用自动配置",
"save_success": "安全补丁成功保存",
"save_failed": "保存安全补丁失败",
"value_empty": "安全补丁配置已禁用",
"invalid_all": "无效格式",
"invalid_boot": "无效 boot 格式",
"invalid_system": "无效 system 格式",
"invalid_vendor": "无效 vendor 格式"
}
}

View File

@@ -1,7 +1,7 @@
{
"language": "中文(繁体)",
"language": "繁體中文",
"header": {
"title": "TS插件 - 更新目標列表"
"title": "TS 插件"
},
"help": {
"help_instructions": "使用指南",
@@ -13,19 +13,26 @@
"select_description": "選擇或取消選擇當前界面中的所有應用。",
"select_denylist": "從排除列表中選擇",
"select_denylist_description": "僅適用於 Magisk選擇在排除列表中的應用。推薦使用。",
"deselect_unnecessary": "取消選擇非必應用",
"deselect_unnecessary_description": "非必要分類Xposed 模、root 管理器、與 root 相關的應用,以及從不檢查 bootloader 狀態的通用應用。此功能需連網使用。",
"deselect_unnecessary": "取消選擇非必應用",
"deselect_unnecessary_description": "非必要分類Xposed 模、root 管理器、與 root 相關的應用,以及從不檢查 bootloader 狀態的通用應用。此功能需連網使用。",
"set_keybox": "設置 AOSP & 有效密鑰",
"set_keybox_description": "替換 Tricky Store 的密鑰keybox.xml。如果沒有有效密鑰將替換為 AOSP 密鑰。有效密鑰選項需連網使用。",
"set_custom_keybox": "設置自定義密鑰",
"set_custom_keybox_description": "從設備存儲導入自定義密鑰。僅支持 xml 文件。",
"set_security_patch": "設置安全補丁",
"set_security_patch_description": "設置自定義安全補丁。自動配置將使用 PIF 模組的安全補丁,預設啟用。留空保存則禁用自動配置。",
"set_verified_boot_hash": "設置哈希值",
"set_verified_boot_hash_description": "從 Key Attestation Demo 獲取 verifiedBootHash哈希值。通過重置 ro.boot.vbmeta.digest 修復異常 boot 狀態。"
},
"update_banner": {
"update_available": "發現新版本",
"redirect_to_release": "點擊跳轉至 GitHub 下載最新版本"
"update": {
"update_available": "發現新版本",
"redirect_to_release": "點擊下載最新版本",
"changelog": "更新日誌",
"install": "安裝",
"reboot": "重啟"
},
"search_bar": {
"search_placeholder": "搜"
"search_placeholder": "搜"
},
"functional_button": {
"save_and_update_button": "保存",
@@ -39,27 +46,30 @@
"select_all": "全選",
"deselect_all": "取消全選",
"select_denylist": "從排除列表中選擇",
"deselect_unnecessary": "取消選擇非必應用",
"deselect_unnecessary": "取消選擇非必應用",
"set_aosp_keybox": "設置 AOSP 密鑰",
"set_valid_keybox": "設置有效密鑰",
"set_custom_keybox": "設置自定義密鑰",
"set_security_patch": "設置安全補丁",
"set_verified_boot_hash": "設置哈希值",
"about": "關於"
},
"reset_vbmeta": {
"boot_hash_input_placeholder": "在此粘貼您的哈希值",
"boot_hash_save_button": "保存"
"boot_hash": {
"title": "哈希值",
"input_placeholder": "在此貼上您的哈希值",
"save_button": "保存"
},
"about": {
"module_name_line1": "TS插件",
"module_name_line1": "TS 插件",
"module_name_line2": "更新目標列表",
"by": "作者:",
"telegram_channel": "TG頻道",
"telegram_channel": "Telegram 頻道",
"github": "GitHub",
"disclaimer": "此 WebUI 不是 Tricky Store 的一部分,遇任何問題請勿向 Tricky Store 作者反饋。",
"disclaimer": "此 WebUI 並非 Tricky Store 的一部分,遇任何問題請勿向 Tricky Store 作者反饋。",
"acknowledgment": "特別鳴謝"
},
"prompt": {
"no_internet": "請檢查您的網連接",
"no_internet": "請檢查您的網連接",
"aosp_key_set": "成功設置 AOSP 密鑰",
"key_set_error": "更新密鑰失敗",
"valid_key_set": "成功設置有效密鑰",
@@ -70,6 +80,36 @@
"save_error": "保存配置失敗",
"uninstall_prompt": "WebUI 將在重啟後被移除",
"uninstall_failed": "卸載 WebUI 失敗",
"new_update": "發現新版本!"
"new_update": "發現新版本!",
"downloading": "正在下載...",
"downloaded": "下載完成",
"download_fail": "下載失敗",
"installing": "正在安裝...",
"installed": "安裝完成,重啟生效",
"install_fail": "安裝失敗,請手動更新",
"rebooting": "正在重啟...",
"reboot_fail": "重啟失敗,請手動重啟",
"custom_key_set": "成功設置自定義密鑰",
"custom_key_set_error": "設置自定義密鑰失敗",
"no_file_selected": "未選擇文件"
},
"security_patch": {
"title": "安全補丁",
"advanced_mode": "進階",
"get_date": "獲取安全補丁日期",
"auto": "自動",
"save": "保存",
"fetching": "獲取中...",
"fetched": "完成",
"get_failed": "獲取安全補丁日期失敗",
"auto_success": "自動配置成功啟用",
"auto_failed": "無法啟用自動配置",
"save_success": "安全補丁成功保存",
"save_failed": "保存安全補丁失敗",
"value_empty": "安全補丁配置已禁用",
"invalid_all": "無效格式",
"invalid_boot": "無效 boot 格式",
"invalid_system": "無效 system 格式",
"invalid_vendor": "無效 vendor 格式"
}
}

View File

@@ -1,10 +1,10 @@
import { execCommand } from './main.js';
import { execCommand, linkRedirect } from './main.js';
const telegramLink = document.getElementById('telegram');
const githubLink = document.getElementById('github');
// Function to show about overlay
export function aboutMenu() {
document.getElementById("about").addEventListener("click", () => {
const aboutOverlay = document.getElementById('about-overlay');
const aboutMenu = document.getElementById('about-menu');
const closeAbout = document.getElementById('close-about');
@@ -35,20 +35,12 @@ export function aboutMenu() {
}
});
menu.addEventListener('click', (event) => event.stopPropagation());
}
});
// Event listener for link redirect
telegramLink.addEventListener('click', async () => {
try {
await execCommand('am start -a android.intent.action.VIEW -d https://t.me/kowchannel');
} catch (error) {
console.error('Error opening Telegram link:', error);
}
telegramLink.addEventListener('click', function() {
linkRedirect('https://t.me/kowchannel');
});
githubLink.addEventListener('click', async () => {
try {
await execCommand('am start -a android.intent.action.VIEW -d https://github.com/KOWX712/Tricky-Addon-Update-Target-List');
} catch (error) {
console.error('Error opening GitHub link:', error);
}
githubLink.addEventListener('click', function() {
linkRedirect('https://github.com/KOWX712/Tricky-Addon-Update-Target-List');
});

View File

@@ -1,8 +1,10 @@
import { basePath, execCommand, floatingBtn, appsWithExclamation, appsWithQuestion } from './main.js';
import { basePath, execCommand, floatingBtn, appsWithExclamation, appsWithQuestion, toast } from './main.js';
const appTemplate = document.getElementById('app-template').content;
const modeOverlay = document.querySelector('.mode-overlay');
export const appListContainer = document.getElementById('apps-list');
export const updateCard = document.getElementById('update-card');
export let modeActive = false;
// Fetch and render applist
export async function fetchAppList() {
@@ -13,6 +15,7 @@ export async function fetchAppList() {
targetList = processTargetList(targetFileContent);
console.log("Current target list:", targetList);
} catch (error) {
toast("Failed to read target.txt!");
console.error("Failed to read target.txt file:", error);
}
@@ -35,11 +38,14 @@ export async function fetchAppList() {
console.warn("Applist file not found or could not be loaded. Skipping applist lookup.");
}
const result = await execCommand("pm list packages -3");
const result = await execCommand(`
pm list packages -3 | awk -F: '{print $2}'
pm list packages -s | awk -F: '{print $2}' | grep -Ex "com.google.android.gms|com.google.android.gsf|com.android.vending" 2>/dev/null || true
`);
const appEntries = result
.split("\n")
.map(line => {
const packageName = line.replace("package:", "").trim();
const packageName = line.trim();
const appName = applistMap[packageName] || null;
return { appName, packageName };
})
@@ -76,6 +82,26 @@ export async function fetchAppList() {
const appElement = document.importNode(appTemplate, true);
const contentElement = appElement.querySelector(".content");
contentElement.setAttribute("data-package", packageName);
// Set unique names for radio button groups
const radioButtons = appElement.querySelectorAll('input[type="radio"]');
radioButtons.forEach((radio) => {
radio.name = `mode-radio-${packageName}`;
});
// Preselect the radio button based on the package name
const generateRadio = appElement.querySelector('#generate-mode');
const hackRadio = appElement.querySelector('#hack-mode');
const normalRadio = appElement.querySelector('#normal-mode');
if (appsWithExclamation.includes(packageName)) {
generateRadio.checked = true;
} else if (appsWithQuestion.includes(packageName)) {
hackRadio.checked = true;
} else {
normalRadio.checked = true;
}
const nameElement = appElement.querySelector(".name");
nameElement.innerHTML = `<strong>${appName || "Unknown App"}</strong><br>${packageName}`;
const checkbox = appElement.querySelector(".checkbox");
@@ -84,13 +110,18 @@ export async function fetchAppList() {
});
console.log("App list with names and packages rendered successfully.");
} catch (error) {
toast("Failed to fetch app list!");
console.error("Failed to fetch or render app list with names:", error);
}
floatingBtn.style.transform = "translateY(-120px)";
floatingBtn.style.transform = 'translateY(0)';
toggleableCheckbox();
if (appListContainer.firstChild !== updateCard) {
appListContainer.insertBefore(updateCard, appListContainer.firstChild);
}
const checkboxes = appListContainer.querySelectorAll(".checkbox");
setupRadioButtonListeners();
setupModeMenu();
updateCheckboxColor();
}
// Function to save app with ! and ? then process target list
@@ -119,9 +150,116 @@ function toggleableCheckbox() {
const content = card.querySelector(".content");
const checkbox = content.querySelector(".checkbox");
content.addEventListener("click", (event) => {
if (event.target !== checkbox) {
checkbox.checked = !checkbox.checked;
}
checkbox.checked = !checkbox.checked;
});
});
}
// Add eventlistener to mode button
function setupRadioButtonListeners() {
const radioButtons = appListContainer.querySelectorAll('input[type="radio"]');
radioButtons.forEach((radioButton) => {
radioButton.addEventListener('change', (event) => {
const card = radioButton.closest(".card");
const packageName = card.querySelector(".content").getAttribute("data-package");
if (radioButton.id === 'generate-mode') {
if (!appsWithExclamation.includes(packageName)) {
appsWithExclamation.push(packageName);
}
const indexInQuestion = appsWithQuestion.indexOf(packageName);
if (indexInQuestion > -1) {
appsWithQuestion.splice(indexInQuestion, 1);
}
} else if (radioButton.id === 'hack-mode') {
if (!appsWithQuestion.includes(packageName)) {
appsWithQuestion.push(packageName);
}
const indexInExclamation = appsWithExclamation.indexOf(packageName);
if (indexInExclamation > -1) {
appsWithExclamation.splice(indexInExclamation, 1);
}
} else if (radioButton.id === 'normal-mode') {
const indexInExclamation = appsWithExclamation.indexOf(packageName);
if (indexInExclamation > -1) {
appsWithExclamation.splice(indexInExclamation, 1);
}
const indexInQuestion = appsWithQuestion.indexOf(packageName);
if (indexInQuestion > -1) {
appsWithQuestion.splice(indexInQuestion, 1);
}
}
updateCheckboxColor();
console.log("Updated appsWithExclamation:", appsWithExclamation);
console.log("Updated appsWithQuestion:", appsWithQuestion);
});
});
}
// Hold to open menu
function setupModeMenu() {
let holdTimeout;
function showMode(card) {
const modeElement = card.querySelector(".mode");
if (modeElement) {
modeActive = true;
modeElement.style.display = "flex";
modeOverlay.style.display = "flex";
setTimeout(() => {
modeElement.classList.add('show');
}, 10);
}
}
function hideAllModes() {
const allModeElements = appListContainer.querySelectorAll(".mode");
allModeElements.forEach((modeElement) => {
modeActive = false;
modeElement.classList.remove('show');
modeOverlay.style.display = "none";
setTimeout(() => {
modeElement.style.display = "none";
}, 200);
});
}
const cards = appListContainer.querySelectorAll(".card");
cards.forEach((card) => {
card.addEventListener("pointerdown", () => {
const checkbox = card.querySelector(".checkbox");
if (checkbox && checkbox.checked) {
holdTimeout = setTimeout(() => {
showMode(card);
}, 500);
}
});
card.addEventListener("pointerup", () => clearTimeout(holdTimeout));
card.addEventListener("pointercancel", () => clearTimeout(holdTimeout));
});
document.addEventListener("click", (event) => {
if (!event.target.closest(".mode") || modeOverlay.contains(event.target)) {
hideAllModes();
} else if (event.target.closest(".status-indicator")) {
setTimeout(() => {
hideAllModes();
}, 300);
}
});
window.addEventListener("scroll", hideAllModes);
}
// Function to update card borders color
function updateCheckboxColor() {
const cards = appListContainer.querySelectorAll(".card");
cards.forEach((card) => {
const packageName = card.querySelector(".content").getAttribute("data-package");
const checkbox = card.querySelector(".checkbox");
checkbox.classList.remove("checkbox-checked-generate", "checkbox-checked-hack");
if (appsWithExclamation.includes(packageName)) {
checkbox.classList.add("checkbox-checked-generate");
} else if (appsWithQuestion.includes(packageName)) {
checkbox.classList.add("checkbox-checked-hack");
} else if (checkbox.checked) {
checkbox.classList.remove("checkbox-checked-generate", "checkbox-checked-hack");
}
});
}

View File

@@ -5,8 +5,13 @@ const card = document.getElementById('boot-hash-card');
const inputBox = document.getElementById('boot-hash-input');
const saveButton = document.getElementById('boot-hash-save-button');
// Remove empty spaces from input
window.trimInput = (input) => {
input.value = input.value.replace(/\s+/g, '');
};
// Function to handle Verified Boot Hash
export async function setBootHash() {
document.getElementById("boot-hash").addEventListener("click", async () => {
const showCard = () => {
bootHashOverlay.style.display = "flex";
card.style.display = "flex";
@@ -51,4 +56,11 @@ export async function setBootHash() {
bootHashOverlay.addEventListener("click", (event) => {
if (event.target === bootHashOverlay) closeCard();
});
}
// Enter to save
inputBox.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
saveButton.click();
}
});
});

View File

@@ -3,28 +3,29 @@ const helpOverlay = document.getElementById('help-overlay');
const closeHelp = document.getElementById('close-help');
const helpList = document.getElementById('help-list');
// Function to setup the help menu
export function setupHelpOverlay() {
helpButton.addEventListener("click", () => {
helpOverlay.classList.remove("hide");
helpOverlay.style.display = "flex";
requestAnimationFrame(() => {
helpOverlay.classList.add("show");
});
document.body.classList.add("no-scroll");
// Open help menu
helpButton.addEventListener("click", () => {
helpOverlay.classList.remove("hide");
helpOverlay.style.display = "flex";
requestAnimationFrame(() => {
helpOverlay.classList.add("show");
});
const hideHelpOverlay = () => {
helpOverlay.classList.remove("show");
helpOverlay.classList.add("hide");
document.body.classList.remove("no-scroll");
setTimeout(() => {
helpOverlay.style.display = "none";
}, 200);
};
closeHelp.addEventListener("click", hideHelpOverlay);
helpOverlay.addEventListener("click", (event) => {
if (event.target === helpOverlay) {
hideHelpOverlay();
}
});
}
document.body.classList.add("no-scroll");
});
const hideHelpOverlay = () => {
helpOverlay.classList.remove("show");
helpOverlay.classList.add("hide");
document.body.classList.remove("no-scroll");
setTimeout(() => {
helpOverlay.style.display = "none";
}, 200);
};
// Close help menu
closeHelp.addEventListener("click", hideHelpOverlay);
helpOverlay.addEventListener("click", (event) => {
if (event.target === helpOverlay) {
hideHelpOverlay();
}
});

View File

@@ -1,4 +1,4 @@
import { basePath, execCommand } from './main.js';
import { basePath, execCommand, toast } from './main.js';
const languageButton = document.querySelector('.language-button');
const languageMenu = document.querySelector('.language-menu');
@@ -16,6 +16,7 @@ export async function initializeAvailableLanguages() {
availableLanguages = multiLang.trim().split('\n');
generateLanguageMenu();
} catch (error) {
toast("Failed to get available langauge!");
console.error('Failed to fetch available languages:', error);
availableLanguages = ['en-US'];
}
@@ -41,6 +42,7 @@ export async function loadTranslations(lang) {
translations = await response.json();
applyTranslations();
} catch (error) {
toast(`Failed to load translation for ${lang}!`);
console.error(`Error loading translations for ${lang}:`, error);
if (lang !== 'en-US') {
console.log("Falling back to English.");
@@ -91,8 +93,10 @@ export function setupLanguageMenu() {
}
});
function openLanguageMenu() {
languageMenu.classList.add("show");
languageOverlay.style.display = 'flex';
setTimeout(() => {
languageMenu.classList.add("show");
}, 10);
}
function closeLanguageMenu() {
languageMenu.classList.remove("show");
@@ -124,7 +128,7 @@ async function generateLanguageMenu() {
const sortedLanguages = languageData.sort((a, b) => a.name.localeCompare(b.name));
sortedLanguages.forEach(({ lang, name }) => {
const button = document.createElement('button');
button.classList.add('language-option');
button.classList.add('language-option', 'ripple-element');
button.setAttribute('data-lang', lang);
button.textContent = name;
languageMenu.appendChild(button);

View File

@@ -1,39 +1,50 @@
import { aboutMenu } from './about.js';
import { appListContainer, updateCard, fetchAppList } from './applist.js';
import { setupHelpOverlay } from './help.js';
import { appListContainer, fetchAppList, modeActive } from './applist.js';
import { initializeAvailableLanguages, detectUserLanguage, loadTranslations, setupLanguageMenu, translations } from './language.js';
import { selectAllApps, deselectAllApps, selectDenylistApps, deselectUnnecessaryApps, aospkb, extrakb } from './menu_option.js';
import { aospkb } from './menu_option.js';
import { searchMenuContainer, searchInput, clearBtn, setupMenuToggle } from './search_menu.js';
import { setBootHash } from './vbmeta-digest.js';
import { updateCheck } from './update.js';
import { securityPatch } from './security_patch.js';
// Header Elements
const headerBlock = document.querySelector('.header-block');
const title = document.querySelector('.header');
const noConnection = document.querySelector('.no-connection');
// Menu Elements
const selectDenylistElement = document.getElementById('select-denylist');
export const noConnection = document.querySelector('.no-connection');
// Loading, Save and Prompt Elements
const permissionPopup = document.getElementById('permission-popup');
const loadingIndicator = document.querySelector('.loading');
const prompt = document.getElementById('prompt');
const floatingCard = document.querySelector('.floating-card');
export const floatingBtn = document.querySelector('.floating-btn');
export const basePath = "set-path";
export const appsWithExclamation = [];
export const appsWithQuestion = [];
const ADDITIONAL_APPS = [ "com.google.android.gms", "io.github.vvb2060.keyattestation", "io.github.vvb2060.mahoshojo", "icu.nullptr.nativetest" ];
const ADDITIONAL_APPS = [ "android", "com.android.vending", "com.google.android.gms", "io.github.vvb2060.keyattestation", "io.github.vvb2060.mahoshojo", "icu.nullptr.nativetest" ]; // Always keep default apps in target.txt
// Variables
let e = 0;
let isRefreshing = false;
let MMRL_API = true;
// Function to load the version from module.prop
async function getModuleVersion() {
const moduleVersion = document.getElementById('module-version');
try {
const version = await execCommand(`grep '^version=' ${basePath}common/update/module.prop | cut -d'=' -f2`);
moduleVersion.textContent = version;
} catch (error) {
console.error("Failed to read version from module.prop:", error);
updateVersion("Error");
}
}
// Function to refresh app list
async function refreshAppList() {
isRefreshing = true;
title.style.transform = 'translateY(0)';
searchMenuContainer.style.transform = 'translateY(0)';
floatingBtn.style.transform = 'translateY(0)';
hideFloatingBtn();
searchInput.value = '';
clearBtn.style.display = "none";
appListContainer.innerHTML = '';
@@ -43,56 +54,59 @@ async function refreshAppList() {
window.scrollTo(0, 0);
if (noConnection.style.display === "flex") {
try {
await updateCheck();
updateCheck();
await execCommand(`[ -f ${basePath}common/tmp/exclude-list ] && rm -f "${basePath}common/tmp/exclude-list"`);
} catch (error) {
toast("Failed!");
console.error("Error occurred:", error);
}
}
await fetchAppList();
applyRippleEffect();
loadingIndicator.style.display = 'none';
document.querySelector('.uninstall-container').classList.remove('hidden-uninstall');
isRefreshing = false;
}
// Function to run the update check
async function updateCheck() {
// Function to check tricky store version
async function checkTrickyStoreVersion() {
const securityPatchElement = document.getElementById('security-patch');
try {
const scriptPath = `sh ${basePath}common/get_extra.sh --update`;
const output = await execCommand(scriptPath);
console.log("update script executed successfully.");
noConnection.style.display = "none";
if (output.includes("update")) {
console.log("Update detected from extra script.");
showPrompt("prompt.new_update");
updateCard.style.display = "flex";
const version = await execCommand(`
TS_version=$(grep "versionCode=" "/data/adb/modules/tricky_store/module.prop" | cut -d'=' -f2)
[ "$TS_version" -ge 158 ] || echo "NO"
`);
if (version.trim() !== "NO") {
console.log("Tricky Store version is 158 or higher, displaying element.");
securityPatchElement.style.display = "flex";
} else {
console.log("No update detected from extra script.");
console.log("Tricky Store version is below 158, leaving security patch element hidden.");
}
} catch (error) {
console.error("Failed to execute update script:", error);
showPrompt("prompt.no_internet", false);
noConnection.style.display = "flex";
toast("Failed to check Tricky Store version!");
console.error("Error while checking Tricky Store version:", error);
}
}
// Function to check if Magisk
async function checkMagisk() {
const selectDenylistElement = document.getElementById('select-denylist');
try {
const magiskEnv = await execCommand(`command -v magisk >/dev/null 2>&1 && echo "OK"`);
if (magiskEnv.trim() === "OK") {
const magiskEnv = await execCommand(`command -v magisk >/dev/null 2>&1 || echo "NO"`);
if (magiskEnv.trim() !== "NO") {
console.log("Denylist conditions met, displaying element.");
selectDenylistElement.style.display = "flex";
} else {
console.log("ksud or apd detected, leaving denylist element hidden.");
console.log("not running on Magisk, leaving denylist element hidden.");
}
} catch (error) {
toast("Failed to check Magisk!");
console.error("Error while checking denylist conditions:", error);
}
}
// Function to show the prompt with a success or error message
export function showPrompt(key, isSuccess = true) {
export function showPrompt(key, isSuccess = true, duration = 3000) {
const message = key.split('.').reduce((acc, k) => acc && acc[k], translations) || key;
prompt.textContent = message;
prompt.classList.toggle('error', !isSuccess);
@@ -100,13 +114,25 @@ export function showPrompt(key, isSuccess = true) {
clearTimeout(window.promptTimeout);
}
setTimeout(() => {
prompt.classList.add('visible');
prompt.classList.remove('hidden');
if (typeof ksu !== 'undefined' && ksu.mmrl) {
prompt.style.transform = 'translateY(calc((var(--window-inset-bottom) + 60%) * -1))';
} else {
prompt.style.transform = 'translateY(-60%)';
}
window.promptTimeout = setTimeout(() => {
prompt.classList.remove('visible');
prompt.classList.add('hidden');
}, 3000);
}, 200);
prompt.style.transform = 'translateY(100%)';
}, duration);
}, 100);
}
// Function to redirect link on external browser
export async function linkRedirect(link) {
try {
await execCommand(`am start -a android.intent.action.VIEW -d ${link}`);
} catch (error) {
toast("Failed!");
console.error('Error redirect link:', error);
}
}
// Save configure and preserve ! and ? in target.txt
@@ -128,7 +154,7 @@ document.getElementById("save").addEventListener("click", async () => {
return app;
});
const updatedTargetContent = modifiedAppsList.join("\n");
await execCommand(`echo "${updatedTargetContent}" > /data/adb/tricky_store/target.txt`);
await execCommand(`echo "${updatedTargetContent}" | sort -u > /data/adb/tricky_store/target.txt`);
console.log("target.txt updated successfully.");
showPrompt("prompt.saved_target");
for (const app of appsWithExclamation) {
@@ -158,70 +184,162 @@ document.querySelector(".uninstall-container").addEventListener("click", async (
});
// Function to check if running in MMRL
function adjustHeaderForMMRL() {
async function checkMMRL() {
if (typeof ksu !== 'undefined' && ksu.mmrl) {
console.log("Running in MMRL");
// Adjust elements position for MMRL
title.style.top = 'var(--window-inset-top)';
const insetTop = getComputedStyle(document.documentElement).getPropertyValue('--window-inset-top');
const insetTopValue = parseInt(insetTop, 10);
searchMenuContainer.style.top = `${insetTopValue + 40}px`;
headerBlock.style.display = 'block';
floatingCard.style.bottom = 'calc(var(--window-inset-bottom) + 50px)';
// Set status bars theme based on device theme
try {
$tricky_store.setLightStatusBars(!window.matchMedia('(prefers-color-scheme: dark)').matches)
} catch (error) {
console.log("Error setting status bars theme:", error)
}
// Request API permission, supported version: 33045+
try {
$tricky_store.requestAdvancedKernelSUAPI();
} catch (error) {
console.log("Error requesting API:", error);
}
// Check permissions
try {
await execCommand('ls /data/adb/modules');
MMRL_API = true;
} catch (error) {
console.error('Permission check failed:', error);
permissionPopup.classList.remove('hidden');
MMRL_API = false;
}
}
}
// Funtion to adapt floating button hide in MMRL
function hideFloatingBtn() {
if (typeof ksu !== 'undefined' && ksu.mmrl) {
floatingBtn.style.transform = 'translateY(calc(var(--window-inset-bottom) + 120px))';
} else {
floatingBtn.style.transform = 'translateY(120px)';
}
}
// Function to apply ripple effect
export function applyRippleEffect() {
document.querySelectorAll('.ripple-element').forEach(element => {
if (element.dataset.rippleListener !== "true") {
element.addEventListener("pointerdown", function (event) {
if (isScrolling) return;
const ripple = document.createElement("span");
ripple.classList.add("ripple");
// Calculate ripple size and position
const rect = element.getBoundingClientRect();
const width = rect.width;
const size = Math.max(rect.width, rect.height);
const x = event.clientX - rect.left - size / 2;
const y = event.clientY - rect.top - size / 2;
// Determine animation duration
let duration = 0.2 + (width / 800) * 0.4;
duration = Math.min(0.8, Math.max(0.2, duration));
// Set ripple styles
ripple.style.width = ripple.style.height = `${size}px`;
ripple.style.left = `${x}px`;
ripple.style.top = `${y}px`;
ripple.style.animationDuration = `${duration}s`;
ripple.style.transition = `opacity ${duration}s ease`;
// Adaptive color
const computedStyle = window.getComputedStyle(element);
const bgColor = computedStyle.backgroundColor || "rgba(0, 0, 0, 0)";
const textColor = computedStyle.color;
const isDarkColor = (color) => {
const rgb = color.match(/\d+/g);
if (!rgb) return false;
const [r, g, b] = rgb.map(Number);
return (r * 0.299 + g * 0.587 + b * 0.114) < 96; // Luma formula
};
ripple.style.backgroundColor = isDarkColor(bgColor) ? "rgba(255, 255, 255, 0.2)" : "";
// Append ripple and handle cleanup
element.appendChild(ripple);
const handlePointerUp = () => {
ripple.classList.add("end");
setTimeout(() => {
ripple.classList.remove("end");
ripple.remove();
}, duration * 1000);
element.removeEventListener("pointerup", handlePointerUp);
element.removeEventListener("pointercancel", handlePointerUp);
};
element.addEventListener("pointerup", handlePointerUp);
element.addEventListener("pointercancel", handlePointerUp);
});
element.dataset.rippleListener = "true";
}
});
}
// Scroll event
let lastScrollY = window.scrollY;
let isScrolling = false;
let scrollTimeout;
const scrollThreshold = 40;
window.addEventListener('scroll', () => {
isScrolling = true;
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(() => {
isScrolling = false;
}, 200);
if (isRefreshing) return;
if (window.scrollY > lastScrollY && window.scrollY > scrollThreshold) {
title.style.transform = 'translateY(-80px)';
headerBlock.style.transform = 'translateY(-80px)';
searchMenuContainer.style.transform = 'translateY(-40px)';
floatingBtn.style.transform = 'translateY(0)';
hideFloatingBtn();
} else if (window.scrollY < lastScrollY) {
headerBlock.style.transform = 'translateY(0)';
title.style.transform = 'translateY(0)';
searchMenuContainer.style.transform = 'translateY(0)';
floatingBtn.style.transform = 'translateY(-120px)';
floatingBtn.style.transform = 'translateY(0)';
}
lastScrollY = window.scrollY;
});
// Initial load
document.addEventListener('DOMContentLoaded', async () => {
adjustHeaderForMMRL();
await checkMMRL();
if (!MMRL_API) return;
hideFloatingBtn();
getModuleVersion();
await initializeAvailableLanguages();
const userLang = detectUserLanguage();
await loadTranslations(userLang);
setupMenuToggle();
setupLanguageMenu();
setupHelpOverlay();
document.getElementById("refresh").addEventListener("click", refreshAppList);
document.getElementById("select-all").addEventListener("click", selectAllApps);
document.getElementById("deselect-all").addEventListener("click", deselectAllApps);
document.getElementById("select-denylist").addEventListener("click", selectDenylistApps);
document.getElementById("deselect-unnecessary").addEventListener("click", deselectUnnecessaryApps);
document.getElementById("aospkb").addEventListener("click", aospkb);
document.getElementById("extrakb").addEventListener("click", extrakb);
document.getElementById("boot-hash").addEventListener("click", setBootHash);
document.getElementById("about").addEventListener("click", aboutMenu);
await fetchAppList();
applyRippleEffect();
checkTrickyStoreVersion();
checkMagisk();
updateCheck();
securityPatch();
loadingIndicator.style.display = "none";
floatingBtn.style.opacity = '1';
setTimeout(() => {
floatingBtn.style.transform = 'translateY(0)';
}, 10);
document.getElementById("refresh").addEventListener("click", refreshAppList);
document.getElementById("aospkb").addEventListener("click", aospkb);
document.querySelector('.uninstall-container').classList.remove('hidden-uninstall');
});
// Redirect to GitHub release page
updateCard.addEventListener('click', async () => {
try {
await execCommand('am start -a android.intent.action.VIEW -d https://github.com/KOWX712/Tricky-Addon-Update-Target-List/releases/latest');
} catch (error) {
console.error('Error opening GitHub Release link:', error);
}
});
// Function to execute shell commands
export async function execCommand(command) {
return new Promise((resolve, reject) => {
@@ -243,3 +361,8 @@ export async function execCommand(command) {
}
});
}
// Function to toast message
export function toast(message) {
ksu.toast(message);
}

6
module/webui/scripts/marked.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
import { basePath, execCommand, showPrompt } from './main.js';
import { basePath, execCommand, showPrompt, toast, applyRippleEffect } from './main.js';
// Function to check or uncheck all app
function toggleCheckboxes(shouldCheck) {
@@ -10,22 +10,17 @@ function toggleCheckboxes(shouldCheck) {
}
// Function to select all visible apps
export function selectAllApps() {
toggleCheckboxes(true);
}
document.getElementById("select-all").addEventListener("click", () => toggleCheckboxes(true));
// Function to deselect all visible apps
export function deselectAllApps() {
toggleCheckboxes(false);
}
document.getElementById("deselect-all").addEventListener("click", () => toggleCheckboxes(false));
// Function to read the denylist and check corresponding apps
export async function selectDenylistApps() {
document.getElementById("select-denylist").addEventListener("click", async () => {
try {
const result = await execCommand(`magisk --denylist ls 2>/dev/null | awk -F'|' '{print $1}' | grep -v "isolated" | sort | uniq`);
const result = await execCommand(`magisk --denylist ls 2>/dev/null | awk -F'|' '{print $1}' | grep -v "isolated" | sort -u`);
const denylistApps = result.split("\n").map(app => app.trim()).filter(Boolean);
const apps = document.querySelectorAll(".card");
await deselectAllApps();
apps.forEach(app => {
const contentElement = app.querySelector(".content");
const packageName = contentElement.getAttribute("data-package");
@@ -34,30 +29,36 @@ export async function selectDenylistApps() {
checkbox.checked = true;
}
});
await execCommand('touch "/data/adb/tricky_store/target_from_denylist"');
console.log("Denylist apps selected successfully.");
} catch (error) {
toast("Failed to read DenyList!");
console.error("Failed to select Denylist apps:", error);
}
}
});
// Function to read the exclude list and uncheck corresponding apps
export async function deselectUnnecessaryApps() {
document.getElementById("deselect-unnecessary").addEventListener("click", async () => {
try {
const fileCheck = await execCommand(`test -f ${basePath}common/tmp/exclude-list && echo "exists" || echo "not found"`);
if (fileCheck.trim() === "not found") {
setTimeout(async () => {
await execCommand(`sh ${basePath}common/get_extra.sh --unnecessary`);
}, 0);
console.log("Exclude list not found. Running the unnecessary apps script.");
} else {
setTimeout(async () => {
await execCommand(`sh ${basePath}common/get_extra.sh --xposed`);
}, 0);
console.log("Exclude list found. Running xposed script.");
}
await new Promise(resolve => setTimeout(resolve, 100));
const result = await execCommand(`cat ${basePath}common/tmp/exclude-list`);
const UnnecessaryApps = result.split("\n").map(app => app.trim()).filter(Boolean);
const excludeList = await fetch("https://raw.githubusercontent.com/KOWX712/Tricky-Addon-Update-Target-List/main/more-exclude.json")
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
return data.data
.flatMap(category => category.apps)
.map(app => app['package-name'])
.join('\n');
})
.catch(error => {
toast("Failed to download unnecessary apps!");
throw error;
});
const xposed = await execCommand(`sh ${basePath}common/get_extra.sh --xposed`);
const UnnecessaryApps = excludeList.split("\n").map(app => app.trim()).filter(Boolean).concat(xposed.split("\n").map(app => app.trim()).filter(Boolean));
const apps = document.querySelectorAll(".card");
apps.forEach(app => {
const contentElement = app.querySelector(".content");
@@ -69,43 +70,286 @@ export async function deselectUnnecessaryApps() {
});
console.log("Unnecessary apps deselected successfully.");
} catch (error) {
console.error("Failed to deselect unnecessary apps:", error);
toast("Failed to get unnecessary apps!");
console.error("Failed to get unnecessary apps:", error);
}
});
// Function to backup previous keybox and set new keybox
async function setKeybox(content) {
try {
await execCommand(`
mv -f /data/adb/tricky_store/keybox.xml /data/adb/tricky_store/keybox.xml.bak 2>/dev/null
echo '${content}' > /data/adb/tricky_store/keybox.xml
chmod 644 /data/adb/tricky_store/keybox.xml
`);
return true;
} catch (error) {
console.error("Failed to set keybox:", error);
return false;
}
}
// Function to replace aosp kb
export async function aospkb() {
try {
const sourcePath = `${basePath}common/.default`;
const destinationPath = "/data/adb/tricky_store/keybox.xml";
await execCommand(`xxd -r -p ${sourcePath} | base64 -d > ${destinationPath}`);
const source = await execCommand(`xxd -r -p ${basePath}common/.default | base64 -d`);
const result = await setKeybox(source);
if (result) {
console.log("AOSP keybox copied successfully.");
showPrompt("prompt.aosp_key_set");
} catch (error) {
console.error("Failed to copy AOSP keybox:", error);
} else {
showPrompt("prompt.key_set_error", false);
}
}
// Function to replace valid kb
export async function extrakb() {
setTimeout(async () => {
await execCommand(`sh ${basePath}common/get_extra.sh --kb`);
}, 100);
const sourcePath = `${basePath}common/tmp/.extra`;
const destinationPath = "/data/adb/tricky_store/keybox.xml";
try {
await new Promise(resolve => setTimeout(resolve, 300));
const fileExists = await execCommand(`[ -f ${sourcePath} ] && echo "exists"`);
if (fileExists.trim() !== "exists") {
throw new Error(".extra file not found");
document.getElementById("validkb").addEventListener("click", async () => {
fetch("https://raw.githubusercontent.com/KOWX712/Tricky-Addon-Update-Target-List/main/.extra")
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
await execCommand(`xxd -r -p ${sourcePath} | base64 -d > ${destinationPath}`);
console.log("Valid keybox copied successfully.");
showPrompt("prompt.valid_key_set");
} catch (error) {
console.error("Failed to copy valid keybox:", error);
await aospkb();
showPrompt("prompt.no_valid_fallback", false);
return response.text();
})
.then(async data => {
if (!data.trim()) {
await aospkb();
showPrompt("prompt.no_valid_fallback", false);
return;
}
try {
const hexBytes = new Uint8Array(data.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
const decodedHex = new TextDecoder().decode(hexBytes);
const source = atob(decodedHex);
const result = await setKeybox(source);
if (result) {
showPrompt("prompt.valid_key_set");
} else {
throw new Error("Failed to copy valid keybox");
}
} catch (error) {
throw new Error("Failed to decode keybox data");
}
})
.catch(async error => {
showPrompt("prompt.no_internet", false);
});
});
// Add file selector dialog elements dynamically
const fileSelector = document.createElement('div');
fileSelector.className = 'file-selector-overlay';
fileSelector.innerHTML = `
<div class="file-selector">
<div class="file-selector-header">
<button class="back-button">
<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M400-80 0-480l400-400 56 57-343 343 343 343-56 57Z"/></svg>
</button>
<div class="current-path">/storage/emulated/0/Download</div>
<button class="close-selector">&#x2715;</button>
</div>
<div class="file-list"></div>
</div>
`;
document.body.appendChild(fileSelector);
// Add styles for animations
const style = document.createElement('style');
style.textContent = `
.file-selector-overlay {
transition: opacity 0.3s ease;
opacity: 0;
}
}
.file-selector-overlay.visible {
opacity: 1;
}
.file-list {
transition: transform 0.3s ease, opacity 0.3s ease;
}
.file-list.switching {
transform: scale(0.95);
opacity: 0;
}
`;
document.head.appendChild(style);
let currentPath = '/storage/emulated/0/Download';
function updateCurrentPath() {
const currentPathElement = document.querySelector('.current-path');
const segments = currentPath.split('/').filter(Boolean);
// Create spans with data-path attribute for each segment
const pathHTML = segments.map((segment, index) => {
const fullPath = '/' + segments.slice(0, index + 1).join('/');
return `<span class="path-segment" data-path="${fullPath}">${segment}</span>`;
}).join('<span class="separator"></span>');
currentPathElement.innerHTML = pathHTML;
currentPathElement.scrollTo({
left: currentPathElement.scrollWidth,
behavior: 'smooth'
});
}
// Function to list files in directory
async function listFiles(path, skipAnimation = false) {
const fileList = document.querySelector('.file-list');
if (!skipAnimation) {
fileList.classList.add('switching');
await new Promise(resolve => setTimeout(resolve, 150));
}
try {
const result = await execCommand(`find "${path}" -maxdepth 1 -type f -name "*.xml" -o -type d ! -name ".*" | sort`);
const items = result.split('\n').filter(Boolean).map(item => ({
path: item,
name: item.split('/').pop(),
isDirectory: !item.endsWith('.xml')
}));
fileList.innerHTML = '';
// Add back button item if not in root directory
if (currentPath !== '/storage/emulated/0') {
const backItem = document.createElement('div');
backItem.className = 'file-item';
backItem.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24">
<path d="M141-160q-24 0-42-18.5T81-220v-520q0-23 18-41.5t42-18.5h280l60 60h340q23 0 41.5 18.5T881-680v460q0 23-18.5 41.5T821-160H141Z"/>
</svg>
<span>..</span>
`;
backItem.addEventListener('click', async () => {
currentPath = currentPath.split('/').slice(0, -1).join('/');
if (currentPath === '') currentPath = '/storage/emulated/0';
const currentPathElement = document.querySelector('.current-path');
currentPathElement.innerHTML = currentPath.split('/').filter(Boolean).join('<span class="separator"></span>');
currentPathElement.scrollTo({
left: currentPathElement.scrollWidth,
behavior: 'smooth'
});
await listFiles(currentPath);
});
fileList.appendChild(backItem);
}
items.forEach(item => {
if (item.path === path) return;
const itemElement = document.createElement('div');
itemElement.className = 'file-item';
itemElement.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24">
${item.isDirectory ?
'<path d="M141-160q-24 0-42-18.5T81-220v-520q0-23 18-41.5t42-18.5h280l60 60h340q23 0 41.5 18.5T881-680v460q0 23-18.5 41.5T821-160H141Z"/>' :
'<path d="M320-240h320v-80H320v80Zm0-160h320v-80H320v80ZM240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z"/>'}
</svg>
<span>${item.name}</span>
`;
itemElement.addEventListener('click', async () => {
if (item.isDirectory) {
currentPath = item.path;
const currentPathElement = document.querySelector('.current-path');
currentPathElement.innerHTML = currentPath.split('/').filter(Boolean).join('<span class="separator"></span>');
currentPathElement.scrollTo({
left: currentPathElement.scrollWidth,
behavior: 'smooth'
});
await listFiles(item.path);
} else {
const source = await execCommand(`cat "${item.path}"`);
const result = await setKeybox(source);
if (result) {
fileSelector.style.display = 'none';
showPrompt('prompt.custom_key_set');
} else {
showPrompt('prompt.custom_key_set_error');
}
}
});
fileList.appendChild(itemElement);
});
if (!skipAnimation) {
fileList.classList.remove('switching');
}
} catch (error) {
console.error('Error listing files:', error);
if (!skipAnimation) {
fileList.classList.remove('switching');
}
}
applyRippleEffect();
updateCurrentPath();
}
// Update click handler to use data-path attribute
document.querySelector('.current-path').addEventListener('click', async (event) => {
const segment = event.target.closest('.path-segment');
if (!segment) return;
const targetPath = segment.dataset.path;
if (!targetPath || targetPath === currentPath) return;
// Return if already at /storage/emulated/0
const clickedSegment = segment.textContent;
if ((clickedSegment === 'storage' || clickedSegment === 'emulated') &&
currentPath === '/storage/emulated/0') {
return;
}
// Always stay within /storage/emulated/0
if (targetPath.split('/').length <= 3) {
currentPath = '/storage/emulated/0';
} else {
currentPath = targetPath;
}
updateCurrentPath();
await listFiles(currentPath);
});
// Back button handler
document.querySelector('.back-button').addEventListener('click', async () => {
if (currentPath === '/storage/emulated/0') return;
currentPath = currentPath.split('/').slice(0, -1).join('/');
if (currentPath === '') currentPath = '/storage/emulated/0';
const currentPathElement = document.querySelector('.current-path');
currentPathElement.innerHTML = currentPath.split('/').filter(Boolean).join('<span class="separator"></span>');
currentPathElement.scrollTo({
left: currentPathElement.scrollWidth,
behavior: 'smooth'
});
await listFiles(currentPath);
});
// Close custom keybox selector
document.querySelector('.close-selector').addEventListener('click', () => {
fileSelector.classList.remove('visible');
document.body.classList.remove("no-scroll");
setTimeout(() => {
fileSelector.style.display = 'none';
}, 300);
});
fileSelector.addEventListener('click', (event) => {
if (event.target === fileSelector) {
fileSelector.classList.remove('visible');
document.body.classList.remove("no-scroll");
setTimeout(() => {
fileSelector.style.display = 'none';
}, 300);
}
});
// Open custom keybox selector
document.getElementById('customkb').addEventListener('click', async () => {
fileSelector.style.display = 'flex';
document.body.classList.add("no-scroll");
fileSelector.offsetHeight;
fileSelector.classList.add('visible');
currentPath = '/storage/emulated/0/Download';
const currentPathElement = document.querySelector('.current-path');
currentPathElement.innerHTML = currentPath.split('/').filter(Boolean).join('<span class="separator"></span>');
currentPathElement.scrollTo({
left: currentPathElement.scrollWidth,
behavior: 'smooth'
});
await listFiles(currentPath, true);
});

View File

@@ -44,10 +44,7 @@ clearBtn.addEventListener("click", () => {
// Function to toggle menu option
export function setupMenuToggle() {
let menuOpen = false;
let menuAnimating = false;
menuButton.addEventListener('click', (event) => {
if (menuAnimating) return;
event.stopPropagation();
if (menuOptions.classList.contains('visible')) {
closeMenu();
@@ -73,31 +70,15 @@ export function setupMenuToggle() {
});
});
function openMenu() {
menuAnimating = true;
menuOptions.style.display = 'block';
setTimeout(() => {
menuOptions.classList.remove('hidden');
menuOptions.classList.add('visible');
menuIcon.classList.add('menu-open');
menuIcon.classList.remove('menu-closed');
menuOverlay.style.display = 'flex';
menuOpen = true;
menuAnimating = false;
}, 10);
}
function closeMenu() {
if (menuOptions.classList.contains('visible')) {
menuAnimating = true;
menuOptions.classList.remove('visible');
menuOptions.classList.add('hidden');
menuIcon.classList.remove('menu-open');
menuIcon.classList.add('menu-closed');
menuOverlay.style.display = 'none';
setTimeout(() => {
menuOptions.style.display = 'none';
menuOpen = false;
menuAnimating = false;
}, 200);
}
menuOptions.classList.remove('visible');
menuIcon.classList.remove('menu-open');
menuOverlay.style.display = 'none';
}
}

View File

@@ -0,0 +1,347 @@
import { basePath, execCommand, showPrompt } from './main.js';
const overlay = document.getElementById('security-patch-overlay');
const card = document.getElementById('security-patch-card');
const advancedToggle = document.getElementById('advanced-mode');
const normalInputs = document.getElementById('normal-mode-inputs');
const advancedInputs = document.getElementById('advanced-mode-inputs');
const allPatchInput = document.getElementById('all-patch');
const bootPatchInput = document.getElementById('boot-patch');
const systemPatchInput = document.getElementById('system-patch');
const vendorPatchInput = document.getElementById('vendor-patch');
const getButton = document.getElementById('get-patch');
const autoButton = document.getElementById('auto-config');
const saveButton = document.getElementById('save-patch');
// Show security patch dialog
function showSecurityPatchDialog() {
document.body.classList.add("no-scroll");
overlay.style.display = 'block';
card.style.display = 'block';
setTimeout(() => {
overlay.style.opacity = '1';
card.style.opacity = '1';
loadCurrentConfig();
}, 10);
}
// Hide security patch dialog
function hideSecurityPatchDialog() {
document.body.classList.remove("no-scroll");
overlay.style.opacity = '0';
card.style.opacity = '0';
setTimeout(() => {
overlay.style.display = 'none';
card.style.display = 'none';
}, 200);
}
// Function to handle security patch operation
async function handleSecurityPatch(mode, value = null) {
if (mode === 'disable') {
try {
await execCommand(`
sed -i "s/^auto_config=.*/auto_config=0/" /data/adb/security_patch
rm -f /data/adb/tricky_store/security_patch.txt
`);
showPrompt('security_patch.value_empty');
return true;
} catch (error) {
showPrompt('security_patch.save_failed', false);
return false;
}
} else if (mode === 'manual') {
try {
await execCommand(`
sed -i "s/^auto_config=.*/auto_config=0/" /data/adb/security_patch
echo "${value}" > /data/adb/tricky_store/security_patch.txt
chmod 644 /data/adb/tricky_store/security_patch.txt
`);
showPrompt('security_patch.save_success');
return true;
} catch (error) {
showPrompt('security_patch.save_failed', false);
return false;
}
}
}
// Load current configuration
async function loadCurrentConfig() {
try {
const result = await execCommand('cat /data/adb/security_patch');
if (result) {
const lines = result.split('\n');
let autoConfig = '1', allValue = '0', systemValue = '0', bootValue = '0', vendorValue = '0';
for (const line of lines) {
if (line.startsWith('auto_config=')) {
autoConfig = line.split('=')[1];
}
}
if (autoConfig === '1') {
allValue = null;
systemValue = null;
bootValue = null;
vendorValue = null;
overlay.classList.add('hidden');
} else {
// Read values from tricky_store if auto_config is 0
const trickyResult = await execCommand('cat /data/adb/tricky_store/security_patch.txt');
if (trickyResult) {
const trickyLines = trickyResult.split('\n');
for (const line of trickyLines) {
if (line.startsWith('all=')) {
allValue = line.split('=')[1] || null;
if (allValue !== null) allPatchInput.value = allValue;
} else {
allValue = null;
}
if (line.startsWith('system=')) {
systemValue = line.split('=')[1] || null;
if (systemValue !== null) systemPatchInput.value = systemValue;
} else {
systemValue = null;
}
if (line.startsWith('boot=')) {
bootValue = line.split('=')[1] || null;
if (bootValue !== null) bootPatchInput.value = bootValue;
} else {
bootValue = null;
}
if (line.startsWith('vendor=')) {
vendorValue = line.split('=')[1] || null;
if (vendorValue !== null) vendorPatchInput.value = vendorValue;
} else {
vendorValue = null;
}
}
}
overlay.classList.add('hidden');
}
// Check if in advanced mode
if (autoConfig === '0' && allValue === null && (bootValue || systemValue || vendorValue)) {
checkAdvanced(true);
}
}
} catch (error) {
console.error('Failed to load security patch config:', error);
}
}
// Function to check advanced mode
function checkAdvanced(shouldCheck) {
if (shouldCheck) {
advancedToggle.checked = true;
normalInputs.classList.add('hidden');
advancedInputs.classList.remove('hidden');
} else {
advancedToggle.checked = false;
normalInputs.classList.remove('hidden');
advancedInputs.classList.add('hidden');
}
}
// Unified date formatting function
window.formatDate = function(input, type) {
let value = input.value.replace(/-/g, '');
let formatted = value.slice(0, 4);
// Allow 'no' input
if (value === 'no') {
input.value = 'no';
input.setSelectionRange(2, 2);
return 'no';
}
if (value.startsWith('n')) {
// Only allow 'o' after 'n'
if (value.length > 1 && value[1] !== 'o') {
value = 'n';
}
formatted = value.slice(0, 2);
if (value.length > 2) {
input.value = formatted;
input.setSelectionRange(2, 2);
return formatted;
}
} else {
// Only allow numbers if not starting with 'n'
const numbersOnly = value.replace(/\D/g, '');
if (numbersOnly !== value) {
input.value = numbersOnly;
value = numbersOnly;
formatted = numbersOnly.slice(0, 4);
}
// Add hyphens on 5th and 7th character
if (value.length >= 4) {
formatted += '-'+ value.slice(4, 6);
}
if (value.length >= 6) {
formatted += '-'+ value.slice(6, 8);
}
}
// Handle backspace/delete
const lastChar = value.slice(-1);
if (lastChar === '-' || (isNaN(lastChar) && !['n'].includes(lastChar))) {
formatted = formatted.slice(0, -1);
}
// Update input value
const startPos = input.selectionStart;
input.value = formatted;
const newLength = formatted.length;
const shouldMoveCursor = (value.length === 4 || value.length === 6) && newLength > startPos;
input.setSelectionRange(shouldMoveCursor ? newLength : startPos, shouldMoveCursor ? newLength : startPos);
return formatted;
}
// Validate date format YYYY-MM-DD
function isValidDateFormat(date) {
if (date === 'no') return true;
const regex = /^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$/;
return regex.test(date);
}
// Validate 6-digit format YYYYMM
function isValid6Digit(value) {
if (value === 'prop') return true;
const regex = /^\d{6}$/;
return regex.test(value);
}
// Validate 8-digit format YYYYMMDD
function isValid8Digit(value) {
const regex = /^\d{8}$/;
return regex.test(value);
}
// Initialize event listeners
export function securityPatch() {
document.getElementById("security-patch").addEventListener("click", showSecurityPatchDialog);
// Toggle advanced mode
advancedToggle.addEventListener('change', () => {
normalInputs.classList.toggle('hidden');
advancedInputs.classList.toggle('hidden');
});
// Close on overlay click
overlay.addEventListener('click', (e) => {
if (e.target === overlay) {
hideSecurityPatchDialog();
}
});
// Auto config button
autoButton.addEventListener('click', async () => {
try {
const output = await execCommand(`sh ${basePath}common/get_extra.sh --security-patch`);
if (output.trim() === "not set") {
showPrompt('security_patch.auto_failed', false);
} else {
await execCommand(`sed -i "s/^auto_config=.*/auto_config=1/" /data/adb/security_patch`);
// Reset inputs
allPatchInput.value = '';
systemPatchInput.value = '';
bootPatchInput.value = '';
vendorPatchInput.value = '';
checkAdvanced(false);
showPrompt('security_patch.auto_success');
}
} catch (error) {
showPrompt('security_patch.auto_failed', false);
}
hideSecurityPatchDialog();
loadCurrentConfig();
});
// Save button
saveButton.addEventListener('click', async () => {
if (!advancedToggle.checked) {
// Normal mode validation
const allValue = allPatchInput.value.trim();
if (!allValue) {
// Save empty value to disable auto config
await handleSecurityPatch('disable');
hideSecurityPatchDialog();
return;
}
if (!isValid8Digit(allValue)) {
showPrompt('security_patch.invalid_all', false);
return;
}
const value = `all=${allValue}`;
const result = await handleSecurityPatch('manual', value);
if (result) {
// Reset inputs
systemPatchInput.value = '';
bootPatchInput.value = '';
vendorPatchInput.value = '';
}
} else {
// Advanced mode validation
const bootValue = formatDate(bootPatchInput, 'boot');
const systemValue = systemPatchInput.value.trim();
const vendorValue = vendorPatchInput.value.trim();
if (!bootValue && !systemValue && !vendorValue) {
// Save empty values to disable auto config
await handleSecurityPatch('disable');
hideSecurityPatchDialog();
return;
}
if (systemValue && !isValid6Digit(systemValue)) {
showPrompt('security_patch.invalid_system', false);
return;
}
if (bootValue && !isValidDateFormat(bootValue)) {
showPrompt('security_patch.invalid_boot', false);
return;
}
if (vendorValue && !isValidDateFormat(vendorValue)) {
showPrompt('security_patch.invalid_vendor', false);
return;
}
const config = [
systemValue ? `system=${systemValue}` : '',
bootValue ? `boot=${bootValue}` : '',
vendorValue ? `vendor=${vendorValue}` : ''
].filter(Boolean);
const value = config.filter(Boolean).join('\n');
const result = await handleSecurityPatch('manual', value);
if (result) {
// Reset inputs
allPatchInput.value = '';
}
}
hideSecurityPatchDialog();
loadCurrentConfig();
});
// Get button
getButton.addEventListener('click', async () => {
try {
showPrompt('security_patch.fetching');
await new Promise(resolve => setTimeout(resolve, 200));
const output = await execCommand(`sh ${basePath}common/get_extra.sh --get-security-patch`);
showPrompt('security_patch.fetched', true, 1000);
checkAdvanced(true);
systemPatchInput.value = 'prop';
bootPatchInput.value = output;
vendorPatchInput.value = output;
} catch (error) {
showPrompt('security_patch.get_failed', false);
}
});
}

View File

@@ -0,0 +1,187 @@
import { basePath, execCommand, showPrompt, noConnection, linkRedirect } from './main.js';
import { updateCard } from './applist.js';
const updateCardText = document.getElementById('redirect-to-release');
const UpdateMenu = document.querySelector('.update-overlay');
const closeUpdate = document.querySelector('.close-update');
const releaseNotes = document.querySelector('.changelog');
const installButton = document.querySelector('.install');
const rebootButton = document.querySelector('.reboot');
let remoteVersionCode, remoteVersion, zipURL, changelogURL, downloading = false;
// Function to download file
function downloadFile(targetURL, fileName) {
return new Promise((resolve, reject) => {
fetch(targetURL)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.blob();
})
.then(blob => {
const file = new File([blob], fileName, { type: blob.type });
const reader = new FileReader();
reader.onload = async function() {
const base64Data = reader.result.split(',')[1];
try {
await execCommand(`echo ${base64Data} | base64 -d > ${basePath}common/tmp/${fileName}`);
resolve();
} catch (error) {
reject(error);
}
};
reader.readAsDataURL(file);
})
.catch(reject);
});
}
// Function to check for updates
export async function updateCheck() {
try {
const response = await fetch("https://raw.githubusercontent.com/KOWX712/Tricky-Addon-Update-Target-List/main/update.json");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
noConnection.style.display = "none";
const data = await response.json();
remoteVersionCode = data.versionCode;
remoteVersion = data.version;
zipURL = data.zipUrl;
changelogURL = data.changelog;
const updateAvailable = await execCommand(`sh ${basePath}common/get_extra.sh --check-update ${remoteVersionCode}`);
if (updateAvailable.includes("update")) {
showPrompt("prompt.new_update", true, 1500);
updateCard.style.display = "flex";
setupUpdateMenu();
}
} catch (error) {
console.error("Error fetching JSON or executing command:", error);
showPrompt("prompt.no_internet", false);
noConnection.style.display = "flex";
}
}
// Function to render changelog
async function renderChangelog() {
const changelog = await execCommand(`sh ${basePath}common/get_extra.sh --release-note ${remoteVersion}`);
window.linkRedirect = linkRedirect;
marked.setOptions({
sanitize: true,
walkTokens(token) {
if (token.type === 'link') {
const href = token.href;
token.href = "javascript:void(0);";
token.type = "html";
token.text = `<a href="javascript:void(0);" onclick="linkRedirect('${href}')">${token.text}</a>`;
}
}
});
const cleanedChangelog = changelog
.split('\n')
.filter(line => line.trim() !== '')
.join('\n');
const formattedChangelog = marked.parse(cleanedChangelog);
releaseNotes.innerHTML = formattedChangelog;
}
// Function to setup update menu
function setupUpdateMenu() {
function openUpdateMenu() {
UpdateMenu.style.display = "flex";
setTimeout(async () => {
UpdateMenu.style.opacity = "1";
}, 10);
document.body.classList.add("no-scroll");
}
function closeUpdateMenu() {
UpdateMenu.style.opacity = "0";
document.body.classList.remove("no-scroll");
setTimeout(async () => {
UpdateMenu.style.display = "none";
}, 200);
}
// Update card
updateCard.addEventListener('click', async () => {
try {
const module = await execCommand(`
[ -f ${basePath}common/tmp/module.zip ] || echo "noModule"
[ -f ${basePath}common/tmp/changelog.md ] || echo "noChangelog"
[ ! -f /data/adb/modules/TA_utl/update ] || echo "updated"
`);
if (module.trim().includes("updated")) {
installButton.style.display = "none";
rebootButton.style.display = "flex";
openUpdateMenu();
} else if (module.trim().includes("noChangelog")) {
showPrompt("prompt.downloading");
await downloadFile(changelogURL, "changelog.md");
await renderChangelog();
openUpdateMenu();
setTimeout(() => {
updateCard.click();
}, 200);
} else if (module.trim().includes("noModule")) {
if (downloading) return;
downloading = true;
try {
await execCommand(`sh ${basePath}common/get_extra.sh --get-update ${zipURL}`);
showPrompt("prompt.downloaded");
installButton.style.display = "flex";
downloading = false;
} catch (error) {
showPrompt("prompt.download_fail", false);
downloading = false;
}
} else {
installButton.style.display = "flex";
await renderChangelog();
openUpdateMenu();
}
} catch (error) {
showPrompt("prompt.download_fail", false);
console.error('Error download module update:', error);
}
});
// Close update menu
closeUpdate.addEventListener("click", closeUpdateMenu);
UpdateMenu.addEventListener("click", (event) => {
if (event.target === UpdateMenu) {
closeUpdateMenu();
}
});
// Install button
installButton.addEventListener('click', async () => {
try {
showPrompt("prompt.installing");
setTimeout(async () => {
await execCommand(`su -c 'sh ${basePath}common/get_extra.sh --install-update'`);
showPrompt("prompt.installed");
installButton.style.display = "none";
rebootButton.style.display = "flex";
}, 300);
} catch (error) {
showPrompt("prompt.install_fail", false);
console.error('Fail to execute installation script:', error);
}
});
// Reboot button
rebootButton.addEventListener('click', async () => {
try {
showPrompt("prompt.rebooting");
setTimeout(async () => {
await execCommand("svc power reboot");
}, 1000);
} catch (error) {
showPrompt("prompt.reboot_fail", false);
console.error('Fail to reboot:', error);
}
});
}

View File

@@ -41,6 +41,7 @@
border: none;
font-size: 18px;
color: #ccc;
user-select: none;
}
.link,
@@ -53,23 +54,34 @@
#module_name_line1 {
font-size: 26px;
user-select: none;
}
#module_name_line2 {
font-size: 22px;
user-select: none;
}
#authored {
font-size: 14px;
user-select: none;
}
#disclaimer {
font-style: italic;
font-family: serif;
width: calc(100% - 80px);
padding: 8px 10px;
left: 0;
right: 0;
margin: auto;
border-radius: 10px;
background-color: #F5F5F5;
}
#acknowledgment {
font-weight: bold;
font-size: 18px;
user-select: none;
}
.link-icon {
@@ -93,10 +105,7 @@
background-color: #38A7ED;
color: #fff;
fill: #fff;
}
#telegram:active {
background-color: #1A78B3;
user-select: none;
}
#github {
@@ -105,13 +114,9 @@
background-color: #606060;
color: #fff;
fill: #fff;
user-select: none;
}
#github:active {
background-color: #4D4D4D;
}
#link-text {
font-size: 17px;
font-weight: bold;
@@ -121,4 +126,8 @@
.about-menu {
background-color: #343434;
}
#disclaimer {
background-color: #6E6E6E;
}
}

View File

@@ -16,50 +16,221 @@
align-items: center;
background-color: #DCDCDC;
border: none;
border-radius: 10px;
border-radius: 12px;
box-sizing: border-box;
margin: 0 auto;
margin-bottom: 10px;
outline: none;
padding: 12px;
width: calc(100% - 30px);
width: calc(100% - 5px);
max-width: 900px;
transition: background-color 0.2s ease;
}
#update-available {
font-size: 20px;
font-weight: bold;
text-align: center;
margin-top: 15px;
margin-bottom: 0;
user-select: none;
}
#redirect-to-release {
text-align: center;
margin-top: 5px;
margin-bottom: 15px;
user-select: none;
}
.update-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1800;
justify-content: center;
align-items: center;
opacity: 0;
transition: opacity 0.2s ease;
}
.update-menu {
position: relative;
width: calc(90% - 60px);
max-width: 800px;
background-color: white;
padding: 30px;
border-radius: 15px;
text-align: left;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
transition: opacity 0.2s ease;
}
.close-update {
position: absolute;
top: 15px;
right: 12px;
background: none;
border: none;
font-size: 20px;
color: #ccc;
}
.update-content h3 {
font-size: 22px;
margin: 0;
}
.changelog {
max-height: 65vh;
overflow-y: auto;
}
.changelog ul {
padding-left: 0;
margin: 0;
}
.changelog ul li {
margin-left: 15px;
margin-bottom: 5px;
list-style-type: disc;
}
.changelog a {
color: #6E6E6E;
cursor: none;
}
.changelog a:active {
color: blue;
}
.update-button-container {
width: 100%;
margin-top: 20px;
display: flex;
justify-content: center;
}
.install,
.reboot {
display: none;
justify-content: center;
font-weight: bold;
background-color: #ddd;
width: 100%;
border: none;
padding: 12px;
border-radius: 12px;
font-size: 18px;
user-select: none;
}
.reboot {
color: #fff;
background-color: #007bff;
}
.card {
background-color: white;
background-color: #fff;
border: none;
box-sizing: border-box;
border-radius: 12px;
margin: 0 auto;
margin-bottom: 10px;
outline: none;
padding: 12px;
width: calc(100% - 30px);
width: calc(100% - 5px);
max-width: 900px;
transition: background-color 0.2s ease;
}
.card:active,
.update-card:active {
background-color: #C8C8C8;
}
.content {
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
}
.mode {
display: none;
flex-direction: row;
gap: 10px;
padding: 10px 12px;
position: absolute;
left: 0;
right: 0;
margin: auto;
width: fit-content;
background-color: #B1B1B1;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
border: 1px solid #ccc;
border-radius: 50px 50px;
opacity: 0;
transform: scale(0);
transition: all 0.2s ease;
z-index: 1200;
}
.mode.show {
opacity: 1;
transform: scale(1);
}
.mode-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: none;
z-index: 1100;
}
.mode-switch {
position: relative;
display: inline-block;
}
.mode-input {
opacity: 0;
position: absolute;
width: 0;
height: 0;
}
.status-indicator {
display: flex;
justify-content: center;
align-items: center;
width: 40px;
height: 40px;
border-radius: 50px 50px;
box-sizing: border-box;
transition: all 0.2s ease;
border: 3px solid transparent;
}
#normal-indicator {
background-color: #007bff;
}
#hack-indicator {
background-color: #FF8400;
}
#generate-indicator {
background-color: #36DB2B;
}
.mode-input[type="radio"]:checked ~ .mode-icon .status-indicator {
transform: scale(1.1);
border-color: #fff;
}
.name {
@@ -69,11 +240,92 @@
max-width: calc(100% - 30px);
overflow-wrap: break-word;
word-break: break-word;
user-select: none;
}
.checkbox-wrapper {
position: relative;
display: inline-block;
width: 20px;
height: 20px;
margin-left: auto;
}
.checkbox {
margin-left: auto;
transform: scale(1.15);
opacity: 0;
position: absolute;
width: 0;
height: 0;
}
.custom-checkbox {
position: relative;
display: inline-block;
width: 100%;
height: 100%;
border: 2px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
transition: border-color 1s ease, transform 0.3s ease, background-color 0.2s ease;
}
.tick-symbol {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0);
opacity: 0;
transition: transform 0.2s ease-out, opacity 0.3s ease;
}
.checkbox:checked + .custom-checkbox {
border-color: #007bff;
background-color: #007bff;
transition: border-color 0.1s ease;
animation: checked-bounce 0.3s ease-out;
}
.checkbox-checked-generate:checked + .custom-checkbox {
border-color: #36DB2B;
background-color: #36DB2B;
}
.checkbox-checked-hack:checked + .custom-checkbox {
border-color: #FF8400;
background-color: #FF8400;
}
.checkbox:not(:checked) + .custom-checkbox {
animation: unchecked-bounce 0.3s ease-out;
}
.checkbox:checked + .custom-checkbox .tick-symbol {
transform: translate(-50%, -50%) scale(1);
opacity: 1;
}
@keyframes checked-bounce {
0% {
transform: scale(1);
}
50% {
transform: scale(0.8);
}
100% {
transform: scale(1);
}
}
@keyframes unchecked-bounce {
0% {
transform: scale(1);
}
50% {
transform: scale(0.8);
}
100% {
transform: scale(1);
}
}
@media (prefers-color-scheme: dark) {
@@ -85,8 +337,21 @@
background-color: #4D4D4D;
}
.card:active,
.update-card:active {
background-color: #616161;
.mode {
background-color: #343434;
border: 1px solid #6E6E6E;
}
.install {
background-color: #6E6E6E;
color: white;
}
.update-menu {
background-color: #343434;
}
.update-content a {
color: #C2C2C2;
}
}

View File

@@ -15,16 +15,16 @@
.boot-hash-card {
position: fixed;
top: 30%;
top: 10%;
left: 50%;
transform: translate(-50%, -50%);
width: 80vw;
max-width: 600px;
transform: translateX(-50%);
width: calc(90% - 60px);
max-width: 300px;
background-color: #fff;
border-radius: 18px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
z-index: 1200;
padding: 20px;
padding: 30px;
display: none;
flex-direction: column;
gap: 15px;
@@ -42,36 +42,38 @@
opacity: 1;
}
.input-box {
width: calc(100% - 20px);
height: 100px;
resize: none;
padding: 9px;
font-size: 16px;
background-color: #FFF;
border: 1px solid #ccc;
border-radius: 10px;
.boot-hash-title {
width: 100%;
font-size: 26px;
text-align: center;
user-select: none;
}
.button-container {
display: flex;
justify-content: flex-start;
.boot-hash-input {
width: 100%;
height: 100px;
font-size: 16px;
padding: 10px;
background-color: #F5F5F5;
border: 1px solid #ccc;
border-radius: 10px;
box-sizing: border-box;
outline-color: #007bff;
resize: none;
}
.boot-hash-save-button {
padding: 10px 20px;
width: 100%;
padding: 12px;
border: none;
border-radius: 38px;
font-size: 18px;
border-radius: 12px;
font-size: 20px;
font-weight: bold;
background-color: #007bff;
color: white;
margin-left: auto;
transition: background-color 0.2s ease;
}
.boot-hash-save-button:active {
background-color: #003d80;
position: relative;
overflow: hidden;
user-select: none;
}
@media (prefers-color-scheme: dark) {
@@ -79,9 +81,9 @@
background-color: #343434;
}
.input-box {
.boot-hash-input {
background-color: #232323;
color: #fff;
background-color: #343434;
border: 1px solid #6E6E6E;
}
}

View File

@@ -12,10 +12,10 @@ body {
display: flex;
justify-content: center;
position: fixed;
bottom: -70px;
bottom: 50px;
left: 50%;
transform: translateX(-50%);
z-index: 3;
z-index: 10;
}
.floating-btn {
@@ -27,15 +27,13 @@ body {
display: flex;
justify-content: center;
align-items: center;
opacity: 0;
padding: 10px 20px;
font-size: 20px;
font-size: 22px;
font-weight: bold;
transition: transform 0.3s ease-in-out, background-color 0.2s ease;
transition: transform 0.4s ease;
border-radius: 50px 50px;
}
.floating-btn:active {
background-color: #003d80;
user-select: none;
}
.prompt {
@@ -48,53 +46,17 @@ body {
color: white;
font-size: 15px;
padding: 5px 10px;
z-index: 2000;
z-index: 2050;
width: auto;
max-width: calc(100% - 40px);
transform: translateY(100%);
transition: transform 0.5s ease;
}
.prompt.visible {
animation: YbounceIn 0.4s forwards;
}
.prompt.hidden {
animation: YbounceOut 0.4s forwards;
transition: transform 0.2s ease;
}
.prompt.error {
background-color: #f44336;
}
@keyframes YbounceIn {
0% {
transform: translateY(100%);
}
50% {
transform: translateY(-80%);
}
100% {
transform: translateY(-60%);
}
}
@keyframes YbounceOut {
0% {
transform: translateY(-60%);
}
50% {
transform: translateY(-80%);
}
100% {
transform: translateY(100%);
}
}
.loading {
position: fixed;
top: 0;
@@ -111,32 +73,24 @@ body {
.footer {
display: flex;
justify-content: space-between;
align-items: center;
width: calc(100% - 10px);
max-width: 1100px;
padding: 25px 0;
position: relative;
margin-left: auto;
margin-right: auto;
justify-content: center;
margin-bottom: 100px;
}
.uninstall-container {
padding: 10px 10px;
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
padding: 8px;
width: calc(100% - 5px);
max-width: 900px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 8px;
background-color: #CE0000;
border-radius: 12px;
border: 3px solid #FF3636;
box-sizing: border-box;
background-color: #F5F5F5;
white-space: nowrap;
transition: background-color 0.2s ease;
}
.uninstall-container:active {
background-color: #830000;
overflow: hidden;
user-select: none;
}
.uninstall-container i {
@@ -146,16 +100,211 @@ body {
.uninstall-container span {
font-size: 16px;
font-weight: bold;
color: #fff;
color: #FF3636;
}
.uninstall-container.hidden-uninstall {
display: none;
}
.file-selector-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.5);
z-index: 2000;
justify-content: center;
align-items: center;
}
.file-selector {
width: 90%;
max-width: 600px;
height: 80vh;
background-color: #fff;
border-radius: 15px;
display: flex;
flex-direction: column;
overflow: hidden;
}
.file-selector-header {
display: flex;
align-items: center;
padding: 10px;
border-bottom: 1px solid #ccc;
}
.current-path .separator {
color: #6E6E6E;
padding: 0 4px;
}
.back-button {
background: none;
border: none;
padding: 5px;
margin-right: 10px;
fill: #6E6E6E;
user-select: none;
}
.current-path {
flex-grow: 1;
font-size: 16px;
overflow: scroll;
white-space: nowrap;
}
.close-selector {
background: none;
border: none;
font-size: 20px;
color: #ccc;
padding: 5px;
}
.file-list {
flex-grow: 1;
overflow-y: auto;
padding: 10px;
}
.file-item {
display: flex;
align-items: center;
padding: 10px;
border-radius: 8px;
background-color: #fff;
position: relative;
overflow: hidden;
user-select: none;
}
.file-item svg {
margin-right: 10px;
fill: #6E6E6E;
}
.file-item span {
flex-grow: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.permission-popup {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.85);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}
.permission-popup.hidden {
display: none;
}
.permission-content {
background-color: #fff;
padding: 20px;
border-radius: 12px;
width: 80%;
max-width: 400px;
text-align: center;
}
.permission-content h2 {
color: #333;
margin-bottom: 20px;
font-size: 18px;
}
.permission-steps {
text-align: left;
padding: 10px 20px;
}
.permission-steps p {
color: #333;
margin: 10px 0;
font-size: 16px;
}
.ripple-element {
position: relative;
overflow: hidden;
}
.ripple {
position: absolute;
border-radius: 50%;
transform: scale(0);
opacity: 1;
animation: ripple-animation ease-out forwards;
pointer-events: none;
background: rgba(0, 0, 0, 0.2);
}
.ripple.end {
opacity: 0;
}
@keyframes ripple-animation {
to {
transform: scale(3);
}
}
@media (prefers-color-scheme: dark) {
body {
background-color: #121212;
color: #fff;
}
.uninstall-container {
background-color: #121212;
}
.file-selector {
background-color: #343434;
color: #fff;
}
.file-selector-header {
border-bottom: 1px solid #6E6E6E;
}
.file-item {
background-color: #343434;
}
.current-path .separator {
color: #C2C2C2;
}
.back-button {
fill: #C2C2C2;
}
.file-item svg {
fill: #C2C2C2;
}
.permission-content {
background-color: #343434;
}
.permission-content h2,
.permission-steps p {
color: #fff;
}
}

View File

@@ -8,12 +8,13 @@
width: calc(100% - 10px);
max-width: 1100px;
background-color: #F5F5F5;
transition: transform 0.3s ease;
transition: transform 0.4s ease;
z-index: 1100;
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
user-select: none;
}
.header-block {
@@ -24,10 +25,11 @@
left: 0;
width: 100%;
z-index: 1100;
transition: transform 0.3s ease;
transition: transform 0.4s ease;
height: var(--window-inset-top);
}
#module-version,
#title {
padding-left: 5px;
font-size: 16.5px;
@@ -59,49 +61,61 @@
.language-menu {
display: flex;
padding: 3px 10px;
flex-direction: column;
position: absolute;
right: 0;
background-color: #fff;
right: 5px;
background-color: white;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
z-index: 1800;
border: 1px solid #ccc;
border-radius: 8px;
box-sizing: border-box;
opacity: 0;
visibility: hidden;
max-height: calc(100vh - 50px);
overflow-y: auto;
transform: translateY(-10px);
transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s ease;
transform: translateY(-30px) scale(0);
transform-origin: top right;
transition: all 0.2s ease;
}
.language-menu.show {
display: block;
opacity: 1;
visibility: visible;
transform: translateY(0);
transform: translateY(0) scale(1);
}
.language-option {
padding: 8px 5px;
padding: 8px 10px;
text-align: left;
background: none;
color: #333;
background-color: white;
border: none;
font-size: 16px;
color: #333;
width: 100%;
white-space: nowrap;
border-bottom: 1px solid #ccc;
transition: background-color 0.2s ease;
position: relative;
user-select: none;
}
.language-option::after {
content: "";
position: absolute;
bottom: 0;
left: 10px;
width: calc(100% - 20px);
height: 1px;
background-color: #ccc;
}
.language-option:last-child::after {
content: none;
}
.language-option:first-child {
padding-top: 10px;
}
.language-option:last-child {
border-bottom: none;
}
.language-option:active {
background-color: #C8C8C8;
padding-bottom: 10px;
}
.language-overlay {
@@ -134,7 +148,7 @@
justify-content: center;
align-items: center;
opacity: 0;
transition: opacity 0.2s ease;
transition: opacity 0.4s ease;
}
.help-overlay.show {
@@ -165,6 +179,7 @@
border: none;
font-size: 20px;
color: #ccc;
user-select: none;
}
.help-content {
@@ -175,6 +190,7 @@
.help-content p {
font-size: 26px;
user-select: none;
}
.help-content ul {
@@ -208,7 +224,6 @@
background-color: #121212;
}
.language-option,
.help-button {
color: #fff;
}
@@ -216,8 +231,10 @@
.language-icon {
fill: #eee;
}
.language-option,
.help-menu {
color: #eee;
background-color: #343434;
}
@@ -226,11 +243,7 @@
border: 1px solid #6E6E6E;
}
.language-option {
border-bottom: 1px solid #6E6E6E;
}
.language-option:active {
background-color: #616161;
.language-option::after {
background-color: #6E6E6E;
}
}

View File

@@ -6,7 +6,7 @@
width: calc(100% - 20px);
max-width: 1100px;
z-index: 1000;
transition: transform 0.3s ease;
transition: transform 0.4s ease;
margin-left: auto;
margin-right: auto;
left: 0;
@@ -40,7 +40,7 @@
outline: none;
left: 10px;
padding: 0 30px;
width: calc(100% - 10);
width: calc(100% - 80px);
}
.clear-btn {
@@ -67,7 +67,7 @@
display: none;
}
#menu-button {
.menu-button {
background-color: white;
border: 1px solid #ccc;
border-radius: 50%;
@@ -75,12 +75,14 @@
width: 48px;
display: flex;
justify-content: center;
z-index: 200;
align-items: center;
}
.menu-icon {
display: inline-block;
fill: #000;
transform: rotate(0deg);
transition: transform 0.2s ease;
}
@@ -88,42 +90,38 @@
transform: rotate(90deg);
}
.menu-icon.menu-closed {
transform: rotate(0deg);
}
.menu-options {
background-color: white;
border: 1px solid #ccc;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
display: none;
box-sizing: border-box;
display: flex;
position: absolute;
padding: 5px 12px;
top: 110%;
right: 0;
z-index: 1200;
transform: translateX(120%);
transition: transform 0.2s ease;
width: auto;
max-height: calc(100vh - 120px);
overflow-y: auto;
white-space: nowrap;
visibility: hidden;
transform: translateX(120%);
transition: all 0.2s ease;
user-select: none;
}
#select-denylist {
#select-denylist,
#security-patch {
display: none;
}
.menu-options.visible {
display: block;
visibility: visible;
transform: translateX(0);
}
.menu-options.hidden {
transform: translateX(140%);
}
.menu-options ul {
list-style: none;
margin: 0;
@@ -131,19 +129,31 @@
}
.menu-options li {
cursor: default;
padding: 12px 4px;
padding: 12px 15px;
text-align: left;
border-bottom: 1px solid #ccc;
transition: background-color 0.2s ease;
background-color: white;
}
.menu-options li:active {
background-color: #C8C8C8;
.menu-options li::after {
content: "";
position: absolute;
bottom: 0;
left: 15px;
width: calc(100% - 30px);
height: 1px;
background-color: #ccc;
}
.menu-options li:last-child::after {
content: none;
}
.menu-options li:first-child {
padding-top: 16px;
}
.menu-options li:last-child {
border-bottom: none;
padding-bottom: 16px;
}
.menu-overlay {
@@ -153,7 +163,7 @@
width: 100vw;
height: 100vh;
background-color: none;
z-index: 1000;
z-index: 100;
display: none;
}
@@ -182,10 +192,10 @@
}
.menu-options li {
border-bottom: 1px solid #6E6E6E;
background-color: #343434;
}
.menu-options li:active {
background-color: #616161;
.menu-options li::after {
background-color: #6E6E6E
}
}

View File

@@ -0,0 +1,183 @@
.security-patch-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 2000;
transition: opacity 0.2s ease;
opacity: 0;
}
.security-patch-card {
display: none;
position: fixed;
top: 10%;
left: 50%;
transform: translateX(-50%);
background-color: white;
padding: 30px;
border-radius: 15px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
z-index: 2001;
width: calc(90% - 60px);
max-width: 300px;
max-height: calc(80% - 60px);
overflow-y: auto;
transition: opacity 0.2s ease;
opacity: 0;
}
.security-patch-content {
display: flex;
flex-direction: column;
gap: 20px;
}
.security-patch-header {
width: 100%;
text-align: center;
font-size: 26px;
user-select: none;
}
.advanced-toggle {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
user-select: none;
}
.advanced-toggle .checkbox-wrapper {
position: relative;
display: inline-block;
width: 20px;
height: 20px;
margin-left: auto;
}
.advanced-toggle .checkbox {
opacity: 0;
position: absolute;
width: 0;
height: 0;
}
.advanced-toggle .custom-checkbox {
position: relative;
display: inline-block;
width: 20px;
height: 20px;
border: 2px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
transition: border-color 1s ease, transform 0.3s ease, background-color 0.4s ease;
}
.advanced-toggle .tick-symbol {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0);
opacity: 0;
transition: transform 0.2s ease-out, opacity 0.3s ease;
}
.advanced-toggle .checkbox:checked + .custom-checkbox {
border-color: #007bff;
background-color: #007bff;
transition: border-color 0.1s ease;
animation: checked-bounce 0.3s ease-out;
}
.advanced-toggle .checkbox:checked + .custom-checkbox .tick-symbol {
transform: translate(-50%, -50%) scale(1);
opacity: 1;
}
.input-group {
display: flex;
flex-direction: column;
gap: 8px;
}
.input-group label {
padding-top: 10px;
font-size: 14px;
color: #666;
user-select: none;
}
.input-group input {
padding: 15px;
background-color: #F5F5F5;
border: 1px solid #ccc;
outline-color: #007bff;
border-radius: 10px;
font-size: 16px;
}
.button-container {
display: flex;
width: 100%;
gap: 10px;
margin-top: 10px;
}
.get-button,
.auto-button,
.save-button {
width: 100%;
padding: 12px;
border: none;
border-radius: 12px;
font-size: 18px;
font-weight: bold;
transition: background-color 0.2s ease;
}
.get-button,
.auto-button {
background-color: #ddd;
user-select: none;
}
.save-button {
background-color: #007bff;
color: white;
user-select: none;
}
.hidden {
display: none;
}
@media (prefers-color-scheme: dark) {
.security-patch-overlay {
background-color: rgba(0, 0, 0, 0.8);
}
.security-patch-card {
background-color: #343434;
color: white;
}
.input-group label {
color: #ccc;
}
.input-group input {
background-color: #232323;
color: #fff;
border: 1px solid #6E6E6E;
}
.get-button,
.auto-button {
background-color: #6E6E6E;
color: white;
}
}

View File

@@ -22,6 +22,10 @@
"name": "KernelSU",
"package-name": "me.weishu.kernelsu"
},
{
"name": "KernelSU Next",
"package-name": "com.rifsxd.ksunext"
},
{
"name": "Apatch",
"package-name": "me.bmax.apatch"

View File

@@ -1,6 +1,6 @@
{
"versionCode": 290,
"version": "v2.9",
"zipUrl": "https://github.com/KOWX712/Tricky-Addon-Update-Target-List/releases/download/v2.9/TrickyAddonModule-v2.9.zip",
"versionCode": 350,
"version": "v3.5",
"zipUrl": "https://github.com/KOWX712/Tricky-Addon-Update-Target-List/releases/download/v3.5/TrickyAddonModule-v3.5.zip",
"changelog": "https://raw.githubusercontent.com/KOWX712/Tricky-Addon-Update-Target-List/main/changelog.md"
}