├── .DS_Store
├── .github
└── workflows
│ └── deploy.yml
├── .gitignore
├── CHANGELOG.md
├── DISCLAIMER.md
├── LICENSE
├── README.md
├── apk
└── SKIP-v3.1.0.apk
├── app
├── .gitignore
├── build.gradle.kts
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── android
│ │ └── skip
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ ├── skip_config.yaml
│ │ ├── skip_config_v2.yaml
│ │ ├── skip_config_v3.json
│ │ └── skip_config_v3.yaml
│ ├── ic_launcher-playstore.png
│ ├── java
│ │ └── com
│ │ │ └── android
│ │ │ └── skip
│ │ │ ├── MyApp.kt
│ │ │ ├── data
│ │ │ ├── SyncWorker.kt
│ │ │ ├── config
│ │ │ │ ├── ConfigLoadRepository.kt
│ │ │ │ ├── ConfigReadRepository.kt
│ │ │ │ └── ConfigViewModel.kt
│ │ │ ├── download
│ │ │ │ ├── ApkDownloadRepository.kt
│ │ │ │ └── ApkDownloadViewModel.kt
│ │ │ ├── network
│ │ │ │ ├── MyApiNetwork.kt
│ │ │ │ ├── ServiceCreator.kt
│ │ │ │ └── api
│ │ │ │ │ └── MyApiService.kt
│ │ │ └── version
│ │ │ │ ├── ApkVersionRepository.kt
│ │ │ │ └── ApkVersionViewModel.kt
│ │ │ ├── dataclass
│ │ │ ├── AccessibilityNodeInfoCarrier.kt
│ │ │ ├── AppListItem.kt
│ │ │ ├── ConfigLoadSchema.kt
│ │ │ ├── ConfigPostSchema.kt
│ │ │ ├── ConfigReadSchema.kt
│ │ │ ├── InspectRecordItem.kt
│ │ │ ├── NodeChildSchema.kt
│ │ │ ├── NodeRootSchema.kt
│ │ │ ├── SemanticVersion.kt
│ │ │ ├── SwitchThemeCarrier.kt
│ │ │ └── VersionPostSchema.kt
│ │ │ ├── service
│ │ │ ├── AccessibilityInspectRepository.kt
│ │ │ ├── AccessibilityInspectViewModel.kt
│ │ │ ├── FloatingWindowService.kt
│ │ │ ├── InspectService.kt
│ │ │ ├── MyAccessibilityService.kt
│ │ │ └── MyForegroundService.kt
│ │ │ ├── ui
│ │ │ ├── about
│ │ │ │ ├── AboutActivity.kt
│ │ │ │ ├── config
│ │ │ │ │ └── ConfigVersionButton.kt
│ │ │ │ ├── download
│ │ │ │ │ └── ApkDownloadDialog.kt
│ │ │ │ └── version
│ │ │ │ │ └── ApkVersionButton.kt
│ │ │ ├── alive
│ │ │ │ ├── AliveActivity.kt
│ │ │ │ ├── backstage
│ │ │ │ │ ├── BackstageButton.kt
│ │ │ │ │ └── BackstageViewModel.kt
│ │ │ │ └── notificationbar
│ │ │ │ │ ├── NotificationBarButton.kt
│ │ │ │ │ ├── NotificationBarRepository.kt
│ │ │ │ │ └── NotificationBarViewModel.kt
│ │ │ ├── components
│ │ │ │ ├── FlatButton.kt
│ │ │ │ ├── FlatButtonMenu.kt
│ │ │ │ ├── PictureDialog.kt
│ │ │ │ ├── ResourceIcon.kt
│ │ │ │ ├── RowContent.kt
│ │ │ │ ├── ScaffoldPage.kt
│ │ │ │ └── notification
│ │ │ │ │ ├── NotificationDialog.kt
│ │ │ │ │ └── NotificationDialogViewModel.kt
│ │ │ ├── inspect
│ │ │ │ ├── InspectActivity.kt
│ │ │ │ ├── floating
│ │ │ │ │ ├── FloatingWindowButton.kt
│ │ │ │ │ ├── FloatingWindowRepository.kt
│ │ │ │ │ └── FloatingWindowViewModel.kt
│ │ │ │ ├── record
│ │ │ │ │ ├── InspectRecordButton.kt
│ │ │ │ │ ├── InspectRecordRepository.kt
│ │ │ │ │ └── InspectRecordViewModel.kt
│ │ │ │ └── start
│ │ │ │ │ ├── StartInspectButton.kt
│ │ │ │ │ ├── StartInspectRepository.kt
│ │ │ │ │ └── StartInspectViewModel.kt
│ │ │ ├── main
│ │ │ │ ├── MainActivity.kt
│ │ │ │ ├── disclaimer
│ │ │ │ │ ├── DisclaimerDialog.kt
│ │ │ │ │ └── DisclaimerViewModel.kt
│ │ │ │ ├── start
│ │ │ │ │ ├── StartAccessibilityButton.kt
│ │ │ │ │ ├── StartAccessibilityRepository.kt
│ │ │ │ │ └── StartAccessibilityViewModel.kt
│ │ │ │ └── tutorial
│ │ │ │ │ ├── TutorialDialog.kt
│ │ │ │ │ └── TutorialViewModel.kt
│ │ │ ├── record
│ │ │ │ ├── InspectRecordActivity.kt
│ │ │ │ ├── dialog
│ │ │ │ │ ├── JpegDialog.kt
│ │ │ │ │ ├── JpegDialogRepository.kt
│ │ │ │ │ └── JpegDialogViewModel.kt
│ │ │ │ └── list
│ │ │ │ │ ├── InspectListColumn.kt
│ │ │ │ │ ├── InspectListPagingSource.kt
│ │ │ │ │ ├── InspectListRepository.kt
│ │ │ │ │ └── InspectListViewModel.kt
│ │ │ ├── settings
│ │ │ │ ├── SettingsActivity.kt
│ │ │ │ ├── custom
│ │ │ │ │ └── CustomButton.kt
│ │ │ │ ├── recent
│ │ │ │ │ ├── RecentButton.kt
│ │ │ │ │ └── RecentViewModel.kt
│ │ │ │ ├── strict
│ │ │ │ │ ├── StrictButton.kt
│ │ │ │ │ ├── StrictRepository.kt
│ │ │ │ │ └── StrictViewModel.kt
│ │ │ │ ├── theme
│ │ │ │ │ ├── SwitchThemeButton.kt
│ │ │ │ │ ├── SwitchThemeRepository.kt
│ │ │ │ │ └── SwitchThemeViewModel.kt
│ │ │ │ ├── tip
│ │ │ │ │ ├── TipButton.kt
│ │ │ │ │ ├── TipRepository.kt
│ │ │ │ │ └── TipViewModel.kt
│ │ │ │ └── update
│ │ │ │ │ ├── AutoUpdateButton.kt
│ │ │ │ │ └── AutoUpdateViewModel.kt
│ │ │ ├── theme
│ │ │ │ ├── AppTheme.kt
│ │ │ │ ├── Color.kt
│ │ │ │ └── Typography.kt
│ │ │ ├── webview
│ │ │ │ └── WebViewActivity.kt
│ │ │ └── whitelist
│ │ │ │ ├── WhiteListActivity.kt
│ │ │ │ ├── WhiteListRepository.kt
│ │ │ │ ├── WhiteListViewModel.kt
│ │ │ │ ├── list
│ │ │ │ ├── AppListColumn.kt
│ │ │ │ ├── AppListPagingSource.kt
│ │ │ │ ├── AppListRepository.kt
│ │ │ │ └── AppListViewModel.kt
│ │ │ │ ├── search
│ │ │ │ ├── SearchTextField.kt
│ │ │ │ └── SearchViewModel.kt
│ │ │ │ └── system
│ │ │ │ ├── ShowSystemButton.kt
│ │ │ │ └── ShowSystemViewModel.kt
│ │ │ └── util
│ │ │ ├── AccessibilityStateUtils.kt
│ │ │ ├── DataStoreUtils.kt
│ │ │ ├── DebounceHelper.kt
│ │ │ ├── MyToast.kt
│ │ │ └── NetworkUtils.kt
│ └── res
│ │ ├── drawable
│ │ ├── all_inclusive.xml
│ │ ├── app_registration.xml
│ │ ├── arrow_back.xml
│ │ ├── backend_lock.jpg
│ │ ├── block.xml
│ │ ├── check_circle.xml
│ │ ├── counter_1.xml
│ │ ├── counter_2.xml
│ │ ├── counter_3.xml
│ │ ├── counter_4.xml
│ │ ├── error.xml
│ │ ├── favicon32.png
│ │ ├── fit_screen.xml
│ │ ├── float_landscape_2.xml
│ │ ├── help.xml
│ │ ├── hide_image.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_launcher_foreground.xml
│ │ ├── info.xml
│ │ ├── lists.xml
│ │ ├── notifications.xml
│ │ ├── photo_camera.xml
│ │ ├── point_scan.xml
│ │ ├── settings.xml
│ │ ├── sync.xml
│ │ ├── target.xml
│ │ ├── theme_auto.xml
│ │ ├── theme_dark.xml
│ │ ├── theme_light.xml
│ │ ├── tune.xml
│ │ └── warning.xml
│ │ ├── layout
│ │ └── floating_window.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.webp
│ │ ├── ic_launcher_foreground.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.webp
│ │ ├── ic_launcher_foreground.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.webp
│ │ ├── ic_launcher_foreground.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.webp
│ │ ├── ic_launcher_foreground.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.webp
│ │ ├── ic_launcher_foreground.webp
│ │ └── ic_launcher_round.webp
│ │ ├── values-night
│ │ └── themes.xml
│ │ ├── values
│ │ ├── colors.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── accessibility.xml
│ │ ├── backup_rules.xml
│ │ ├── data_extraction_rules.xml
│ │ └── file_paths.xml
│ └── test
│ └── java
│ └── com
│ └── android
│ └── skip
│ └── ExampleUnitTest.kt
├── build.gradle.kts
├── capture
├── 0f84d874-ada4-4b90-9829-a99f43950071.zip
├── 20f3db03-af60-4dc3-885a-b954b985931f.zip
├── 28b730a3-5ac7-44c7-8f8a-9daf1b8effbe.zip
├── 2adae253-623d-4fd3-ad75-b5b32b667dcd.zip
├── 368caf09-c152-4f6b-b8dd-3ee4718df65d.zip
├── 3737625b-383a-4891-aada-493e811f048a.zip
├── 43bcef4b-4b5b-4b63-a7f2-ad28e4f5f690.zip
├── 450b0add-b8e2-4cac-9b49-015744bb786f.zip
├── 5656e116-5a93-44da-8687-1a1dec170984.zip
├── 57861a13-956b-4ae1-be60-d77c33b82010.zip
├── 7aa2544b-8a80-41f3-bf0c-ee03c7cf83b2.zip
├── 7ba85f98-5b07-4947-95e0-dca6431b1fc6.zip
├── 7d45a0ad-f0ce-4856-b38b-dd545bfadeb5.zip
├── 812b304e-63fd-42da-b200-7497a2e635c4.zip
├── 84603cb6-3647-42aa-a0f9-e013a3c1e74c.zip
├── 88ad5f6b-e65b-4424-be8e-ab57e0eb613b.zip
├── 92e729ea-dd19-4384-93af-ec7581f306cf.zip
├── 94969846-73e3-41de-aca0-ad9994566fc6.zip
├── a310356a-4841-40fd-8a4f-314e77318230.zip
├── ab69a19e-56e8-4983-9656-cdbab1b09682.zip
├── b8592c72-1a8a-42ea-8022-2ba15bc83444.zip
├── bb3de897-19d4-4c6d-ac7a-e11130420b4a.zip
├── c1c0b4c7-9bed-4f11-93e8-6fcd08bb4717.zip
├── cfe9660a-1d45-4904-a8a7-8d846faa1a49.zip
├── dba416c1-f18d-45c4-8042-16e2c15bead5.zip
├── e2c456c9-2db5-4ff9-9f79-f42acf557358.zip
├── e835b293-7845-4988-9423-fe7f9d740d43.zip
├── ee283a25-cbbf-43b0-84dd-aaf9ccf24c83.zip
└── f074f9ba-2fdd-4885-8b16-df8afdcbb46d.zip
├── dist
└── .gitkeep
├── docs
├── .vitepress
│ ├── config.mts
│ ├── index.css
│ └── theme
│ │ ├── custom.css
│ │ └── index.js
├── CNAME
├── advance
│ ├── custom-config
│ │ ├── data-structure.md
│ │ ├── field-meaning.md
│ │ ├── full-reference.md
│ │ └── intro.md
│ └── layout-inspect
│ │ ├── intro.md
│ │ └── usage.md
├── guide
│ ├── about
│ │ └── intro.md
│ ├── contributing
│ │ ├── config-file.md
│ │ ├── core-logic.md
│ │ └── layout-view.md
│ ├── intro
│ │ ├── DownloadApp.vue
│ │ ├── download-app.md
│ │ ├── getting-started.md
│ │ └── what-is-skip.md
│ ├── keep-alive
│ │ └── intro.md
│ ├── settings
│ │ └── intro.md
│ ├── usage
│ │ ├── background-process-keep-alive.md
│ │ └── enable-accessibility-service.md
│ └── white-list
│ │ └── intro.md
├── index.md
├── inspect
│ ├── InspectContainer.vue
│ ├── InspectHeader.vue
│ ├── InspectHome.vue
│ ├── InspectTable.vue
│ ├── NodePic.vue
│ ├── NodeTable.vue
│ ├── NodeTree.vue
│ ├── hook
│ │ └── useZip.ts
│ ├── index.md
│ ├── inspect-node-container
│ │ └── NodeCode.vue
│ └── types.ts
├── my-index-db
│ ├── file-item.ts
│ ├── file-table.ts
│ └── index.ts
├── public
│ ├── 5f686585-c5d0-4057-93b2-c54832ffb393.zip
│ ├── android-rect.png
│ ├── click-button-on-the-screen-dark.png
│ ├── click-button-on-the-screen-light.png
│ ├── images
│ │ ├── favicon.ico
│ │ ├── getting-started-step-1.png
│ │ ├── getting-started-step-2.png
│ │ ├── getting-started-step-3.png
│ │ ├── getting-started-step-4.png
│ │ ├── getting-started-step-5.png
│ │ ├── images.7z
│ │ ├── inspect-intro.png
│ │ ├── logo.png
│ │ └── main-interface-light.png
│ ├── js
│ │ └── baidu-analytics.js
│ ├── layout-reference.png
│ ├── main-interface-dark.png
│ ├── main-interface-light.png
│ ├── skip-bottom-screenshot.jpg
│ ├── skip-icon.png
│ ├── use-accessibility-dark.png
│ ├── use-accessibility-light.png
│ ├── xiaomi-app-backend-lock-dark.png
│ ├── xiaomi-app-backend-lock-light.png
│ ├── xiaomi-enable-self-start-dark.png
│ ├── xiaomi-enable-self-start-light.png
│ ├── xiaomi-enable-self-start.jpg
│ ├── xiaomi-ignoring-battery-optimization-dark.png
│ └── xiaomi-ignoring-battery-optimization-light.png
└── visual
│ ├── Header.vue
│ ├── Home.vue
│ ├── LeftForm.vue
│ ├── RightCode.vue
│ └── index.md
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── gui
├── .DS_Store
├── backend_lock.jpg
├── background.png
├── favicon-16x16.png
├── favicon-32x32.png
├── main.png
├── start_icon
│ ├── .DS_Store
│ ├── android
│ │ ├── ic_launcher.png
│ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-ldpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ └── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ └── ios
│ │ ├── .DS_Store
│ │ └── AppIcon.appiconset
│ │ ├── icon-1024.png
│ │ ├── icon-20-ipad.png
│ │ ├── icon-20@2x-ipad.png
│ │ ├── icon-20@2x.png
│ │ ├── icon-20@3x.png
│ │ ├── icon-29-ipad.png
│ │ ├── icon-29.png
│ │ ├── icon-29@2x-ipad.png
│ │ ├── icon-29@2x.png
│ │ ├── icon-29@3x.png
│ │ ├── icon-40.png
│ │ ├── icon-40@2x.png
│ │ ├── icon-40@3x.png
│ │ ├── icon-60@2x.png
│ │ ├── icon-60@3x.png
│ │ ├── icon-76.png
│ │ ├── icon-76@2x.png
│ │ └── icon-83.5@2x.png
└── svg
│ ├── all_inclusive_FILL0_wght400_GRAD0_opsz24.svg
│ ├── app_registration_FILL0_wght400_GRAD0_opsz24.svg
│ ├── arrow_back_FILL0_wght400_GRAD0_opsz24.svg
│ ├── block_FILL0_wght400_GRAD0_opsz24.svg
│ ├── brightness_4_FILL0_wght400_GRAD0_opsz24.svg
│ ├── brightness_5_FILL0_wght400_GRAD0_opsz24.svg
│ ├── brightness_6_FILL0_wght400_GRAD0_opsz24.svg
│ ├── check_circle_FILL0_wght400_GRAD0_opsz24.svg
│ ├── cloud_download_FILL0_wght400_GRAD0_opsz24.svg
│ ├── counter_1_FILL0_wght400_GRAD0_opsz24.svg
│ ├── counter_2_FILL0_wght400_GRAD0_opsz24.svg
│ ├── counter_3_FILL0_wght400_GRAD0_opsz24.svg
│ ├── counter_4_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg
│ ├── error_24dp_000000_FILL0_wght0_GRAD0_opszNaN.svg
│ ├── fit_screen_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg
│ ├── float_landscape_2_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg
│ ├── help_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg
│ ├── hide_image_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg
│ ├── info_FILL0_wght400_GRAD0_opsz24.svg
│ ├── list_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg
│ ├── lists_FILL0_wght400_GRAD0_opsz24.svg
│ ├── notifications_FILL0_wght400_GRAD0_opsz24.svg
│ ├── photo_camera_64dp_000000_FILL1_wght400_GRAD0_opsz48.svg
│ ├── point_scan_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg
│ ├── screenshot_keyboard_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg
│ ├── settings_FILL0_wght400_GRAD0_opsz24.svg
│ ├── sync_FILL0_wght400_GRAD0_opsz24.svg
│ ├── target_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg
│ ├── tune_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg
│ └── warning_FILL0_wght400_GRAD0_opsz24.svg
├── jest.config.ts
├── package-lock.json
├── package.json
├── postcss.config.js
├── scripts
├── __tests__
│ ├── examples
│ │ ├── apk-has-version
│ │ │ └── SKIP-v2.1.1.apk
│ │ ├── apk-multiple
│ │ │ ├── SKIP-v2.0.0.apk
│ │ │ └── SKIP-v2.0.1.apk
│ │ ├── apk-no-version
│ │ │ └── SKIP.apk
│ │ ├── apk-not-apk
│ │ │ └── SKIP-v2.0.0.txt
│ │ ├── correct-yaml.yaml
│ │ ├── missing-packageName.yaml
│ │ ├── only-packageName.yaml
│ │ ├── packageName-empty.yaml
│ │ ├── packageName-leading-space.yaml
│ │ ├── packageName-not-string.yaml
│ │ ├── skipBounds-bound-empty.yaml
│ │ ├── skipBounds-bound-not-4-parts.yaml
│ │ ├── skipBounds-bound-not-number.yaml
│ │ ├── skipBounds-bound-not-string.yaml
│ │ ├── skipBounds-missing-bound.yaml
│ │ ├── skipBounds-missing-resolution.yaml
│ │ ├── skipBounds-not-array.yaml
│ │ ├── skipBounds-resolution-empty.yaml
│ │ ├── skipBounds-resolution-not-2-parts.yaml
│ │ ├── skipBounds-resolution-not-number.yaml
│ │ ├── skipBounds-resolution-not-string.yaml
│ │ ├── skipIds-id-empty.yaml
│ │ ├── skipIds-id-leading-space.yaml
│ │ ├── skipIds-id-not-string.yaml
│ │ ├── skipIds-missing-id.yaml
│ │ ├── skipIds-not-array.yaml
│ │ ├── skipTexts-length-negative.yaml
│ │ ├── skipTexts-length-not-number.yaml
│ │ ├── skipTexts-not-array.yaml
│ │ ├── skipTexts-text-empty.yaml
│ │ ├── skipTexts-text-leading-space.yaml
│ │ ├── skipTexts-text-not-string.yaml
│ │ ├── skipTexts-unknown-keys.yaml
│ │ └── unknown-keys.yaml
│ ├── release-file.test.ts
│ └── yaml-check.test.ts
├── index.ts
├── release-file.ts
└── yaml-check.ts
├── settings.gradle.kts
├── tailwind.config.js
└── tsconfig.json
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/.DS_Store
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | # 构建 VitePress 站点并将其部署到 GitHub Pages 的示例工作流程
2 | #
3 | name: Deploy VitePress site to Pages
4 |
5 | on:
6 | # 在针对 `main` 分支的推送上运行。如果你
7 | # 使用 `master` 分支作为默认分支,请将其更改为 `master`
8 | push:
9 | branches: [main]
10 |
11 | # 允许你从 Actions 选项卡手动运行此工作流程
12 | workflow_dispatch:
13 |
14 | # 设置 GITHUB_TOKEN 的权限,以允许部署到 GitHub Pages
15 | permissions:
16 | contents: read
17 | pages: write
18 | id-token: write
19 |
20 | # 只允许同时进行一次部署,跳过正在运行和最新队列之间的运行队列
21 | # 但是,不要取消正在进行的运行,因为我们希望允许这些生产部署完成
22 | concurrency:
23 | group: pages
24 | cancel-in-progress: false
25 |
26 | jobs:
27 | # 构建工作
28 | build:
29 | runs-on: ubuntu-latest
30 | steps:
31 | - name: Checkout
32 | uses: actions/checkout@v4
33 | with:
34 | fetch-depth: 0 # 如果未启用 lastUpdated,则不需要
35 | # - uses: pnpm/action-setup@v3 # 如果使用 pnpm,请取消注释
36 | # - uses: oven-sh/setup-bun@v1 # 如果使用 Bun,请取消注释
37 | - name: Setup Node
38 | uses: actions/setup-node@v4
39 | with:
40 | node-version: 20
41 | cache: npm # 或 pnpm / yarn
42 | - name: Setup Pages
43 | uses: actions/configure-pages@v4
44 | - name: Install dependencies
45 | run: npm ci
46 | - name: Build with VitePress
47 | run: npm run docs:build
48 | - name: Release
49 | run: npm run release-file
50 | - name: Upload artifact
51 | uses: actions/upload-pages-artifact@v3
52 | with:
53 | path: docs/.vitepress/dist
54 |
55 | # 部署工作
56 | deploy:
57 | environment:
58 | name: github-pages
59 | url: ${{ steps.deployment.outputs.page_url }}
60 | needs: build
61 | runs-on: ubuntu-latest
62 | name: Deploy
63 | steps:
64 | - name: Deploy to GitHub Pages
65 | id: deployment
66 | uses: actions/deploy-pages@v4
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## v3.1.0 - 2025.04.27
2 |
3 | - 新增「悬浮窗按钮」用于执行布局检查功能
4 | - 新增应用白名单搜索功能
5 | - 新增「严格模式」下可在应用内执行「跳过」
6 | - 修复加载的配置文件包含 Unicode 编码时未转换为中文的问题
7 | - 修复点击右上角「功能介绍」后菜单未自动关闭的问题
8 | - 修复断网后无法使用的问题
9 | - 修复「后台任务隐藏」失效的问题
10 |
11 | ## v3.0.0 - 2024.09.27
12 |
13 | ### 新增
14 |
15 | - 依赖库版本更新,并基于 Android MVVM 架构重构项目
16 | - 新增「发生故障」标识,方便判断无障碍是否发生故障
17 | - 新增「布局检查」功能
18 | - 新增「自定义配置」功能 [#188](https://github.com/GuoXiCheng/SKIP/issues/188) [#237](https://github.com/GuoXiCheng/SKIP/issues/237)
19 | - 新的可配置项:`activityName`、`click`
20 | - 新增「后台隐藏」选项 [#196](https://github.com/GuoXiCheng/SKIP/issues/196)
21 | - 应用保活新增常驻通知栏功能
22 | - 新增「严格模式」启用开关
23 | - 页面右上角新增「功能介绍」入口
24 | - 新增后台定时自动检查更新功能
25 |
--------------------------------------------------------------------------------
/DISCLAIMER.md:
--------------------------------------------------------------------------------
1 | # 免责声明
2 |
3 | 感谢您信任并使用「SKIP」,为了保障您的权益,请在使用「SKIP」前,仔细阅读本免责声明。
4 |
5 | 本项目遵循 GNU 通用公共许可证第 3 版(GPLv3)发布。在使用本项目的过程中,请注意以下事项:
6 |
7 | ## 一、无任何担保
8 |
9 | 本项目“按现状”(as-is)提供,开发者不对其做出任何明示或暗示的担保。无论是适销性、特定用途的适用性,还是非侵权性,本项目均不做任何承诺。使用本项目的风险完全由您自己承担。
10 |
11 | ## 二、不承担任何责任
12 |
13 | 在适用法律允许的最大范围内,项目的开发者、贡献者不对因使用或无法使用本项目或其衍生物而引起的任何形式的损失、损害或法律责任负责。这包括但不限于直接损失、间接损失、特殊损害、偶然损害或惩罚性赔偿。
14 |
15 | ## 三、知识产权声明
16 |
17 | 本项目中所涉及的任何代码、文档或其他文件均受 GPLv3 许可证的约束。您可以自由使用、修改和分发本项目,但必须保留原始许可条款,并且在适用的情况下,任何分发的衍生作品也必须遵循相同的许可证。
18 |
19 | ## 四、责任自负
20 |
21 | 您在使用本项目的过程中,可能需要遵守您所在国家或地区的相关法律和规定。请确保您在使用、修改或分发本项目之前,已经了解并遵循所有适用的法律要求。项目的开发者和贡献者不承担您在使用本项目时产生的任何法律后果。
22 |
23 | ## 五、第三方依赖
24 |
25 | 本项目包含来自第三方的开源组件或依赖项,这些第三方的许可条款可能与 GPLv3 不同。请在使用这些组件时仔细阅读并遵守相应的许可证要求。
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |   
2 |
3 | ## SKIP 介绍
4 |
5 | SKIP 是一款免费开源的安卓应用,旨在利用安卓无障碍服务帮助用户快速点击 APP 开屏广告的跳过按钮,让你的使用体验更加流畅。
6 |
7 | ## 主界面预览
8 |
9 |
10 |
11 | ## 文档
12 |
13 | [SKIP 文档](https://skip.guoxicheng.top/)
14 |
15 | ## 许可证
16 |
17 | [GPL-3.0 license](https://github.com/GuoXiCheng/SKIP/blob/main/LICENSE)
18 |
19 | ## 补充说明
20 |
21 | [免责声明](https://github.com/GuoXiCheng/SKIP/blob/main/DISCLAIMER.md)
22 |
23 | ## Star History
24 |
25 | [](https://star-history.com/#GuoXiCheng/SKIP&Date)
26 |
27 | ## 自定义规则订阅
28 |
29 |
30 |
31 |
32 | 规则描述 |
33 | 订阅链接 |
34 | 作者 |
35 | 源码地址 |
36 |
37 |
38 |
39 |
40 | 默认订阅 |
41 | https://skip.guoxicheng.top/skip_config_v3.yaml |
42 | GuoXiCheng |
43 |
44 | skip_config_v3
47 | |
48 |
49 |
50 |
51 |
52 |
53 | > 添加自定义订阅规则订阅请修改[README.md](https://github.com/GuoXiCheng/SKIP/edit/main/README.md)提交 PR。
54 |
--------------------------------------------------------------------------------
/apk/SKIP-v3.1.0.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/apk/SKIP-v3.1.0.apk
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/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/android/skip/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip
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.android.skip", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/assets/skip_config.yaml:
--------------------------------------------------------------------------------
1 | # 蚂蚁财富
2 | - package_name: com.antfortune.wealth
3 | max_click_count: 1
4 | skip_bounds:
5 | - 1440,3024#1139,224,1370,315
6 |
7 | # 酷安
8 | - package_name: com.coolapk.market
9 | skip_id: com.byted.pangle.m:id/tt_splash_skip_btn
10 | skip_bounds:
11 | - 1440,3024#1116,219,1332,316
12 |
13 | # 支付宝
14 | - package_name: com.eg.android.AlipayGphone
15 | max_click_count: 0
16 |
17 | # Github
18 | - package_name: com.github.android
19 | max_click_count: 0
20 |
21 | # 京东阅读
22 | - package_name: com.jd.app.reader
23 | skip_id: com.jd.app.reader:id/mJumpBtn
24 | skip_bounds:
25 | - 1440,3024#1209,113,1338,165
26 |
27 | # 铁路12306
28 | - package_name: com.MobileTicket
29 | skip_id: com.MobileTicket:id/tv_skip
30 |
31 | # 爱奇艺
32 | - package_name: com.qiyi.video
33 | skip_text: 关闭
34 |
35 | # 爱奇艺极速版
36 | - package_name: com.qiyi.video.lite
37 | skip_text: 关闭
38 |
39 | # 腾讯微云
40 | - package_name: com.qq.qcloud
41 | skip_id: com.qq.qcloud:id/gdt_ad_text
42 | skip_bounds:
43 | - 1440,3024#1223,196,1384,308
44 |
45 | # 夸克
46 | - package_name: com.quark.browser
47 | max_click_count: 0
48 |
49 | # 微信
50 | - package_name: com.tencent.mm
51 | max_click_count: 0
52 |
53 | # 华为自带时钟
54 | - package_name: com.android.deskclock
55 | max_click_count: 0
56 |
57 | # CSDN
58 | - package_name: net.csdn.csdnplus
59 | skip_id: com.byted.pangle.m:id/tt_splash_skip_btn
60 |
61 |
62 | # 小度
63 | - package_name: com.baidu.duer.superapp
64 | skip_id: com.byted.pangle:id/tt_splash_skip_btn
65 |
66 |
67 | # VIVO 应用商店, 跳过开屏应用推荐
68 | - package_name: com.bbk.appstore
69 | skip_text: 进入首页
70 | skip_ids: com.bbk.appstore:id/vbutton_title
71 |
72 | # 民生银行
73 | - package_name: cn.com.cmbc.newmbank
74 | skip_id: cn.com.cmbc.newmbank:id/view_count_down
75 |
76 | # 菜鸟
77 | - package_name: com.cainiao.wireless
78 | skip_id: com.cainiao.wireless:id/tt_splash_skip_btn
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/MyApp.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.Application
5 | import android.content.Context
6 | import android.os.Build
7 | import androidx.hilt.work.HiltWorkerFactory
8 | import androidx.work.Configuration
9 | import com.android.skip.util.DataStoreUtils
10 | import com.blankj.utilcode.util.LogUtils
11 | import com.blankj.utilcode.util.Utils
12 | import dagger.hilt.android.HiltAndroidApp
13 | import javax.inject.Inject
14 |
15 | @HiltAndroidApp
16 | class MyApp : Application(), Configuration.Provider {
17 | @Inject
18 | lateinit var workerFactory: HiltWorkerFactory
19 |
20 | override fun onCreate() {
21 | super.onCreate()
22 | context = this
23 | deviceName = "${Build.MANUFACTURER} ${Build.MODEL}"
24 |
25 | DataStoreUtils.init(this)
26 |
27 | Utils.init(this)
28 | LogUtils.getConfig()
29 | .setLogSwitch(false) // 是否输出日志开关
30 | .setConsoleSwitch(true) // 是否在控制台输出日志开关
31 | .setGlobalTag("SKIP_APP") // 全局标签
32 | .setLog2FileSwitch(true) // 是否写入日志文件开关
33 | .setDir("${this.cacheDir}/logs") // 日志文件目录
34 | .setFilePrefix("log") // 日志文件前缀
35 | .setBorderSwitch(true) // 日志边框开关
36 | .setConsoleFilter(LogUtils.V) // 控制台过滤器
37 | .setFileFilter(LogUtils.V) // 文件过滤器
38 | .setStackDeep(1) // 栈深度
39 | .setSaveDays(7) // 日志保留天数
40 | }
41 |
42 | companion object {
43 | @SuppressLint("StaticFieldLeak")
44 | lateinit var context: Context
45 |
46 | lateinit var deviceName: String
47 | }
48 |
49 | override fun getWorkManagerConfiguration() =
50 | Configuration.Builder()
51 | .setWorkerFactory(workerFactory)
52 | .build()
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/data/SyncWorker.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.data
2 |
3 | import android.content.Context
4 | import androidx.hilt.work.HiltWorker
5 | import androidx.work.WorkerParameters
6 | import androidx.work.CoroutineWorker
7 | import com.android.skip.data.config.ConfigReadRepository
8 | import com.android.skip.data.version.ApkVersionRepository
9 | import com.blankj.utilcode.util.LogUtils
10 | import dagger.assisted.Assisted
11 | import dagger.assisted.AssistedInject
12 |
13 | @HiltWorker
14 | class SyncWorker@AssistedInject constructor(
15 | @Assisted context: Context,
16 | @Assisted workerParams: WorkerParameters,
17 | private val configReadRepository: ConfigReadRepository,
18 | private val versionRepository: ApkVersionRepository
19 | ) : CoroutineWorker(context, workerParams) {
20 | override suspend fun doWork(): Result {
21 | return try {
22 | LogUtils.d("SyncWorker doWork")
23 | val configPostSchema = configReadRepository.readConfig()
24 | configReadRepository.changeConfigPostState(configPostSchema)
25 |
26 | versionRepository.checkVersion()
27 | Result.success()
28 | } catch (e: Exception) {
29 | LogUtils.e(e)
30 | Result.failure()
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/data/config/ConfigViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.data.config
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.ViewModel
5 | import androidx.lifecycle.viewModelScope
6 | import com.android.skip.R
7 | import com.android.skip.dataclass.ConfigPostSchema
8 | import com.android.skip.dataclass.ConfigState
9 | import com.blankj.utilcode.util.StringUtils.getString
10 | import dagger.hilt.android.lifecycle.HiltViewModel
11 | import kotlinx.coroutines.launch
12 | import javax.inject.Inject
13 |
14 | @HiltViewModel
15 | class ConfigViewModel @Inject constructor(
16 | private val configReadRepository: ConfigReadRepository,
17 | private val configLoadRepository: ConfigLoadRepository
18 | ) : ViewModel() {
19 | var configPostState: LiveData = configReadRepository.configPostState
20 |
21 | fun readConfig() {
22 | viewModelScope.launch {
23 | val configPostSchema = configReadRepository.readConfig()
24 | configReadRepository.changeConfigPostState(configPostSchema)
25 | }
26 | }
27 |
28 | fun loadConfig(configPostSchema: ConfigPostSchema) {
29 | if (configPostSchema.status == ConfigState.SUCCESS) {
30 | val configMap = configReadRepository.handleConfig(configPostSchema)
31 | if (configMap != null) {
32 | configLoadRepository.loadConfig(configMap)
33 | } else {
34 | configLoadRepository.loadConfig(mutableMapOf())
35 | changeConfigPostState(ConfigPostSchema(ConfigState.FAIL, getString(R.string.invalid_config)))
36 | }
37 | }
38 | }
39 |
40 | fun changeConfigPostState(configPostSchema: ConfigPostSchema) =
41 | configReadRepository.changeConfigPostState(configPostSchema)
42 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/data/download/ApkDownloadRepository.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.data.download
2 |
3 | import com.android.skip.data.network.MyApiNetwork
4 | import kotlinx.coroutines.Dispatchers
5 | import kotlinx.coroutines.withContext
6 | import javax.inject.Inject
7 | import javax.inject.Singleton
8 |
9 | @Singleton
10 | class ApkDownloadRepository @Inject constructor(
11 | private val myApiNetwork: MyApiNetwork
12 | ) {
13 | suspend fun downloadAPK(latestVersion: String, onDownloadProcess: (process: Int) -> Unit) =
14 | withContext(Dispatchers.IO) {
15 | myApiNetwork.fetchAPK(latestVersion, onDownloadProcess)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/data/download/ApkDownloadViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.data.download
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.viewModelScope
7 | import dagger.hilt.android.lifecycle.HiltViewModel
8 | import kotlinx.coroutines.Dispatchers
9 | import kotlinx.coroutines.launch
10 | import kotlinx.coroutines.withContext
11 | import javax.inject.Inject
12 |
13 | @HiltViewModel
14 | class ApkDownloadViewModel @Inject constructor(
15 | private val apkDownloadRepository: ApkDownloadRepository
16 | ) : ViewModel() {
17 | private val _isShowDialog = MutableLiveData(false)
18 | val isShowDialog: LiveData = _isShowDialog
19 |
20 | private val _apkDownloadProcess = MutableLiveData(0)
21 | val apkDownloadProcess: LiveData = _apkDownloadProcess
22 |
23 | fun changeDialogState(showDialog: Boolean) {
24 | _isShowDialog.postValue(showDialog)
25 | }
26 |
27 | private fun changeApkDownloadProcess(process: Int) {
28 | _apkDownloadProcess.postValue(process)
29 | }
30 |
31 | fun downloadAPK(latestVersion: String) {
32 | viewModelScope.launch {
33 | withContext(Dispatchers.IO) {
34 | apkDownloadRepository.downloadAPK(latestVersion) {
35 | changeApkDownloadProcess(it)
36 | }
37 | }
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/data/network/ServiceCreator.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.data.network
2 |
3 | import okhttp3.OkHttpClient
4 | import retrofit2.Retrofit
5 | import retrofit2.converter.gson.GsonConverterFactory
6 | import retrofit2.converter.scalars.ScalarsConverterFactory
7 |
8 | object ServiceCreator {
9 | private const val BASE_URL = "https://skip.guoxicheng.top"
10 |
11 | private val httpClient = OkHttpClient.Builder()
12 |
13 | private val builder = Retrofit.Builder()
14 | .baseUrl(BASE_URL)
15 | .client(httpClient.build())
16 | .addConverterFactory(ScalarsConverterFactory.create())
17 | .addConverterFactory(GsonConverterFactory.create())
18 |
19 | private val retrofit = builder.build()
20 |
21 | fun create(serviceClass: Class): T = retrofit.create(serviceClass)
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/data/network/api/MyApiService.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.data.network.api
2 |
3 | import okhttp3.ResponseBody
4 | import retrofit2.Response
5 | import retrofit2.http.GET
6 | import retrofit2.http.Path
7 | import retrofit2.http.Streaming
8 | import retrofit2.http.Url
9 |
10 | interface MyApiService {
11 | @GET
12 | suspend fun getConfigFromUrl(@Url url: String): Response
13 |
14 | @GET("/latest_version.txt")
15 | suspend fun getLatestVersion(): Response
16 |
17 | @GET("/SKIP-v{version}.apk")
18 | @Streaming
19 | suspend fun downloadAPK(@Path("version") latestVersion: String): Response
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/data/version/ApkVersionViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.data.version
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.android.skip.R
6 | import com.android.skip.util.DataStoreUtils
7 | import com.blankj.utilcode.util.StringUtils.getString
8 | import dagger.hilt.android.lifecycle.HiltViewModel
9 | import kotlinx.coroutines.launch
10 | import javax.inject.Inject
11 |
12 | @HiltViewModel
13 | class ApkVersionViewModel @Inject constructor(
14 | private val apkVersionRepository: ApkVersionRepository
15 | ) : ViewModel() {
16 | val versionPostState = apkVersionRepository.versionPostState
17 |
18 | fun checkVersion() {
19 | viewModelScope.launch {
20 | apkVersionRepository.checkVersion()
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/dataclass/AccessibilityNodeInfoCarrier.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.dataclass
2 |
3 | import android.view.accessibility.AccessibilityNodeInfo
4 |
5 | data class AccessibilityNodeInfoCarrier(
6 | val node: AccessibilityNodeInfo,
7 | val depth: Int,
8 | val parentId: Int,
9 | val nodeId: Int
10 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/dataclass/AppListItem.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.dataclass
2 |
3 | import android.graphics.drawable.Drawable
4 | import androidx.compose.runtime.MutableState
5 |
6 | data class AppListItem(
7 | val appName: String,
8 | val packageName: String,
9 | val appIcon: Drawable,
10 | val checked: Boolean
11 | )
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/dataclass/ConfigLoadSchema.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.dataclass
2 |
3 | import android.graphics.Rect
4 |
5 | data class LoadSkipText(
6 | val text: String,
7 | val activityName: String? = null,
8 | val length: Int? = null,
9 | val click: Rect? = null
10 | )
11 |
12 | data class LoadSkipId(
13 | val id: String,
14 | val activityName: String? = null,
15 | val click: Rect? = null
16 | )
17 |
18 | data class LoadSkipBound(
19 | val bound: Rect,
20 | val activityName: String? = null,
21 | val click: Rect? = null
22 | )
23 |
24 | data class ConfigLoadSchema(
25 | val packageName: String,
26 | var skipTexts: List? = null,
27 | val skipIds: List? = null,
28 | val skipBounds: List? = null
29 | )
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/dataclass/ConfigPostSchema.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.dataclass
2 |
3 | enum class ConfigState {
4 | SUCCESS, PENDING, FAIL
5 | }
6 |
7 | data class ConfigPostSchema(
8 | val status: ConfigState,
9 | val value: String,
10 | val configReadSchemaList: List? = null
11 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/dataclass/ConfigReadSchema.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.dataclass
2 |
3 | data class ReadSkipText(
4 | val text: String,
5 | val length: Int? = null,
6 | val activityName: String? = null,
7 | val click: String? = null
8 | )
9 |
10 | data class ReadSkipId(
11 | val id: String,
12 | val activityName: String? = null,
13 | val click: String? = null
14 | )
15 |
16 | data class ReadSkipBound(
17 | val bound: String,
18 | val activityName: String? = null,
19 | val click: String? = null
20 | )
21 |
22 | data class ConfigReadSchema(
23 | val packageName: String,
24 | val skipTexts: List? = null,
25 | val skipIds: List? = null,
26 | val skipBounds: List? = null
27 | )
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/dataclass/InspectRecordItem.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.dataclass
2 |
3 | import android.graphics.drawable.Drawable
4 |
5 | data class InspectRecordItem(
6 | val fileId: String,
7 | val appIcon: Drawable,
8 | val appName: String,
9 | val packageName: String,
10 | val activityName: String,
11 | val createTime: Long
12 | )
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/dataclass/NodeChildSchema.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.dataclass
2 |
3 | data class NodeChildSchema(
4 | val depth: Int,
5 | val childCount: Int,
6 | val parentId: Int,
7 | val nodeId: Int,
8 | val left: Int,
9 | val top: Int,
10 | val right: Int,
11 | val bottom: Int,
12 | val isClickable: Boolean,
13 | var className: String? = null,
14 | var text: String? = null,
15 | var viewIdResourceName: String? = null
16 | )
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/dataclass/NodeRootSchema.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.dataclass
2 |
3 | data class NodeRootSchema(
4 | val fileId: String,
5 | val appName: String,
6 | val packageName: String,
7 | val activityName: String,
8 | val screenHeight: Int,
9 | val screenWidth: Int,
10 | val createTime: Long,
11 | val deviceName: String,
12 | val nodes: MutableList
13 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/dataclass/SemanticVersion.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.dataclass
2 |
3 | data class SemanticVersion(val major: Int, val minor: Int, val patch: Int)
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/dataclass/SwitchThemeCarrier.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.dataclass
2 |
3 | enum class ThemeMode {
4 | UI_LIGHT,UI_DARK, UI_AUTO
5 | }
6 |
7 | data class SwitchThemeCarrier(val themeMode: ThemeMode, val themeName: Int, val themeIcon: Int)
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/dataclass/VersionPostSchema.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.dataclass
2 |
3 | enum class VersionState {
4 | PENDING, CURRENT_LATEST, DISCOVER_LATEST
5 | }
6 |
7 | data class VersionPostSchema(
8 | val status: VersionState,
9 | val value: String,
10 | val latestVersion: String
11 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/service/AccessibilityInspectViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.service
2 |
3 | import androidx.lifecycle.ViewModel
4 | import dagger.hilt.android.lifecycle.HiltViewModel
5 | import javax.inject.Inject
6 |
7 | @HiltViewModel
8 | class AccessibilityInspectViewModel @Inject constructor(
9 | accessibilityInspectRepository: AccessibilityInspectRepository,
10 | ) : ViewModel() {
11 | val accessibilityInspectSuccess = accessibilityInspectRepository.accessibilityInspectSuccess
12 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/service/MyForegroundService.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.service
2 |
3 | import android.app.Notification
4 | import android.app.NotificationChannel
5 | import android.app.NotificationManager
6 | import android.app.PendingIntent
7 | import android.app.Service
8 | import android.content.Context
9 | import android.content.Intent
10 | import android.os.IBinder
11 | import androidx.core.app.NotificationCompat
12 | import com.android.skip.R
13 | import com.android.skip.ui.main.MainActivity
14 |
15 | class MyForegroundService : Service() {
16 | private lateinit var notification: Notification
17 |
18 | override fun onBind(p0: Intent?): IBinder? {
19 | TODO("Not yet implemented")
20 | }
21 |
22 | override fun onCreate() {
23 | super.onCreate()
24 |
25 | val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
26 | val channel = NotificationChannel(
27 | "SKIP_FOREGROUND_SERVICE",
28 | "SKIP 无障碍服务",
29 | NotificationManager.IMPORTANCE_DEFAULT
30 | )
31 | manager.createNotificationChannel(channel)
32 |
33 | val intent = Intent(this, MainActivity::class.java)
34 | val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)
35 | notification = NotificationCompat.Builder(this, "SKIP_FOREGROUND_SERVICE")
36 | .setContentTitle(getString(R.string.app_name))
37 | .setContentText(getString(R.string.notification_accessibility_service_running))
38 | .setSmallIcon(R.drawable.favicon32)
39 | // .setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.favicon32))
40 | .setContentIntent(pendingIntent)
41 | .setOngoing(true)
42 | .build()
43 |
44 | startForeground(2, notification)
45 | }
46 |
47 | override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
48 | super.onStartCommand(intent, flags, startId)
49 | startForeground(2, notification)
50 | return START_STICKY
51 | }
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/about/config/ConfigVersionButton.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.about.config
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.livedata.observeAsState
5 | import com.android.skip.R
6 | import com.android.skip.data.config.ConfigViewModel
7 | import com.android.skip.dataclass.ConfigPostSchema
8 | import com.android.skip.dataclass.ConfigState
9 | import com.android.skip.ui.components.FlatButton
10 | import com.android.skip.ui.components.RowContent
11 | import com.blankj.utilcode.util.StringUtils.getString
12 |
13 | @Composable
14 | fun ConfigVersionButton(configViewModel: ConfigViewModel) {
15 | val configState = configViewModel.configPostState.observeAsState()
16 |
17 | FlatButton(content = {
18 | RowContent(
19 | title = R.string.about_config_version,
20 | subTitle = configState.value?.value
21 | )
22 | }, onClick = {
23 | configViewModel.changeConfigPostState(
24 | ConfigPostSchema(
25 | ConfigState.PENDING,
26 | getString(R.string.checking)
27 | )
28 | )
29 | configViewModel.readConfig()
30 | })
31 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/about/version/ApkVersionButton.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.about.version
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.livedata.observeAsState
5 | import com.android.skip.R
6 | import com.android.skip.data.version.ApkVersionViewModel
7 | import com.android.skip.ui.components.FlatButton
8 | import com.android.skip.ui.components.RowContent
9 | import com.android.skip.util.DataStoreUtils
10 | import com.blankj.utilcode.util.StringUtils.getString
11 |
12 | @Composable
13 | fun ApkVersionButton(apkVersionViewModel: ApkVersionViewModel) {
14 | val versionPostState = apkVersionViewModel.versionPostState.observeAsState()
15 |
16 | FlatButton(content = {
17 | RowContent(
18 | title = R.string.about_app_version,
19 | subTitle = versionPostState.value?.value
20 | )
21 | }, {
22 | DataStoreUtils.removeSync(getString(R.string.store_not_update))
23 | apkVersionViewModel.checkVersion()
24 | })
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/alive/backstage/BackstageButton.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.alive.backstage
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.livedata.observeAsState
5 | import androidx.compose.ui.res.painterResource
6 | import com.android.skip.R
7 | import com.android.skip.ui.components.FlatButton
8 | import com.android.skip.ui.components.PictureDialog
9 | import com.android.skip.ui.components.ResourceIcon
10 | import com.android.skip.ui.components.RowContent
11 |
12 | @Composable
13 | fun BackstageButton(
14 | backstageViewModel:BackstageViewModel,
15 | onClick: ()->Unit={}
16 | ) {
17 | val state = backstageViewModel.showDialog.observeAsState()
18 | PictureDialog(showDialog = state.value == true, painter = painterResource(R.drawable.backend_lock)) {
19 | backstageViewModel.changeDialogState(false)
20 | }
21 | FlatButton(
22 | content = {
23 | RowContent(
24 | R.string.alive_backstage,
25 | R.string.alive_backstage_subtitle,
26 | { ResourceIcon(iconResource = R.drawable.counter_3) })
27 | }, onClick = onClick
28 | )
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/alive/backstage/BackstageViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.alive.backstage
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import dagger.hilt.android.lifecycle.HiltViewModel
7 | import javax.inject.Inject
8 |
9 | @HiltViewModel
10 | class BackstageViewModel @Inject constructor() : ViewModel() {
11 | private val _showDialog = MutableLiveData(false)
12 | val showDialog: LiveData = _showDialog
13 |
14 | fun changeDialogState(isShow: Boolean) {
15 | _showDialog.postValue(isShow)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/alive/notificationbar/NotificationBarButton.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.alive.notificationbar
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.livedata.observeAsState
5 | import com.android.skip.R
6 | import com.android.skip.ui.components.FlatButton
7 | import com.android.skip.ui.components.ResourceIcon
8 | import com.android.skip.ui.components.RowContent
9 |
10 | @Composable
11 | fun NotificationBarButton(
12 | notificationBarViewModel: NotificationBarViewModel,
13 | onClick: () -> Unit = {}
14 | ) {
15 | val enable = notificationBarViewModel.enable.observeAsState()
16 | FlatButton(
17 | content = {
18 | RowContent(
19 | R.string.alive_notification_bar,
20 | R.string.alive_notification_bar_subtitle,
21 | { ResourceIcon(iconResource = R.drawable.counter_4) },
22 | enable.value, {
23 | notificationBarViewModel.changeEnable(it)
24 | })
25 | }, onClick = onClick
26 | )
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/alive/notificationbar/NotificationBarRepository.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.alive.notificationbar
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import com.android.skip.R
6 | import com.android.skip.util.DataStoreUtils
7 | import com.blankj.utilcode.util.StringUtils.getString
8 | import javax.inject.Inject
9 | import javax.inject.Singleton
10 |
11 | @Singleton
12 | class NotificationBarRepository @Inject constructor() {
13 | private val _enable = MutableLiveData(
14 | DataStoreUtils.getSyncData(getString(R.string.store_resident_notification_bar), false)
15 | )
16 | val enable: LiveData = _enable
17 |
18 | fun changeEnable(enable: Boolean) {
19 | _enable.postValue(enable)
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/alive/notificationbar/NotificationBarViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.alive.notificationbar
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.android.skip.R
6 | import com.android.skip.util.DataStoreUtils
7 | import com.blankj.utilcode.util.StringUtils.getString
8 | import dagger.hilt.android.lifecycle.HiltViewModel
9 | import kotlinx.coroutines.Dispatchers
10 | import kotlinx.coroutines.launch
11 | import kotlinx.coroutines.withContext
12 | import javax.inject.Inject
13 |
14 | @HiltViewModel
15 | class NotificationBarViewModel @Inject constructor(
16 | private val notificationBarRepository:NotificationBarRepository
17 | ) : ViewModel() {
18 | val enable = notificationBarRepository.enable
19 |
20 | fun changeEnable(enable: Boolean) {
21 | notificationBarRepository.changeEnable(enable)
22 |
23 | viewModelScope.launch {
24 | withContext(Dispatchers.IO) {
25 | DataStoreUtils.putSyncData(getString(R.string.store_resident_notification_bar), enable)
26 | }
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/components/FlatButton.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.components
2 |
3 | import androidx.compose.foundation.layout.RowScope
4 | import androidx.compose.foundation.layout.fillMaxWidth
5 | import androidx.compose.foundation.layout.heightIn
6 | import androidx.compose.material3.ExtendedFloatingActionButton
7 | import androidx.compose.material3.FloatingActionButtonDefaults
8 | import androidx.compose.material3.MaterialTheme
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.unit.dp
12 |
13 |
14 | typealias ButtonContent = @Composable RowScope.() -> Unit
15 |
16 | @Composable
17 | fun FlatButton(content: ButtonContent, onClick: () -> Unit = {}) {
18 | ExtendedFloatingActionButton(
19 | modifier = Modifier
20 | .fillMaxWidth()
21 | .heightIn(min=60.dp),
22 | onClick = onClick,
23 | content = content,
24 | elevation = FloatingActionButtonDefaults.elevation(
25 | defaultElevation = 0.dp,
26 | pressedElevation = 0.dp,
27 | hoveredElevation = 0.dp,
28 | focusedElevation = 0.dp
29 | ),
30 | containerColor = MaterialTheme.colorScheme.background
31 | )
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/components/FlatButtonMenu.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.components
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.ColumnScope
5 | import androidx.compose.foundation.layout.Row
6 | import androidx.compose.foundation.layout.RowScope
7 | import androidx.compose.material3.DropdownMenu
8 | import androidx.compose.material3.MaterialTheme
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.runtime.MutableState
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.unit.Dp
13 | import androidx.compose.ui.unit.DpOffset
14 | import androidx.compose.ui.unit.dp
15 | import com.blankj.utilcode.util.ScreenUtils
16 |
17 | @Composable
18 | fun FlatButtonMenu(
19 | content: @Composable RowScope.() -> Unit,
20 | menuItems: @Composable (ColumnScope.() -> Unit),
21 | expanded: MutableState
22 | ) {
23 | Row {
24 | FlatButton(content = content) {
25 | expanded.value = true
26 | }
27 |
28 | DropdownMenu(
29 | expanded = expanded.value,
30 | modifier = Modifier
31 | .background(MaterialTheme.colorScheme.background),
32 | offset = DpOffset(Dp(ScreenUtils.getScreenXDpi() / 3), (-30).dp),
33 | onDismissRequest = { expanded.value = false },
34 | ) {
35 | menuItems()
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/components/PictureDialog.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.components
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.foundation.layout.heightIn
6 | import androidx.compose.material3.MaterialTheme
7 | import androidx.compose.material3.Surface
8 | import androidx.compose.material3.Text
9 | import androidx.compose.material3.TextButton
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.ui.Alignment
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.graphics.painter.Painter
14 | import androidx.compose.ui.res.stringResource
15 | import androidx.compose.ui.unit.Dp
16 | import androidx.compose.ui.window.Dialog
17 | import com.android.skip.R
18 | import com.blankj.utilcode.util.ScreenUtils
19 |
20 | @Composable
21 | fun PictureDialog(
22 | showDialog: Boolean,
23 | painter: Painter?,
24 | onClick: () -> Unit
25 | ) {
26 | if (showDialog) {
27 | Dialog(onDismissRequest = { /*TODO*/ }) {
28 | Surface(shape = MaterialTheme.shapes.medium) {
29 | Column(horizontalAlignment = Alignment.CenterHorizontally) {
30 | if (painter != null) {
31 | Image(
32 | painter = painter,
33 | contentDescription = null,
34 | modifier = Modifier.heightIn(max = Dp(ScreenUtils.getScreenYDpi() * 2))
35 | )
36 | }
37 | TextButton(onClick = onClick) {
38 | Text(stringResource(id = R.string.dialog_close))
39 | }
40 | }
41 | }
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/components/ResourceIcon.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.components
2 |
3 | import androidx.compose.material3.Icon
4 | import androidx.compose.material3.MaterialTheme
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.ui.res.painterResource
7 |
8 | @Composable
9 | fun ResourceIcon(iconResource: Int) {
10 | Icon(
11 | painter = painterResource(id = iconResource),
12 | contentDescription = null,
13 | tint = MaterialTheme.colorScheme.onBackground
14 | )
15 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/components/notification/NotificationDialogViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.components.notification
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import dagger.hilt.android.lifecycle.HiltViewModel
7 | import javax.inject.Inject
8 |
9 | @HiltViewModel
10 | class NotificationDialogViewModel @Inject constructor(): ViewModel() {
11 | private val _showDialog = MutableLiveData(false)
12 | val showDialog: LiveData = _showDialog
13 |
14 | fun changeDialogState(isShow: Boolean) {
15 | _showDialog.postValue(isShow)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/inspect/floating/FloatingWindowButton.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.inspect.floating
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.getValue
5 | import androidx.compose.runtime.livedata.observeAsState
6 | import com.android.skip.R
7 | import com.android.skip.ui.components.FlatButton
8 | import com.android.skip.ui.components.ResourceIcon
9 | import com.android.skip.ui.components.RowContent
10 |
11 | @Composable
12 | fun FloatingWindowButton(floatingWindowViewModel: FloatingWindowViewModel) {
13 | val floatingWindowState by floatingWindowViewModel.floatingWindowState.observeAsState()
14 |
15 | FlatButton(content = {
16 | RowContent(
17 | title = R.string.inspect_floating_window_title,
18 | subTitle = R.string.inspect_floating_window_subtitle,
19 | icon = { ResourceIcon(iconResource = R.drawable.float_landscape_2) },
20 | checked = floatingWindowState,
21 | {
22 | floatingWindowViewModel.changeFloatingWindowState(it)
23 | }
24 | )
25 | })
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/inspect/floating/FloatingWindowRepository.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.inspect.floating
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import com.android.skip.service.InspectService
6 | import com.blankj.utilcode.util.ServiceUtils
7 | import javax.inject.Inject
8 | import javax.inject.Singleton
9 |
10 | @Singleton
11 | class FloatingWindowRepository @Inject constructor() {
12 | private val _floatingWindowState = MutableLiveData(ServiceUtils.isServiceRunning(InspectService::class.java))
13 | val floatingWindowState: LiveData = _floatingWindowState
14 |
15 | fun changeFloatingWindowState(state: Boolean) {
16 | _floatingWindowState.postValue(state)
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/inspect/floating/FloatingWindowViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.inspect.floating
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.ViewModel
5 | import dagger.hilt.android.lifecycle.HiltViewModel
6 | import javax.inject.Inject
7 |
8 | @HiltViewModel
9 | class FloatingWindowViewModel @Inject constructor(private val repository: FloatingWindowRepository): ViewModel() {
10 | val floatingWindowState: LiveData = repository.floatingWindowState
11 |
12 | fun changeFloatingWindowState(state: Boolean) = repository.changeFloatingWindowState(state)
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/inspect/record/InspectRecordButton.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.inspect.record
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.getValue
5 | import androidx.compose.runtime.livedata.observeAsState
6 | import androidx.compose.ui.res.stringResource
7 | import com.android.skip.R
8 | import com.android.skip.ui.components.FlatButton
9 | import com.android.skip.ui.components.ResourceIcon
10 | import com.android.skip.ui.components.RowContent
11 |
12 | @Composable
13 | fun InspectRecordButton(inspectRecordViewModel: InspectRecordViewModel, onClick: () -> Unit = {}) {
14 | val zipFileCount by inspectRecordViewModel.zipFileCount.observeAsState()
15 |
16 | FlatButton(content = {
17 | RowContent(
18 | title = R.string.inspect_record_title,
19 | subTitle = zipFileCount?.let {
20 | stringResource(
21 | id = R.string.inspect_record_subtitle,
22 | it
23 | )
24 | },
25 | icon = { ResourceIcon(iconResource = R.drawable.lists) },
26 | )
27 | }, onClick = onClick)
28 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/inspect/record/InspectRecordRepository.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.inspect.record
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import com.android.skip.MyApp
6 | import com.blankj.utilcode.util.FileUtils
7 | import javax.inject.Inject
8 | import javax.inject.Singleton
9 |
10 | @Singleton
11 | class InspectRecordRepository @Inject constructor() {
12 | private val _zipFileCount = MutableLiveData(0)
13 | var zipFileCount: LiveData = _zipFileCount
14 |
15 | fun changeZipFileCount() {
16 | val fileList = FileUtils.listFilesInDirWithFilter("${MyApp.context.filesDir}/capture") {
17 | it.name.endsWith("zip")
18 | }
19 | _zipFileCount.postValue(fileList.size)
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/inspect/record/InspectRecordViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.inspect.record
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.ViewModel
5 | import dagger.hilt.android.lifecycle.HiltViewModel
6 | import javax.inject.Inject
7 |
8 | @HiltViewModel
9 | class InspectRecordViewModel @Inject constructor(private val repository: InspectRecordRepository): ViewModel() {
10 | val zipFileCount: LiveData = repository.zipFileCount
11 |
12 | init {
13 | changeZipFileCount()
14 | }
15 |
16 | fun changeZipFileCount() = repository.changeZipFileCount()
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/inspect/start/StartInspectButton.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.inspect.start
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.getValue
5 | import androidx.compose.runtime.livedata.observeAsState
6 | import com.android.skip.R
7 | import com.android.skip.ui.components.FlatButton
8 | import com.android.skip.ui.components.ResourceIcon
9 | import com.android.skip.ui.components.RowContent
10 |
11 | @Composable
12 | fun StartInspectButton(startInspectViewModel: StartInspectViewModel) {
13 | val inspectState by startInspectViewModel.inspectState.observeAsState()
14 |
15 | FlatButton(content = {
16 | RowContent(
17 | title = R.string.inspect_start_title,
18 | subTitle = R.string.inspect_start_subtitle,
19 | icon = { ResourceIcon(iconResource = R.drawable.fit_screen) },
20 | checked = inspectState,
21 | {
22 | startInspectViewModel.changeInspectState(it)
23 | }
24 | )
25 | })
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/inspect/start/StartInspectRepository.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.inspect.start
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import com.android.skip.R
6 | import com.android.skip.util.AccessibilityState
7 | import com.android.skip.util.AccessibilityStateUtils
8 | import com.android.skip.util.MyToast
9 | import javax.inject.Inject
10 | import javax.inject.Singleton
11 |
12 | @Singleton
13 | class StartInspectRepository @Inject constructor() {
14 | private val _inspectState = MutableLiveData(false)
15 | val inspectState: LiveData = _inspectState
16 |
17 | fun changeInspectState(state: Boolean) {
18 | if (state && AccessibilityStateUtils.getAccessibilityState() != AccessibilityState.STARTED) {
19 | MyToast.show(R.string.toast_start_accessibility_first)
20 | return
21 | }
22 | _inspectState.postValue(state)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/inspect/start/StartInspectViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.inspect.start
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.ViewModel
5 | import dagger.hilt.android.lifecycle.HiltViewModel
6 | import javax.inject.Inject
7 |
8 | @HiltViewModel
9 | class StartInspectViewModel @Inject constructor(private val repository: StartInspectRepository): ViewModel() {
10 | val inspectState: LiveData = repository.inspectState
11 |
12 | fun changeInspectState(state: Boolean) = repository.changeInspectState(state)
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/main/disclaimer/DisclaimerViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.main.disclaimer
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import com.android.skip.R
7 | import com.android.skip.util.DataStoreUtils
8 | import com.blankj.utilcode.util.StringUtils.getString
9 | import dagger.hilt.android.lifecycle.HiltViewModel
10 | import javax.inject.Inject
11 |
12 | @HiltViewModel
13 | class DisclaimerViewModel @Inject constructor() : ViewModel() {
14 | private val _isShowDialog =
15 | MutableLiveData(DataStoreUtils.getSyncData(getString(R.string.store_show_disclaimer), true))
16 | val isShowDialog: LiveData = _isShowDialog
17 |
18 | fun changeDialogState(showDialog: Boolean) {
19 | _isShowDialog.postValue(showDialog)
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/main/start/StartAccessibilityButton.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.main.start
2 |
3 | import androidx.compose.foundation.layout.Arrangement
4 | import androidx.compose.foundation.layout.Row
5 | import androidx.compose.foundation.layout.Spacer
6 | import androidx.compose.foundation.layout.fillMaxWidth
7 | import androidx.compose.foundation.layout.heightIn
8 | import androidx.compose.foundation.layout.width
9 | import androidx.compose.material3.ExtendedFloatingActionButton
10 | import androidx.compose.material3.Icon
11 | import androidx.compose.material3.Text
12 | import androidx.compose.runtime.Composable
13 | import androidx.compose.runtime.collectAsState
14 | import androidx.compose.runtime.getValue
15 | import androidx.compose.ui.Alignment
16 | import androidx.compose.ui.Modifier
17 | import androidx.compose.ui.graphics.Color
18 | import androidx.compose.ui.res.painterResource
19 | import androidx.compose.ui.unit.dp
20 | import androidx.compose.ui.unit.sp
21 |
22 | @Composable
23 | fun StartButton(startAccessibilityViewModel: StartAccessibilityViewModel, onClick: () -> Unit = {}) {
24 | val buttonState by startAccessibilityViewModel.buttonState.collectAsState()
25 |
26 | ExtendedFloatingActionButton(
27 | modifier = Modifier
28 | .fillMaxWidth()
29 | .heightIn(min=80.dp),
30 | onClick = onClick,
31 | content = {
32 | Row(
33 | modifier = Modifier.fillMaxWidth(),
34 | verticalAlignment = Alignment.CenterVertically,
35 | horizontalArrangement = Arrangement.Start
36 | ) {
37 | Icon(
38 | painter = painterResource(id = buttonState.iconResource),
39 | tint = Color.White,
40 | contentDescription = "StartButton"
41 | )
42 | Spacer(modifier = Modifier.width(16.dp))
43 | Text(buttonState.buttonText, color = Color.White, fontSize = 16.sp)
44 | }
45 | },
46 | containerColor = buttonState.backgroundColor
47 | )
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/main/start/StartAccessibilityRepository.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.main.start
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import com.android.skip.service.InspectService
6 | import com.android.skip.util.AccessibilityState
7 | import com.android.skip.util.AccessibilityStateUtils
8 | import com.blankj.utilcode.util.ServiceUtils
9 | import javax.inject.Inject
10 | import javax.inject.Singleton
11 |
12 | @Singleton
13 | class StartAccessibilityRepository @Inject constructor() {
14 | private val _accessibilityState =
15 | MutableLiveData(AccessibilityStateUtils.getAccessibilityState())
16 | val accessibilityState: LiveData = _accessibilityState
17 |
18 | fun changeAccessibilityState(state: AccessibilityState) {
19 | _accessibilityState.postValue(state)
20 | if (state != AccessibilityState.STARTED) {
21 | ServiceUtils.stopService(InspectService::class.java)
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/main/start/StartAccessibilityViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.main.start
2 |
3 | import androidx.compose.ui.graphics.Color
4 | import androidx.lifecycle.Observer
5 | import androidx.lifecycle.ViewModel
6 | import com.android.skip.R
7 | import com.android.skip.util.AccessibilityState
8 | import dagger.hilt.android.lifecycle.HiltViewModel
9 | import kotlinx.coroutines.flow.MutableStateFlow
10 | import kotlinx.coroutines.flow.asStateFlow
11 | import javax.inject.Inject
12 |
13 | @HiltViewModel
14 | class StartAccessibilityViewModel @Inject constructor(private val repository: StartAccessibilityRepository) : ViewModel() {
15 | private val stopped = ButtonState(Color(0xFF808080), "已停止\n点此启动", R.drawable.block)
16 | private val started = ButtonState(Color(0xFF1E4377), "运行中", R.drawable.check_circle)
17 | private val faulted = ButtonState(Color(0xFF771E1E), "发生故障\n点此重新启动", R.drawable.error)
18 |
19 | private val _buttonState = MutableStateFlow(stopped)
20 | val buttonState = _buttonState.asStateFlow()
21 |
22 | private val observer = Observer {
23 | changeButtonState(it)
24 | }
25 |
26 | init {
27 | repository.accessibilityState.observeForever(observer)
28 | }
29 |
30 | private fun changeButtonState(isRunning: AccessibilityState) {
31 | _buttonState.value = when (isRunning) {
32 | AccessibilityState.STARTED -> started
33 | AccessibilityState.STOPPED -> stopped
34 | AccessibilityState.FAULTED -> faulted
35 | }
36 | }
37 |
38 | override fun onCleared() {
39 | super.onCleared()
40 | repository.accessibilityState.removeObserver(observer)
41 | }
42 |
43 | data class ButtonState(
44 | val backgroundColor: Color,
45 | val buttonText: String,
46 | val iconResource: Int
47 | )
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/main/tutorial/TutorialDialog.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.main.tutorial
2 |
3 | import androidx.compose.material3.AlertDialog
4 | import androidx.compose.material3.Button
5 | import androidx.compose.material3.MaterialTheme
6 | import androidx.compose.material3.Text
7 | import androidx.compose.material3.TextButton
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.runtime.livedata.observeAsState
10 | import androidx.compose.ui.res.stringResource
11 | import com.android.skip.R
12 |
13 | @Composable
14 | fun TutorialDialog(
15 | tutorialViewModel: TutorialViewModel,
16 | onDismiss: () -> Unit,
17 | onConfirm: () -> Unit
18 | ) {
19 | val isShowDialog = tutorialViewModel.isShowDialog.observeAsState()
20 | if (isShowDialog.value == true) {
21 | AlertDialog(
22 | containerColor = MaterialTheme.colorScheme.background,
23 | title = {
24 | Text(text = stringResource(id = R.string.dialog_get_started))
25 | },
26 | text = {
27 | Text(text = stringResource(id = R.string.dialog_get_started_content))
28 | },
29 | onDismissRequest = {},
30 | confirmButton = {
31 | Button(
32 | onClick = onConfirm
33 | ) {
34 | Text(stringResource(id = R.string.dialog_go_at_once))
35 | }
36 | },
37 | dismissButton = {
38 | TextButton(
39 | onClick = onDismiss
40 | ) {
41 | Text(stringResource(id = R.string.dialog_no_more_reminders))
42 | }
43 | }
44 | )
45 | }
46 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/main/tutorial/TutorialViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.main.tutorial
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import dagger.hilt.android.lifecycle.HiltViewModel
7 | import javax.inject.Inject
8 |
9 | @HiltViewModel
10 | class TutorialViewModel @Inject constructor() : ViewModel() {
11 | private val _isShowDialog = MutableLiveData()
12 | val isShowDialog: LiveData = _isShowDialog
13 |
14 | fun changeDialogState(showDialog: Boolean) {
15 | _isShowDialog.postValue(showDialog)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/record/dialog/JpegDialog.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.record.dialog
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.livedata.observeAsState
5 | import androidx.compose.ui.graphics.asImageBitmap
6 | import androidx.compose.ui.graphics.painter.BitmapPainter
7 | import com.android.skip.ui.components.PictureDialog
8 |
9 | @Composable
10 | fun JpegDialog(jpegDialogViewModel: JpegDialogViewModel) {
11 | val jpegFileIdState = jpegDialogViewModel.jpegFileId.observeAsState()
12 | PictureDialog(
13 | showDialog = jpegFileIdState.value != null,
14 | painter = jpegDialogViewModel.bitmapJpeg?.let { BitmapPainter(it.asImageBitmap()) }
15 | ) {
16 | jpegDialogViewModel.changeJpegFileId(null)
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/record/dialog/JpegDialogRepository.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.record.dialog
2 |
3 | import android.graphics.Bitmap
4 | import android.graphics.BitmapFactory
5 | import com.android.skip.MyApp
6 | import javax.inject.Inject
7 | import javax.inject.Singleton
8 |
9 | @Singleton
10 | class JpegDialogRepository @Inject constructor(){
11 | fun getJpegByFileId(fileId: String): Bitmap {
12 | val filePath = "${MyApp.context.filesDir}/capture/${fileId}.jpeg"
13 | val bitmap = BitmapFactory.decodeFile(filePath)
14 | return bitmap
15 | }
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/record/dialog/JpegDialogViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.record.dialog
2 |
3 | import android.graphics.Bitmap
4 | import androidx.lifecycle.LiveData
5 | import androidx.lifecycle.MutableLiveData
6 | import androidx.lifecycle.ViewModel
7 | import dagger.hilt.android.lifecycle.HiltViewModel
8 | import javax.inject.Inject
9 |
10 | @HiltViewModel
11 | class JpegDialogViewModel @Inject constructor(
12 | private val jpegDialogRepository: JpegDialogRepository
13 | ) : ViewModel() {
14 | private val _jpegFileId = MutableLiveData()
15 | val jpegFileId: LiveData = _jpegFileId
16 |
17 | private var _bitmapJpeg: Bitmap? = null
18 | val bitmapJpeg
19 | get() = _bitmapJpeg
20 |
21 | fun changeJpegFileId(fileId: String?) {
22 | if (fileId != null) {
23 | _bitmapJpeg = jpegDialogRepository.getJpegByFileId(fileId)
24 | }
25 | _jpegFileId.postValue(fileId)
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/record/list/InspectListPagingSource.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.record.list
2 |
3 | import androidx.paging.PagingSource
4 | import androidx.paging.PagingState
5 | import com.android.skip.dataclass.InspectRecordItem
6 | import com.blankj.utilcode.util.LogUtils
7 | import javax.inject.Inject
8 |
9 |
10 | class ZipFilePagingSource @Inject constructor(private val inspectListRepository: InspectListRepository) :
11 | PagingSource() {
12 | override fun getRefreshKey(state: PagingState): Int? {
13 | return state.anchorPosition?.let { anchorPosition ->
14 | state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
15 | ?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus((1))
16 | }
17 | }
18 |
19 | override suspend fun load(params: LoadParams): LoadResult {
20 | return try {
21 | val currentPage = params.key ?: 0
22 | val pageSize = params.loadSize
23 |
24 | val pageData = inspectListRepository.getData(currentPage, pageSize)
25 |
26 | val fromIndex = currentPage * pageSize
27 | val toIndex = minOf(fromIndex + pageSize, pageData.size)
28 |
29 | LoadResult.Page(
30 | data = pageData,
31 | prevKey = if (currentPage == 0) null else currentPage - 1,
32 | nextKey = if (toIndex == pageData.size) null else currentPage + 1
33 | )
34 | } catch (e: Exception) {
35 | LogUtils.e(e)
36 | LoadResult.Error(e)
37 | }
38 | }
39 |
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/record/list/InspectListViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.record.list
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.viewModelScope
7 | import androidx.paging.Pager
8 | import androidx.paging.PagingConfig
9 | import androidx.paging.PagingData
10 | import androidx.paging.cachedIn
11 | import com.android.skip.dataclass.InspectRecordItem
12 | import dagger.hilt.android.lifecycle.HiltViewModel
13 | import kotlinx.coroutines.flow.Flow
14 | import javax.inject.Inject
15 |
16 | @HiltViewModel
17 | class InspectListViewModel @Inject constructor(
18 | private val inspectListRepository: InspectListRepository
19 | ) : ViewModel() {
20 | private val _delFileId = MutableLiveData()
21 | val delFileId: LiveData = _delFileId
22 |
23 | private var currentPagingSource: ZipFilePagingSource? = null
24 |
25 | fun deleteByFileId(fileId: String) = inspectListRepository.deleteByFileId(fileId)
26 |
27 | fun deleteAllFile() = inspectListRepository.deleteAllFile()
28 |
29 | fun changeDeleteFileId(fileId: String) {
30 | _delFileId.postValue(fileId)
31 | }
32 |
33 | fun reloadData() {
34 | currentPagingSource?.invalidate()
35 | filePagingData = createPager().flow.cachedIn(viewModelScope)
36 | }
37 |
38 | var filePagingData: Flow> = createPager().flow.cachedIn(viewModelScope)
39 |
40 | private fun createPager(): Pager {
41 | return Pager(
42 | config = PagingConfig(
43 | pageSize = 20,
44 | enablePlaceholders = false
45 | ),
46 | pagingSourceFactory = {
47 | val newPagingSource = ZipFilePagingSource(inspectListRepository)
48 | currentPagingSource = newPagingSource
49 | newPagingSource
50 | }
51 | )
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/settings/recent/RecentButton.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.settings.recent
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.livedata.observeAsState
5 | import com.android.skip.R
6 | import com.android.skip.ui.components.FlatButton
7 | import com.android.skip.ui.components.ResourceIcon
8 | import com.android.skip.ui.components.RowContent
9 |
10 | @Composable
11 | fun RecentButton(recentViewModel: RecentViewModel) {
12 | val excludeFromRecent = recentViewModel.excludeFromRecent.observeAsState()
13 | FlatButton(content = {
14 | RowContent(
15 | title = R.string.settings_background_task,
16 | subTitle = R.string.settings_background_task_subtitle,
17 | icon = { ResourceIcon(iconResource = R.drawable.hide_image)},
18 | checked =excludeFromRecent.value,
19 | onCheckedChange = {
20 | recentViewModel.changeExcludeFromRecent(it)
21 | }
22 | )
23 | })
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/settings/recent/RecentViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.settings.recent
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.viewModelScope
7 | import com.android.skip.R
8 | import com.android.skip.util.DataStoreUtils
9 | import com.blankj.utilcode.util.StringUtils.getString
10 | import dagger.hilt.android.lifecycle.HiltViewModel
11 | import kotlinx.coroutines.Dispatchers
12 | import kotlinx.coroutines.launch
13 | import kotlinx.coroutines.withContext
14 | import javax.inject.Inject
15 |
16 | @HiltViewModel
17 | class RecentViewModel @Inject constructor() : ViewModel() {
18 | private val _excludeFromRecent = MutableLiveData(
19 | DataStoreUtils.getSyncData(
20 | getString(R.string.store_exclude_from_recent),
21 | false
22 | )
23 | )
24 | val excludeFromRecent: LiveData = _excludeFromRecent
25 |
26 | fun changeExcludeFromRecent(excludeFromRecent: Boolean) {
27 | _excludeFromRecent.postValue(excludeFromRecent)
28 |
29 | viewModelScope.launch {
30 | withContext(Dispatchers.IO) {
31 | DataStoreUtils.putData(getString(R.string.store_exclude_from_recent), excludeFromRecent)
32 | }
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/settings/strict/StrictButton.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.settings.strict
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.livedata.observeAsState
5 | import androidx.compose.ui.res.stringResource
6 | import com.android.skip.R
7 | import com.android.skip.ui.components.FlatButton
8 | import com.android.skip.ui.components.ResourceIcon
9 | import com.android.skip.ui.components.RowContent
10 |
11 | @Composable
12 | fun StrictButton(
13 | strictViewModel: StrictViewModel
14 | ) {
15 | val enable = strictViewModel.enable.observeAsState()
16 | val strictText = if (enable.value == true) {
17 | R.string.settings_strict_yes
18 | } else {
19 | R.string.settings_strict_no
20 | }
21 |
22 | FlatButton(
23 | content = {
24 | RowContent(
25 | R.string.settings_strict,
26 | stringResource(id = strictText),
27 | { ResourceIcon(iconResource = R.drawable.target) },
28 | enable.value, {
29 | strictViewModel.changeEnable(it)
30 | })
31 | }, onClick = {}
32 | )
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/settings/strict/StrictRepository.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.settings.strict
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import com.android.skip.R
6 | import com.android.skip.util.DataStoreUtils
7 | import com.blankj.utilcode.util.StringUtils.getString
8 | import javax.inject.Inject
9 | import javax.inject.Singleton
10 |
11 | @Singleton
12 | class StrictRepository @Inject constructor() {
13 | private val _enable = MutableLiveData(
14 | DataStoreUtils.getSyncData(getString(R.string.store_strict_mode), false)
15 | )
16 |
17 | val enable: LiveData = _enable
18 |
19 | fun changeEnable(enable: Boolean) {
20 | _enable.postValue(enable)
21 | }
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/settings/strict/StrictViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.settings.strict
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.android.skip.R
6 | import com.android.skip.util.DataStoreUtils
7 | import com.blankj.utilcode.util.StringUtils.getString
8 | import dagger.hilt.android.lifecycle.HiltViewModel
9 | import kotlinx.coroutines.Dispatchers
10 | import kotlinx.coroutines.launch
11 | import kotlinx.coroutines.withContext
12 | import javax.inject.Inject
13 |
14 | @HiltViewModel
15 | class StrictViewModel @Inject constructor(
16 | private val strictRepository: StrictRepository,
17 | ): ViewModel(){
18 | val enable = strictRepository.enable
19 |
20 | fun changeEnable(enable: Boolean) {
21 | strictRepository.changeEnable(enable)
22 |
23 | viewModelScope.launch {
24 | withContext(Dispatchers.IO) {
25 | DataStoreUtils.putData(getString(R.string.store_strict_mode), enable)
26 | }
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/settings/theme/SwitchThemeRepository.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.settings.theme
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import com.android.skip.R
6 | import com.android.skip.dataclass.SwitchThemeCarrier
7 | import com.android.skip.dataclass.ThemeMode
8 | import com.android.skip.util.DataStoreUtils
9 | import com.blankj.utilcode.util.StringUtils.getString
10 | import javax.inject.Inject
11 | import javax.inject.Singleton
12 |
13 | @Singleton
14 | class SwitchThemeRepository @Inject constructor() {
15 | private val _currentTheme = MutableLiveData(
16 | getThemeCarrier(
17 | DataStoreUtils.getSyncData(
18 | getString(R.string.store_current_theme),
19 | ThemeMode.UI_AUTO.toString()
20 | )
21 | )
22 | )
23 | val currentTheme: LiveData = _currentTheme
24 |
25 | fun changeCurrentTheme(currentTheme: String) {
26 | _currentTheme.postValue(getThemeCarrier(currentTheme))
27 | }
28 |
29 | private fun getThemeCarrier(theme: String): SwitchThemeCarrier {
30 | return when (theme) {
31 | ThemeMode.UI_LIGHT.toString() -> SwitchThemeCarrier(
32 | themeMode = ThemeMode.UI_LIGHT,
33 | themeName = R.string.settings_theme_light,
34 | themeIcon = R.drawable.theme_light
35 | )
36 |
37 | ThemeMode.UI_DARK.toString() -> SwitchThemeCarrier(
38 | themeMode = ThemeMode.UI_DARK,
39 | themeName = R.string.settings_theme_dark,
40 | themeIcon = R.drawable.theme_dark
41 | )
42 |
43 | else -> SwitchThemeCarrier(
44 | themeMode = ThemeMode.UI_AUTO,
45 | themeName = R.string.settings_theme_auto,
46 | themeIcon = R.drawable.theme_auto
47 | )
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/settings/theme/SwitchThemeViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.settings.theme
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.ViewModel
5 | import androidx.lifecycle.viewModelScope
6 | import com.android.skip.R
7 | import com.android.skip.dataclass.SwitchThemeCarrier
8 | import com.android.skip.util.DataStoreUtils
9 | import com.blankj.utilcode.util.StringUtils.getString
10 | import dagger.hilt.android.lifecycle.HiltViewModel
11 | import kotlinx.coroutines.Dispatchers
12 | import kotlinx.coroutines.launch
13 | import kotlinx.coroutines.withContext
14 | import javax.inject.Inject
15 |
16 | @HiltViewModel
17 | class SwitchThemeViewModel @Inject constructor(
18 | private val switchThemeRepository: SwitchThemeRepository
19 | ) : ViewModel() {
20 | val currentTheme: LiveData = switchThemeRepository.currentTheme
21 |
22 | fun changeCurrentTheme(currentTheme: String) {
23 | switchThemeRepository.changeCurrentTheme(currentTheme)
24 |
25 | viewModelScope.launch {
26 | withContext(Dispatchers.IO) {
27 | DataStoreUtils.putData(getString(R.string.store_current_theme), currentTheme)
28 | }
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/settings/tip/TipButton.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.settings.tip
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.livedata.observeAsState
5 | import androidx.compose.ui.platform.LocalContext
6 | import androidx.compose.ui.res.stringResource
7 | import com.android.skip.R
8 | import com.android.skip.ui.components.FlatButton
9 | import com.android.skip.ui.components.ResourceIcon
10 | import com.android.skip.ui.components.RowContent
11 |
12 | @Composable
13 | fun TipButton(tipViewModel: TipViewModel) {
14 | val enable = tipViewModel.enable.observeAsState()
15 | val context = LocalContext.current
16 | val isShowText =
17 | if (enable.value == true)
18 | context.getString(R.string.settings_tip_yes)
19 | else
20 | context.getString(R.string.settings_tip_no)
21 |
22 | FlatButton(
23 | content = {
24 | RowContent(
25 | R.string.settings_tip,
26 | stringResource(id = R.string.settings_tip_subtitle, isShowText),
27 | { ResourceIcon(iconResource = R.drawable.notifications) },
28 | enable.value, {
29 | tipViewModel.changeEnable(it)
30 | })
31 | }, onClick = {}
32 | )
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/settings/tip/TipRepository.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.settings.tip
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import com.android.skip.R
6 | import com.android.skip.util.DataStoreUtils
7 | import com.blankj.utilcode.util.StringUtils.getString
8 | import javax.inject.Inject
9 | import javax.inject.Singleton
10 |
11 | @Singleton
12 | class TipRepository @Inject constructor() {
13 | private val _enable = MutableLiveData(
14 | DataStoreUtils.getSyncData(getString(R.string.store_skip_tip), false)
15 | )
16 |
17 | val enable: LiveData = _enable
18 |
19 | fun changeEnable(enable: Boolean) {
20 | _enable.postValue(enable)
21 | }
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/settings/tip/TipViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.settings.tip
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.android.skip.R
6 | import com.android.skip.util.DataStoreUtils
7 | import com.blankj.utilcode.util.StringUtils.getString
8 | import dagger.hilt.android.lifecycle.HiltViewModel
9 | import kotlinx.coroutines.Dispatchers
10 | import kotlinx.coroutines.launch
11 | import kotlinx.coroutines.withContext
12 | import javax.inject.Inject
13 |
14 | @HiltViewModel
15 | class TipViewModel @Inject constructor(
16 | private val tipRepository: TipRepository
17 | ) : ViewModel() {
18 | val enable = tipRepository.enable
19 | fun changeEnable(enable: Boolean) {
20 | tipRepository.changeEnable(enable)
21 |
22 | viewModelScope.launch {
23 | withContext(Dispatchers.IO) {
24 | DataStoreUtils.putData(getString(R.string.store_skip_tip), enable)
25 | }
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/settings/update/AutoUpdateButton.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.settings.update
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.livedata.observeAsState
5 | import com.android.skip.R
6 | import com.android.skip.ui.components.FlatButton
7 | import com.android.skip.ui.components.ResourceIcon
8 | import com.android.skip.ui.components.RowContent
9 |
10 | @Composable
11 | fun AutoUpdateButton(autoUpdateViewModel: AutoUpdateViewModel) {
12 | val autoUpdate = autoUpdateViewModel.autoUpdate.observeAsState()
13 |
14 | FlatButton(content = {
15 | RowContent(
16 | title = R.string.settings_auto_update,
17 | subTitle = R.string.settings_auto_update_subtitle,
18 | icon = { ResourceIcon(iconResource = R.drawable.sync)},
19 | checked = autoUpdate.value,
20 | {
21 | autoUpdateViewModel.changeAutoUpdate(it)
22 | }
23 | )
24 | })
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/settings/update/AutoUpdateViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.settings.update
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.viewModelScope
7 | import com.android.skip.R
8 | import com.android.skip.util.DataStoreUtils
9 | import com.blankj.utilcode.util.StringUtils.getString
10 | import dagger.hilt.android.lifecycle.HiltViewModel
11 | import kotlinx.coroutines.Dispatchers
12 | import kotlinx.coroutines.launch
13 | import kotlinx.coroutines.withContext
14 | import javax.inject.Inject
15 |
16 | @HiltViewModel
17 | class AutoUpdateViewModel @Inject constructor() : ViewModel() {
18 | private val _autoUpdate =
19 | MutableLiveData(DataStoreUtils.getSyncData(getString(R.string.store_auto_update), false))
20 | val autoUpdate: LiveData = _autoUpdate
21 |
22 | fun changeAutoUpdate(autoUpdate: Boolean) {
23 | _autoUpdate.postValue(autoUpdate)
24 |
25 | viewModelScope.launch {
26 | withContext(Dispatchers.IO) {
27 | DataStoreUtils.putData(getString(R.string.store_auto_update), autoUpdate)
28 | }
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/theme/Color.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.theme
2 |
3 | import androidx.compose.ui.graphics.Color
4 |
5 | val Purple80 = Color(0xFFD0BCFF)
6 | val PurpleGrey80 = Color(0xFFCCC2DC)
7 | val Pink80 = Color(0xFFEFB8C8)
8 | val Purple40 = Color(0xFF6650a4)
9 | val PurpleGrey40 = Color(0xFF625b71)
10 | val Pink40 = Color(0xFF7D5260)
11 | val White = Color.White
12 | val Black = Color.Black
13 | val Gray232 = Color(0xFFE8E8E8)
14 | val Gray172 = Color(0xFFACACAC)
15 | val Black54 = Color(0xFF363636)
16 | val Black91 = Color(0xFF5B5B5B)
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/theme/Typography.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.theme
2 |
3 | import androidx.compose.material3.Typography
4 | import androidx.compose.ui.text.TextStyle
5 | import androidx.compose.ui.text.font.FontFamily
6 | import androidx.compose.ui.text.font.FontWeight
7 | import androidx.compose.ui.unit.sp
8 |
9 | val Typography = Typography(
10 | bodyLarge = TextStyle(
11 | fontFamily = FontFamily.Default,
12 | fontWeight = FontWeight.Normal,
13 | fontSize = 16.sp,
14 | lineHeight = 24.sp,
15 | letterSpacing = 0.5.sp
16 | )
17 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/webview/WebViewActivity.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.webview
2 |
3 | import android.os.Bundle
4 | import android.webkit.WebView
5 | import android.webkit.WebViewClient
6 | import androidx.activity.compose.setContent
7 | import androidx.activity.viewModels
8 | import androidx.appcompat.app.AppCompatActivity
9 | import androidx.compose.foundation.layout.fillMaxSize
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.viewinterop.AndroidView
13 | import com.android.skip.ui.settings.theme.SwitchThemeViewModel
14 | import com.android.skip.ui.theme.AppTheme
15 | import dagger.hilt.android.AndroidEntryPoint
16 |
17 | @AndroidEntryPoint
18 | class WebViewActivity : AppCompatActivity() {
19 |
20 | private val switchThemeViewModel by viewModels()
21 |
22 | override fun onCreate(savedInstanceState: Bundle?) {
23 | super.onCreate(savedInstanceState)
24 | setContent {
25 | AppTheme(switchThemeViewModel) {
26 | val url = intent.getIntExtra("url", -1)
27 | if (url != -1) {
28 | WebViewPage(url = getString(url))
29 | } else {
30 | val address = intent.getStringExtra("address")
31 | if (address != null) {
32 | WebViewPage(url = address)
33 | }
34 | }
35 | }
36 | }
37 | }
38 |
39 | @Composable
40 | fun WebViewPage(url: String) {
41 | AndroidView(
42 | factory = { context ->
43 | WebView(context).apply {
44 | webViewClient = WebViewClient()
45 | settings.javaScriptEnabled = true
46 | loadUrl(url)
47 | }
48 | },
49 | modifier = Modifier.fillMaxSize()
50 | )
51 | }
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/whitelist/WhiteListRepository.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.whitelist
2 |
3 | import com.android.skip.MyApp
4 | import com.android.skip.R
5 | import com.android.skip.util.dataStore
6 | import com.blankj.utilcode.util.StringUtils.getString
7 | import kotlinx.coroutines.Dispatchers
8 | import kotlinx.coroutines.flow.first
9 | import kotlinx.coroutines.runBlocking
10 | import kotlinx.coroutines.withContext
11 | import javax.inject.Inject
12 | import javax.inject.Singleton
13 |
14 | @Singleton
15 | class WhiteListRepository @Inject constructor() {
16 | private val _whiteList: MutableList by lazy {
17 | runBlocking {
18 | initWhitelist().toMutableList()
19 | }
20 | }
21 |
22 | private suspend fun initWhitelist() = withContext(Dispatchers.IO) {
23 | val allPreferences = MyApp.context.dataStore.data.first()
24 | allPreferences.asMap()
25 | .filter {
26 | it.key.name.startsWith(getString(R.string.whitelist_dot)) && it.value == true
27 | }.keys.map {
28 | it.name.substringAfter(
29 | getString(R.string.whitelist_dot)
30 | )
31 | }
32 | }
33 |
34 | fun updateWhiteList(packageName: String, checked: Boolean) {
35 | if (checked) {
36 | _whiteList.add(packageName)
37 | } else {
38 | _whiteList.remove(packageName)
39 | }
40 | }
41 |
42 | fun isAppInWhiteList(packageName: String): Boolean {
43 | return _whiteList.indexOf(packageName) != -1
44 | }
45 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/whitelist/WhiteListViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.whitelist
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.android.skip.R
6 | import com.android.skip.util.DataStoreUtils
7 | import com.blankj.utilcode.util.StringUtils.getString
8 | import dagger.hilt.android.lifecycle.HiltViewModel
9 | import kotlinx.coroutines.Dispatchers
10 | import kotlinx.coroutines.launch
11 | import kotlinx.coroutines.withContext
12 | import javax.inject.Inject
13 |
14 | @HiltViewModel
15 | class WhiteListViewModel @Inject constructor(
16 | private val whiteListRepository: WhiteListRepository
17 | ) : ViewModel() {
18 | fun updateWhiteList(packageName: String, checked: Boolean) {
19 | whiteListRepository.updateWhiteList(packageName, checked)
20 | viewModelScope.launch {
21 | withContext(Dispatchers.IO) {
22 | DataStoreUtils.putData(getString(R.string.whitelist_dot) + packageName, checked)
23 | }
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/whitelist/list/AppListPagingSource.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.whitelist.list
2 |
3 | import androidx.paging.PagingSource
4 | import androidx.paging.PagingState
5 | import com.android.skip.dataclass.AppListItem
6 | import javax.inject.Inject
7 |
8 | class AppListPagingSource @Inject constructor(
9 | private val appListRepository: AppListRepository,
10 | private val isShowSystem: Boolean,
11 | private val query: String
12 | ) : PagingSource() {
13 | override fun getRefreshKey(state: PagingState): Int? {
14 | return state.anchorPosition?.let { anchorPosition ->
15 | state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
16 | ?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus((1))
17 | }
18 | }
19 |
20 | override suspend fun load(params: LoadParams): LoadResult {
21 | val currentPage = params.key ?: 0
22 | val pageSize = params.loadSize
23 |
24 | val pageData = appListRepository.getData(currentPage, pageSize, isShowSystem, query)
25 |
26 | return LoadResult.Page(
27 | data = pageData,
28 | prevKey = if (currentPage > 0) currentPage - 1 else null,
29 | nextKey = if (pageData.isEmpty()) null else currentPage + 1,
30 | )
31 | }
32 |
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/whitelist/list/AppListRepository.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.whitelist.list
2 |
3 | import android.content.pm.ApplicationInfo
4 | import android.content.pm.PackageManager
5 | import com.android.skip.MyApp
6 | import com.android.skip.dataclass.AppListItem
7 | import com.android.skip.ui.whitelist.WhiteListRepository
8 | import javax.inject.Inject
9 |
10 | class AppListRepository @Inject constructor() {
11 |
12 | @Inject
13 | lateinit var whiteListRepository: WhiteListRepository
14 |
15 | private val appInfos: MutableList by lazy {
16 | MyApp.context.packageManager.getInstalledApplications(PackageManager.GET_META_DATA)
17 | }
18 |
19 | fun getData(currentPage: Int, pageSize: Int, isShowSystem: Boolean, query: String = ""): List {
20 | try {
21 | val pkgManager = MyApp.context.packageManager
22 |
23 | // 是否显示系统应用的过滤
24 | val apps = if (isShowSystem) {
25 | appInfos
26 | } else {
27 | appInfos.filter { (it.flags and ApplicationInfo.FLAG_SYSTEM) == 0 }
28 | }
29 |
30 | // 根据关键字进行过滤
31 | val filteredApps = if (query.isNotEmpty()) {
32 | apps.filter { it.loadLabel(pkgManager).toString().contains(query, ignoreCase = true) }
33 | } else {
34 | apps
35 | }
36 |
37 | val fromIndex = currentPage * pageSize
38 | val toIndex = minOf(fromIndex + pageSize, filteredApps.size)
39 |
40 | return filteredApps.subList(fromIndex, toIndex)
41 | .map {
42 | AppListItem(
43 | it.loadLabel(pkgManager).toString(),
44 | it.packageName,
45 | it.loadIcon(pkgManager),
46 | whiteListRepository.isAppInWhiteList(it.packageName)
47 | )
48 | }
49 | } catch (e: Exception) {
50 | return listOf()
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/whitelist/list/AppListViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.whitelist.list
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import androidx.paging.Pager
6 | import androidx.paging.PagingConfig
7 | import androidx.paging.PagingData
8 | import androidx.paging.cachedIn
9 | import com.android.skip.dataclass.AppListItem
10 | import dagger.hilt.android.lifecycle.HiltViewModel
11 | import kotlinx.coroutines.flow.Flow
12 | import kotlinx.coroutines.flow.MutableStateFlow
13 | import kotlinx.coroutines.flow.StateFlow
14 | import javax.inject.Inject
15 |
16 | @HiltViewModel
17 | class AppListViewModel @Inject constructor(
18 | private val appListRepository: AppListRepository
19 | ): ViewModel() {
20 | private val _pagingData = MutableStateFlow(createPager(false).flow.cachedIn(viewModelScope))
21 | val pagingData: StateFlow>> = _pagingData
22 |
23 | private var currentPagingSource: AppListPagingSource? = null
24 |
25 | fun reloadData(isShowSystem: Boolean, query: String = "") {
26 | currentPagingSource?.invalidate()
27 | _pagingData.value = createPager(isShowSystem, query).flow.cachedIn(viewModelScope)
28 | }
29 |
30 | private fun createPager(isShowSystem: Boolean, query: String = ""): Pager {
31 | return Pager(
32 | config = PagingConfig(
33 | pageSize = 20,
34 | enablePlaceholders = false
35 | ),
36 | pagingSourceFactory = {
37 | val newPagingSource = AppListPagingSource(appListRepository, isShowSystem, query)
38 | currentPagingSource = newPagingSource
39 | newPagingSource
40 | }
41 | )
42 | }
43 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/whitelist/search/SearchViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.whitelist.search
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import dagger.hilt.android.lifecycle.HiltViewModel
7 | import javax.inject.Inject
8 |
9 | @HiltViewModel
10 | class SearchViewModel @Inject constructor(): ViewModel() {
11 | private val _query = MutableLiveData("")
12 | val query: LiveData = _query
13 |
14 | fun changeQuery(query: String) {
15 | _query.postValue(query)
16 | }
17 |
18 | fun getQuery(): String {
19 | return _query.value ?: ""
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/whitelist/system/ShowSystemButton.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.whitelist.system
2 |
3 | import androidx.compose.foundation.layout.Row
4 | import androidx.compose.foundation.layout.Spacer
5 | import androidx.compose.foundation.layout.width
6 | import androidx.compose.material3.Checkbox
7 | import androidx.compose.material3.Text
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.runtime.livedata.observeAsState
10 | import androidx.compose.ui.Alignment
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.res.stringResource
13 | import androidx.compose.ui.unit.dp
14 | import com.android.skip.R
15 |
16 | @Composable
17 | fun ShowSystemButton(showSystemViewModel: ShowSystemViewModel) {
18 | val isShowSystem = showSystemViewModel.isShowSystem.observeAsState()
19 | Row(verticalAlignment = Alignment.CenterVertically) {
20 | Checkbox(
21 | checked = isShowSystem.value == true,
22 | onCheckedChange = {
23 | showSystemViewModel.changeIsShowSystem(it)
24 | }
25 | )
26 | Text(stringResource(id = R.string.whitelist_show_system))
27 | Spacer(modifier = Modifier.width(10.dp))
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/ui/whitelist/system/ShowSystemViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.ui.whitelist.system
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import dagger.hilt.android.lifecycle.HiltViewModel
7 | import javax.inject.Inject
8 |
9 | @HiltViewModel
10 | class ShowSystemViewModel @Inject constructor():ViewModel() {
11 | private val _isShowSystem = MutableLiveData(false)
12 | val isShowSystem: LiveData = _isShowSystem
13 |
14 | fun changeIsShowSystem(isShow: Boolean) {
15 | _isShowSystem.postValue(isShow)
16 | }
17 |
18 | fun getIsShowSystem(): Boolean {
19 | return _isShowSystem.value ?: false
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/util/DebounceHelper.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.util
2 |
3 | class DebounceHelper(private val delayMillis: Long) {
4 | private var lastTime: Long = 0
5 |
6 | fun run(action: () -> Unit) {
7 | val currentTime = System.currentTimeMillis()
8 | if (currentTime - lastTime >= delayMillis) {
9 | action()
10 | lastTime = currentTime
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/util/MyToast.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.util
2 |
3 | import android.os.Handler
4 | import android.os.Looper
5 | import android.widget.Toast
6 | import com.android.skip.MyApp
7 |
8 | object MyToast {
9 | fun show(content: Int) {
10 | Handler(Looper.getMainLooper()).post{
11 | Toast.makeText(MyApp.context, MyApp.context.getString(content), Toast.LENGTH_SHORT).show()
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/skip/util/NetworkUtils.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip.util
2 |
3 | import android.content.Context
4 | import android.net.ConnectivityManager
5 | import android.net.NetworkCapabilities
6 | import android.os.Build
7 |
8 |
9 | object NetworkUtil {
10 | fun isNetworkConnected(context: Context): Boolean {
11 | val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
12 | val network = cm.activeNetwork ?: return false
13 | val capabilities = cm.getNetworkCapabilities(network) ?: return false
14 | return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
15 | }
16 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/all_inclusive.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/app_registration.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/arrow_back.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/backend_lock.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/app/src/main/res/drawable/backend_lock.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/block.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/check_circle.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/counter_1.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/counter_2.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/counter_3.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/counter_4.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/error.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/favicon32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/app/src/main/res/drawable/favicon32.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/fit_screen.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/float_landscape_2.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/help.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/hide_image.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/info.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/lists.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/notifications.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/photo_camera.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/point_scan.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/settings.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sync.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/target.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/theme_auto.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/theme_dark.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/theme_light.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tune.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/warning.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/floating_window.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #FFBB86FC
5 | #FF3700B3
6 | #FFFFFF
7 |
8 | #FFBB86FC
9 | #FF3700B3
10 | #FFFFFF
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/accessibility.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/file_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/test/java/com/android/skip/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.android.skip
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.android.application) apply false
4 | alias(libs.plugins.jetbrains.kotlin.android) apply false
5 | alias(libs.plugins.compose.compiler) apply false
6 | id("com.google.dagger.hilt.android") version "2.51.1" apply false
7 | }
--------------------------------------------------------------------------------
/capture/0f84d874-ada4-4b90-9829-a99f43950071.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/0f84d874-ada4-4b90-9829-a99f43950071.zip
--------------------------------------------------------------------------------
/capture/20f3db03-af60-4dc3-885a-b954b985931f.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/20f3db03-af60-4dc3-885a-b954b985931f.zip
--------------------------------------------------------------------------------
/capture/28b730a3-5ac7-44c7-8f8a-9daf1b8effbe.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/28b730a3-5ac7-44c7-8f8a-9daf1b8effbe.zip
--------------------------------------------------------------------------------
/capture/2adae253-623d-4fd3-ad75-b5b32b667dcd.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/2adae253-623d-4fd3-ad75-b5b32b667dcd.zip
--------------------------------------------------------------------------------
/capture/368caf09-c152-4f6b-b8dd-3ee4718df65d.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/368caf09-c152-4f6b-b8dd-3ee4718df65d.zip
--------------------------------------------------------------------------------
/capture/3737625b-383a-4891-aada-493e811f048a.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/3737625b-383a-4891-aada-493e811f048a.zip
--------------------------------------------------------------------------------
/capture/43bcef4b-4b5b-4b63-a7f2-ad28e4f5f690.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/43bcef4b-4b5b-4b63-a7f2-ad28e4f5f690.zip
--------------------------------------------------------------------------------
/capture/450b0add-b8e2-4cac-9b49-015744bb786f.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/450b0add-b8e2-4cac-9b49-015744bb786f.zip
--------------------------------------------------------------------------------
/capture/5656e116-5a93-44da-8687-1a1dec170984.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/5656e116-5a93-44da-8687-1a1dec170984.zip
--------------------------------------------------------------------------------
/capture/57861a13-956b-4ae1-be60-d77c33b82010.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/57861a13-956b-4ae1-be60-d77c33b82010.zip
--------------------------------------------------------------------------------
/capture/7aa2544b-8a80-41f3-bf0c-ee03c7cf83b2.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/7aa2544b-8a80-41f3-bf0c-ee03c7cf83b2.zip
--------------------------------------------------------------------------------
/capture/7ba85f98-5b07-4947-95e0-dca6431b1fc6.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/7ba85f98-5b07-4947-95e0-dca6431b1fc6.zip
--------------------------------------------------------------------------------
/capture/7d45a0ad-f0ce-4856-b38b-dd545bfadeb5.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/7d45a0ad-f0ce-4856-b38b-dd545bfadeb5.zip
--------------------------------------------------------------------------------
/capture/812b304e-63fd-42da-b200-7497a2e635c4.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/812b304e-63fd-42da-b200-7497a2e635c4.zip
--------------------------------------------------------------------------------
/capture/84603cb6-3647-42aa-a0f9-e013a3c1e74c.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/84603cb6-3647-42aa-a0f9-e013a3c1e74c.zip
--------------------------------------------------------------------------------
/capture/88ad5f6b-e65b-4424-be8e-ab57e0eb613b.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/88ad5f6b-e65b-4424-be8e-ab57e0eb613b.zip
--------------------------------------------------------------------------------
/capture/92e729ea-dd19-4384-93af-ec7581f306cf.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/92e729ea-dd19-4384-93af-ec7581f306cf.zip
--------------------------------------------------------------------------------
/capture/94969846-73e3-41de-aca0-ad9994566fc6.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/94969846-73e3-41de-aca0-ad9994566fc6.zip
--------------------------------------------------------------------------------
/capture/a310356a-4841-40fd-8a4f-314e77318230.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/a310356a-4841-40fd-8a4f-314e77318230.zip
--------------------------------------------------------------------------------
/capture/ab69a19e-56e8-4983-9656-cdbab1b09682.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/ab69a19e-56e8-4983-9656-cdbab1b09682.zip
--------------------------------------------------------------------------------
/capture/b8592c72-1a8a-42ea-8022-2ba15bc83444.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/b8592c72-1a8a-42ea-8022-2ba15bc83444.zip
--------------------------------------------------------------------------------
/capture/bb3de897-19d4-4c6d-ac7a-e11130420b4a.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/bb3de897-19d4-4c6d-ac7a-e11130420b4a.zip
--------------------------------------------------------------------------------
/capture/c1c0b4c7-9bed-4f11-93e8-6fcd08bb4717.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/c1c0b4c7-9bed-4f11-93e8-6fcd08bb4717.zip
--------------------------------------------------------------------------------
/capture/cfe9660a-1d45-4904-a8a7-8d846faa1a49.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/cfe9660a-1d45-4904-a8a7-8d846faa1a49.zip
--------------------------------------------------------------------------------
/capture/dba416c1-f18d-45c4-8042-16e2c15bead5.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/dba416c1-f18d-45c4-8042-16e2c15bead5.zip
--------------------------------------------------------------------------------
/capture/e2c456c9-2db5-4ff9-9f79-f42acf557358.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/e2c456c9-2db5-4ff9-9f79-f42acf557358.zip
--------------------------------------------------------------------------------
/capture/e835b293-7845-4988-9423-fe7f9d740d43.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/e835b293-7845-4988-9423-fe7f9d740d43.zip
--------------------------------------------------------------------------------
/capture/ee283a25-cbbf-43b0-84dd-aaf9ccf24c83.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/ee283a25-cbbf-43b0-84dd-aaf9ccf24c83.zip
--------------------------------------------------------------------------------
/capture/f074f9ba-2fdd-4885-8b16-df8afdcbb46d.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/capture/f074f9ba-2fdd-4885-8b16-df8afdcbb46d.zip
--------------------------------------------------------------------------------
/dist/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/dist/.gitkeep
--------------------------------------------------------------------------------
/docs/.vitepress/index.css:
--------------------------------------------------------------------------------
1 | @import "tailwindcss/base";
2 | @import "tailwindcss/components";
3 | @import "tailwindcss/utilities";
4 |
5 | @layer utilities {
6 | .hide-scrollbar {
7 | /* 对于大多数现代浏览器 */
8 | scrollbar-width: none; /* Firefox */
9 | -ms-overflow-style: none; /* IE 10+ */
10 |
11 | /* 对于 Webkit 浏览器 */
12 | &::-webkit-scrollbar {
13 | display: none; /* Chrome, Safari, Opera */
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/custom.css:
--------------------------------------------------------------------------------
1 | p img {
2 | width: 300px;
3 | }
4 | :root {
5 | --vp-home-hero-name-color: transparent;
6 | --vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe 30%, #41d1ff);
7 | --vp-home-hero-image-filter: blur(56px);
8 | --vp-home-hero-image-background-image: linear-gradient(-45deg, #bd34fe 50%, #47caff 50%);
9 | }
10 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/index.js:
--------------------------------------------------------------------------------
1 | import DefaultTheme from 'vitepress/theme'
2 | import './custom.css'
3 | import 'element-plus/dist/index.css'
4 | import ElementPlus from "element-plus";
5 | import 'element-plus/theme-chalk/dark/css-vars.css'
6 | import '../index.css'
7 |
8 | export default {
9 | ...DefaultTheme,
10 | enhanceApp({ app }) {
11 | app.use(ElementPlus)
12 | }
13 | }
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | skip.guoxicheng.top
--------------------------------------------------------------------------------
/docs/advance/custom-config/data-structure.md:
--------------------------------------------------------------------------------
1 | # 可配置字段数据结构
2 |
3 | <<< @/../app/src/main/java/com/android/skip/dataclass/ConfigReadSchema.kt
4 |
--------------------------------------------------------------------------------
/docs/advance/custom-config/field-meaning.md:
--------------------------------------------------------------------------------
1 | # 可配置字段
2 |
3 | ## packageName `必填`
4 |
5 | ### skipTexts `可选`
6 |
7 | #### text `必填`
8 |
9 | 根据节点的`text`属性跳过指定的文本。
10 |
11 | #### length `可选`
12 |
13 | 判断节点的`text`属性的长度是否小于等于`length`的值。
14 |
15 | #### activityName `可选`
16 |
17 | 判断当前页面的`activityName`是否等于`activityName`的值。相等时才会执行。
18 |
19 | #### click `可选`
20 |
21 | 点击的坐标,格式为`x,y`。
22 |
23 | 默认情况下,会点击找到节点的中心点。可以通过`click`属性可额外指定点击的坐标,而不点击所找到节点的中心点。
24 |
25 | #### 参考
26 |
27 | ```yaml
28 | - packageName: com.android.skip
29 | skipTexts:
30 | - text: 布局检查
31 | length: 4
32 | activityName: com.android.skip.ui.inspect.InspectActivity
33 | click: 123,456
34 | ```
35 |
36 | ### skipIds `可选`
37 |
38 | #### id `必填`
39 |
40 | 根据节点的`viewIdResourceName`属性搜索指定的节点。
41 |
42 | #### activityName `可选`
43 |
44 | #### click `可选`
45 |
46 | #### 参考
47 |
48 | ```yaml
49 | - packageName: com.android.skip
50 | skipIds:
51 | - id: android:id/navigationBarBackground
52 | activityName: com.android.skip.ui.inspect.InspectActivity
53 | click: 123,456
54 | ```
55 |
56 | ### skipBounds `可选`
57 |
58 | #### bound `必填`
59 |
60 | 根据节点的`boundsInScreen`属性搜索指定的节点,即:`bound(left,top,right,bottom)`。
61 |
62 | #### activityName `可选`
63 |
64 | #### click `可选`
65 |
66 | #### 参考
67 |
68 | ```yaml
69 | - packageName: com.android.skip
70 | skipBounds:
71 | - bound: 53,639,1387,849
72 | activityName: com.android.skip.ui.inspect.InspectActivity
73 | click: 123,456
74 | ```
75 |
--------------------------------------------------------------------------------
/docs/advance/custom-config/full-reference.md:
--------------------------------------------------------------------------------
1 | # 完整的配置参考
2 |
3 | ## 默认配置文件
4 |
5 | ::: code-group
6 |
7 | <<< @/../app/src/main/assets/skip_config_v3.yaml [YAML 格式]
8 |
9 | <<< @/../app/src/main/assets/skip_config_v3.json [JSON 格式]
10 |
11 | :::
12 |
--------------------------------------------------------------------------------
/docs/advance/custom-config/intro.md:
--------------------------------------------------------------------------------
1 | # 自定义配置功能介绍
2 |
3 | 由于应用市场的软件繁多,各种手机的型号也不一样,因此没有一种配置能够适应所有的情况。
4 |
5 | 你可以根据自己的需求,通过布局检查获取屏幕的节点信息,再通过自定义配置功能,维护好自己的配置文件。
6 |
--------------------------------------------------------------------------------
/docs/advance/layout-inspect/intro.md:
--------------------------------------------------------------------------------
1 | # 布局检查功能介绍
2 |
3 | 布局检查功能可以用于探查屏幕的节点布局信息。
4 |
5 | 掌握屏幕的节点信息,有助于编写自定义配置文件。
6 |
7 |
8 |
--------------------------------------------------------------------------------
/docs/advance/layout-inspect/usage.md:
--------------------------------------------------------------------------------
1 | # 使用方法
2 |
3 | ::: tip
4 | 布局检查功能需要通知权限。
5 | :::
6 |
7 | ## 首先
8 |
9 | 开启「SKIP 无障碍服务」
10 |
11 | ## 然后
12 |
13 | 开启「是否启用布局检查」的开关
14 |
15 | ## 通过
16 |
17 | 按下一次「音量-」按键,可以执行一次布局检查。
18 |
19 | ## 最后
20 |
21 | 在布局检查记录页面中,可以查看或删除布局检查记录,或是分享到其他应用转存。
22 |
23 | 再在 Web 端通过 [布局检查工具](/inspect/index) 导入并查看详细的节点信息。
24 |
--------------------------------------------------------------------------------
/docs/guide/about/intro.md:
--------------------------------------------------------------------------------
1 | # 关于功能介绍
2 |
3 | ## 源代码
4 |
5 | 点击「源代码」功能按钮时,会跳转到 GitHub 仓库页面,方便查看源代码。
6 |
7 | 但某些情况下,如果网络缓慢,可能会出现无法访问的情况。
8 |
9 | ## 文档
10 |
11 | 点击「文档」功能按钮时,会跳转到「SKIP」文档页面,可以查看完整文档。
12 |
13 | ## 应用版本号
14 |
15 | 点击「应用版本号」功能按钮时,会主动检查应用的版本号:
16 |
17 | - 如果有新版本,会提示更新
18 | - 如果没有新版本,会显示当前版本号
19 |
20 | ## 配置版本号
21 |
22 | 点击「配置版本号」功能按钮时,会主动检查配置的版本号。
23 |
24 | 如果在自定义配置输入框中填写了:
25 |
26 | - 有效的 URL 地址,会从该地址获取配置文件,并显示版本号。如果反复点击配置版本号,会重新获取配置文件并显示最新的版本号
27 | - 有效的纯文本的配置内容,会显示对应的版本号,并且即使反复点击配置版本号也不会变化
28 | - 无效的配置内容,会显示「未检测到有效的配置」
29 |
30 | ### 配置版本号的算法
31 |
32 | 配置版本号的算法是通过计算 JSON 字符串格式配置文件的 MD5 值来实现的,因此,只要配置内容不变,配置版本号就不会变化。
33 |
34 | <<< @/../app/src/main/java/com/android/skip/data/config/ConfigReadRepository.kt#MD5
35 |
--------------------------------------------------------------------------------
/docs/guide/contributing/config-file.md:
--------------------------------------------------------------------------------
1 | # 配置文件
2 |
3 | 配置文件是一个 YAML 文件,用于根据不同的 App 应用不同的配置。
4 |
5 | 配置文件位置:[配置文件](https://github.com/GuoXiCheng/SKIP/blob/main/app/src/main/assets/skip_config_v2.yaml)
6 |
7 | ## 配置文件选项
8 |
9 | ### packageName(必填)
10 |
11 | 应用包名称。
12 |
13 | 在 SKIP 的应用白名单中,可以查看应用的包名。
14 |
15 | ### skipTexts (选填)
16 |
17 | 根据文本匹配,当节点的文本**包含**指定字符串时,执行点击动作。可以配置多组。
18 |
19 | 在手机屏幕上看到的文本是什么就可以填什么,但是实际节点 text = null 时,会失效。
20 |
21 | ```yaml
22 | - packageName: com.xxx.xxx
23 | skipTexts:
24 | - text: 跳过广告
25 | length: 4
26 | ```
27 |
28 | ### skipIds (选填)
29 |
30 | 根据 id 匹配,当节点的 id **等于**指定字符串时,执行点击动作。可以配置多组。
31 |
32 | id 需要使用 Android 布局分析工具查询,但实际节点 id = null 时,不可用。
33 |
34 | ```yaml
35 | - packageName: com.xxx.xxx
36 | skipIds:
37 | - id: com.xxx.xxx:id/view_count_down
38 | ```
39 |
40 | ### skipBounds(选填)
41 |
42 | 根据 bounds 匹配,当所设定的 bounds **包含**节点的 bounds 时,执行点击动作。可以配置多组。
43 |
44 | 一般可交互的节点都会具有 bounds,需要使用 Android 布局分析工具查询。
45 |
--------------------------------------------------------------------------------
/docs/guide/contributing/core-logic.md:
--------------------------------------------------------------------------------
1 | # 核心逻辑
2 |
3 | ## 实现原理
4 |
5 | 利用 Android 无障碍服务,获取当前窗口对象,遍历窗口节点,当节点符合指定条件时,执行点击的动作。
6 |
7 | ## 核心逻辑
8 |
9 | 主要分为以下几个步骤:
10 |
11 | ```mermaid
12 | graph
13 | A[根据text查找节点] --> B{是否存在}
14 | B -- 是 --> C[点击节点]
15 | B -- 否 --> D[根据id查找节点] --> E{是否存在}
16 | E -- 是 --> C
17 | E -- 否 --> F[根据bounds查找节点] --> G{是否存在}
18 | G -- 是 --> C
19 | G -- 否 --> H[结束]
20 |
21 | classDef default color:#fff;
22 | ```
23 |
--------------------------------------------------------------------------------
/docs/guide/contributing/layout-view.md:
--------------------------------------------------------------------------------
1 | # 布局查看
2 |
3 | 使用布局查看器可以探查屏幕节点的布局结构,例如使用[web-editor](https://github.com/alibaba/web-editor)或 Android Studio 的布局查看器。
4 |
5 | ## 应用布局参考图
6 |
7 | 当选中想要的目标节点时,会显示该节点的布局结构,参考如下:
8 |
9 | 
10 |
11 | ### 配置 skipTexts 和 skipIds
12 |
13 | text 呈现的值,可以对应到配置文件中的 text
14 |
15 | resourceId 呈现的值,可以对应到配置文件中的 id
16 |
17 | ### 配置 skipBounds
18 |
19 | skipBounds 的值是需要计算得到的,可能长得像这样
20 |
21 | ```yaml
22 | - packageName: com.xxx.xxx
23 | skipBounds:
24 | - bound: 1223,196,1384,308
25 | resolution: 1440,3024
26 | ```
27 |
28 | 其中的 1440,3024 是你当前手机屏幕的最大宽高。
29 |
30 | 其中的 1223,196,1384,308 分别表示一个节点在屏幕中的: left,top,right,bottom
31 |
32 | 参考上图中 rect 的信息: left=x,top=y,right=x+width,bottom=y+height
33 |
34 | 
35 |
--------------------------------------------------------------------------------
/docs/guide/intro/DownloadApp.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ downloadApkName }}
3 |
4 |
5 |
21 |
--------------------------------------------------------------------------------
/docs/guide/intro/download-app.md:
--------------------------------------------------------------------------------
1 | # 下载 APP
2 |
3 | | 下载方式 | 下载地址 |
4 | | -------- | -------------------------------------------------------------------- |
5 | | 直接下载 | |
6 | | Github | [点击跳转](https://github.com/GuoXiCheng/SKIP/releases) |
7 | | 夸克网盘 | [点击跳转](https://pan.quark.cn/s/8502a8ff74c3) |
8 | | 百度网盘 | [点击跳转](https://pan.baidu.com/s/1tDXPcEUSZj5qNkOEmToz0A?pwd=m9u9) |
9 |
10 |
13 |
--------------------------------------------------------------------------------
/docs/guide/intro/getting-started.md:
--------------------------------------------------------------------------------
1 | # 开始使用
2 |
3 | ## 步骤一: 点击“启动”按钮
4 |
5 | 
6 |
7 | ## 步骤二: 点击“已下载的应用”
8 |
9 | 
10 |
11 | ## 步骤三: 点击“SKIP”
12 |
13 | 
14 |
15 | ## 步骤四: 开启“无障碍服务”
16 |
17 | 
18 |
19 | ## 步骤五: 勾选“同意”并点击“确定”
20 |
21 | 
22 |
--------------------------------------------------------------------------------
/docs/guide/intro/what-is-skip.md:
--------------------------------------------------------------------------------
1 | # 基本介绍
2 |
3 | ## 什么是 SKIP
4 |
5 | SKIP 是一款免费开源的安卓应用,旨在利用安卓无障碍服务帮助用户快速点击 APP 开屏广告的跳过按钮,让你的使用体验更加流畅。
6 |
7 | ## 主界面预览
8 |
9 | 
10 |
11 |
12 |
--------------------------------------------------------------------------------
/docs/guide/keep-alive/intro.md:
--------------------------------------------------------------------------------
1 | # 应用保活功能介绍
2 |
3 | ## 为什么要应用保活
4 |
5 | 在移动端,应用保活是指应用在后台运行时,保持应用的一些功能或服务持续运行,以提升用户体验。例如,音乐播放器在后台播放音乐。
6 |
7 | 为了保证无障碍服务的正常运行,需要保证应用在后台运行时,服务不会被系统回收。因此,需要使用应用保活功能。
8 |
9 | ## 应用保活的方式
10 |
11 | - 允许应用自启动
12 | - 锁定应用
13 | - 使用前台服务常驻通知栏
14 |
--------------------------------------------------------------------------------
/docs/guide/settings/intro.md:
--------------------------------------------------------------------------------
1 | # 设置功能介绍
2 |
3 | ## 自动更新
4 |
5 | 开启「自动更新」后,应用会在后台每隔 12 小时左右检查:
6 |
7 | - 「应用版本号」是否有新版本,如果有,在「关于」页面会显示提示。
8 | - 「配置版本号」是否有新版本,如果有,会主动更新当前的配置文件。
9 |
10 | ## 后台任务隐藏
11 |
12 | 开启「后台任务隐藏」后,在后台任务窗口中,「SKIP」应用窗口会被隐藏。
13 |
14 | ## 是否允许提示
15 |
16 | 该功能需要开启「允许通知」。
17 |
18 | 开启「是否允许提示」后,当成功执行「点击」操作时,会显示提示「已为您跳过广告」。
19 |
20 | ## 是否使用严格模式
21 |
22 | 如果开启「严格模式」,「SKIP」会完全遵循配置文件中定义的规则,因此,如果配置文件中没有定义规则的应用,就不会执行「点击」操作。
23 |
24 | 如果关闭「严格模式」,「SKIP」会默认搜索界面中的「跳过」关键字,如果找到,就会执行「点击」操作。因此,即使没有在配置文件中定义规则的应用,也可以实现「跳过广告」的功能。但同时,也会存在误触发的情况出现。
25 |
26 | ## 自定义配置
27 |
28 | 点击「自定义配置」,可以输入自定义配置规则。
29 |
30 | 支持输入纯文本的 YAML 格式或 JSON 格式,或可以返回 JSON 或 YAML 文本的 URL 链接。
31 |
32 | 配置规则参考:[自定义配置](/advance/custom-config/intro)
33 |
34 | ## 切换主题
35 |
36 | 点击「切换主题」,可以选择「浅色主题」、「深色主题」、「跟随系统」。
37 |
--------------------------------------------------------------------------------
/docs/guide/usage/background-process-keep-alive.md:
--------------------------------------------------------------------------------
1 | # 后台进程保活
2 |
3 | ## 1. 应用后台锁定
4 |
5 | 进入「后台管理」,长按「SKIP」,锁定
6 |
7 | 
8 |
9 | ## 2. 忽略电池优化
10 |
11 | 进入「应用信息」,进入「省电策略」,选择「无限制」
12 |
13 | 
14 |
15 | ## 3. 允许自启动
16 |
17 | 进入「应用信息」,打开「自启动」
18 |
19 | 
20 |
--------------------------------------------------------------------------------
/docs/guide/usage/enable-accessibility-service.md:
--------------------------------------------------------------------------------
1 | # 启用无障碍服务
2 |
3 | ## 1. 点击屏幕中央按钮
4 |
5 | 
6 |
7 | ## 2. 点击「使用“SKIP”」
8 |
9 | 
10 |
--------------------------------------------------------------------------------
/docs/guide/white-list/intro.md:
--------------------------------------------------------------------------------
1 | # 应用白名单功能介绍
2 |
3 | 应用白名单功能会列出所有已经安装的应用,可以在右上角的菜单中选择是否「列出系统应用」。因为系统应用较多,所以默认是不列出的。
4 |
5 | 当把一个应用加入白名单时(开关打开状态),「SKIP」就不会对这个应用执行任何「点击」的动作(无论是否在配置中定义),因此,该功能可以用来防止「SKIP」对某些应用的干扰。
6 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: home
3 |
4 | hero:
5 | name: SKIP
6 | text: 基于安卓无障碍服务的自动跳过开屏广告 App
7 | image:
8 | src: /images/logo.png
9 | actions:
10 | - theme: brand
11 | text: Get Started
12 | link: /guide/intro/what-is-skip
13 | - theme: alt
14 | text: View on GitHub
15 | link: https://github.com/GuoXiCheng/SKIP
16 | ---
17 |
--------------------------------------------------------------------------------
/docs/inspect/NodeTree.vue:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/inspect/hook/useZip.ts:
--------------------------------------------------------------------------------
1 | import JSZip from "jszip";
2 | import { AccessibilityWindow } from "../types";
3 | import { ref } from "vue";
4 | import { FileTable } from "../../my-index-db/file-table";
5 | import { MyIndexDB } from "../../my-index-db";
6 |
7 | export function useZip(arrayBuffer: ArrayBuffer) {
8 | const pic = ref();
9 | const raw = ref();
10 | const added = ref(false);
11 |
12 | const extractZip = async () => {
13 | const zip = await JSZip.loadAsync(arrayBuffer);
14 |
15 | const jpegFile = zip.filter((relativePath, file) => relativePath.endsWith(".jpeg"));
16 | const blobPromise = jpegFile[0].async("blob");
17 |
18 | const jsonFile = zip.filter((relativePath, file) => relativePath.endsWith(".json"));
19 | const jsonPromise = jsonFile[0].async("text");
20 |
21 | const [blobFile, jsonText] = await Promise.all([blobPromise, jsonPromise]);
22 | const jsonObj = JSON.parse(jsonText) as AccessibilityWindow;
23 |
24 | raw.value = jsonObj;
25 | pic.value = blobFile;
26 |
27 | const { fileId, appName, packageName, deviceName, createTime } = jsonObj;
28 | const targetFileTable = await FileTable.findFileTableByFileId(fileId);
29 | if (targetFileTable == null) {
30 | MyIndexDB.addFileData({
31 | fileId,
32 | pic: blobFile,
33 | raw: jsonObj,
34 | createTime,
35 | appName,
36 | packageName,
37 | deviceName,
38 | });
39 | added.value = true;
40 | }
41 | };
42 |
43 | return { pic, raw, added, extractZip };
44 | }
45 |
--------------------------------------------------------------------------------
/docs/inspect/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: false
3 | ---
4 |
5 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/inspect/types.ts:
--------------------------------------------------------------------------------
1 | export interface Tree {
2 | label: string;
3 | children?: Tree[];
4 | }
5 |
6 | export interface AccessibilityWindow {
7 | fileId: string;
8 | appName: string;
9 | activityName: string;
10 | packageName: string;
11 | screenHeight: number;
12 | screenWidth: number;
13 | createTime: number;
14 | deviceName: string;
15 | nodes: AccessibilityNode[];
16 | }
17 |
18 | export interface AccessibilityNode {
19 | childCount: number;
20 | className: string;
21 | depth: number;
22 | nodeId: number;
23 | parentId: number;
24 | left: number;
25 | top: number;
26 | right: number;
27 | bottom: number;
28 | isClickable: boolean;
29 | text?: string;
30 | viewIdResourceName?: string;
31 | [key: string]: any;
32 | }
33 |
34 | export interface AccessibilityNodeTree {
35 | label: string;
36 | children: AccessibilityNodeTree[];
37 | text?: string;
38 | className?: string;
39 | viewIdResourceName?: string;
40 | childCount: number;
41 | }
42 |
43 | export interface FileTableData {
44 | fileId: string;
45 | createTime: number;
46 | appName: string;
47 | packageName: string;
48 | deviceName: string;
49 | }
50 |
51 | export interface FileItemData {
52 | fileId: string;
53 | pic: Blob;
54 | raw: AccessibilityWindow;
55 | }
56 |
57 | export type FileData = FileTableData & FileItemData;
58 |
--------------------------------------------------------------------------------
/docs/my-index-db/file-item.ts:
--------------------------------------------------------------------------------
1 | import { MyIndexDB } from ".";
2 |
3 | export const FILE_ITEM_NAME = "FileItem";
4 |
5 | export class FileItem {
6 | static async findFileItemByFileId(fileId: string) {
7 | const db = await MyIndexDB.getMyIndexDB();
8 | return db.get(FILE_ITEM_NAME, fileId);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/docs/my-index-db/file-table.ts:
--------------------------------------------------------------------------------
1 | import { MyIndexDB } from ".";
2 |
3 | export const FILE_TABLE_NAME = "FileTable";
4 |
5 | export class FileTable {
6 | static async findFileTableByFileId(fileId: string) {
7 | const db = await MyIndexDB.getMyIndexDB();
8 | return db.get(FILE_TABLE_NAME, fileId);
9 | }
10 |
11 | static async findAllFileTable() {
12 | const db = await MyIndexDB.getMyIndexDB();
13 | return db.getAll(FILE_TABLE_NAME);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/docs/public/5f686585-c5d0-4057-93b2-c54832ffb393.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/5f686585-c5d0-4057-93b2-c54832ffb393.zip
--------------------------------------------------------------------------------
/docs/public/android-rect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/android-rect.png
--------------------------------------------------------------------------------
/docs/public/click-button-on-the-screen-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/click-button-on-the-screen-dark.png
--------------------------------------------------------------------------------
/docs/public/click-button-on-the-screen-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/click-button-on-the-screen-light.png
--------------------------------------------------------------------------------
/docs/public/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/images/favicon.ico
--------------------------------------------------------------------------------
/docs/public/images/getting-started-step-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/images/getting-started-step-1.png
--------------------------------------------------------------------------------
/docs/public/images/getting-started-step-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/images/getting-started-step-2.png
--------------------------------------------------------------------------------
/docs/public/images/getting-started-step-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/images/getting-started-step-3.png
--------------------------------------------------------------------------------
/docs/public/images/getting-started-step-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/images/getting-started-step-4.png
--------------------------------------------------------------------------------
/docs/public/images/getting-started-step-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/images/getting-started-step-5.png
--------------------------------------------------------------------------------
/docs/public/images/images.7z:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/images/images.7z
--------------------------------------------------------------------------------
/docs/public/images/inspect-intro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/images/inspect-intro.png
--------------------------------------------------------------------------------
/docs/public/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/images/logo.png
--------------------------------------------------------------------------------
/docs/public/images/main-interface-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/images/main-interface-light.png
--------------------------------------------------------------------------------
/docs/public/js/baidu-analytics.js:
--------------------------------------------------------------------------------
1 | var _hmt = _hmt || [];
2 | (function () {
3 | var hm = document.createElement("script");
4 | hm.src = "https://hm.baidu.com/hm.js?d3d747ec2508d20c876d4d06e9dbd248";
5 | var s = document.getElementsByTagName("script")[0];
6 | s.parentNode.insertBefore(hm, s);
7 | })();
8 |
9 |
--------------------------------------------------------------------------------
/docs/public/layout-reference.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/layout-reference.png
--------------------------------------------------------------------------------
/docs/public/main-interface-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/main-interface-dark.png
--------------------------------------------------------------------------------
/docs/public/main-interface-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/main-interface-light.png
--------------------------------------------------------------------------------
/docs/public/skip-bottom-screenshot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/skip-bottom-screenshot.jpg
--------------------------------------------------------------------------------
/docs/public/skip-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/skip-icon.png
--------------------------------------------------------------------------------
/docs/public/use-accessibility-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/use-accessibility-dark.png
--------------------------------------------------------------------------------
/docs/public/use-accessibility-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/use-accessibility-light.png
--------------------------------------------------------------------------------
/docs/public/xiaomi-app-backend-lock-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/xiaomi-app-backend-lock-dark.png
--------------------------------------------------------------------------------
/docs/public/xiaomi-app-backend-lock-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/xiaomi-app-backend-lock-light.png
--------------------------------------------------------------------------------
/docs/public/xiaomi-enable-self-start-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/xiaomi-enable-self-start-dark.png
--------------------------------------------------------------------------------
/docs/public/xiaomi-enable-self-start-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/xiaomi-enable-self-start-light.png
--------------------------------------------------------------------------------
/docs/public/xiaomi-enable-self-start.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/xiaomi-enable-self-start.jpg
--------------------------------------------------------------------------------
/docs/public/xiaomi-ignoring-battery-optimization-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/xiaomi-ignoring-battery-optimization-dark.png
--------------------------------------------------------------------------------
/docs/public/xiaomi-ignoring-battery-optimization-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/docs/public/xiaomi-ignoring-battery-optimization-light.png
--------------------------------------------------------------------------------
/docs/visual/Header.vue:
--------------------------------------------------------------------------------
1 |
2 | 配置版本号: {{ configVersion }}
3 |
4 |
5 |
19 |
--------------------------------------------------------------------------------
/docs/visual/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
30 |
--------------------------------------------------------------------------------
/docs/visual/LeftForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
25 |
--------------------------------------------------------------------------------
/docs/visual/RightCode.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
23 |
--------------------------------------------------------------------------------
/docs/visual/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: false
3 | ---
4 |
5 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/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
24 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Aug 29 10:36:05 CST 2024
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.7-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gui/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/.DS_Store
--------------------------------------------------------------------------------
/gui/backend_lock.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/backend_lock.jpg
--------------------------------------------------------------------------------
/gui/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/background.png
--------------------------------------------------------------------------------
/gui/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/favicon-16x16.png
--------------------------------------------------------------------------------
/gui/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/favicon-32x32.png
--------------------------------------------------------------------------------
/gui/main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/main.png
--------------------------------------------------------------------------------
/gui/start_icon/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/.DS_Store
--------------------------------------------------------------------------------
/gui/start_icon/android/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/android/ic_launcher.png
--------------------------------------------------------------------------------
/gui/start_icon/android/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/android/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/gui/start_icon/android/mipmap-ldpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/android/mipmap-ldpi/ic_launcher.png
--------------------------------------------------------------------------------
/gui/start_icon/android/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/android/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/gui/start_icon/android/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/android/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/gui/start_icon/android/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/android/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/gui/start_icon/android/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/android/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/gui/start_icon/ios/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/ios/.DS_Store
--------------------------------------------------------------------------------
/gui/start_icon/ios/AppIcon.appiconset/icon-1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/ios/AppIcon.appiconset/icon-1024.png
--------------------------------------------------------------------------------
/gui/start_icon/ios/AppIcon.appiconset/icon-20-ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/ios/AppIcon.appiconset/icon-20-ipad.png
--------------------------------------------------------------------------------
/gui/start_icon/ios/AppIcon.appiconset/icon-20@2x-ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/ios/AppIcon.appiconset/icon-20@2x-ipad.png
--------------------------------------------------------------------------------
/gui/start_icon/ios/AppIcon.appiconset/icon-20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/ios/AppIcon.appiconset/icon-20@2x.png
--------------------------------------------------------------------------------
/gui/start_icon/ios/AppIcon.appiconset/icon-20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/ios/AppIcon.appiconset/icon-20@3x.png
--------------------------------------------------------------------------------
/gui/start_icon/ios/AppIcon.appiconset/icon-29-ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/ios/AppIcon.appiconset/icon-29-ipad.png
--------------------------------------------------------------------------------
/gui/start_icon/ios/AppIcon.appiconset/icon-29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/ios/AppIcon.appiconset/icon-29.png
--------------------------------------------------------------------------------
/gui/start_icon/ios/AppIcon.appiconset/icon-29@2x-ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/ios/AppIcon.appiconset/icon-29@2x-ipad.png
--------------------------------------------------------------------------------
/gui/start_icon/ios/AppIcon.appiconset/icon-29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/ios/AppIcon.appiconset/icon-29@2x.png
--------------------------------------------------------------------------------
/gui/start_icon/ios/AppIcon.appiconset/icon-29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/ios/AppIcon.appiconset/icon-29@3x.png
--------------------------------------------------------------------------------
/gui/start_icon/ios/AppIcon.appiconset/icon-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/ios/AppIcon.appiconset/icon-40.png
--------------------------------------------------------------------------------
/gui/start_icon/ios/AppIcon.appiconset/icon-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/ios/AppIcon.appiconset/icon-40@2x.png
--------------------------------------------------------------------------------
/gui/start_icon/ios/AppIcon.appiconset/icon-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/ios/AppIcon.appiconset/icon-40@3x.png
--------------------------------------------------------------------------------
/gui/start_icon/ios/AppIcon.appiconset/icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/ios/AppIcon.appiconset/icon-60@2x.png
--------------------------------------------------------------------------------
/gui/start_icon/ios/AppIcon.appiconset/icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/ios/AppIcon.appiconset/icon-60@3x.png
--------------------------------------------------------------------------------
/gui/start_icon/ios/AppIcon.appiconset/icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/ios/AppIcon.appiconset/icon-76.png
--------------------------------------------------------------------------------
/gui/start_icon/ios/AppIcon.appiconset/icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/ios/AppIcon.appiconset/icon-76@2x.png
--------------------------------------------------------------------------------
/gui/start_icon/ios/AppIcon.appiconset/icon-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/gui/start_icon/ios/AppIcon.appiconset/icon-83.5@2x.png
--------------------------------------------------------------------------------
/gui/svg/all_inclusive_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/app_registration_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/arrow_back_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/block_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/brightness_4_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/brightness_5_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/brightness_6_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/check_circle_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/cloud_download_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/counter_1_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/counter_2_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/counter_3_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/counter_4_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/error_24dp_000000_FILL0_wght0_GRAD0_opszNaN.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/fit_screen_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/float_landscape_2_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/help_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/hide_image_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/info_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/list_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/lists_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/notifications_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/photo_camera_64dp_000000_FILL1_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/point_scan_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/screenshot_keyboard_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/settings_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/sync_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/target_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/tune_24dp_000000_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/svg/warning_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/jest.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | testTimeout: 30000, // 设置测试超时时间
3 | preset: "ts-jest",
4 | testEnvironment: "node",
5 | collectCoverage: true, // 开启测试覆盖率
6 | coverageDirectory: "coverage", // 指定覆盖率报告输出目录
7 | collectCoverageFrom: [
8 | // 指定需要收集覆盖率的文件
9 | "scripts/**/*.ts", // 包括 src 目录下所有的 TypeScript 文件
10 | "!scripts/**/*.d.ts", // 排除 TypeScript 声明文件
11 | "!scripts/__tests__/**/*.ts",
12 | ],
13 | testMatch: ["/scripts/__tests__/*.test.ts"], // 指定测试文件的匹配规则
14 | testPathIgnorePatterns: [], // 指定需要忽略的测试文件
15 | };
16 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "skip",
3 | "version": "1.0.0",
4 | "description": "  ",
5 | "main": "index.js",
6 | "scripts": {
7 | "docs:dev": "vitepress dev docs",
8 | "docs:build": "vitepress build docs",
9 | "docs:preview": "vitepress preview docs",
10 | "release-file": "ts-node scripts/index.ts --func=release-file --apkPath=apk --releasePath=docs/.vitepress/dist",
11 | "yaml-check": "ts-node ./scripts/yaml-check.ts",
12 | "test": "jest --coverage"
13 | },
14 | "author": "",
15 | "license": "ISC",
16 | "devDependencies": {
17 | "@codemirror/lang-yaml": "^6.1.2",
18 | "@codemirror/theme-one-dark": "^6.1.2",
19 | "@types/crypto-js": "^4.2.2",
20 | "@types/jest": "^29.5.14",
21 | "@types/js-yaml": "^4.0.9",
22 | "autoprefixer": "^10.4.20",
23 | "codemirror": "^6.0.1",
24 | "crypto-js": "^4.2.0",
25 | "element-plus": "^2.9.2",
26 | "idb": "^8.0.1",
27 | "jest": "^29.7.0",
28 | "js-yaml": "^4.1.0",
29 | "jszip": "^3.10.1",
30 | "postcss": "^8.4.49",
31 | "tailwindcss": "^3.4.17",
32 | "ts-jest": "^29.2.5",
33 | "ts-node": "^10.9.2",
34 | "vitepress": "^1.5.0",
35 | "vitepress-plugin-mermaid": "^2.0.17",
36 | "vue-codemirror6": "^1.3.8",
37 | "zod": "^3.24.1"
38 | },
39 | "dependencies": {
40 | "skip": "file:"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/scripts/__tests__/examples/apk-has-version/SKIP-v2.1.1.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/scripts/__tests__/examples/apk-has-version/SKIP-v2.1.1.apk
--------------------------------------------------------------------------------
/scripts/__tests__/examples/apk-multiple/SKIP-v2.0.0.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/scripts/__tests__/examples/apk-multiple/SKIP-v2.0.0.apk
--------------------------------------------------------------------------------
/scripts/__tests__/examples/apk-multiple/SKIP-v2.0.1.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/scripts/__tests__/examples/apk-multiple/SKIP-v2.0.1.apk
--------------------------------------------------------------------------------
/scripts/__tests__/examples/apk-no-version/SKIP.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/scripts/__tests__/examples/apk-no-version/SKIP.apk
--------------------------------------------------------------------------------
/scripts/__tests__/examples/apk-not-apk/SKIP-v2.0.0.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GuoXiCheng/SKIP/3f4dc18e8d53939c3ed7ade1541361916228c84e/scripts/__tests__/examples/apk-not-apk/SKIP-v2.0.0.txt
--------------------------------------------------------------------------------
/scripts/__tests__/examples/correct-yaml.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipTexts:
3 | - text: 跳过
4 | length: 2
5 | skipIds:
6 | - id: com.test.skip:id/skip
7 | skipBounds:
8 | - bound: 123,456,789,1011
9 | resolution: 1080,1920
10 |
--------------------------------------------------------------------------------
/scripts/__tests__/examples/missing-packageName.yaml:
--------------------------------------------------------------------------------
1 | - package: com.test.skip
2 | skipTexts:
3 | - text: 跳过
4 | length: 2
5 | skipIds:
6 | - id: com.test.skip:id/skip
7 | skipBounds:
8 | - bound: 123,456,789,1011
9 | resolution: 1080,1920
--------------------------------------------------------------------------------
/scripts/__tests__/examples/only-packageName.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
--------------------------------------------------------------------------------
/scripts/__tests__/examples/packageName-empty.yaml:
--------------------------------------------------------------------------------
1 | - packageName: " "
2 | skipTexts:
3 | - text: 跳过
4 | length: 2
5 | skipIds:
6 | - id: com.test.skip:id/skip
7 | skipBounds:
8 | - bound: 123,456,789,1011
9 | resolution: 1080,1920
--------------------------------------------------------------------------------
/scripts/__tests__/examples/packageName-leading-space.yaml:
--------------------------------------------------------------------------------
1 | - packageName: " com.test.skip"
2 | skipTexts:
3 | - text: 跳过
4 | length: 2
5 | skipIds:
6 | - id: com.test.skip:id/skip
7 | skipBounds:
8 | - bound: 123,456,789,1011
9 | resolution: 1080,1920
--------------------------------------------------------------------------------
/scripts/__tests__/examples/packageName-not-string.yaml:
--------------------------------------------------------------------------------
1 | - packageName: 123456
2 | skipTexts:
3 | - text: 跳过
4 | length: 2
5 | skipIds:
6 | - id: com.test.skip:id/skip
7 | skipBounds:
8 | - bound: 123,456,789,1011
9 | resolution: 1080,1920
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipBounds-bound-empty.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipBounds:
3 | - resolution: 1920,1080
4 | bound: " "
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipBounds-bound-not-4-parts.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipBounds:
3 | - resolution: 1920,1080
4 | bound: 123,456,789,1011
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipBounds-bound-not-number.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipBounds:
3 | - resolution: 1920,1080
4 | bound: "a,b,c,d"
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipBounds-bound-not-string.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipBounds:
3 | - resolution: 1920,1080
4 | bound: 1234
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipBounds-missing-bound.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipBounds:
3 | - resolution: 1920,1080
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipBounds-missing-resolution.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipBounds:
3 | - bound: 123,456,789,1011
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipBounds-not-array.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipBounds: "123"
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipBounds-resolution-empty.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipBounds:
3 | - resolution: " "
4 | bound: 123,456,789,321
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipBounds-resolution-not-2-parts.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipBounds:
3 | - resolution: 1920,1080
4 | bound: 123,456,789,321
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipBounds-resolution-not-number.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipBounds:
3 | - resolution: a,b
4 | bound: 123,456,789,321
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipBounds-resolution-not-string.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipBounds:
3 | - resolution: 1920
4 | bound: 123,456,789,321
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipIds-id-empty.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipIds:
3 | - id: " "
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipIds-id-leading-space.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipIds:
3 | - id: " com.test.skip:id/skip"
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipIds-id-not-string.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipIds:
3 | - id: 123
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipIds-missing-id.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipIds:
3 | - ids: com.test.skip:id/skip
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipIds-not-array.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipIds: com.test.skip:id/skip
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipTexts-length-negative.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipTexts:
3 | - length: -1
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipTexts-length-not-number.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipTexts:
3 | - length: "123"
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipTexts-not-array.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipTexts: 跳过
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipTexts-text-empty.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipTexts:
3 | - text: " "
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipTexts-text-leading-space.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipTexts:
3 | - text: " 跳过"
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipTexts-text-not-string.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipTexts:
3 | - text: 123
--------------------------------------------------------------------------------
/scripts/__tests__/examples/skipTexts-unknown-keys.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipTexts:
3 | - unknownKey: "123"
--------------------------------------------------------------------------------
/scripts/__tests__/examples/unknown-keys.yaml:
--------------------------------------------------------------------------------
1 | - packageName: com.test.skip
2 | skipTexts:
3 | - text: 跳过
4 | length: 2
5 | skipIds:
6 | - id: com.test.skip:id/skip
7 | skipBounds:
8 | - bound: 123,456,789,1011
9 | resolution: 1080,1920
10 | unknownKey: unknownValue
--------------------------------------------------------------------------------
/scripts/index.ts:
--------------------------------------------------------------------------------
1 | (() => {
2 | const args = process.argv.slice(2);
3 | const params: Record = {};
4 | args.forEach((arg) => {
5 | const [key, value] = arg.split("=");
6 | params[key.substring(2)] = value;
7 | });
8 |
9 | if (params.func === "release-file") {
10 | const { releaseFile } = require("./release-file");
11 | releaseFile(params);
12 | }
13 | })();
14 |
--------------------------------------------------------------------------------
/scripts/release-file.ts:
--------------------------------------------------------------------------------
1 | import fs from "node:fs";
2 |
3 | interface ReleaseFileOptions {
4 | apkPath: string;
5 | releasePath: string;
6 | }
7 |
8 | export function releaseFile(options: ReleaseFileOptions) {
9 | const { apkPath, releasePath } = options;
10 | if (!fs.existsSync(apkPath) || !fs.existsSync(releasePath)) {
11 | throw new Error("apk path and release path should exist");
12 | }
13 |
14 | const apkFileList = fs.readdirSync(apkPath);
15 |
16 | if (apkFileList.length !== 1) {
17 | throw new Error("apk path should contain only one file");
18 | }
19 |
20 | const apkFile = apkFileList[0];
21 | if (!apkFile.endsWith(".apk")) {
22 | throw new Error("apk file should end with .apk");
23 | }
24 |
25 | const regex = /SKIP-v(\d+\.\d+\.\d+)\.apk/;
26 | const match = apkFile.match(regex);
27 | if (!match) {
28 | throw new Error("apk file should contain version number");
29 | }
30 |
31 | const apkVersion = match[1];
32 |
33 | // 写入 apkVersion 到 releasePath
34 | fs.writeFileSync(`${releasePath}/latest_version.txt`, apkVersion);
35 | // 复制 apkFile 到 releasePath
36 | fs.copyFileSync(`${apkPath}/${apkFile}`, `${releasePath}/${apkFile}`);
37 | // 复制 config
38 | fs.copyFileSync("app/src/main/assets/skip_config.yaml", `${releasePath}/skip_config.yaml`);
39 | fs.copyFileSync("app/src/main/assets/skip_config_v2.yaml", `${releasePath}/skip_config_v2.yaml`);
40 | fs.copyFileSync("app/src/main/assets/skip_config_v3.yaml", `${releasePath}/skip_config_v3.yaml`);
41 | }
42 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | maven { setUrl("https://maven.aliyun.com/repository/central") }
4 | maven { setUrl("https://maven.aliyun.com/repository/jcenter") }
5 | maven { setUrl("https://maven.aliyun.com/repository/google") }
6 | maven { setUrl("https://maven.aliyun.com/repository/gradle-plugin") }
7 | maven { setUrl("https://maven.aliyun.com/repository/public") }
8 | maven { setUrl("https://jitpack.io") }
9 |
10 | google()
11 | mavenCentral()
12 | gradlePluginPortal()
13 | }
14 | }
15 |
16 | dependencyResolutionManagement {
17 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
18 | repositories {
19 | maven { setUrl("https://maven.aliyun.com/repository/central") }
20 | maven { setUrl("https://maven.aliyun.com/repository/jcenter") }
21 | maven { setUrl("https://maven.aliyun.com/repository/google") }
22 | maven { setUrl("https://maven.aliyun.com/repository/gradle-plugin") }
23 | maven { setUrl("https://maven.aliyun.com/repository/public") }
24 | maven { setUrl("https://jitpack.io") }
25 |
26 | google()
27 | mavenCentral()
28 | }
29 | }
30 |
31 | rootProject.name = "SKIP"
32 | include(":app")
33 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | './docs/.vitepress/**/*.{js,ts,vue}',
5 | './docs/**/*.{js,ts,vue,md}',
6 | ],
7 | theme: {
8 | extend: {},
9 | },
10 | plugins: [],
11 | }
12 |
13 |
--------------------------------------------------------------------------------