The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .github
    ├── back
    │   ├── build.yml
    │   └── release.yml
    └── workflows
    │   ├── build.yml
    │   └── tips.md
├── .gitignore
├── LICENSE
├── README.md
├── app-icon.png
├── app
    ├── .gitignore
    ├── build.gradle.kts
    ├── proguard-rules.pro
    └── src
    │   ├── androidTest
    │       └── java
    │       │   └── com
    │       │       └── app
    │       │           └── pakeplus
    │       │               └── ExampleInstrumentedTest.kt
    │   ├── main
    │       ├── AndroidManifest.xml
    │       ├── assets
    │       │   ├── assets
    │       │   │   ├── javascript.svg
    │       │   │   └── tauri.svg
    │       │   ├── custom.js
    │       │   ├── index.html
    │       │   ├── main.js
    │       │   ├── styles.css
    │       │   └── vConsole.js
    │       ├── ic_launcher-playstore.png
    │       ├── java
    │       │   └── com
    │       │   │   └── app
    │       │   │       └── pakeplus
    │       │   │           ├── MainActivity.kt
    │       │   │           └── ui
    │       │   │               ├── gallery
    │       │   │                   ├── GalleryFragment.kt
    │       │   │                   └── GalleryViewModel.kt
    │       │   │               ├── home
    │       │   │                   ├── HomeFragment.kt
    │       │   │                   └── HomeViewModel.kt
    │       │   │               └── slideshow
    │       │   │                   ├── SlideshowFragment.kt
    │       │   │                   └── SlideshowViewModel.kt
    │       └── res
    │       │   ├── drawable-anydpi-v26
    │       │       └── ic_launcher_foreground.png
    │       │   ├── drawable
    │       │       ├── ic_launcher_background.xml
    │       │       ├── ic_launcher_foreground.xml
    │       │       ├── ic_menu_camera.xml
    │       │       ├── ic_menu_gallery.xml
    │       │       ├── ic_menu_slideshow.xml
    │       │       └── side_nav_bar.xml
    │       │   ├── layout
    │       │       ├── activity_main.xml
    │       │       ├── app_bar_main.xml
    │       │       ├── content_main.xml
    │       │       ├── fragment_gallery.xml
    │       │       ├── fragment_home.xml
    │       │       ├── fragment_slideshow.xml
    │       │       ├── nav_header_main.xml
    │       │       └── single_main.xml
    │       │   ├── menu
    │       │       ├── activity_main_drawer.xml
    │       │       └── main.xml
    │       │   ├── mipmap-anydpi-v26
    │       │       ├── ic_launcher.xml
    │       │       └── ic_launcher_round.xml
    │       │   ├── mipmap-hdpi
    │       │       ├── ic_launcher.webp
    │       │       ├── ic_launcher_background.webp
    │       │       ├── ic_launcher_foreground.webp
    │       │       └── ic_launcher_round.webp
    │       │   ├── mipmap-mdpi
    │       │       ├── ic_launcher.webp
    │       │       ├── ic_launcher_background.webp
    │       │       ├── ic_launcher_foreground.webp
    │       │       └── ic_launcher_round.webp
    │       │   ├── mipmap-xhdpi
    │       │       ├── ic_launcher.webp
    │       │       ├── ic_launcher_background.webp
    │       │       ├── ic_launcher_foreground.webp
    │       │       └── ic_launcher_round.webp
    │       │   ├── mipmap-xxhdpi
    │       │       ├── ic_launcher.webp
    │       │       ├── ic_launcher_background.webp
    │       │       ├── ic_launcher_foreground.webp
    │       │       └── ic_launcher_round.webp
    │       │   ├── mipmap-xxxhdpi
    │       │       ├── ic_launcher.webp
    │       │       ├── ic_launcher_background.webp
    │       │       ├── ic_launcher_foreground.webp
    │       │       └── ic_launcher_round.webp
    │       │   ├── navigation
    │       │       └── mobile_navigation.xml
    │       │   ├── values-land
    │       │       └── dimens.xml
    │       │   ├── values-night
    │       │       └── themes.xml
    │       │   ├── values-w1240dp
    │       │       └── dimens.xml
    │       │   ├── values-w600dp
    │       │       └── dimens.xml
    │       │   ├── values
    │       │       ├── colors.xml
    │       │       ├── dimens.xml
    │       │       ├── strings.xml
    │       │       └── themes.xml
    │       │   └── xml
    │       │       ├── backup_rules.xml
    │       │       └── data_extraction_rules.xml
    │   └── test
    │       └── java
    │           └── com
    │               └── app
    │                   └── pakeplus
    │                       └── ExampleUnitTest.kt
├── build.gradle.kts
├── gradle.properties
├── gradle
    ├── libs.versions.toml
    └── wrapper
    │   ├── gradle-wrapper.jar
    │   └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── package.json
├── pnpm-lock.yaml
├── scripts
    ├── ppconfig.json
    └── ppworker.cjs
└── settings.gradle.kts


/.github/back/build.yml:
--------------------------------------------------------------------------------
 1 | name: Android CI
 2 | 
 3 | on:
 4 |     push:
 5 |         branches:
 6 |             - main
 7 |     pull_request:
 8 |         branches:
 9 |             - main
10 | 
11 | jobs:
12 |     build:
13 |         runs-on: ubuntu-latest
14 | 
15 |         steps:
16 |             - name: Checkout code
17 |               uses: actions/checkout@v4
18 | 
19 |             - name: Set up JDK 17
20 |               uses: actions/setup-java@v4
21 |               with:
22 |                   java-version: '17'
23 |                   distribution: 'temurin'
24 | 
25 |             - name: Cache Gradle packages
26 |               uses: actions/cache@v4
27 |               with:
28 |                   path: |
29 |                       ~/.gradle/caches
30 |                       ~/.gradle/wrapper
31 |                   key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
32 |                   restore-keys: |
33 |                       ${{ runner.os }}-gradle-
34 | 
35 |             - name: Build with Gradle
36 |               run: |
37 |                   ./gradlew assembleRelease
38 |                   ls -l app/build/outputs/apk/release
39 | 
40 |             - name: Upload APK
41 |               uses: actions/upload-artifact@v4
42 |               with:
43 |                   name: app-release.apk
44 |                   path: app/build/outputs/apk/release/*-unsigned.apk
45 | 


--------------------------------------------------------------------------------
/.github/back/release.yml:
--------------------------------------------------------------------------------
 1 | name: Android Build & Release
 2 | 
 3 | on:
 4 |     push:
 5 |         branches:
 6 |             - 'main'
 7 | 
 8 | jobs:
 9 |     build:
10 |         name: Build APK
11 |         runs-on: ubuntu-latest
12 |         steps:
13 |             - name: Checkout Repository
14 |               uses: actions/checkout@v4
15 | 
16 |             - name: Set up JDK 17
17 |               uses: actions/setup-java@v3
18 |               with:
19 |                   distribution: 'temurin'
20 |                   java-version: '17'
21 |                   cache: gradle
22 | 
23 |             - name: Set up Android SDK
24 |               uses: android-actions/setup-android@v3
25 | 
26 |             - name: Grant Execute Permission for Gradle
27 |               run: chmod +x ./gradlew
28 | 
29 |             - name: Build Debug APK (可安装版本)
30 |               run: ./gradlew assembleDebug
31 | 
32 |             - name: Create GitHub Release
33 |               uses: softprops/action-gh-release@v2
34 |               with:
35 |                   files: app/build/outputs/apk/debug/*.apk
36 |                   tag_name: 'PakePlus-v0.0.1'
37 |                   body: 'PakePlus-v0.0.1'
38 |                   draft: false
39 |                   prerelease: false
40 |               env:
41 |                   GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
42 | 


--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
 1 | name: Android Build
 2 | 
 3 | on:
 4 |     workflow_dispatch:
 5 |     # push:
 6 |     #     branches:
 7 |     #         - 'main'
 8 | 
 9 | jobs:
10 |     build:
11 |         name: Build APK
12 |         runs-on: ubuntu-latest
13 |         steps:
14 |             - name: Checkout Repository
15 |               uses: actions/checkout@v4
16 | 
17 |             - name: Set up JDK 17
18 |               uses: actions/setup-java@v3
19 |               with:
20 |                   distribution: 'temurin'
21 |                   java-version: '17'
22 |                   cache: gradle
23 | 
24 |             - name: Set up Android SDK
25 |               uses: android-actions/setup-android@v3
26 | 
27 |             - uses: pnpm/action-setup@v3
28 |               with:
29 |                   version: latest
30 | 
31 |             - name: Sync node version and setup cache
32 |               uses: actions/setup-node@v4
33 |               with:
34 |                   node-version: 20
35 |                   cache: pnpm
36 | 
37 |             - name: Init Project Config
38 |               run: |
39 |                   pnpm install
40 |                   pnpm pp:worker
41 | 
42 |             - name: Grant Execute Permission for Gradle
43 |               run: chmod +x ./gradlew
44 | 
45 |             - name: Build Debug APK
46 |               run: ./gradlew assembleDebug
47 | 
48 |             - name: Rename APK file
49 |               run: |
50 |                   cd app/build/outputs/apk/debug/
51 |                   mv app-debug.apk ${{ env.NAME }}-v${{ env.VERSION }}.apk
52 | 
53 |             - name: Create GitHub Release
54 |               uses: softprops/action-gh-release@v1
55 |               with:
56 |                   files: app/build/outputs/apk/debug/*.apk
57 |                   tag_name: '${{ env.NAME }}'
58 |                   name: '${{ env.NAME }} v${{ env.VERSION }}'
59 |                   body: '${{ env.PUBBODY }}'
60 |                   draft: false
61 |               env:
62 |                   GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
63 |                   NAME: ${{ env.NAME }}
64 |                   VERSION: ${{ env.VERSION }}
65 |                   PUBBODY: ${{ env.PUBBODY }}
66 | 


--------------------------------------------------------------------------------
/.github/workflows/tips.md:
--------------------------------------------------------------------------------
 1 | # 安装包损坏
 2 | 因为assembleRelease模式下的apk需要签名才可以使用。
 3 | 
 4 | 
 5 | # 签名
 6 | 在本地生成签名文件:
 7 | ```agsl
 8 | keytool -genkeypair -v \
 9 | -keystore release.keystore \
10 | -keyalg RSA -keysize 2048 -validity 10000 \
11 | -alias pakeplus_android
12 | ```
13 | keytool是jdk自带的工具,路径在jdk/bin目录下。
14 | 
15 | 
16 | 
17 | # 或者使用assembleDebug
18 | 


--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
 1 | *.iml
 2 | .gradle
 3 | /local.properties
 4 | /.idea/caches
 5 | /.idea/libraries
 6 | /.idea/modules.xml
 7 | /.idea/workspace.xml
 8 | /.idea/navEditor.xml
 9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 | /.idea
17 | node_modules
18 | # Built application files
19 | *.apk
20 | *.aar
21 | *.ap_
22 | *.aab
23 | 
24 | # Files for the ART/Dalvik VM
25 | *.dex
26 | 
27 | # Java class files
28 | *.class
29 | 
30 | # Generated files
31 | bin/
32 | gen/
33 | out/
34 | 
35 | # Gradle files
36 | .gradle/
37 | build/
38 | 
39 | # Local configuration file (sdk path, etc)
40 | local.properties
41 | 
42 | # Log Files
43 | *.log
44 | 
45 | # Android Studio files
46 | .idea/
47 | *.iml
48 | .navigation/
49 | captures/
50 | 
51 | # Keystore files
52 | *.jks
53 | *.keystore
54 | 
55 | # External native build folder
56 | .externalNativeBuild/
57 | .cxx/
58 | 
59 | # Google Services (e.g., Firebase)
60 | google-services.json
61 | 
62 | # Freeline
63 | freeline.py
64 | freeline/
65 | freeline_project_description.json
66 | 
67 | # Fastlane
68 | fastlane/report.xml
69 | fastlane/Preview.html
70 | fastlane/screenshots
71 | fastlane/test_output
72 | fastlane/readme.md
73 | 
74 | # Version control
75 | vcs.xml
76 | 
77 | # lint
78 | lint/intermediates/
79 | lint/generated/
80 | lint/outputs/
81 | lint/tmp/
82 | # lint/reports/


--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
 1 | MIT License
 2 | 
 3 | Copyright (c) 2025 1024 小神
 4 | 
 5 | Permission is hereby granted, free of charge, to any person obtaining a copy
 6 | of this software and associated documentation files (the "Software"), to deal
 7 | in the Software without restriction, including without limitation the rights
 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 | 
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 | 
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 | 


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
  1 | <h4 align="right"> 
  2 | <span href=".README.md">English</span> 
  3 | <a href="http://www.pakeplus.com/" 
  4 | style="margin: 0 10px;" >简体中文</a> 
  5 | <a href="https://github.com/Sjj1024/PakePlus/discussions/108">日本语</a>
  6 | </h4>  
  7 | <p align="center">
  8 |     <img src="https://github.com/Sjj1024/PakePlus/raw/main/docs/static/imgs/pakeplus.png" width=138/>
  9 | </p>  
 10 | <h1 align="center">PakePlus-Android</h1>  
 11 | <p align="center"><strong>Turn any webpage into a desktop or mobile app in just 9 minutes. Simple and easy to use.</strong></p>
 12 | 
 13 | <div align="left">PakePlus supports Mac, Windows, and Linux, and support Android and iOS. There’s no need to install complex dependencies locally— all you need is a Github Token. Plus, PakePlus is only about 5MB in size. For the latest version, please see the <a href="[#popular-packages](https://github.com/Sjj1024/PakePlus/releases)">release page</a>. or visit: <a href="https://pakeplus.pages.dev" target="_blank">PakePlus Web</a>. Check the README for information on <a href="#popular-packages">popular packages</a> and <a href="#development">custom development</a>. Feel free to share your suggestions in the <a href="https://github.com/Sjj1024/PakePlus/discussions">discussion area</a>.</div>
 14 | 
 15 | https://github.com/user-attachments/assets/b88bf541-0b26-4020-9eec-da79e1734fc9
 16 | 
 17 | ## Features
 18 | 
 19 | -   🎐 Approximately 20 times smaller than Electron (less than 5MB!) and 10 times faster.
 20 | -   🚀 Built with Rust Tauri, PakePlus is lighter and faster than JavaScript-based frameworks.
 21 | -   📦 Comes with rich built-in features — supports shortcuts, immersive windows, and minimalist customization.
 22 | -   👻 PakePlus is a minimalist tool that replaces traditional packaging with Tauri for cross-platform desktop apps.
 23 | -   📲 Uses native frameworks to package Android and iOS apps — smaller and faster than Tauri2.
 24 | -   🤗 Easy to use — just one GitHub Token is all you need to get a desktop app.
 25 | -   🌹 No need to install complex dependencies locally — use GitHub Actions for cloud-based automatic packaging.
 26 | -   🧑‍🤝‍🧑 Internationalization support — automatically follows your system language.
 27 | -   💡 Supports custom JavaScript injection — write your own JS to inject into the page.
 28 | -   🎨 Beautiful and user-friendly UI — better experience for beginners, supports Chinese names for packaging.
 29 | -   📡 Usable directly via the web, but the client offers stronger functionality and is recommended.
 30 | -   🔐 Data security — your token is stored only locally, and your project stays safely in your own Git repo.
 31 | -   🍀 Supports static file packaging — drop in a compiled dist folder or index.html from Vue/React to create a client app.
 32 | -   🐞 Debug mode supported — find and eliminate bugs during preview or release.
 33 | -   💬 If you run into any issues, feel free to join our technical community for help.
 34 | 
 35 | ## Use Cases
 36 | 
 37 | -   Have a website? Instantly turn it into a app and elevate its appearance.
 38 | -   Have a Vue/React project and don’t want to buy a server? Package it as a desktop app.
 39 | -   Want your Cocos game to run as a cross-platform client? No problem.
 40 | -   Need to build your Unity project as a cross-platform client? Also no problem.
 41 | -   Hide your website address from casual sharing or bots scraping your content.
 42 | -   For internal company platforms — restrict access to your site via a dedicated client only.
 43 | -   Turn any website into your custom client — inject JS for automation and custom features.
 44 | -   Annoyed by website ads? Hide them with powerful JS.
 45 | -   Want to use Tauri2 but the environment is too heavy? Use PakePlus instead!
 46 | 
 47 | ## Popular Packages
 48 | 
 49 | <img src=https://sjj1024.github.io/PakePlus/static/imgs/preview.webp  width=1920/>
 50 | 
 51 | PakePlus supports installation packages for both ARM and Intel architectures. Most popular program installation packages only include the ARM architecture for macOS and the Intel architecture for Windows. If you need installation packages for additional architectures, please use PakePlus to compile the required package separately.
 52 | 
 53 | <table>
 54 |     <tr>
 55 |         <td>DeepSeek
 56 |             <a href="https://github.com/Sjj1024/PakePlus/releases/download/OtherFiles/DeepSeek_0.0.1_aarch64.dmg">Mac(Arm)</a>
 57 |             <a href="https://github.com/Sjj1024/PakePlus/releases/download/OtherFiles/DeepSeek_0.0.1_x64-setup.exe">Windows(x64)</a>
 58 |             <a href="https://github.com/Sjj1024/PakePlus/releases/download/OtherFiles/DeepSeek_0.0.1_amd64.deb">Linux(x64)</a>
 59 |         </td>
 60 |         <td>X (Twitter)
 61 |             <a href="https://github.com/codegirle/PakePlus/releases/download/Twitter/Twitter_0.0.1_aarch64.dmg">Mac(Arm)</a>
 62 |             <a href="https://github.com/codegirle/PakePlus/releases/download/Twitter/Twitter_0.0.1_x64-setup.exe">Windows(x64)</a>
 63 |             <a href="https://github.com/codegirle/PakePlus/releases/download/Twitter/twitter_0.0.1_amd64.deb">Linux(x64)</a>
 64 |         </td>
 65 |     </tr>
 66 |     <tr>
 67 |         <td><img src=https://sjj1024.github.io/PakePlus/static/imgs/deepseek.png width=600/></td>
 68 |         <td><img src=https://sjj1024.github.io/PakePlus/static/imgs/xtwitter.png width=600/></td>
 69 |     </tr>
 70 |     <tr>
 71 |         <td>YouTube
 72 |             <a href="https://github.com/codegirle/PakePlus/releases/download/YouTube/YouTube_0.0.2_aarch64.dmg">Mac(Arm)</a>
 73 |             <a href="https://github.com/codegirle/PakePlus/releases/download/YouTube/YouTube_0.0.2_x64-setup.exe">Windows(x64)</a>
 74 |             <a href="https://github.com/codegirle/PakePlus/releases/download/YouTube/you-tube_0.0.2_amd64.deb">Linux(x64)</a>
 75 |         </td>
 76 |         <td>小红书
 77 |             <a href="https://github.com/Sjj1024/PakePlus/releases/download/OtherFiles/_0.0.1_aarch64.dmg">Mac(Arm)</a>
 78 |             <a href="https://github.com/Sjj1024/PakePlus/releases/download/OtherFiles/_0.0.1_x64-setup.exe">Windows(x64)</a>
 79 |             <a href="https://github.com/Sjj1024/PakePlus/releases/download/OtherFiles/_0.0.1_amd64.deb">Linux(x64)</a>
 80 |         </td>
 81 |     </tr>
 82 |     <tr>
 83 |         <td><img src=https://sjj1024.github.io/PakePlus/static/imgs/youtube.png width=600/></td>
 84 |         <td><img src=https://sjj1024.github.io/PakePlus/static/imgs/hongshu.png width=600/></td>
 85 |     </tr>
 86 |         <tr>
 87 |         <td>Tiktok
 88 |             <a href="https://github.com/codegirle/PakePlus/releases/download/Tiktok/Tiktok_0.0.2_aarch64.dmg">Mac(Arm)</a>
 89 |             <a href="https://github.com/codegirle/PakePlus/releases/download/Tiktok/Tiktok_0.0.2_x64-setup.exe">Windows(x64)</a>
 90 |             <a href="https://github.com/codegirle/PakePlus/releases/download/Tiktok/tiktok_0.0.2_amd64.deb">Linux(x64)</a>
 91 |         </td>
 92 |         <td>抖音
 93 |             <a href="https://github.com/codegirle/PakePlus/releases/download/Douyin/Douyin_0.0.2_aarch64.dmg">Mac(Arm)</a>
 94 |             <a href="https://github.com/codegirle/PakePlus/releases/download/Douyin/Douyin_0.0.2_x64-setup.exe">Windows(x64)</a>
 95 |             <a href="https://github.com/codegirle/PakePlus/releases/download/Douyin/douyin_0.0.2_amd64.deb">Linux(x64)</a>
 96 |         </td>
 97 |     </tr>
 98 |     <tr>
 99 |         <td><img src=https://sjj1024.github.io/PakePlus/static/imgs/tiktok.png width=600/></td>
100 |         <td><img src=https://sjj1024.github.io/PakePlus/static/imgs/douyin.png width=600/></td>
101 |     </tr>
102 | </table>
103 | 
104 | ## Getting Started
105 | 
106 | 1. Download the app from the release page:https://github.com/Sjj1024/PakePlus/releases,  
107 |    double-click to install, and run the app. or visit web: <a href="https://pakeplus.pages.dev" target="_blank">PakePlus Web</a>
108 | 
109 | 2. Configure a Github Token, create a new project, and set up the configurations. get token guide:  
110 |    <a href="https://sjj1024.github.io/PakePlus/index_en.html">English</a> <a href="https://sjj1024.github.io/PakePlus/index_zh.html" style="margin: 0 50px;">简体中文</a><a href="https://sjj1024.github.io/PakePlus/index_ja.html">日本语</a>
111 | 
112 | ```
113 | Explanation of Github Token permissions:
114 | 1. For the beta version, token permissions required:
115 | All repositories: Fork an original template repository
116 | Actions: Manage GitHub actions
117 | Administration: Fork and manage files in the repository
118 | Contents: Add, delete, modify, and find repository contents
119 | Issues: Submit issues to PakePlus
120 | 
121 | 1. For the classic version, token permissions required:
122 | repo: Fork and manage template code
123 | workflow: Compile and release your software
124 | ```
125 | 
126 | 1. You can preview the app in a new window and click the publish button to package the app.
127 | 2. You can download the app from the release page.
128 | 
129 | ## FAQ
130 | 
131 | 1. Mac users may see an “App is damaged” warning on installation. click cancel and Run the following command, then reopen the app:(This is because the application requires an official signature to avoid the prompt of "The application is damaged" popping up after installation. However, the cost of the official signature is $99 per year... Therefore, it is necessary to manually bypass the signature to use it normally)
132 | 
133 | ```sh
134 | sudo xattr -r -d com.apple.quarantine /Applications/PakePlus.app
135 | ```
136 | 
137 | 1. When you package the app, Mac users may see an “App is damaged” warning on installation. click cancel and Run the following command, then reopen the app:
138 | 
139 | ```sh
140 | sudo xattr -r -d com.apple.quarantine /Applications/YourAppName.app
141 | ```
142 | 
143 | 3. If you encounter any issues while using the program, please download the latest version, as versions developed before 2025 were based on Tauri v1.0. In 2025, Tauri was upgraded to v2.0. If the latest version still has issues, please submit an issue with detailed information so that we can update and resolve it more quickly.
144 | 
145 | 4. After you add the GitHub Token, PakePlus will fork a PakePlus repository into your own repository. All your future projects will rely on this repository for creation and compilation, so please do not delete your PakePlus repository.
146 | 
147 | ## Developing PakePlus
148 | 
149 | If you want to develop PakePlus locally, ensure your environment is prepared beforehand. Make sure Rust `>=1.63` and Node `>=16` (e.g., `16.18.1`) are installed on your computer. For installation guidance, please refer to the [Tauri Documentation](https://tauri.app/v1/guides/getting-started/prerequisites).
150 | 
151 | If you’re unfamiliar with these, it’s best to try the one-click packaging tool above.
152 | 
153 | ```sh
154 | # Install dependencies
155 | pnpm i
156 | 
157 | # Local development [Right-click to open debug mode.]
158 | pnpm run dev
159 | 
160 | # Package the app
161 | pnpm run build
162 | 
163 | ```
164 | 
165 | ## Support
166 | 
167 | 1. wechat and group,my wechat is lanxingme,welcome to join the wechat group.
168 |  <p align="center" style="display:flex; justify-content: flex-start;" >
169 |     <img src="https://github.com/Sjj1024/PakePlus/raw/main/docs/static/imgs/mywx.png" width=200/>
170 |     <img src="https://github.com/Sjj1024/PakePlus/raw/main/docs/static/imgs/wxcode.png" width=200/>
171 |     <img src="https://github.com/Sjj1024/PakePlus/raw/main/docs/static/imgs/qq.jpg" width=200/>
172 |  </p>
173 | 
174 | 2. 💖If PakePlus has brought joy to your life, feel free to support it.
175 |  <p align="center" style="display:flex; justify-content: flex-start;">
176 |     <img src="https://github.com/Sjj1024/PakePlus/raw/main/docs/static/imgs/sponsor.webp" width=620/>
177 |  </p>
178 | 
179 | ## Star History
180 | 
181 | [![Star History Chart](https://api.star-history.com/svg?repos=Sjj1024/PakePlus&type=Date)](https://www.star-history.com/#Sjj1024/PakePlus&Date)
182 | 


--------------------------------------------------------------------------------
/app-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app-icon.png


--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build


--------------------------------------------------------------------------------
/app/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |     alias(libs.plugins.androidApplication)
 3 |     alias(libs.plugins.jetbrainsKotlinAndroid)
 4 | }
 5 | 
 6 | android {
 7 |     namespace = "com.app.pakeplus"
 8 |     compileSdk = 34
 9 | 
10 |     defaultConfig {
11 |         applicationId = "com.app.pakeplus.android"
12 |         minSdk = 24
13 |         targetSdk = 34
14 |         versionCode = 1
15 |         versionName = "1.0"
16 |         testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
17 |     }
18 | 
19 |     buildTypes {
20 |         release {
21 |             isMinifyEnabled = false
22 |             proguardFiles(
23 |                 getDefaultProguardFile("proguard-android-optimize.txt"),
24 |                 "proguard-rules.pro"
25 |             )
26 |         }
27 |     }
28 |     compileOptions {
29 |         sourceCompatibility = JavaVersion.VERSION_1_8
30 |         targetCompatibility = JavaVersion.VERSION_1_8
31 |     }
32 |     kotlinOptions {
33 |         jvmTarget = "1.8"
34 |     }
35 |     buildFeatures {
36 |         viewBinding = true
37 |     }
38 | }
39 | 
40 | dependencies {
41 | 
42 |     implementation(libs.androidx.core.ktx)
43 |     implementation(libs.androidx.appcompat)
44 |     implementation(libs.material)
45 |     implementation(libs.androidx.constraintlayout)
46 |     implementation(libs.androidx.lifecycle.livedata.ktx)
47 |     implementation(libs.androidx.lifecycle.viewmodel.ktx)
48 |     implementation(libs.androidx.navigation.fragment.ktx)
49 |     implementation(libs.androidx.navigation.ui.ktx)
50 |     testImplementation(libs.junit)
51 |     androidTestImplementation(libs.androidx.junit)
52 |     androidTestImplementation(libs.androidx.espresso.core)
53 | }


--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
 1 | # Add project specific ProGuard rules here.
 2 | # You can control the set of applied configuration files using the
 3 | # proguardFiles setting in build.gradle.
 4 | #
 5 | # For more details, see
 6 | #   http://developer.android.com/guide/developing/tools/proguard.html
 7 | 
 8 | # If your project uses WebView with JS, uncomment the following
 9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | #   public *;
13 | #}
14 | 
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 | 
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile


--------------------------------------------------------------------------------
/app/src/androidTest/java/com/app/pakeplus/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
 1 | package com.app.pakeplus
 2 | 
 3 | import androidx.test.platform.app.InstrumentationRegistry
 4 | import androidx.test.ext.junit.runners.AndroidJUnit4
 5 | 
 6 | import org.junit.Test
 7 | import org.junit.runner.RunWith
 8 | 
 9 | import org.junit.Assert.*
10 | 
11 | /**
12 |  * Instrumented test, which will execute on an Android device.
13 |  *
14 |  * See [testing documentation](http://d.android.com/tools/testing).
15 |  */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 |     @Test
19 |     fun useAppContext() {
20 |         // Context of the app under test.
21 |         val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 |         assertEquals("com.app.pakeplus", appContext.packageName)
23 |     }
24 | }


--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     xmlns:tools="http://schemas.android.com/tools">
 4 | 
 5 |     <!-- 添加网络权限 -->
 6 |     <uses-permission android:name="android.permission.INTERNET" />
 7 |     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 8 |     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
 9 | 
10 | 
11 |     <application
12 |         android:allowBackup="true"
13 |         android:dataExtractionRules="@xml/data_extraction_rules"
14 |         android:fullBackupContent="@xml/backup_rules"
15 |         android:icon="@mipmap/ic_launcher"
16 |         android:label="@string/app_name"
17 |         android:roundIcon="@mipmap/ic_launcher_round"
18 |         android:supportsRtl="true"
19 |         android:theme="@style/Theme.PakePlus"
20 |         android:usesCleartextTraffic="true"
21 |         tools:targetApi="31">
22 |         <activity
23 |             android:name=".MainActivity"
24 |             android:exported="true"
25 |             android:theme="@style/Theme.PakePlus.NoActionBar">
26 |             <intent-filter>
27 |                 <action android:name="android.intent.action.MAIN" />
28 |                 <category android:name="android.intent.category.LAUNCHER" />
29 |             </intent-filter>
30 |         </activity>
31 |     </application>
32 | 
33 | </manifest>


--------------------------------------------------------------------------------
/app/src/main/assets/assets/javascript.svg:
--------------------------------------------------------------------------------
1 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="32" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path fill="#F7DF1E" d="M0 0h256v256H0V0Z"></path><path d="m67.312 213.932l19.59-11.856c3.78 6.701 7.218 12.371 15.465 12.371c7.905 0 12.89-3.092 12.89-15.12v-81.798h24.057v82.138c0 24.917-14.606 36.259-35.916 36.259c-19.245 0-30.416-9.967-36.087-21.996m85.07-2.576l19.588-11.341c5.157 8.421 11.859 14.607 23.715 14.607c9.969 0 16.325-4.984 16.325-11.858c0-8.248-6.53-11.17-17.528-15.98l-6.013-2.58c-17.357-7.387-28.87-16.667-28.87-36.257c0-18.044 13.747-31.792 35.228-31.792c15.294 0 26.292 5.328 34.196 19.247l-18.732 12.03c-4.125-7.389-8.591-10.31-15.465-10.31c-7.046 0-11.514 4.468-11.514 10.31c0 7.217 4.468 10.14 14.778 14.608l6.014 2.577c20.45 8.765 31.963 17.7 31.963 37.804c0 21.654-17.012 33.51-39.867 33.51c-22.339 0-36.774-10.654-43.819-24.574"></path></svg>


--------------------------------------------------------------------------------
/app/src/main/assets/assets/tauri.svg:
--------------------------------------------------------------------------------
1 | <svg width="206" height="231" viewBox="0 0 206 231" fill="none" xmlns="http://www.w3.org/2000/svg">
2 | <path d="M143.143 84C143.143 96.1503 133.293 106 121.143 106C108.992 106 99.1426 96.1503 99.1426 84C99.1426 71.8497 108.992 62 121.143 62C133.293 62 143.143 71.8497 143.143 84Z" fill="#FFC131"/>
3 | <ellipse cx="84.1426" cy="147" rx="22" ry="22" transform="rotate(180 84.1426 147)" fill="#24C8DB"/>
4 | <path fill-rule="evenodd" clip-rule="evenodd" d="M166.738 154.548C157.86 160.286 148.023 164.269 137.757 166.341C139.858 160.282 141 153.774 141 147C141 144.543 140.85 142.121 140.558 139.743C144.975 138.204 149.215 136.139 153.183 133.575C162.73 127.404 170.292 118.608 174.961 108.244C179.63 97.8797 181.207 86.3876 179.502 75.1487C177.798 63.9098 172.884 53.4021 165.352 44.8883C157.82 36.3744 147.99 30.2165 137.042 27.1546C126.095 24.0926 114.496 24.2568 103.64 27.6274C92.7839 30.998 83.1319 37.4317 75.8437 46.1553C74.9102 47.2727 74.0206 48.4216 73.176 49.5993C61.9292 50.8488 51.0363 54.0318 40.9629 58.9556C44.2417 48.4586 49.5653 38.6591 56.679 30.1442C67.0505 17.7298 80.7861 8.57426 96.2354 3.77762C111.685 -1.01901 128.19 -1.25267 143.769 3.10474C159.348 7.46215 173.337 16.2252 184.056 28.3411C194.775 40.457 201.767 55.4101 204.193 71.404C206.619 87.3978 204.374 103.752 197.73 118.501C191.086 133.25 180.324 145.767 166.738 154.548ZM41.9631 74.275L62.5557 76.8042C63.0459 72.813 63.9401 68.9018 65.2138 65.1274C57.0465 67.0016 49.2088 70.087 41.9631 74.275Z" fill="#FFC131"/>
5 | <path fill-rule="evenodd" clip-rule="evenodd" d="M38.4045 76.4519C47.3493 70.6709 57.2677 66.6712 67.6171 64.6132C65.2774 70.9669 64 77.8343 64 85.0001C64 87.1434 64.1143 89.26 64.3371 91.3442C60.0093 92.8732 55.8533 94.9092 51.9599 97.4256C42.4128 103.596 34.8505 112.392 30.1816 122.756C25.5126 133.12 23.9357 144.612 25.6403 155.851C27.3449 167.09 32.2584 177.598 39.7906 186.112C47.3227 194.626 57.153 200.784 68.1003 203.846C79.0476 206.907 90.6462 206.743 101.502 203.373C112.359 200.002 122.011 193.568 129.299 184.845C130.237 183.722 131.131 182.567 131.979 181.383C143.235 180.114 154.132 176.91 164.205 171.962C160.929 182.49 155.596 192.319 148.464 200.856C138.092 213.27 124.357 222.426 108.907 227.222C93.458 232.019 76.9524 232.253 61.3736 227.895C45.7948 223.538 31.8055 214.775 21.0867 202.659C10.3679 190.543 3.37557 175.59 0.949823 159.596C-1.47592 143.602 0.768139 127.248 7.41237 112.499C14.0566 97.7497 24.8183 85.2327 38.4045 76.4519ZM163.062 156.711L163.062 156.711C162.954 156.773 162.846 156.835 162.738 156.897C162.846 156.835 162.954 156.773 163.062 156.711Z" fill="#24C8DB"/>
6 | </svg>
7 | 


--------------------------------------------------------------------------------
/app/src/main/assets/custom.js:
--------------------------------------------------------------------------------
 1 | //console.log(
 2 | //    '%cbuild from PakePlus: https://github.com/Sjj1024/PakePlus',
 3 | //    'color:orangered;font-weight:bolder'
 4 | //)
 5 | //
 6 | //// very important, if you don't know what it is, don't touch it
 7 | //// 非常重要,不懂代码不要动
 8 | //const hookClick = (e) => {
 9 | //    const origin = e.target.closest('a')
10 | //    const isBaseTargetBlank = document.querySelector(
11 | //        'head base[target="_blank"]'
12 | //    )
13 | //    console.log('origin', origin, isBaseTargetBlank)
14 | //    if (
15 | //        (origin && origin.href && origin.target === '_blank') ||
16 | //        (origin && origin.href && isBaseTargetBlank)
17 | //    ) {
18 | //        e.preventDefault()
19 | //        console.log('handle origin', origin)
20 | //        location.href = origin.href
21 | //    } else {
22 | //        console.log('not handle origin', origin)
23 | //    }
24 | //}
25 | //
26 | //document.addEventListener('click', hookClick, { capture: true })
27 | 


--------------------------------------------------------------------------------
/app/src/main/assets/index.html:
--------------------------------------------------------------------------------
 1 | <!DOCTYPE html>
 2 | <html lang="en">
 3 |     <head>
 4 |         <meta charset="UTF-8" />
 5 |         <link rel="stylesheet" href="./styles.css" />
 6 |         <meta
 7 |             http-equiv="Content-Security-Policy"
 8 |             content="default-src * 'unsafe-inline' 'unsafe-eval'"
 9 |         />
10 |         <meta name="viewport" content="width=device-width, initial-scale=1.0" />
11 |         <title>Tauri App</title>
12 |         <script src="main.js"></script>
13 |     </head>
14 |     <body>
15 |         <main class="container">
16 |             <h1>Welcome to TauriMan</h1>
17 | 
18 |             <div class="row">
19 |                 <a
20 |                     href="https://tauri.app"
21 |                     target="_blank"
22 |                     rel="noopener noreferrer"
23 |                 >
24 |                     <img
25 |                         src="./assets/tauri.svg"
26 |                         class="logo tauri"
27 |                         alt="Tauri logo"
28 |                     />
29 |                 </a>
30 |                 <a
31 |                     href="https://pakeplus.com/"
32 |                     target="_blank"
33 |                     rel="noopener noreferrer"
34 |                 >
35 |                     <img
36 |                         src="https://files.pakeplus.com/pakeplus.png"
37 |                         class="logo vanilla"
38 |                         alt="JavaScript logo"
39 |                     />
40 |                 </a>
41 |             </div>
42 |             <p>Click to get data</p>
43 |             <form class="row" id="greet-form">
44 |                 <input id="greet-input" placeholder="Enter a name..." />
45 |                 <button type="submit" id="getdata">GET DATA</button>
46 |             </form>
47 |             <button onclick="sayHello()">点击我</button>
48 |             <p id="greet-msg"></p>
49 |             <video
50 |                 src="https://files.pakeplus.com/test.mp4"
51 |                 autoplay
52 |                 controls
53 |                 style="width: 100%; height: 100%"
54 |             ></video>
55 |         </main>
56 |     </body>
57 | </html>
58 | 


--------------------------------------------------------------------------------
/app/src/main/assets/main.js:
--------------------------------------------------------------------------------
 1 | function sayHello() {
 2 |     alert('你好,这是本地JS代码!')
 3 | }
 4 | 
 5 | 
 6 | console.log('main.js---')
 7 | 
 8 | window.addEventListener('DOMContentLoaded', () => {
 9 |     console.log('DOMContentLoaded-----')
10 |     const getdata = document.querySelector('#getdata')
11 |     getdata.addEventListener('click', (e) => {
12 |         e.preventDefault()
13 |         console.log('getdata')
14 |         fetch('https://api.github.com/users/octocat')
15 |             .then((response) => response.json())
16 |             .then((data) => {
17 |                 console.log('data', data)
18 |                 const greetMsgEl = document.querySelector('#greet-msg')
19 |                 greetMsgEl.textContent = data.login
20 |             })
21 |             .catch((error) => {
22 |                 console.error('error', error)
23 |             })
24 |     })
25 | })
26 | 


--------------------------------------------------------------------------------
/app/src/main/assets/styles.css:
--------------------------------------------------------------------------------
  1 | .logo.vanilla:hover {
  2 |   filter: drop-shadow(0 0 2em #ffe21c);
  3 | }
  4 | :root {
  5 |   font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
  6 |   font-size: 16px;
  7 |   line-height: 24px;
  8 |   font-weight: 400;
  9 | 
 10 |   color: #0f0f0f;
 11 |   background-color: #f6f6f6;
 12 | 
 13 |   font-synthesis: none;
 14 |   text-rendering: optimizeLegibility;
 15 |   -webkit-font-smoothing: antialiased;
 16 |   -moz-osx-font-smoothing: grayscale;
 17 |   -webkit-text-size-adjust: 100%;
 18 | }
 19 | 
 20 | .container {
 21 |   margin: 0;
 22 |   padding-top: 10vh;
 23 |   display: flex;
 24 |   flex-direction: column;
 25 |   justify-content: center;
 26 |   text-align: center;
 27 | }
 28 | 
 29 | .logo {
 30 |   height: 6em;
 31 |   padding: 1.5em;
 32 |   will-change: filter;
 33 |   transition: 0.75s;
 34 | }
 35 | 
 36 | .logo.tauri:hover {
 37 |   filter: drop-shadow(0 0 2em #24c8db);
 38 | }
 39 | 
 40 | .row {
 41 |   display: flex;
 42 |   justify-content: center;
 43 | }
 44 | 
 45 | a {
 46 |   font-weight: 500;
 47 |   color: #646cff;
 48 |   text-decoration: inherit;
 49 | }
 50 | 
 51 | a:hover {
 52 |   color: #535bf2;
 53 | }
 54 | 
 55 | h1 {
 56 |   text-align: center;
 57 | }
 58 | 
 59 | input,
 60 | button {
 61 |   border-radius: 8px;
 62 |   border: 1px solid transparent;
 63 |   padding: 0.6em 1.2em;
 64 |   font-size: 1em;
 65 |   font-weight: 500;
 66 |   font-family: inherit;
 67 |   color: #0f0f0f;
 68 |   background-color: #ffffff;
 69 |   transition: border-color 0.25s;
 70 |   box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
 71 | }
 72 | 
 73 | button {
 74 |   cursor: pointer;
 75 | }
 76 | 
 77 | button:hover {
 78 |   border-color: #396cd8;
 79 | }
 80 | button:active {
 81 |   border-color: #396cd8;
 82 |   background-color: #e8e8e8;
 83 | }
 84 | 
 85 | input,
 86 | button {
 87 |   outline: none;
 88 | }
 89 | 
 90 | #greet-input {
 91 |   margin-right: 5px;
 92 | }
 93 | 
 94 | @media (prefers-color-scheme: dark) {
 95 |   :root {
 96 |     color: #f6f6f6;
 97 |     background-color: #2f2f2f;
 98 |   }
 99 | 
100 |   a:hover {
101 |     color: #24c8db;
102 |   }
103 | 
104 |   input,
105 |   button {
106 |     color: #ffffff;
107 |     background-color: #0f0f0f98;
108 |   }
109 |   button:active {
110 |     background-color: #0f0f0f69;
111 |   }
112 | }
113 | 


--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/ic_launcher-playstore.png


--------------------------------------------------------------------------------
/app/src/main/java/com/app/pakeplus/MainActivity.kt:
--------------------------------------------------------------------------------
  1 | package com.app.pakeplus
  2 | 
  3 | import android.annotation.SuppressLint
  4 | import android.graphics.Bitmap
  5 | import android.os.Bundle
  6 | import android.view.GestureDetector
  7 | import android.view.MotionEvent
  8 | import android.webkit.WebChromeClient
  9 | import android.webkit.WebResourceError
 10 | import android.webkit.WebResourceRequest
 11 | import android.webkit.WebView
 12 | import android.webkit.WebViewClient
 13 | import androidx.activity.enableEdgeToEdge
 14 | // import android.view.Menu
 15 | // import android.view.WindowInsets
 16 | // import com.google.android.material.snackbar.Snackbar
 17 | // import com.google.android.material.navigation.NavigationView
 18 | // import androidx.navigation.findNavController
 19 | // import androidx.navigation.ui.AppBarConfiguration
 20 | // import androidx.navigation.ui.navigateUp
 21 | // import androidx.navigation.ui.setupActionBarWithNavController
 22 | // import androidx.navigation.ui.setupWithNavController
 23 | // import androidx.drawerlayout.widget.DrawerLayout
 24 | // import com.app.pakeplus.databinding.ActivityMainBinding
 25 | import androidx.appcompat.app.AppCompatActivity
 26 | import androidx.core.view.GestureDetectorCompat
 27 | import androidx.core.view.ViewCompat
 28 | import androidx.core.view.WindowInsetsCompat
 29 | 
 30 | class MainActivity : AppCompatActivity() {
 31 | 
 32 | //    private lateinit var appBarConfiguration: AppBarConfiguration
 33 | //    private lateinit var binding: ActivityMainBinding
 34 | 
 35 |     private lateinit var webView: WebView
 36 |     private lateinit var gestureDetector: GestureDetectorCompat
 37 | 
 38 |     @SuppressLint("SetJavaScriptEnabled", "ClickableViewAccessibility")
 39 |     override fun onCreate(savedInstanceState: Bundle?) {
 40 |         super.onCreate(savedInstanceState)
 41 | 
 42 |         enableEdgeToEdge()
 43 |         setContentView(R.layout.single_main)
 44 | 
 45 |         ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.ConstraintLayout)) { view, insets ->
 46 |             val systemBar = insets.getInsets(WindowInsetsCompat.Type.systemBars())
 47 |             view.setPadding(
 48 |                 0, systemBar.top, 0, 0
 49 |             )
 50 |             insets
 51 |         }
 52 | 
 53 |         webView = findViewById<WebView>(R.id.webview)
 54 | 
 55 |         webView.settings.apply {
 56 |             javaScriptEnabled = true       // 启用JS
 57 |             domStorageEnabled = true       // 启用DOM存储(Vue 需要)
 58 |             allowFileAccess = true         // 允许文件访问
 59 |             setSupportMultipleWindows(true)
 60 |         }
 61 | 
 62 |         // webView.settings.userAgentString = ""
 63 | 
 64 |         webView.settings.loadWithOverviewMode = true
 65 |         webView.settings.setSupportZoom(false)
 66 | 
 67 |         // clear cache
 68 |         webView.clearCache(true)
 69 | 
 70 |         // inject js
 71 |         webView.webViewClient = MyWebViewClient()
 72 | 
 73 |         // get web load progress
 74 |         webView.webChromeClient = MyChromeClient()
 75 | 
 76 |         // Setup gesture detector
 77 |         gestureDetector =
 78 |             GestureDetectorCompat(this, object : GestureDetector.SimpleOnGestureListener() {
 79 |                 override fun onFling(
 80 |                     e1: MotionEvent?,
 81 |                     e2: MotionEvent,
 82 |                     velocityX: Float,
 83 |                     velocityY: Float
 84 |                 ): Boolean {
 85 |                     if (e1 == null) return false
 86 | 
 87 |                     val diffX = e2.x - e1.x
 88 |                     val diffY = e2.y - e1.y
 89 | 
 90 |                     // Only handle horizontal swipes
 91 |                     if (Math.abs(diffX) > Math.abs(diffY)) {
 92 |                         if (Math.abs(diffX) > 100 && Math.abs(velocityX) > 100) {
 93 |                             if (diffX > 0) {
 94 |                                 // Swipe right - go back
 95 |                                 if (webView.canGoBack()) {
 96 |                                     webView.goBack()
 97 |                                     return true
 98 |                                 }
 99 |                             } else {
100 |                                 // Swipe left - go forward
101 |                                 if (webView.canGoForward()) {
102 |                                     webView.goForward()
103 |                                     return true
104 |                                 }
105 |                             }
106 |                         }
107 |                     }
108 |                     return false
109 |                 }
110 |             })
111 | 
112 |         // Set touch listener for WebView
113 |         webView.setOnTouchListener { _, event ->
114 |             gestureDetector.onTouchEvent(event)
115 |             false
116 |         }
117 | 
118 |         // webView.loadUrl("https://juejin.cn/")
119 |         webView.loadUrl("file:///android_asset/index.html")
120 | 
121 | //        binding = ActivityMainBinding.inflate(layoutInflater)
122 | //        setContentView(R.layout.single_main)
123 | 
124 | //        setSupportActionBar(binding.appBarMain.toolbar)
125 | 
126 | //        binding.appBarMain.fab.setOnClickListener { view ->
127 | //            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
128 | //                .setAction("Action", null)
129 | //                .setAnchorView(R.id.fab).show()
130 | //        }
131 | 
132 | //        val drawerLayout: DrawerLayout = binding.drawerLayout
133 | //        val navView: NavigationView = binding.navView
134 | //        val navController = findNavController(R.id.nav_host_fragment_content_main)
135 | 
136 |         // Passing each menu ID as a set of Ids because each
137 |         // menu should be considered as top level destinations.
138 | //        appBarConfiguration = AppBarConfiguration(
139 | //            setOf(
140 | //                R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow
141 | //            ), drawerLayout
142 | //        )
143 | //        setupActionBarWithNavController(navController, appBarConfiguration)
144 | //        navView.setupWithNavController(navController)
145 |     }
146 | 
147 | 
148 |     @Deprecated("Deprecated in Java")
149 |     override fun onBackPressed() {
150 |         if (webView.canGoBack()) {
151 |             webView.goBack()
152 |         } else {
153 |             super.onBackPressed()
154 |         }
155 |     }
156 | 
157 | //    override fun onCreateOptionsMenu(menu: Menu): Boolean {
158 | //        // Inflate the menu; this adds items to the action bar if it is present.
159 | //        menuInflater.inflate(R.menu.main, menu)
160 | //        return true
161 | //    }
162 | 
163 | //    override fun onSupportNavigateUp(): Boolean {
164 | //        val navController = findNavController(R.id.nav_host_fragment_content_main)
165 | //        return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
166 | //    }
167 | 
168 |     inner class MyWebViewClient : WebViewClient() {
169 | 
170 |         // vConsole debug
171 |         private var debug = true
172 | 
173 |         @Deprecated("Deprecated in Java", ReplaceWith("false"))
174 |         override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
175 |             return false
176 |         }
177 | 
178 |         override fun doUpdateVisitedHistory(view: WebView?, url: String?, isReload: Boolean) {
179 |             super.doUpdateVisitedHistory(view, url, isReload)
180 |         }
181 | 
182 |         override fun onReceivedError(
183 |             view: WebView?,
184 |             request: WebResourceRequest?,
185 |             error: WebResourceError?
186 |         ) {
187 |             super.onReceivedError(view, request, error)
188 |             println("webView onReceivedError: ${error?.description}")
189 |         }
190 | 
191 |         override fun onPageFinished(view: WebView?, url: String?) {
192 |             super.onPageFinished(view, url)
193 |         }
194 | 
195 |         override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
196 |             super.onPageStarted(view, url, favicon)
197 |             if (debug) {
198 |                 // vConsole
199 |                 val vConsole = assets.open("vConsole.js").bufferedReader().use { it.readText() }
200 |                 val openDebug = """var vConsole = new window.VConsole()"""
201 |                 view?.evaluateJavascript(vConsole + openDebug, null)
202 |             }
203 |             // inject js
204 |             val injectJs = assets.open("custom.js").bufferedReader().use { it.readText() }
205 |             view?.evaluateJavascript(injectJs, null)
206 |         }
207 |     }
208 | 
209 |     inner class MyChromeClient : WebChromeClient() {
210 |         override fun onProgressChanged(view: WebView?, newProgress: Int) {
211 |             super.onProgressChanged(view, newProgress)
212 |             val url = view?.url
213 |             println("wev view url:$url")
214 |         }
215 |     }
216 | }


--------------------------------------------------------------------------------
/app/src/main/java/com/app/pakeplus/ui/gallery/GalleryFragment.kt:
--------------------------------------------------------------------------------
 1 | package com.app.pakeplus.ui.gallery
 2 | 
 3 | import android.os.Bundle
 4 | import android.view.LayoutInflater
 5 | import android.view.View
 6 | import android.view.ViewGroup
 7 | import android.widget.TextView
 8 | import androidx.fragment.app.Fragment
 9 | import androidx.lifecycle.ViewModelProvider
10 | import com.app.pakeplus.databinding.FragmentGalleryBinding
11 | 
12 | class GalleryFragment : Fragment() {
13 | 
14 |     private var _binding: FragmentGalleryBinding? = null
15 | 
16 |     // This property is only valid between onCreateView and
17 |     // onDestroyView.
18 |     private val binding get() = _binding!!
19 | 
20 |     override fun onCreateView(
21 |         inflater: LayoutInflater,
22 |         container: ViewGroup?,
23 |         savedInstanceState: Bundle?
24 |     ): View {
25 |         val galleryViewModel =
26 |             ViewModelProvider(this).get(GalleryViewModel::class.java)
27 | 
28 |         _binding = FragmentGalleryBinding.inflate(inflater, container, false)
29 |         val root: View = binding.root
30 | 
31 |         val textView: TextView = binding.textGallery
32 |         galleryViewModel.text.observe(viewLifecycleOwner) {
33 |             textView.text = it
34 |         }
35 |         return root
36 |     }
37 | 
38 |     override fun onDestroyView() {
39 |         super.onDestroyView()
40 |         _binding = null
41 |     }
42 | }


--------------------------------------------------------------------------------
/app/src/main/java/com/app/pakeplus/ui/gallery/GalleryViewModel.kt:
--------------------------------------------------------------------------------
 1 | package com.app.pakeplus.ui.gallery
 2 | 
 3 | import androidx.lifecycle.LiveData
 4 | import androidx.lifecycle.MutableLiveData
 5 | import androidx.lifecycle.ViewModel
 6 | 
 7 | class GalleryViewModel : ViewModel() {
 8 | 
 9 |     private val _text = MutableLiveData<String>().apply {
10 |         value = "This is gallery Fragment"
11 |     }
12 |     val text: LiveData<String> = _text
13 | }


--------------------------------------------------------------------------------
/app/src/main/java/com/app/pakeplus/ui/home/HomeFragment.kt:
--------------------------------------------------------------------------------
 1 | package com.app.pakeplus.ui.home
 2 | 
 3 | import android.os.Bundle
 4 | import android.view.LayoutInflater
 5 | import android.view.View
 6 | import android.view.ViewGroup
 7 | import android.widget.TextView
 8 | import androidx.fragment.app.Fragment
 9 | import androidx.lifecycle.ViewModelProvider
10 | import com.app.pakeplus.databinding.FragmentHomeBinding
11 | 
12 | class HomeFragment : Fragment() {
13 | 
14 |     private var _binding: FragmentHomeBinding? = null
15 | 
16 |     // This property is only valid between onCreateView and
17 |     // onDestroyView.
18 |     private val binding get() = _binding!!
19 | 
20 |     override fun onCreateView(
21 |         inflater: LayoutInflater,
22 |         container: ViewGroup?,
23 |         savedInstanceState: Bundle?
24 |     ): View {
25 |         val homeViewModel =
26 |             ViewModelProvider(this).get(HomeViewModel::class.java)
27 | 
28 |         _binding = FragmentHomeBinding.inflate(inflater, container, false)
29 |         val root: View = binding.root
30 | 
31 |         val textView: TextView = binding.textHome
32 |         homeViewModel.text.observe(viewLifecycleOwner) {
33 |             textView.text = it
34 |         }
35 |         return root
36 |     }
37 | 
38 |     override fun onDestroyView() {
39 |         super.onDestroyView()
40 |         _binding = null
41 |     }
42 | }


--------------------------------------------------------------------------------
/app/src/main/java/com/app/pakeplus/ui/home/HomeViewModel.kt:
--------------------------------------------------------------------------------
 1 | package com.app.pakeplus.ui.home
 2 | 
 3 | import androidx.lifecycle.LiveData
 4 | import androidx.lifecycle.MutableLiveData
 5 | import androidx.lifecycle.ViewModel
 6 | 
 7 | class HomeViewModel : ViewModel() {
 8 | 
 9 |     private val _text = MutableLiveData<String>().apply {
10 |         value = "This is home Fragment"
11 |     }
12 |     val text: LiveData<String> = _text
13 | }


--------------------------------------------------------------------------------
/app/src/main/java/com/app/pakeplus/ui/slideshow/SlideshowFragment.kt:
--------------------------------------------------------------------------------
 1 | package com.app.pakeplus.ui.slideshow
 2 | 
 3 | import android.os.Bundle
 4 | import android.view.LayoutInflater
 5 | import android.view.View
 6 | import android.view.ViewGroup
 7 | import android.widget.TextView
 8 | import androidx.fragment.app.Fragment
 9 | import androidx.lifecycle.ViewModelProvider
10 | import com.app.pakeplus.databinding.FragmentSlideshowBinding
11 | 
12 | class SlideshowFragment : Fragment() {
13 | 
14 |     private var _binding: FragmentSlideshowBinding? = null
15 | 
16 |     // This property is only valid between onCreateView and
17 |     // onDestroyView.
18 |     private val binding get() = _binding!!
19 | 
20 |     override fun onCreateView(
21 |         inflater: LayoutInflater,
22 |         container: ViewGroup?,
23 |         savedInstanceState: Bundle?
24 |     ): View {
25 |         val slideshowViewModel =
26 |             ViewModelProvider(this).get(SlideshowViewModel::class.java)
27 | 
28 |         _binding = FragmentSlideshowBinding.inflate(inflater, container, false)
29 |         val root: View = binding.root
30 | 
31 |         val textView: TextView = binding.textSlideshow
32 |         slideshowViewModel.text.observe(viewLifecycleOwner) {
33 |             textView.text = it
34 |         }
35 |         return root
36 |     }
37 | 
38 |     override fun onDestroyView() {
39 |         super.onDestroyView()
40 |         _binding = null
41 |     }
42 | }


--------------------------------------------------------------------------------
/app/src/main/java/com/app/pakeplus/ui/slideshow/SlideshowViewModel.kt:
--------------------------------------------------------------------------------
 1 | package com.app.pakeplus.ui.slideshow
 2 | 
 3 | import androidx.lifecycle.LiveData
 4 | import androidx.lifecycle.MutableLiveData
 5 | import androidx.lifecycle.ViewModel
 6 | 
 7 | class SlideshowViewModel : ViewModel() {
 8 | 
 9 |     private val _text = MutableLiveData<String>().apply {
10 |         value = "This is slideshow Fragment"
11 |     }
12 |     val text: LiveData<String> = _text
13 | }


--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi-v26/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/drawable-anydpi-v26/ic_launcher_foreground.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <vector
 3 |     android:height="108dp"
 4 |     android:width="108dp"
 5 |     android:viewportHeight="108"
 6 |     android:viewportWidth="108"
 7 |     xmlns:android="http://schemas.android.com/apk/res/android">
 8 |     <path android:fillColor="#3DDC84"
 9 |           android:pathData="M0,0h108v108h-108z"/>
10 |     <path android:fillColor="#00000000" android:pathData="M9,0L9,108"
11 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
12 |     <path android:fillColor="#00000000" android:pathData="M19,0L19,108"
13 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
14 |     <path android:fillColor="#00000000" android:pathData="M29,0L29,108"
15 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
16 |     <path android:fillColor="#00000000" android:pathData="M39,0L39,108"
17 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
18 |     <path android:fillColor="#00000000" android:pathData="M49,0L49,108"
19 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
20 |     <path android:fillColor="#00000000" android:pathData="M59,0L59,108"
21 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
22 |     <path android:fillColor="#00000000" android:pathData="M69,0L69,108"
23 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
24 |     <path android:fillColor="#00000000" android:pathData="M79,0L79,108"
25 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
26 |     <path android:fillColor="#00000000" android:pathData="M89,0L89,108"
27 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
28 |     <path android:fillColor="#00000000" android:pathData="M99,0L99,108"
29 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
30 |     <path android:fillColor="#00000000" android:pathData="M0,9L108,9"
31 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
32 |     <path android:fillColor="#00000000" android:pathData="M0,19L108,19"
33 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
34 |     <path android:fillColor="#00000000" android:pathData="M0,29L108,29"
35 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
36 |     <path android:fillColor="#00000000" android:pathData="M0,39L108,39"
37 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
38 |     <path android:fillColor="#00000000" android:pathData="M0,49L108,49"
39 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
40 |     <path android:fillColor="#00000000" android:pathData="M0,59L108,59"
41 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
42 |     <path android:fillColor="#00000000" android:pathData="M0,69L108,69"
43 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
44 |     <path android:fillColor="#00000000" android:pathData="M0,79L108,79"
45 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
46 |     <path android:fillColor="#00000000" android:pathData="M0,89L108,89"
47 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
48 |     <path android:fillColor="#00000000" android:pathData="M0,99L108,99"
49 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
50 |     <path android:fillColor="#00000000" android:pathData="M19,29L89,29"
51 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
52 |     <path android:fillColor="#00000000" android:pathData="M19,39L89,39"
53 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
54 |     <path android:fillColor="#00000000" android:pathData="M19,49L89,49"
55 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
56 |     <path android:fillColor="#00000000" android:pathData="M19,59L89,59"
57 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
58 |     <path android:fillColor="#00000000" android:pathData="M19,69L89,69"
59 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
60 |     <path android:fillColor="#00000000" android:pathData="M19,79L89,79"
61 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
62 |     <path android:fillColor="#00000000" android:pathData="M29,19L29,89"
63 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
64 |     <path android:fillColor="#00000000" android:pathData="M39,19L39,89"
65 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
66 |     <path android:fillColor="#00000000" android:pathData="M49,19L49,89"
67 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
68 |     <path android:fillColor="#00000000" android:pathData="M59,19L59,89"
69 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
70 |     <path android:fillColor="#00000000" android:pathData="M69,19L69,89"
71 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
72 |     <path android:fillColor="#00000000" android:pathData="M79,19L79,89"
73 |           android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
74 | </vector>
75 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
 1 | <vector xmlns:android="http://schemas.android.com/apk/res/android"
 2 |     xmlns:aapt="http://schemas.android.com/aapt"
 3 |     android:width="108dp"
 4 |     android:height="108dp"
 5 |     android:viewportWidth="108"
 6 |     android:viewportHeight="108">
 7 |     <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
 8 |         <aapt:attr name="android:fillColor">
 9 |             <gradient
10 |                 android:endX="85.84757"
11 |                 android:endY="92.4963"
12 |                 android:startX="42.9492"
13 |                 android:startY="49.59793"
14 |                 android:type="linear">
15 |                 <item
16 |                     android:color="#44000000"
17 |                     android:offset="0.0" />
18 |                 <item
19 |                     android:color="#00000000"
20 |                     android:offset="1.0" />
21 |             </gradient>
22 |         </aapt:attr>
23 |     </path>
24 |     <path
25 |         android:fillColor="#FFFFFF"
26 |         android:fillType="nonZero"
27 |         android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
28 |         android:strokeWidth="1"
29 |         android:strokeColor="#00000000" />
30 | </vector>


--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_menu_camera.xml:
--------------------------------------------------------------------------------
 1 | <vector xmlns:android="http://schemas.android.com/apk/res/android"
 2 |     android:width="24dp"
 3 |     android:height="24dp"
 4 |     android:viewportWidth="24.0"
 5 |     android:viewportHeight="24.0">
 6 |     <path
 7 |         android:fillColor="#FF000000"
 8 |         android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0" />
 9 |     <path
10 |         android:fillColor="#FF000000"
11 |         android:pathData="M9,2L7.17,4H4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2H9zm3,15c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z" />
12 | </vector>
13 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_menu_gallery.xml:
--------------------------------------------------------------------------------
 1 | <vector xmlns:android="http://schemas.android.com/apk/res/android"
 2 |     android:width="24dp"
 3 |     android:height="24dp"
 4 |     android:viewportWidth="24.0"
 5 |     android:viewportHeight="24.0">
 6 |     <path
 7 |         android:fillColor="#FF000000"
 8 |         android:pathData="M22,16V4c0,-1.1 -0.9,-2 -2,-2H8c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2zm-11,-4l2.03,2.71L16,11l4,5H8l3,-4zM2,6v14c0,1.1 0.9,2 2,2h14v-2H4V6H2z" />
 9 | </vector>
10 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_menu_slideshow.xml:
--------------------------------------------------------------------------------
 1 | <vector xmlns:android="http://schemas.android.com/apk/res/android"
 2 |     android:width="24dp"
 3 |     android:height="24dp"
 4 |     android:viewportWidth="24.0"
 5 |     android:viewportHeight="24.0">
 6 |     <path
 7 |         android:fillColor="#FF000000"
 8 |         android:pathData="M4,6H2v14c0,1.1 0.9,2 2,2h14v-2H4V6zm16,-4H8c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4c0,-1.1 -0.9,-2 -2,-2zm-8,12.5v-9l6,4.5 -6,4.5z" />
 9 | </vector>
10 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable/side_nav_bar.xml:
--------------------------------------------------------------------------------
1 | <shape xmlns:android="http://schemas.android.com/apk/res/android"
2 |     android:shape="rectangle">
3 |     <gradient
4 |         android:angle="135"
5 |         android:centerColor="#009688"
6 |         android:endColor="#00695C"
7 |         android:startColor="#4DB6AC"
8 |         android:type="linear" />
9 | </shape>


--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     xmlns:app="http://schemas.android.com/apk/res-auto"
 4 |     xmlns:tools="http://schemas.android.com/tools"
 5 |     android:id="@+id/drawer_layout"
 6 |     android:layout_width="match_parent"
 7 |     android:layout_height="match_parent"
 8 |     android:fitsSystemWindows="true"
 9 |     tools:openDrawer="start">
10 | 
11 |     <include
12 |         android:id="@+id/app_bar_main"
13 |         layout="@layout/app_bar_main"
14 |         android:layout_width="match_parent"
15 |         android:layout_height="match_parent" />
16 | 
17 |     <com.google.android.material.navigation.NavigationView
18 |         android:id="@+id/nav_view"
19 |         android:layout_width="wrap_content"
20 |         android:layout_height="match_parent"
21 |         android:layout_gravity="start"
22 |         android:fitsSystemWindows="true"
23 |         app:headerLayout="@layout/nav_header_main"
24 |         app:menu="@menu/activity_main_drawer" />
25 | </androidx.drawerlayout.widget.DrawerLayout>


--------------------------------------------------------------------------------
/app/src/main/res/layout/app_bar_main.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     xmlns:app="http://schemas.android.com/apk/res-auto"
 4 |     xmlns:tools="http://schemas.android.com/tools"
 5 |     android:layout_width="match_parent"
 6 |     android:layout_height="match_parent"
 7 |     tools:context=".MainActivity">
 8 | 
 9 |     <com.google.android.material.appbar.AppBarLayout
10 |         android:layout_width="match_parent"
11 |         android:layout_height="wrap_content"
12 |         android:theme="@style/Theme.PakePlus.AppBarOverlay">
13 | 
14 |         <androidx.appcompat.widget.Toolbar
15 |             android:id="@+id/toolbar"
16 |             android:layout_width="match_parent"
17 |             android:layout_height="?attr/actionBarSize"
18 |             android:background="?attr/colorPrimary"
19 |             app:popupTheme="@style/Theme.PakePlus.PopupOverlay" />
20 | 
21 |     </com.google.android.material.appbar.AppBarLayout>
22 | 
23 |     <include layout="@layout/content_main" />
24 | 
25 |     <com.google.android.material.floatingactionbutton.FloatingActionButton
26 |         android:id="@+id/fab"
27 |         android:layout_width="wrap_content"
28 |         android:layout_height="wrap_content"
29 |         android:layout_gravity="bottom|end"
30 |         android:layout_marginEnd="@dimen/fab_margin"
31 |         android:layout_marginBottom="16dp"
32 |         app:srcCompat="@android:drawable/ic_dialog_email" />
33 | 
34 | </androidx.coordinatorlayout.widget.CoordinatorLayout>


--------------------------------------------------------------------------------
/app/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     xmlns:app="http://schemas.android.com/apk/res-auto"
 4 |     xmlns:tools="http://schemas.android.com/tools"
 5 |     android:layout_width="match_parent"
 6 |     android:layout_height="match_parent"
 7 |     app:layout_behavior="@string/appbar_scrolling_view_behavior"
 8 |     tools:showIn="@layout/app_bar_main">
 9 | 
10 |     <fragment
11 |         android:id="@+id/nav_host_fragment_content_main"
12 |         android:name="androidx.navigation.fragment.NavHostFragment"
13 |         android:layout_width="match_parent"
14 |         android:layout_height="match_parent"
15 |         app:defaultNavHost="true"
16 |         app:layout_constraintLeft_toLeftOf="parent"
17 |         app:layout_constraintRight_toRightOf="parent"
18 |         app:layout_constraintTop_toTopOf="parent"
19 |         app:navGraph="@navigation/mobile_navigation" />
20 | </androidx.constraintlayout.widget.ConstraintLayout>


--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_gallery.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     xmlns:app="http://schemas.android.com/apk/res-auto"
 4 |     xmlns:tools="http://schemas.android.com/tools"
 5 |     android:layout_width="match_parent"
 6 |     android:layout_height="match_parent"
 7 |     tools:context=".ui.gallery.GalleryFragment">
 8 | 
 9 |     <TextView
10 |         android:id="@+id/text_gallery"
11 |         android:layout_width="match_parent"
12 |         android:layout_height="wrap_content"
13 |         android:layout_marginStart="8dp"
14 |         android:layout_marginTop="8dp"
15 |         android:layout_marginEnd="8dp"
16 |         android:textAlignment="center"
17 |         android:textSize="20sp"
18 |         app:layout_constraintBottom_toBottomOf="parent"
19 |         app:layout_constraintEnd_toEndOf="parent"
20 |         app:layout_constraintStart_toStartOf="parent"
21 |         app:layout_constraintTop_toTopOf="parent" />
22 | </androidx.constraintlayout.widget.ConstraintLayout>


--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_home.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     xmlns:app="http://schemas.android.com/apk/res-auto"
 4 |     xmlns:tools="http://schemas.android.com/tools"
 5 |     android:layout_width="match_parent"
 6 |     android:layout_height="match_parent"
 7 |     tools:context=".ui.home.HomeFragment">
 8 | 
 9 |     <TextView
10 |         android:id="@+id/text_home"
11 |         android:layout_width="match_parent"
12 |         android:layout_height="wrap_content"
13 |         android:layout_marginStart="8dp"
14 |         android:layout_marginTop="8dp"
15 |         android:layout_marginEnd="8dp"
16 |         android:textAlignment="center"
17 |         android:textSize="20sp"
18 |         app:layout_constraintBottom_toBottomOf="parent"
19 |         app:layout_constraintEnd_toEndOf="parent"
20 |         app:layout_constraintStart_toStartOf="parent"
21 |         app:layout_constraintTop_toTopOf="parent" />
22 | </androidx.constraintlayout.widget.ConstraintLayout>


--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_slideshow.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     xmlns:app="http://schemas.android.com/apk/res-auto"
 4 |     xmlns:tools="http://schemas.android.com/tools"
 5 |     android:layout_width="match_parent"
 6 |     android:layout_height="match_parent"
 7 |     tools:context=".ui.slideshow.SlideshowFragment">
 8 | 
 9 |     <TextView
10 |         android:id="@+id/text_slideshow"
11 |         android:layout_width="match_parent"
12 |         android:layout_height="wrap_content"
13 |         android:layout_marginStart="8dp"
14 |         android:layout_marginTop="8dp"
15 |         android:layout_marginEnd="8dp"
16 |         android:textAlignment="center"
17 |         android:textSize="20sp"
18 |         app:layout_constraintBottom_toBottomOf="parent"
19 |         app:layout_constraintEnd_toEndOf="parent"
20 |         app:layout_constraintStart_toStartOf="parent"
21 |         app:layout_constraintTop_toTopOf="parent" />
22 | </androidx.constraintlayout.widget.ConstraintLayout>


--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_header_main.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     xmlns:app="http://schemas.android.com/apk/res-auto"
 4 |     android:layout_width="match_parent"
 5 |     android:layout_height="@dimen/nav_header_height"
 6 |     android:background="@drawable/side_nav_bar"
 7 |     android:gravity="bottom"
 8 |     android:orientation="vertical"
 9 |     android:paddingLeft="@dimen/activity_horizontal_margin"
10 |     android:paddingTop="@dimen/activity_vertical_margin"
11 |     android:paddingRight="@dimen/activity_horizontal_margin"
12 |     android:paddingBottom="@dimen/activity_vertical_margin"
13 |     android:theme="@style/ThemeOverlay.AppCompat.Dark">
14 | 
15 |     <ImageView
16 |         android:id="@+id/imageView"
17 |         android:layout_width="wrap_content"
18 |         android:layout_height="wrap_content"
19 |         android:contentDescription="@string/nav_header_desc"
20 |         android:paddingTop="@dimen/nav_header_vertical_spacing"
21 |         app:srcCompat="@mipmap/ic_launcher_round" />
22 | 
23 |     <TextView
24 |         android:layout_width="match_parent"
25 |         android:layout_height="wrap_content"
26 |         android:paddingTop="@dimen/nav_header_vertical_spacing"
27 |         android:text="@string/nav_header_title"
28 |         android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
29 | 
30 |     <TextView
31 |         android:id="@+id/textView"
32 |         android:layout_width="wrap_content"
33 |         android:layout_height="wrap_content"
34 |         android:text="@string/nav_header_subtitle" />
35 | </LinearLayout>


--------------------------------------------------------------------------------
/app/src/main/res/layout/single_main.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     xmlns:app="http://schemas.android.com/apk/res-auto"
 4 |     xmlns:tools="http://schemas.android.com/tools"
 5 |     android:id="@+id/ConstraintLayout"
 6 |     android:layout_width="match_parent"
 7 |     android:layout_height="match_parent">
 8 | 
 9 |     <WebView
10 |         android:id="@+id/webview"
11 |         android:layout_width="match_parent"
12 |         android:layout_height="match_parent" />
13 | </androidx.constraintlayout.widget.ConstraintLayout>


--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_main_drawer.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <menu xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     xmlns:tools="http://schemas.android.com/tools"
 4 |     tools:showIn="navigation_view">
 5 | 
 6 |     <group android:checkableBehavior="single">
 7 |         <item
 8 |             android:id="@+id/nav_home"
 9 |             android:icon="@drawable/ic_menu_camera"
10 |             android:title="@string/menu_home" />
11 |         <item
12 |             android:id="@+id/nav_gallery"
13 |             android:icon="@drawable/ic_menu_gallery"
14 |             android:title="@string/menu_gallery" />
15 |         <item
16 |             android:id="@+id/nav_slideshow"
17 |             android:icon="@drawable/ic_menu_slideshow"
18 |             android:title="@string/menu_slideshow" />
19 |     </group>
20 | </menu>


--------------------------------------------------------------------------------
/app/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <menu xmlns:android="http://schemas.android.com/apk/res/android"
3 |     xmlns:app="http://schemas.android.com/apk/res-auto">
4 |     <item
5 |         android:id="@+id/action_settings"
6 |         android:orderInCategory="100"
7 |         android:title="@string/action_settings"
8 |         app:showAsAction="never" />
9 | </menu>


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 | <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
2 |     <background android:drawable="@mipmap/ic_launcher_background"/>
3 |     <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
4 | </adaptive-icon>


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 | <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
2 |     <background android:drawable="@mipmap/ic_launcher_background"/>
3 |     <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
4 | </adaptive-icon>


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-hdpi/ic_launcher.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_background.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-hdpi/ic_launcher_background.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-mdpi/ic_launcher.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_background.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-mdpi/ic_launcher_background.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-xhdpi/ic_launcher.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_background.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-xhdpi/ic_launcher_background.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp


--------------------------------------------------------------------------------
/app/src/main/res/navigation/mobile_navigation.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <navigation xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     xmlns:app="http://schemas.android.com/apk/res-auto"
 4 |     xmlns:tools="http://schemas.android.com/tools"
 5 |     android:id="@+id/mobile_navigation"
 6 |     app:startDestination="@+id/nav_home">
 7 | 
 8 |     <fragment
 9 |         android:id="@+id/nav_home"
10 |         android:name="com.app.pakeplus.ui.home.HomeFragment"
11 |         android:label="@string/menu_home"
12 |         tools:layout="@layout/fragment_home" />
13 | 
14 |     <fragment
15 |         android:id="@+id/nav_gallery"
16 |         android:name="com.app.pakeplus.ui.gallery.GalleryFragment"
17 |         android:label="@string/menu_gallery"
18 |         tools:layout="@layout/fragment_gallery" />
19 | 
20 |     <fragment
21 |         android:id="@+id/nav_slideshow"
22 |         android:name="com.app.pakeplus.ui.slideshow.SlideshowFragment"
23 |         android:label="@string/menu_slideshow"
24 |         tools:layout="@layout/fragment_slideshow" />
25 | </navigation>


--------------------------------------------------------------------------------
/app/src/main/res/values-land/dimens.xml:
--------------------------------------------------------------------------------
1 | <resources>
2 |     <dimen name="fab_margin">48dp</dimen>
3 | </resources>


--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
 1 | <resources xmlns:tools="http://schemas.android.com/tools">
 2 |     <!-- Base application theme. -->
 3 |     <style name="Theme.PakePlus" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
 4 |         <!-- Primary brand color. -->
 5 |         <item name="colorPrimary">@color/purple_200</item>
 6 |         <item name="colorPrimaryVariant">@color/purple_700</item>
 7 |         <item name="colorOnPrimary">@color/black</item>
 8 |         <!-- Secondary brand color. -->
 9 |         <item name="colorSecondary">@color/teal_200</item>
10 |         <item name="colorSecondaryVariant">@color/teal_200</item>
11 |         <item name="colorOnSecondary">@color/black</item>
12 |         <!-- Status bar color. -->
13 |         <item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
14 |         <!-- Customize your theme here. -->
15 |     </style>
16 | </resources>


--------------------------------------------------------------------------------
/app/src/main/res/values-w1240dp/dimens.xml:
--------------------------------------------------------------------------------
1 | <resources>
2 |     <dimen name="fab_margin">200dp</dimen>
3 | </resources>


--------------------------------------------------------------------------------
/app/src/main/res/values-w600dp/dimens.xml:
--------------------------------------------------------------------------------
1 | <resources>
2 |     <dimen name="fab_margin">48dp</dimen>
3 | </resources>


--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <resources>
 3 |     <color name="purple_200">#FFBB86FC</color>
 4 |     <color name="purple_500">#FF6200EE</color>
 5 |     <color name="purple_700">#FF3700B3</color>
 6 |     <color name="teal_200">#FF03DAC5</color>
 7 |     <color name="teal_700">#FF018786</color>
 8 |     <color name="black">#FF000000</color>
 9 |     <color name="white">#FFFFFFFF</color>
10 | </resources>


--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 | <resources>
2 |     <!-- Default screen margins, per the Android Design guidelines. -->
3 |     <dimen name="activity_horizontal_margin">16dp</dimen>
4 |     <dimen name="activity_vertical_margin">16dp</dimen>
5 |     <dimen name="nav_header_vertical_spacing">8dp</dimen>
6 |     <dimen name="nav_header_height">176dp</dimen>
7 |     <dimen name="fab_margin">16dp</dimen>
8 | </resources>


--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
 1 | <resources>
 2 |     <string name="app_name">PakePlus</string>
 3 |     <string name="navigation_drawer_open">Open navigation drawer</string>
 4 |     <string name="navigation_drawer_close">Close navigation drawer</string>
 5 |     <string name="nav_header_title">Android Studio</string>
 6 |     <string name="nav_header_subtitle">android.studio@android.com</string>
 7 |     <string name="nav_header_desc">Navigation header</string>
 8 |     <string name="action_settings">Settings</string>
 9 |     <string name="debug">close</string>
10 | 
11 |     <string name="menu_home">Home</string>
12 |     <string name="menu_gallery">Gallery</string>
13 |     <string name="menu_slideshow">Slideshow</string>
14 | </resources>


--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
 1 | <resources xmlns:tools="http://schemas.android.com/tools">
 2 |     <!-- Base application theme. -->
 3 |     <style name="Theme.PakePlus" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
 4 |         <!-- Primary brand color. -->
 5 |         <item name="colorPrimary">@color/purple_500</item>
 6 |         <item name="colorPrimaryVariant">@color/purple_700</item>
 7 |         <item name="colorOnPrimary">@color/white</item>
 8 |         <!-- Secondary brand color. -->
 9 |         <item name="colorSecondary">@color/teal_200</item>
10 |         <item name="colorSecondaryVariant">@color/teal_700</item>
11 |         <item name="colorOnSecondary">@color/black</item>
12 |         <!-- Status bar color. -->
13 |         <item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
14 |         <!-- Customize your theme here. -->
15 |     </style>
16 | 
17 |     <style name="Theme.PakePlus.NoActionBar">
18 |         <item name="windowActionBar">false</item>
19 |         <item name="windowNoTitle">true</item>
20 |     </style>
21 | 
22 |     <style name="Theme.PakePlus.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
23 | 
24 |     <style name="Theme.PakePlus.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
25 | </resources>


--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?><!--
 2 |    Sample backup rules file; uncomment and customize as necessary.
 3 |    See https://developer.android.com/guide/topics/data/autobackup
 4 |    for details.
 5 |    Note: This file is ignored for devices older that API 31
 6 |    See https://developer.android.com/about/versions/12/backup-restore
 7 | -->
 8 | <full-backup-content>
 9 |     <!--
10 |    <include domain="sharedpref" path="."/>
11 |    <exclude domain="sharedpref" path="device.xml"/>
12 | -->
13 | </full-backup-content>


--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?><!--
 2 |    Sample data extraction rules file; uncomment and customize as necessary.
 3 |    See https://developer.android.com/about/versions/12/backup-restore#xml-changes
 4 |    for details.
 5 | -->
 6 | <data-extraction-rules>
 7 |     <cloud-backup>
 8 |         <!-- TODO: Use <include> and <exclude> to control what is backed up.
 9 |         <include .../>
10 |         <exclude .../>
11 |         -->
12 |     </cloud-backup>
13 |     <!--
14 |     <device-transfer>
15 |         <include .../>
16 |         <exclude .../>
17 |     </device-transfer>
18 |     -->
19 | </data-extraction-rules>


--------------------------------------------------------------------------------
/app/src/test/java/com/app/pakeplus/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
 1 | package com.app.pakeplus
 2 | 
 3 | import org.junit.Test
 4 | 
 5 | import org.junit.Assert.*
 6 | 
 7 | /**
 8 |  * Example local unit test, which will execute on the development machine (host).
 9 |  *
10 |  * See [testing documentation](http://d.android.com/tools/testing).
11 |  */
12 | class ExampleUnitTest {
13 |     @Test
14 |     fun addition_isCorrect() {
15 |         assertEquals(4, 2 + 2)
16 |     }
17 | }


--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 |     alias(libs.plugins.androidApplication) apply false
4 |     alias(libs.plugins.jetbrainsKotlinAndroid) apply false
5 | }


--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
 1 | # Project-wide Gradle settings.
 2 | # IDE (e.g. Android Studio) users:
 3 | # Gradle settings configured through the IDE *will override*
 4 | # any settings specified in this file.
 5 | # For more details on how to configure your build environment visit
 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
 7 | # Specifies the JVM arguments used for the daemon process.
 8 | # The setting is particularly useful for tweaking memory settings.
 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. For more details, visit
12 | # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true


--------------------------------------------------------------------------------
/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
 1 | [versions]
 2 | agp = "8.3.0"
 3 | kotlin = "1.9.0"
 4 | coreKtx = "1.10.1"
 5 | junit = "4.13.2"
 6 | junitVersion = "1.1.5"
 7 | espressoCore = "3.5.1"
 8 | appcompat = "1.6.1"
 9 | material = "1.10.0"
10 | constraintlayout = "2.1.4"
11 | lifecycleLivedataKtx = "2.6.1"
12 | lifecycleViewmodelKtx = "2.6.1"
13 | navigationFragmentKtx = "2.6.0"
14 | navigationUiKtx = "2.6.0"
15 | 
16 | [libraries]
17 | androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
18 | junit = { group = "junit", name = "junit", version.ref = "junit" }
19 | androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
20 | androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
21 | androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
22 | material = { group = "com.google.android.material", name = "material", version.ref = "material" }
23 | androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
24 | androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtx" }
25 | androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" }
26 | androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigationFragmentKtx" }
27 | androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigationUiKtx" }
28 | 
29 | [plugins]
30 | androidApplication = { id = "com.android.application", version.ref = "agp" }
31 | jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
32 | 
33 | 


--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sjj1024/PakePlus-Android/76eb6beac03fafd97a962bb2be517c81be161462/gradle/wrapper/gradle-wrapper.jar


--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Mar 29 18:10:52 CST 2025
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 | 


--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
  1 | #!/usr/bin/env sh
  2 | 
  3 | #
  4 | # Copyright 2015 the original author or authors.
  5 | #
  6 | # Licensed under the Apache License, Version 2.0 (the "License");
  7 | # you may not use this file except in compliance with the License.
  8 | # You may obtain a copy of the License at
  9 | #
 10 | #      https://www.apache.org/licenses/LICENSE-2.0
 11 | #
 12 | # Unless required by applicable law or agreed to in writing, software
 13 | # distributed under the License is distributed on an "AS IS" BASIS,
 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15 | # See the License for the specific language governing permissions and
 16 | # limitations under the License.
 17 | #
 18 | 
 19 | ##############################################################################
 20 | ##
 21 | ##  Gradle start up script for UN*X
 22 | ##
 23 | ##############################################################################
 24 | 
 25 | # Attempt to set APP_HOME
 26 | # Resolve links: $0 may be a link
 27 | PRG="$0"
 28 | # Need this for relative symlinks.
 29 | while [ -h "$PRG" ] ; do
 30 |     ls=`ls -ld "$PRG"`
 31 |     link=`expr "$ls" : '.*-> \(.*\)
#39;`
 32 |     if expr "$link" : '/.*' > /dev/null; then
 33 |         PRG="$link"
 34 |     else
 35 |         PRG=`dirname "$PRG"`"/$link"
 36 |     fi
 37 | done
 38 | SAVED="`pwd`"
 39 | cd "`dirname \"$PRG\"`/" >/dev/null
 40 | APP_HOME="`pwd -P`"
 41 | cd "$SAVED" >/dev/null
 42 | 
 43 | APP_NAME="Gradle"
 44 | APP_BASE_NAME=`basename "$0"`
 45 | 
 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
 48 | 
 49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
 50 | MAX_FD="maximum"
 51 | 
 52 | warn () {
 53 |     echo "$*"
 54 | }
 55 | 
 56 | die () {
 57 |     echo
 58 |     echo "$*"
 59 |     echo
 60 |     exit 1
 61 | }
 62 | 
 63 | # OS specific support (must be 'true' or 'false').
 64 | cygwin=false
 65 | msys=false
 66 | darwin=false
 67 | nonstop=false
 68 | case "`uname`" in
 69 |   CYGWIN* )
 70 |     cygwin=true
 71 |     ;;
 72 |   Darwin* )
 73 |     darwin=true
 74 |     ;;
 75 |   MINGW* )
 76 |     msys=true
 77 |     ;;
 78 |   NONSTOP* )
 79 |     nonstop=true
 80 |     ;;
 81 | esac
 82 | 
 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 84 | 
 85 | 
 86 | # Determine the Java command to use to start the JVM.
 87 | if [ -n "$JAVA_HOME" ] ; then
 88 |     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
 89 |         # IBM's JDK on AIX uses strange locations for the executables
 90 |         JAVACMD="$JAVA_HOME/jre/sh/java"
 91 |     else
 92 |         JAVACMD="$JAVA_HOME/bin/java"
 93 |     fi
 94 |     if [ ! -x "$JAVACMD" ] ; then
 95 |         die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
 96 | 
 97 | Please set the JAVA_HOME variable in your environment to match the
 98 | location of your Java installation."
 99 |     fi
100 | else
101 |     JAVACMD="java"
102 |     which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 | 
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 | 
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 |     MAX_FD_LIMIT=`ulimit -H -n`
111 |     if [ $? -eq 0 ] ; then
112 |         if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 |             MAX_FD="$MAX_FD_LIMIT"
114 |         fi
115 |         ulimit -n $MAX_FD
116 |         if [ $? -ne 0 ] ; then
117 |             warn "Could not set maximum file descriptor limit: $MAX_FD"
118 |         fi
119 |     else
120 |         warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 |     fi
122 | fi
123 | 
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 |     GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 | 
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 |     APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 |     CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 | 
134 |     JAVACMD=`cygpath --unix "$JAVACMD"`
135 | 
136 |     # We build the pattern for arguments to be converted via cygpath
137 |     ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 |     SEP=""
139 |     for dir in $ROOTDIRSRAW ; do
140 |         ROOTDIRS="$ROOTDIRS$SEP$dir"
141 |         SEP="|"
142 |     done
143 |     OURCYGPATTERN="(^($ROOTDIRS))"
144 |     # Add a user-defined pattern to the cygpath arguments
145 |     if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 |         OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 |     fi
148 |     # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 |     i=0
150 |     for arg in "$@" ; do
151 |         CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 |         CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
153 | 
154 |         if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
155 |             eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 |         else
157 |             eval `echo args$i`="\"$arg\""
158 |         fi
159 |         i=`expr $i + 1`
160 |     done
161 |     case $i in
162 |         0) set -- ;;
163 |         1) set -- "$args0" ;;
164 |         2) set -- "$args0" "$args1" ;;
165 |         3) set -- "$args0" "$args1" "$args2" ;;
166 |         4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 |         5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 |         6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 |         7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 |         8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 |         9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 |     esac
173 | fi
174 | 
175 | # Escape application args
176 | save () {
177 |     for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 |     echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 | 
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 | 
185 | exec "$JAVACMD" "$@"
186 | 


--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
 1 | @rem
 2 | @rem Copyright 2015 the original author or authors.
 3 | @rem
 4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
 5 | @rem you may not use this file except in compliance with the License.
 6 | @rem You may obtain a copy of the License at
 7 | @rem
 8 | @rem      https://www.apache.org/licenses/LICENSE-2.0
 9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 | 
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem  Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 | 
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 | 
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 | 
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 | 
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 | 
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 | 
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 | 
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 | 
51 | goto fail
52 | 
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 | 
57 | if exist "%JAVA_EXE%" goto execute
58 | 
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 | 
65 | goto fail
66 | 
67 | :execute
68 | @rem Setup the command line
69 | 
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 | 
72 | 
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 | 
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 | 
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 | 
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 | 
89 | :omega
90 | 


--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "name": "pakeplus-android",
 3 |     "version": "1.0.0",
 4 |     "description": "Pake Plus Android",
 5 |     "main": "index.js",
 6 |     "scripts": {
 7 |         "pp:worker": "node ./scripts/ppworker.cjs",
 8 |         "restore": "git restore ."
 9 |     },
10 |     "keywords": [
11 |         "pakeplus",
12 |         "pakeplus-android"
13 |     ],
14 |     "author": "1024小神",
15 |     "license": "ISC",
16 |     "dependencies": {
17 |         "commander": "^13.1.0",
18 |         "fs-extra": "^11.3.0",
19 |         "sharp": "^0.34.1"
20 |     }
21 | }
22 | 


--------------------------------------------------------------------------------
/pnpm-lock.yaml:
--------------------------------------------------------------------------------
  1 | lockfileVersion: '9.0'
  2 | 
  3 | settings:
  4 |   autoInstallPeers: true
  5 |   excludeLinksFromLockfile: false
  6 | 
  7 | importers:
  8 | 
  9 |   .:
 10 |     dependencies:
 11 |       commander:
 12 |         specifier: ^13.1.0
 13 |         version: 13.1.0
 14 |       fs-extra:
 15 |         specifier: ^11.3.0
 16 |         version: 11.3.0
 17 |       sharp:
 18 |         specifier: ^0.34.1
 19 |         version: 0.34.1
 20 | 
 21 | packages:
 22 | 
 23 |   '@emnapi/runtime@1.4.0':
 24 |     resolution: {integrity: sha512-64WYIf4UYcdLnbKn/umDlNjQDSS8AgZrI/R9+x5ilkUVFxXcA1Ebl+gQLc/6mERA4407Xof0R7wEyEuj091CVw==}
 25 | 
 26 |   '@img/sharp-darwin-arm64@0.34.1':
 27 |     resolution: {integrity: sha512-pn44xgBtgpEbZsu+lWf2KNb6OAf70X68k+yk69Ic2Xz11zHR/w24/U49XT7AeRwJ0Px+mhALhU5LPci1Aymk7A==}
 28 |     engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
 29 |     cpu: [arm64]
 30 |     os: [darwin]
 31 | 
 32 |   '@img/sharp-darwin-x64@0.34.1':
 33 |     resolution: {integrity: sha512-VfuYgG2r8BpYiOUN+BfYeFo69nP/MIwAtSJ7/Zpxc5QF3KS22z8Pvg3FkrSFJBPNQ7mmcUcYQFBmEQp7eu1F8Q==}
 34 |     engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
 35 |     cpu: [x64]
 36 |     os: [darwin]
 37 | 
 38 |   '@img/sharp-libvips-darwin-arm64@1.1.0':
 39 |     resolution: {integrity: sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==}
 40 |     cpu: [arm64]
 41 |     os: [darwin]
 42 | 
 43 |   '@img/sharp-libvips-darwin-x64@1.1.0':
 44 |     resolution: {integrity: sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==}
 45 |     cpu: [x64]
 46 |     os: [darwin]
 47 | 
 48 |   '@img/sharp-libvips-linux-arm64@1.1.0':
 49 |     resolution: {integrity: sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==}
 50 |     cpu: [arm64]
 51 |     os: [linux]
 52 |     libc: [glibc]
 53 | 
 54 |   '@img/sharp-libvips-linux-arm@1.1.0':
 55 |     resolution: {integrity: sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==}
 56 |     cpu: [arm]
 57 |     os: [linux]
 58 |     libc: [glibc]
 59 | 
 60 |   '@img/sharp-libvips-linux-ppc64@1.1.0':
 61 |     resolution: {integrity: sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==}
 62 |     cpu: [ppc64]
 63 |     os: [linux]
 64 |     libc: [glibc]
 65 | 
 66 |   '@img/sharp-libvips-linux-s390x@1.1.0':
 67 |     resolution: {integrity: sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==}
 68 |     cpu: [s390x]
 69 |     os: [linux]
 70 |     libc: [glibc]
 71 | 
 72 |   '@img/sharp-libvips-linux-x64@1.1.0':
 73 |     resolution: {integrity: sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==}
 74 |     cpu: [x64]
 75 |     os: [linux]
 76 |     libc: [glibc]
 77 | 
 78 |   '@img/sharp-libvips-linuxmusl-arm64@1.1.0':
 79 |     resolution: {integrity: sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==}
 80 |     cpu: [arm64]
 81 |     os: [linux]
 82 |     libc: [musl]
 83 | 
 84 |   '@img/sharp-libvips-linuxmusl-x64@1.1.0':
 85 |     resolution: {integrity: sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==}
 86 |     cpu: [x64]
 87 |     os: [linux]
 88 |     libc: [musl]
 89 | 
 90 |   '@img/sharp-linux-arm64@0.34.1':
 91 |     resolution: {integrity: sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ==}
 92 |     engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
 93 |     cpu: [arm64]
 94 |     os: [linux]
 95 |     libc: [glibc]
 96 | 
 97 |   '@img/sharp-linux-arm@0.34.1':
 98 |     resolution: {integrity: sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA==}
 99 |     engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
100 |     cpu: [arm]
101 |     os: [linux]
102 |     libc: [glibc]
103 | 
104 |   '@img/sharp-linux-s390x@0.34.1':
105 |     resolution: {integrity: sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA==}
106 |     engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
107 |     cpu: [s390x]
108 |     os: [linux]
109 |     libc: [glibc]
110 | 
111 |   '@img/sharp-linux-x64@0.34.1':
112 |     resolution: {integrity: sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA==}
113 |     engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
114 |     cpu: [x64]
115 |     os: [linux]
116 |     libc: [glibc]
117 | 
118 |   '@img/sharp-linuxmusl-arm64@0.34.1':
119 |     resolution: {integrity: sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ==}
120 |     engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
121 |     cpu: [arm64]
122 |     os: [linux]
123 |     libc: [musl]
124 | 
125 |   '@img/sharp-linuxmusl-x64@0.34.1':
126 |     resolution: {integrity: sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg==}
127 |     engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
128 |     cpu: [x64]
129 |     os: [linux]
130 |     libc: [musl]
131 | 
132 |   '@img/sharp-wasm32@0.34.1':
133 |     resolution: {integrity: sha512-YDybQnYrLQfEpzGOQe7OKcyLUCML4YOXl428gOOzBgN6Gw0rv8dpsJ7PqTHxBnXnwXr8S1mYFSLSa727tpz0xg==}
134 |     engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
135 |     cpu: [wasm32]
136 | 
137 |   '@img/sharp-win32-ia32@0.34.1':
138 |     resolution: {integrity: sha512-WKf/NAZITnonBf3U1LfdjoMgNO5JYRSlhovhRhMxXVdvWYveM4kM3L8m35onYIdh75cOMCo1BexgVQcCDzyoWw==}
139 |     engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
140 |     cpu: [ia32]
141 |     os: [win32]
142 | 
143 |   '@img/sharp-win32-x64@0.34.1':
144 |     resolution: {integrity: sha512-hw1iIAHpNE8q3uMIRCgGOeDoz9KtFNarFLQclLxr/LK1VBkj8nby18RjFvr6aP7USRYAjTZW6yisnBWMX571Tw==}
145 |     engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
146 |     cpu: [x64]
147 |     os: [win32]
148 | 
149 |   color-convert@2.0.1:
150 |     resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
151 |     engines: {node: '>=7.0.0'}
152 | 
153 |   color-name@1.1.4:
154 |     resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
155 | 
156 |   color-string@1.9.1:
157 |     resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
158 | 
159 |   color@4.2.3:
160 |     resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
161 |     engines: {node: '>=12.5.0'}
162 | 
163 |   commander@13.1.0:
164 |     resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==}
165 |     engines: {node: '>=18'}
166 | 
167 |   detect-libc@2.0.3:
168 |     resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
169 |     engines: {node: '>=8'}
170 | 
171 |   fs-extra@11.3.0:
172 |     resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==}
173 |     engines: {node: '>=14.14'}
174 | 
175 |   graceful-fs@4.2.11:
176 |     resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
177 | 
178 |   is-arrayish@0.3.2:
179 |     resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
180 | 
181 |   jsonfile@6.1.0:
182 |     resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
183 | 
184 |   semver@7.7.1:
185 |     resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==}
186 |     engines: {node: '>=10'}
187 |     hasBin: true
188 | 
189 |   sharp@0.34.1:
190 |     resolution: {integrity: sha512-1j0w61+eVxu7DawFJtnfYcvSv6qPFvfTaqzTQ2BLknVhHTwGS8sc63ZBF4rzkWMBVKybo4S5OBtDdZahh2A1xg==}
191 |     engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
192 | 
193 |   simple-swizzle@0.2.2:
194 |     resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
195 | 
196 |   tslib@2.8.1:
197 |     resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
198 | 
199 |   universalify@2.0.1:
200 |     resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
201 |     engines: {node: '>= 10.0.0'}
202 | 
203 | snapshots:
204 | 
205 |   '@emnapi/runtime@1.4.0':
206 |     dependencies:
207 |       tslib: 2.8.1
208 |     optional: true
209 | 
210 |   '@img/sharp-darwin-arm64@0.34.1':
211 |     optionalDependencies:
212 |       '@img/sharp-libvips-darwin-arm64': 1.1.0
213 |     optional: true
214 | 
215 |   '@img/sharp-darwin-x64@0.34.1':
216 |     optionalDependencies:
217 |       '@img/sharp-libvips-darwin-x64': 1.1.0
218 |     optional: true
219 | 
220 |   '@img/sharp-libvips-darwin-arm64@1.1.0':
221 |     optional: true
222 | 
223 |   '@img/sharp-libvips-darwin-x64@1.1.0':
224 |     optional: true
225 | 
226 |   '@img/sharp-libvips-linux-arm64@1.1.0':
227 |     optional: true
228 | 
229 |   '@img/sharp-libvips-linux-arm@1.1.0':
230 |     optional: true
231 | 
232 |   '@img/sharp-libvips-linux-ppc64@1.1.0':
233 |     optional: true
234 | 
235 |   '@img/sharp-libvips-linux-s390x@1.1.0':
236 |     optional: true
237 | 
238 |   '@img/sharp-libvips-linux-x64@1.1.0':
239 |     optional: true
240 | 
241 |   '@img/sharp-libvips-linuxmusl-arm64@1.1.0':
242 |     optional: true
243 | 
244 |   '@img/sharp-libvips-linuxmusl-x64@1.1.0':
245 |     optional: true
246 | 
247 |   '@img/sharp-linux-arm64@0.34.1':
248 |     optionalDependencies:
249 |       '@img/sharp-libvips-linux-arm64': 1.1.0
250 |     optional: true
251 | 
252 |   '@img/sharp-linux-arm@0.34.1':
253 |     optionalDependencies:
254 |       '@img/sharp-libvips-linux-arm': 1.1.0
255 |     optional: true
256 | 
257 |   '@img/sharp-linux-s390x@0.34.1':
258 |     optionalDependencies:
259 |       '@img/sharp-libvips-linux-s390x': 1.1.0
260 |     optional: true
261 | 
262 |   '@img/sharp-linux-x64@0.34.1':
263 |     optionalDependencies:
264 |       '@img/sharp-libvips-linux-x64': 1.1.0
265 |     optional: true
266 | 
267 |   '@img/sharp-linuxmusl-arm64@0.34.1':
268 |     optionalDependencies:
269 |       '@img/sharp-libvips-linuxmusl-arm64': 1.1.0
270 |     optional: true
271 | 
272 |   '@img/sharp-linuxmusl-x64@0.34.1':
273 |     optionalDependencies:
274 |       '@img/sharp-libvips-linuxmusl-x64': 1.1.0
275 |     optional: true
276 | 
277 |   '@img/sharp-wasm32@0.34.1':
278 |     dependencies:
279 |       '@emnapi/runtime': 1.4.0
280 |     optional: true
281 | 
282 |   '@img/sharp-win32-ia32@0.34.1':
283 |     optional: true
284 | 
285 |   '@img/sharp-win32-x64@0.34.1':
286 |     optional: true
287 | 
288 |   color-convert@2.0.1:
289 |     dependencies:
290 |       color-name: 1.1.4
291 | 
292 |   color-name@1.1.4: {}
293 | 
294 |   color-string@1.9.1:
295 |     dependencies:
296 |       color-name: 1.1.4
297 |       simple-swizzle: 0.2.2
298 | 
299 |   color@4.2.3:
300 |     dependencies:
301 |       color-convert: 2.0.1
302 |       color-string: 1.9.1
303 | 
304 |   commander@13.1.0: {}
305 | 
306 |   detect-libc@2.0.3: {}
307 | 
308 |   fs-extra@11.3.0:
309 |     dependencies:
310 |       graceful-fs: 4.2.11
311 |       jsonfile: 6.1.0
312 |       universalify: 2.0.1
313 | 
314 |   graceful-fs@4.2.11: {}
315 | 
316 |   is-arrayish@0.3.2: {}
317 | 
318 |   jsonfile@6.1.0:
319 |     dependencies:
320 |       universalify: 2.0.1
321 |     optionalDependencies:
322 |       graceful-fs: 4.2.11
323 | 
324 |   semver@7.7.1: {}
325 | 
326 |   sharp@0.34.1:
327 |     dependencies:
328 |       color: 4.2.3
329 |       detect-libc: 2.0.3
330 |       semver: 7.7.1
331 |     optionalDependencies:
332 |       '@img/sharp-darwin-arm64': 0.34.1
333 |       '@img/sharp-darwin-x64': 0.34.1
334 |       '@img/sharp-libvips-darwin-arm64': 1.1.0
335 |       '@img/sharp-libvips-darwin-x64': 1.1.0
336 |       '@img/sharp-libvips-linux-arm': 1.1.0
337 |       '@img/sharp-libvips-linux-arm64': 1.1.0
338 |       '@img/sharp-libvips-linux-ppc64': 1.1.0
339 |       '@img/sharp-libvips-linux-s390x': 1.1.0
340 |       '@img/sharp-libvips-linux-x64': 1.1.0
341 |       '@img/sharp-libvips-linuxmusl-arm64': 1.1.0
342 |       '@img/sharp-libvips-linuxmusl-x64': 1.1.0
343 |       '@img/sharp-linux-arm': 0.34.1
344 |       '@img/sharp-linux-arm64': 0.34.1
345 |       '@img/sharp-linux-s390x': 0.34.1
346 |       '@img/sharp-linux-x64': 0.34.1
347 |       '@img/sharp-linuxmusl-arm64': 0.34.1
348 |       '@img/sharp-linuxmusl-x64': 0.34.1
349 |       '@img/sharp-wasm32': 0.34.1
350 |       '@img/sharp-win32-ia32': 0.34.1
351 |       '@img/sharp-win32-x64': 0.34.1
352 | 
353 |   simple-swizzle@0.2.2:
354 |     dependencies:
355 |       is-arrayish: 0.3.2
356 | 
357 |   tslib@2.8.1:
358 |     optional: true
359 | 
360 |   universalify@2.0.1: {}
361 | 


--------------------------------------------------------------------------------
/scripts/ppconfig.json:
--------------------------------------------------------------------------------
  1 | {
  2 |     "name": "",
  3 |     "url": "",
  4 |     "showName": "",
  5 |     "appid": "",
  6 |     "icon": "",
  7 |     "iconRound": true,
  8 |     "state": true,
  9 |     "single": true,
 10 |     "injectJq": true,
 11 |     "tauriApi": false,
 12 |     "devbug": false,
 13 |     "version": "0.0.1",
 14 |     "platform": "desktop",
 15 |     "width": 800,
 16 |     "height": 600,
 17 |     "desc": "",
 18 |     "jsFile": [],
 19 |     "filterCss": "",
 20 |     "customJs": "",
 21 |     "isHtml": false,
 22 |     "htmlPath": "",
 23 |     "htmlFiles": [],
 24 |     "more": {
 25 |         "windows": {
 26 |             "label": "",
 27 |             "title": "",
 28 |             "url": "",
 29 |             "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36",
 30 |             "width": 800,
 31 |             "height": 600,
 32 |             "theme": null,
 33 |             "resizable": true,
 34 |             "fullscreen": false,
 35 |             "maximized": false,
 36 |             "minWidth": 400,
 37 |             "minHeight": 300,
 38 |             "maxWidth": 1920,
 39 |             "maxHeight": 1080,
 40 |             "decorations": true,
 41 |             "transparent": false,
 42 |             "titleBarStyle": "Visible",
 43 |             "visible": true,
 44 |             "focus": true,
 45 |             "closable": true,
 46 |             "minimizable": true,
 47 |             "maximizable": true,
 48 |             "alwaysOnTop": false,
 49 |             "alwaysOnBottom": false,
 50 |             "center": false,
 51 |             "skipTaskbar": false,
 52 |             "tabbingIdentifier": null,
 53 |             "parent": null,
 54 |             "dragDropEnabled": true,
 55 |             "browserExtensionsEnabled": false,
 56 |             "devtools": true,
 57 |             "contentProtected": false,
 58 |             "hiddenTitle": false,
 59 |             "incognito": false,
 60 |             "proxyUrl": null,
 61 |             "useHttpsScheme": false,
 62 |             "zoomHotkeysEnabled": false,
 63 |             "acceptFirstMouse": false,
 64 |             "create": false
 65 |         }
 66 |     },
 67 |     "phone": {
 68 |         "safeArea": {
 69 |             "top": 0,
 70 |             "bottom": 0,
 71 |             "left": 0,
 72 |             "right": 0
 73 |         },
 74 |         "header": {
 75 |             "show": false,
 76 |             "title": "",
 77 |             "backgroundColor": "",
 78 |             "color": "",
 79 |             "fontSize": 16,
 80 |             "fontWeight": "bold",
 81 |             "loading": false,
 82 |             "toolBar": false,
 83 |             "toolBarBackgroundColor": "",
 84 |             "toolBarColor": "",
 85 |             "toolBarFontSize": 16,
 86 |             "toolBarFontWeight": "bold"
 87 |         },
 88 |         "siderMenu": {
 89 |             "show": false,
 90 |             "width": 0,
 91 |             "backgroundColor": "",
 92 |             "color": "",
 93 |             "fontSize": 16,
 94 |             "fontWeight": "bold",
 95 |             "title": "",
 96 |             "titleColor": "",
 97 |             "titleFontSize": 16,
 98 |             "titleFontWeight": "bold"
 99 |         },
100 |         "tabBar": {
101 |             "show": false,
102 |             "backgroundColor": "",
103 |             "color": "",
104 |             "activeColor": "",
105 |             "fontSize": 16,
106 |             "fontWeight": "bold",
107 |             "tabBarItem": []
108 |         },
109 |         "webview": {
110 |             "userAgent": "",
111 |             "javaScriptEnabled": true,
112 |             "domStorageEnabled": true,
113 |             "allowFileAccess": true,
114 |             "loadWithOverviewMode": true,
115 |             "setSupportZoom": true,
116 |             "clearCache": true
117 |         }
118 |     },
119 |     "ios": {
120 |         "name": "PakePlus",
121 |         "showName": "PakePlus",
122 |         "version": "0.0.1",
123 |         "webUrl": "https://juejin.cn/",
124 |         "id": "com.oaikes.app",
125 |         "icon": "./app-icon.png",
126 |         "desc": "PakePlus Project by 1024xiaoshen",
127 |         "pubBody": "PakePlus ios build body",
128 |         "isHtml": false,
129 |         "debug": false
130 |     },
131 |     "android": {
132 |         "name": "PakePlus",
133 |         "showName": "PakePlus",
134 |         "version": "0.0.1",
135 |         "webUrl": "https://juejin.cn/",
136 |         "id": "com.oaikes.pakeplus.android",
137 |         "icon": "./app-icon.png",
138 |         "input": "./app-icon.png",
139 |         "output": "./res",
140 |         "rounded": true,
141 |         "copyTo": "./app/src/main/res",
142 |         "androidResDir": "./app/src/main/res",
143 |         "desc": "PakePlus Project by 1024xiaoshen",
144 |         "pubBody": "PakePlus android build body",
145 |         "isHtml": false,
146 |         "debug": false
147 |     },
148 |     "desktop": {
149 |         "name": "PakePlus2",
150 |         "showName": "oaikes",
151 |         "version": "0.0.2",
152 |         "id": "com.oaikes.app",
153 |         "desc": "PakePlus Project by 1024xiaoshen",
154 |         "webUrl": "https://juejin.cn/",
155 |         "iconPath": "../app-icon.png",
156 |         "inputPath": "../app-icon.png",
157 |         "tempPath": "./processed-image.png",
158 |         "icnsPath": "../src-tauri/icons/icon.icns",
159 |         "pubBody": "PakePlus desktop build body",
160 |         "isHtml": false,
161 |         "single": true,
162 |         "state": true,
163 |         "injectJq": false,
164 |         "tauriApi": false,
165 |         "debug": false
166 |     }
167 | }
168 | 


--------------------------------------------------------------------------------
/scripts/ppworker.cjs:
--------------------------------------------------------------------------------
  1 | const sharp = require('sharp')
  2 | const fs = require('fs-extra')
  3 | const path = require('path')
  4 | const ppconfig = require('./ppconfig.json')
  5 | 
  6 | // icon size
  7 | const DENSITIES = {
  8 |     mdpi: 48,
  9 |     hdpi: 72,
 10 |     xhdpi: 96,
 11 |     xxhdpi: 144,
 12 |     xxxhdpi: 192,
 13 | }
 14 | 
 15 | // generate adaptive icons
 16 | const generateAdaptiveIcons = async (input, outputDir) => {
 17 |     for (const [dpi, size] of Object.entries(DENSITIES)) {
 18 |         const mipmapDir = path.join(outputDir, `mipmap-${dpi}`)
 19 |         await fs.ensureDir(mipmapDir)
 20 |         const foregroundPath = path.join(
 21 |             mipmapDir,
 22 |             'ic_launcher_foreground.webp'
 23 |         )
 24 |         const backgroundPath = path.join(
 25 |             mipmapDir,
 26 |             'ic_launcher_background.webp'
 27 |         )
 28 |         const legacyPath = path.join(mipmapDir, 'ic_launcher.webp')
 29 |         const legacyRoundPath = path.join(mipmapDir, 'ic_launcher_round.webp')
 30 | 
 31 |         // 创建圆形遮罩
 32 |         const roundedMask = Buffer.from(
 33 |             `<svg><circle cx="${size / 2}" cy="${size / 2}" r="${
 34 |                 size / 2
 35 |             }" fill="white"/></svg>`
 36 |         )
 37 | 
 38 |         // 生成普通图标
 39 |         const img = sharp(input).resize(size, size)
 40 |         await img.webp().toFile(foregroundPath)
 41 |         await img.webp().toFile(legacyPath)
 42 | 
 43 |         // 生成圆形图标
 44 |         const roundedImg = img.composite([
 45 |             {
 46 |                 input: roundedMask,
 47 |                 blend: 'dest-in',
 48 |             },
 49 |         ])
 50 |         await roundedImg.webp().toFile(legacyRoundPath)
 51 | 
 52 |         // 生成背景
 53 |         await sharp({
 54 |             create: {
 55 |                 width: size,
 56 |                 height: size,
 57 |                 channels: 4,
 58 |                 background: '#FFFFFF',
 59 |             },
 60 |         })
 61 |             .webp()
 62 |             .toFile(backgroundPath)
 63 |     }
 64 | 
 65 |     // Generate XML
 66 |     const xmlPath = path.join(outputDir, 'mipmap-anydpi-v26')
 67 |     await fs.ensureDir(xmlPath)
 68 |     await fs.writeFile(
 69 |         path.join(xmlPath, 'ic_launcher.xml'),
 70 |         `
 71 | <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
 72 |     <background android:drawable="@mipmap/ic_launcher_background"/>
 73 |     <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
 74 | </adaptive-icon>
 75 |   `.trim()
 76 |     )
 77 | 
 78 |     await fs.writeFile(
 79 |         path.join(xmlPath, 'ic_launcher_round.xml'),
 80 |         `
 81 | <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
 82 |     <background android:drawable="@mipmap/ic_launcher_background"/>
 83 |     <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
 84 | </adaptive-icon>
 85 |   `.trim()
 86 |     )
 87 | 
 88 |     console.log('✅ Adaptive icons generated in WebP format.')
 89 | }
 90 | 
 91 | const updateAppName = async (androidResDir, appName) => {
 92 |     // workerflow build apk name always is app-debug.apk
 93 |     try {
 94 |         const stringsPath = path.join(androidResDir, 'values', 'strings.xml')
 95 | 
 96 |         // Check if strings.xml exists
 97 |         const exists = await fs.pathExists(stringsPath)
 98 |         if (!exists) {
 99 |             console.log('⚠️ strings.xml not found, creating a new one')
100 |             await fs.ensureDir(path.dirname(stringsPath))
101 |             await fs.writeFile(
102 |                 stringsPath,
103 |                 `<?xml version="1.0" encoding="utf-8"?>
104 | <resources>
105 |     <string name="app_name">${appName}</string>
106 | </resources>`
107 |             )
108 |             console.log(`✅ Created strings.xml with app_name: ${appName}`)
109 |             return
110 |         }
111 | 
112 |         // Read and update existing strings.xml
113 |         let content = await fs.readFile(stringsPath, 'utf8')
114 | 
115 |         // Check if app_name already exists
116 |         if (content.includes('<string name="app_name">')) {
117 |             content = content.replace(
118 |                 /<string name="app_name">.*?<\/string>/,
119 |                 `<string name="app_name">${appName}</string>`
120 |             )
121 |         } else {
122 |             // Add app_name if it doesn't exist
123 |             content = content.replace(
124 |                 /<\/resources>/,
125 |                 `    <string name="app_name">${appName}</string>\n</resources>`
126 |             )
127 |         }
128 | 
129 |         await fs.writeFile(stringsPath, content)
130 |         console.log(`✅ Updated app_name to: ${appName}`)
131 |     } catch (error) {
132 |         console.error('❌ Error updating app name:', error)
133 |     }
134 | }
135 | 
136 | const updateWebEnv = async (androidResDir, webUrl, debug, webview) => {
137 |     try {
138 |         const { userAgent } = webview
139 | 
140 |         // Assuming MainActivity.kt is in the standard location
141 |         const mainActivityPath = path.join(
142 |             androidResDir.replace('res', ''),
143 |             'java/com/app/pakeplus/MainActivity.kt'
144 |         )
145 | 
146 |         // Check if file exists
147 |         const exists = await fs.pathExists(mainActivityPath)
148 |         if (!exists) {
149 |             console.log(
150 |                 '⚠️ MainActivity.kt not found at expected location:',
151 |                 mainActivityPath
152 |             )
153 |             return
154 |         }
155 | 
156 |         // Read and update the file
157 |         let content = await fs.readFile(mainActivityPath, 'utf8')
158 | 
159 |         // Replace the web URL in the loadUrl call
160 |         let updatedContent = content.replace(
161 |             /webView\.loadUrl\(".*?"\)/,
162 |             `webView.loadUrl("${webUrl}")`
163 |         )
164 |         // if debug is true, add debug mode
165 |         console.log('webview debug to:', debug)
166 |         if (debug) {
167 |             updatedContent = updatedContent.replace(
168 |                 'private var debug = false',
169 |                 'private var debug = true'
170 |             )
171 |         }
172 | 
173 |         // update webview userAgent
174 |         if (userAgent) {
175 |             updatedContent = updatedContent.replace(
176 |                 '// webView.settings.userAgentString = ""',
177 |                 `webView.settings.userAgentString = "${userAgent}"`
178 |             )
179 |         }
180 | 
181 |         await fs.writeFile(mainActivityPath, updatedContent)
182 |         console.log(`✅ Updated web URL to: ${webUrl}`)
183 |     } catch (error) {
184 |         console.error('❌ Error updating web URL:', error)
185 |     }
186 | }
187 | 
188 | // update build yml
189 | const updateBuildYml = async (tagName, releaseName, releaseBody) => {
190 |     try {
191 |         const buildYmlPath = path.join('.github', 'workflows', 'build.yml')
192 |         const exists = await fs.pathExists(buildYmlPath)
193 |         if (!exists) {
194 |             console.log(
195 |                 '⚠️ build.yml not found at expected location:',
196 |                 buildYmlPath
197 |             )
198 |             return
199 |         }
200 | 
201 |         // Read the file
202 |         let content = await fs.readFile(buildYmlPath, 'utf8')
203 | 
204 |         // Replace all occurrences of PakePlus-v0.0.1
205 |         const tagUpdate = content.replaceAll('PakePlus-v0.0.1', tagName)
206 |         const releaseUpdate = tagUpdate.replaceAll(
207 |             'PakePlus v0.0.1',
208 |             releaseName
209 |         )
210 |         const bodyUpdate = releaseUpdate.replaceAll(
211 |             'PakePlus ReleaseBody',
212 |             releaseBody
213 |         )
214 | 
215 |         // Write back only if changes were made
216 |         if (bodyUpdate !== content) {
217 |             await fs.writeFile(buildYmlPath, bodyUpdate)
218 |             console.log(`✅ Updated build.yml with new app name: ${tagName}`)
219 |         } else {
220 |             console.log('ℹ️ No changes needed in build.yml')
221 |         }
222 |     } catch (error) {
223 |         console.error('❌ Error updating build.yml:', error)
224 |     }
225 | }
226 | 
227 | // set github env
228 | const setGithubEnv = (name, version, pubBody) => {
229 |     console.log('setGithubEnv......')
230 |     const envPath = process.env.GITHUB_ENV
231 |     if (!envPath) {
232 |         console.error('GITHUB_ENV is not defined')
233 |         return
234 |     }
235 |     try {
236 |         const entries = {
237 |             NAME: name,
238 |             VERSION: version,
239 |             PUBBODY: pubBody,
240 |         }
241 |         for (const [key, value] of Object.entries(entries)) {
242 |             if (value !== undefined) {
243 |                 fs.appendFileSync(envPath, `${key}=${value}\n`)
244 |             }
245 |         }
246 |         console.log('✅ Environment variables written to GITHUB_ENV')
247 |         // 查看env 变量
248 |         console.log(fs.readFileSync(envPath, 'utf-8'))
249 |     } catch (err) {
250 |         console.error('❌ Failed to parse config or write to GITHUB_ENV:', err)
251 |     }
252 |     console.log('setGithubEnv success')
253 | }
254 | 
255 | // update android applicationId
256 | const updateAndroidId = async (id) => {
257 |     const gradlePath = path.join(__dirname, '../app/build.gradle.kts')
258 |     const exists = await fs.pathExists(gradlePath)
259 |     if (!exists) {
260 |         console.log('⚠️ build.gradle.kts not found, creating a new one')
261 |         return
262 |     }
263 | 
264 |     // Read and update the file
265 |     let content = await fs.readFile(gradlePath, 'utf8')
266 | 
267 |     // Replace the applicationId
268 |     const updatedContent = content.replace(
269 |         /applicationId = ".*?"/,
270 |         `applicationId = "${id}"`
271 |     )
272 | 
273 |     // Write back only if changes were made
274 |     if (updatedContent !== content) {
275 |         await fs.writeFile(gradlePath, updatedContent)
276 |         console.log(`✅ Updated applicationId to: ${id}`)
277 |     } else {
278 |         console.log('ℹ️ No changes needed in build.gradle.kts')
279 |     }
280 | }
281 | 
282 | // Main execution
283 | const main = async () => {
284 |     const { webview } = ppconfig.phone
285 |     const {
286 |         name,
287 |         version,
288 |         id,
289 |         pubBody,
290 |         input,
291 |         output,
292 |         copyTo,
293 |         webUrl,
294 |         showName,
295 |         debug,
296 |     } = ppconfig.android
297 | 
298 |     const outPath = path.resolve(output)
299 |     await generateAdaptiveIcons(input, outPath)
300 | 
301 |     const dest = path.resolve(copyTo)
302 |     await fs.copy(outPath, dest, { overwrite: true })
303 |     console.log(`📦 Icons copied to Android res dir: ${dest}`)
304 | 
305 |     // Update app name if provided
306 |     await updateAppName(dest, showName)
307 | 
308 |     // Update web URL if provided
309 |     await updateWebEnv(dest, webUrl, debug, webview)
310 | 
311 |     // 删除根目录的res
312 |     await fs.remove(outPath)
313 | 
314 |     // update android applicationId
315 |     await updateAndroidId(id)
316 | 
317 |     // set github env
318 |     setGithubEnv(name, version, pubBody)
319 | 
320 |     // success
321 |     console.log('✅ Worker Success')
322 | }
323 | 
324 | // run
325 | ;(async () => {
326 |     try {
327 |         console.log('🚀 worker start')
328 |         await main()
329 |         console.log('🚀 worker end')
330 |     } catch (error) {
331 |         console.error('❌ Worker Error:', error)
332 |     }
333 | })()
334 | 


--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
 1 | pluginManagement {
 2 |     repositories {
 3 |         google {
 4 |             content {
 5 |                 includeGroupByRegex("com\\.android.*")
 6 |                 includeGroupByRegex("com\\.google.*")
 7 |                 includeGroupByRegex("androidx.*")
 8 |             }
 9 |         }
10 |         mavenCentral()
11 |         gradlePluginPortal()
12 |     }
13 | }
14 | dependencyResolutionManagement {
15 |     repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
16 |     repositories {
17 |         google()
18 |         mavenCentral()
19 |     }
20 | }
21 | 
22 | rootProject.name = "PakePlus"
23 | include(":app")
24 | 


--------------------------------------------------------------------------------