├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ ├── error_report.yml │ └── feature_request.yml └── workflows │ ├── build_pre_release_apk.yml │ └── build_release_apk.yml ├── .gitignore ├── .idea ├── .gitignore ├── AndroidProjectSystem.xml ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── compiler.xml ├── deploymentTargetDropDown.xml ├── deploymentTargetSelector.xml ├── dictionaries │ └── Hamza.xml ├── gradle.xml ├── icon.svg ├── inspectionProfiles │ └── Project_Default.xml ├── kotlinc.xml ├── migrations.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── .imgbotconfig ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── schemas │ ├── app.simple.peri.database.instances.EffectsDatabase │ │ ├── 1.json │ │ └── 2.json │ ├── app.simple.peri.database.instances.LastHomeWallpapersDatabase │ │ └── 9.json │ ├── app.simple.peri.database.instances.LastLockWallpapersDatabase │ │ └── 9.json │ ├── app.simple.peri.database.instances.LastWallpapersDatabase │ │ └── 9.json │ ├── app.simple.peri.database.instances.TagsDatabase │ │ ├── 1.json │ │ ├── 2.json │ │ └── 3.json │ └── app.simple.peri.database.instances.WallpaperDatabase │ │ ├── 4.json │ │ ├── 5.json │ │ ├── 6.json │ │ ├── 7.json │ │ ├── 8.json │ │ └── 9.json └── src │ ├── androidTest │ └── java │ │ └── app │ │ └── simple │ │ └── peri │ │ └── ExampleInstrumentedTest.kt │ ├── dev │ └── res │ │ └── values │ │ └── strings.xml │ ├── main │ ├── AndroidManifest.xml │ ├── ic_launcher-playstore.png │ ├── ic_next-playstore.png │ ├── java │ │ └── app │ │ │ └── simple │ │ │ └── peri │ │ │ ├── abstraction │ │ │ ├── AbstractAutoLiveWallpaperService.kt │ │ │ ├── AbstractAutoWallpaperService.kt │ │ │ ├── AbstractComposeAutoWallpaperService.kt │ │ │ └── AutoWallpaperUtils.kt │ │ │ ├── activities │ │ │ ├── association │ │ │ │ └── WallpaperAssociationActivity.kt │ │ │ └── main │ │ │ │ ├── ComposePreferencesActivity.kt │ │ │ │ ├── EffectsActivity.kt │ │ │ │ ├── MainComposeActivity.kt │ │ │ │ └── PathChooserActivity.kt │ │ │ ├── application │ │ │ └── PeriApplication.java │ │ │ ├── constants │ │ │ └── Misc.kt │ │ │ ├── crash │ │ │ ├── CrashReport.java │ │ │ └── Utils.java │ │ │ ├── data │ │ │ └── Page.kt │ │ │ ├── database │ │ │ ├── converters │ │ │ │ └── IDListConverter.kt │ │ │ ├── dao │ │ │ │ ├── EffectsDao.kt │ │ │ │ ├── TagsDao.kt │ │ │ │ └── WallpaperDao.kt │ │ │ ├── instances │ │ │ │ ├── EffectsDatabase.kt │ │ │ │ ├── LastHomeWallpapersDatabase.kt │ │ │ │ ├── LastLockWallpapersDatabase.kt │ │ │ │ ├── LastWallpapersDatabase.kt │ │ │ │ ├── TagsDatabase.kt │ │ │ │ └── WallpaperDatabase.kt │ │ │ └── migrations │ │ │ │ └── TagsMigration.java │ │ │ ├── extensions │ │ │ ├── BaseComponentActivity.kt │ │ │ ├── CompressorViewModel.kt │ │ │ └── DoubleTapListener.kt │ │ │ ├── factories │ │ │ ├── FolderViewModelFactory.kt │ │ │ └── TagsViewModelFactory.kt │ │ │ ├── glide │ │ │ ├── effect │ │ │ │ ├── Effect.kt │ │ │ │ ├── EffectLoader.kt │ │ │ │ └── EffectsFetcher.kt │ │ │ ├── folders │ │ │ │ ├── ContextFolder.kt │ │ │ │ ├── FolderFetcher.kt │ │ │ │ └── FolderLoader.kt │ │ │ ├── modules │ │ │ │ ├── EffectModule.kt │ │ │ │ ├── FolderModule.kt │ │ │ │ ├── TagModule.kt │ │ │ │ └── WallpaperModule.kt │ │ │ ├── tags │ │ │ │ ├── ContextTag.kt │ │ │ │ ├── TagsFetcher.kt │ │ │ │ └── TagsLoader.kt │ │ │ ├── transitions │ │ │ │ ├── ZoomInTransitionFactory.java │ │ │ │ └── ZoomOut.kt │ │ │ └── wallpaper │ │ │ │ ├── Wallpaper.kt │ │ │ │ ├── WallpaperFetcher.kt │ │ │ │ └── WallpaperLoader.kt │ │ │ ├── interfaces │ │ │ └── WallpaperCallbacks.java │ │ │ ├── math │ │ │ └── Ratio.kt │ │ │ ├── models │ │ │ ├── DisplayDimension.kt │ │ │ ├── Effect.java │ │ │ ├── Folder.java │ │ │ ├── LiveWallpaperInfo.kt │ │ │ ├── PostWallpaperData.java │ │ │ ├── Ratio.java │ │ │ ├── Tag.java │ │ │ └── Wallpaper.kt │ │ │ ├── preferences │ │ │ ├── CrashPreferences.kt │ │ │ ├── MainComposePreferences.kt │ │ │ ├── MainPreferences.kt │ │ │ └── SharedPreferences.kt │ │ │ ├── receivers │ │ │ ├── BootReceiver.java │ │ │ ├── CopyActionReceiver.kt │ │ │ └── WallpaperActionReceiver.kt │ │ │ ├── repository │ │ │ └── WallpaperRepository.kt │ │ │ ├── services │ │ │ ├── AutoWallpaperService.kt │ │ │ ├── LiveAutoWallpaperService.kt │ │ │ └── NextWallpaperTileService.kt │ │ │ ├── tools │ │ │ └── StackBlur.java │ │ │ ├── ui │ │ │ ├── commons │ │ │ │ ├── AnimatedCircularProgress.kt │ │ │ │ ├── CircularCountdownProgress.kt │ │ │ │ ├── DisplayDimension.kt │ │ │ │ ├── Effect.kt │ │ │ │ ├── Header.kt │ │ │ │ ├── Permission.kt │ │ │ │ ├── Preference.kt │ │ │ │ ├── TextWithIcon.kt │ │ │ │ ├── VignetteImage.kt │ │ │ │ └── WallpaperListCommons.kt │ │ │ ├── constants │ │ │ │ └── DialogConstants.kt │ │ │ ├── dialogs │ │ │ │ ├── autowallpaper │ │ │ │ │ ├── AutoWallpaperPageSelectionDialog.kt │ │ │ │ │ ├── FoldersDialog.kt │ │ │ │ │ ├── ScreenSelectionDialog.kt │ │ │ │ │ ├── TagsDialog.kt │ │ │ │ │ └── TimeSelectionDialog.kt │ │ │ │ ├── common │ │ │ │ │ ├── AddTagDialog.kt │ │ │ │ │ ├── PleaseWaitDialog.kt │ │ │ │ │ ├── PostScalingChangeDailog.kt │ │ │ │ │ ├── ShowWarningDialog.kt │ │ │ │ │ └── SureDialog.kt │ │ │ │ ├── folders │ │ │ │ │ └── FolderMenu.kt │ │ │ │ ├── livewallpapers │ │ │ │ │ └── LiveWallpapersMenu.kt │ │ │ │ ├── menus │ │ │ │ │ ├── CompressOptions.kt │ │ │ │ │ └── WallpaperMenu.kt │ │ │ │ ├── settings │ │ │ │ │ ├── CacheDirectoryDialog.kt │ │ │ │ │ ├── ConcurrencyDialog.kt │ │ │ │ │ ├── DeveloperProfileDialog.kt │ │ │ │ │ ├── GridSpanDialog.kt │ │ │ │ │ ├── OrderDialog.kt │ │ │ │ │ ├── ShowInureAppManagerDialog.kt │ │ │ │ │ ├── ShowPositionalDialog.kt │ │ │ │ │ └── SortDialog.kt │ │ │ │ ├── tags │ │ │ │ │ └── TagsMenu.kt │ │ │ │ └── wallpaper │ │ │ │ │ ├── EffectsDialog.kt │ │ │ │ │ └── ScreenSelectionDialog.kt │ │ │ ├── nav │ │ │ │ ├── Navigation.kt │ │ │ │ └── Routes.kt │ │ │ ├── screens │ │ │ │ ├── AutoWallpaper.kt │ │ │ │ ├── Folders.kt │ │ │ │ ├── Home.kt │ │ │ │ ├── LiveAutoWallpaper.kt │ │ │ │ ├── LiveWallpapers.kt │ │ │ │ ├── Settings.kt │ │ │ │ ├── Setup.kt │ │ │ │ ├── Tags.kt │ │ │ │ └── Wallpaper.kt │ │ │ ├── settings │ │ │ │ └── SkipColumn.kt │ │ │ ├── subscreens │ │ │ │ ├── TaggedWallpapers.kt │ │ │ │ └── WallpaperList.kt │ │ │ └── theme │ │ │ │ ├── Color.kt │ │ │ │ ├── Theme.kt │ │ │ │ └── Typography.kt │ │ │ ├── utils │ │ │ ├── BatteryUtils.kt │ │ │ ├── BitmapUtils.kt │ │ │ ├── CommonUtils.kt │ │ │ ├── ConditionUtils.kt │ │ │ ├── DoubleTapDetector.kt │ │ │ ├── FileUtils.kt │ │ │ ├── ListUtils.kt │ │ │ ├── ParcelUtils.kt │ │ │ ├── PermissionUtils.kt │ │ │ ├── ProcessUtils.kt │ │ │ ├── SDCard.java │ │ │ ├── ScreenUtils.kt │ │ │ ├── ServiceUtils.kt │ │ │ ├── StringUtils.kt │ │ │ ├── WallpaperServiceNotification.kt │ │ │ └── WallpaperSort.kt │ │ │ ├── viewmodels │ │ │ ├── ComposeWallpaperViewModel.kt │ │ │ ├── EffectsViewModel.kt │ │ │ ├── FolderDataViewModel.kt │ │ │ ├── HomeScreenViewModel.kt │ │ │ ├── LiveWallpapersViewModel.kt │ │ │ ├── StateViewModel.kt │ │ │ ├── TagsViewModel.kt │ │ │ └── WallpaperListViewModel.kt │ │ │ └── widgets │ │ │ ├── NextWallpaper.kt │ │ │ ├── NextWallpaperWidget.kt │ │ │ └── NextWallpaperWidgetTransparent.kt │ └── res │ │ ├── drawable-nodpi │ │ ├── inure.png │ │ └── positional.png │ │ ├── drawable │ │ ├── ic_copy_all.xml │ │ ├── ic_delete.xml │ │ ├── ic_fast_forward.xml │ │ ├── ic_launcher_foreground.xml │ │ ├── ic_next_foreground.xml │ │ ├── ic_peristyle.xml │ │ ├── ic_share.xml │ │ └── swap_vert.xml │ │ ├── layout │ │ ├── widget_next_wallpaper.xml │ │ └── widget_next_wallpaper_transparent.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ ├── ic_launcher_round.xml │ │ ├── ic_next.xml │ │ └── ic_next_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.webp │ │ ├── ic_launcher_round.png │ │ ├── ic_next.webp │ │ └── ic_next_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.webp │ │ ├── ic_launcher_round.png │ │ ├── ic_next.webp │ │ └── ic_next_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.webp │ │ ├── ic_launcher_round.png │ │ ├── ic_next.webp │ │ └── ic_next_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.webp │ │ ├── ic_launcher_round.png │ │ ├── ic_next.webp │ │ └── ic_next_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.webp │ │ ├── ic_launcher_round.png │ │ ├── ic_next.webp │ │ └── ic_next_round.webp │ │ ├── values-ar-rSA │ │ └── strings.xml │ │ ├── values-de-rDE │ │ └── strings.xml │ │ ├── values-es-rES │ │ └── strings.xml │ │ ├── values-fr-rFR │ │ └── strings.xml │ │ ├── values-it-rIT │ │ └── strings.xml │ │ ├── values-pl-rPL │ │ └── strings.xml │ │ ├── values-ru-rRU │ │ └── strings.xml │ │ ├── values-tr-rTR │ │ └── strings.xml │ │ ├── values-vi-rVN │ │ └── strings.xml │ │ ├── values-zh-rCN │ │ └── strings.xml │ │ ├── values-zh-rTW │ │ └── strings.xml │ │ ├── values │ │ ├── ic_launcher_background.xml │ │ ├── ic_next_background.xml │ │ ├── non_translatable_strings.xml │ │ └── strings.xml │ │ └── xml │ │ ├── backup_rules.xml │ │ ├── data_extraction_rules.xml │ │ ├── live_auto_wallpaper.xml │ │ ├── provider_paths.xml │ │ ├── widget_next_wallpaper.xml │ │ └── widget_next_wallpaper_transparent.xml │ └── test │ └── java │ └── app │ └── simple │ └── peri │ └── ExampleUnitTest.kt ├── build.gradle ├── crowdin.yml ├── fastlane └── metadata │ └── android │ ├── ar-SA │ ├── full_description.txt │ └── short_description.txt │ ├── de-DE │ ├── full_description.txt │ └── short_description.txt │ ├── en-US │ ├── changelogs │ │ ├── 107.txt │ │ ├── 122.txt │ │ ├── 123.txt │ │ ├── 124.txt │ │ ├── 126.txt │ │ ├── 127.txt │ │ ├── 129.txt │ │ ├── 130.txt │ │ ├── 131.txt │ │ ├── 132.txt │ │ ├── 133.txt │ │ ├── 134.txt │ │ ├── 136.txt │ │ ├── 137.txt │ │ ├── 138.txt │ │ ├── 139.txt │ │ ├── 140.txt │ │ ├── 141.txt │ │ ├── 142.txt │ │ ├── 143.txt │ │ ├── 144.txt │ │ ├── 145.txt │ │ ├── 146.txt │ │ ├── 147.txt │ │ ├── 148.txt │ │ ├── 149.txt │ │ ├── 150.txt │ │ ├── 151.txt │ │ ├── 152.txt │ │ ├── 153.txt │ │ ├── 154.txt │ │ ├── 200.txt │ │ ├── 201.txt │ │ ├── 202.txt │ │ ├── 203.txt │ │ ├── 204.txt │ │ ├── 205.txt │ │ ├── 300.txt │ │ ├── 310.txt │ │ ├── 320.txt │ │ ├── 330.txt │ │ ├── 331.txt │ │ ├── 340.txt │ │ ├── 400.txt │ │ ├── 500.txt │ │ ├── 510.txt │ │ ├── 520.txt │ │ ├── 600.txt │ │ ├── 610.txt │ │ ├── 620.txt │ │ ├── 630.txt │ │ ├── 640.txt │ │ ├── 700.txt │ │ ├── 704.txt │ │ ├── 810.txt │ │ ├── 820.txt │ │ ├── 830.txt │ │ ├── 840.txt │ │ ├── 850.txt │ │ └── 860.txt │ ├── full_description.txt │ ├── images │ │ ├── icon.png │ │ └── phoneScreenshots │ │ │ ├── 01.png │ │ │ ├── 02.png │ │ │ ├── 03.png │ │ │ ├── 04.png │ │ │ ├── 05.png │ │ │ ├── 06.png │ │ │ ├── 07.png │ │ │ ├── 08.png │ │ │ ├── 09.png │ │ │ ├── 10.png │ │ │ ├── 11.png │ │ │ └── 12.png │ ├── short_description.txt │ └── title │ ├── pl-PL │ ├── full_description.txt │ └── short_description.txt │ ├── ru-RU │ ├── full_description.txt │ └── short_description.txt │ ├── tr-TR │ ├── full_description.txt │ └── short_description.txt │ └── zh-CN │ ├── full_description.txt │ └── short_description.txt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots ├── 01.png ├── 02.png ├── 03.png ├── 04.png ├── 05.png └── 06.gif └── settings.gradle /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | Thank you for considering contributing to Peristyle! Here are some guidelines to help you get 4 | started: 5 | 6 | ## How to Contribute 7 | 8 | 1. **Fork the repository**: Click the "Fork" button at the top right of the repository page. 9 | 2. **Clone your fork**: Clone your forked repository to your local machine. 10 | ```sh 11 | git clone https://github.com/your-username/Peristyle.git 12 | ``` 13 | 3. **Create a branch**: Create a new branch for your contribution. 14 | 4. **Make changes**: Make your changes to the codebase. 15 | 5. **Commit your changes**: Commit your changes to your branch. 16 | ```sh 17 | git commit -m "Your message here 18 | ``` 19 | 6. **Push your changes**: Push your changes to your forked repository. 20 | ```sh 21 | git push origin your-branch-name 22 | ``` 23 | 7. **Submit a pull request**: Go to the original repository and click the "New pull request" button. 24 | 8. **Wait for review**: Wait for your pull request to be reviewed and merged. 25 | 9. **Sync your fork**: Sync your forked repository with the original repository. 26 | ```sh 27 | git remote add upstream 28 | git fetch upstream 29 | git checkout main 30 | git merge upstream/main 31 | git push origin main 32 | ``` 33 | 10. **Delete your branch**: After your pull request has been merged, you can delete your branch. 34 | ```sh 35 | git branch -d your-branch-name 36 | ``` 37 | 11. **Celebrate**: Your contribution has been merged! 🎉 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Code of Conduct 4 | url: https://github.com/Hamza417/Peristyle/blob/master/CODE_OF_CONDUCT.md 5 | about: Please read and adhere to our Code of Conduct before submitting an issue. Any violation of our Code of Conduct will result in the immediate closure of the issue and a possible ban from the repository. 6 | - name: Contribution Guidelines 7 | url: https://github.com/Hamza417/Peristyle/blob/master/.github/CONTRIBUTING.md 8 | about: Please follow our Contribution Guidelines before submitting a pull request. 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Suggest a new feature or enhancement. 3 | title: "[Feature Request] Your Title Here" 4 | labels: [ feature request ] 5 | 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Thanks for suggesting a feature! Please provide as much detail as possible. 11 | 12 | - type: checkboxes 13 | id: confirmation 14 | attributes: 15 | label: Confirmation 16 | description: | 17 | Please confirm the following: 18 | options: 19 | - label: I have read the [Code of Conduct](https://github.com/Hamza417/Peristyle/blob/master/CODE_OF_CONDUCT.md) 20 | required: true 21 | - label: I have searched the existing issues 22 | required: true 23 | 24 | - type: input 25 | id: feature_description 26 | attributes: 27 | label: Feature Description 28 | description: A clear and concise description of what the feature is and what problem it solves. 29 | placeholder: Describe the feature here 30 | validations: 31 | required: true 32 | 33 | - type: input 34 | id: solution 35 | attributes: 36 | label: Describe the Solution 37 | description: A clear and concise description of what you want to happen. 38 | placeholder: Describe the solution here 39 | validations: 40 | required: true 41 | 42 | - type: textarea 43 | id: alternatives 44 | attributes: 45 | label: Describe Alternatives 46 | description: A clear and concise description of any alternative solutions or features you've considered. 47 | placeholder: Describe alternatives here 48 | 49 | - type: textarea 50 | id: additional_context 51 | attributes: 52 | label: Additional Context 53 | description: Add any other context or screenshots about the feature request here. 54 | placeholder: Provide additional context here 55 | 56 | - type: checkboxes 57 | id: confirmation_2 58 | attributes: 59 | label: Sufficiency Confirmation 60 | description: | 61 | Please confirm the following: 62 | options: 63 | - label: I have provided all the information requested above and deemed sufficient for the developer to address the issue 64 | required: true 65 | -------------------------------------------------------------------------------- /.github/workflows/build_pre_release_apk.yml: -------------------------------------------------------------------------------- 1 | name: Build Pre-Release APK 2 | 3 | on: 4 | workflow_dispatch: # Allow manual triggering 5 | 6 | jobs: 7 | build: 8 | name: Build Pre-Release APK 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v4 14 | 15 | - name: Set up Java and Android SDK 16 | uses: actions/setup-java@v3 17 | with: 18 | java-version: '21' 19 | distribution: 'temurin' 20 | 21 | - name: Decode Keystore 22 | id: decode_keystore 23 | uses: timheuer/base64-to-file@v1 24 | with: 25 | fileName: 'keystore/key.jks' 26 | encodedString: ${{ secrets.SIGN_KEY }} 27 | 28 | - name: Build GitHub Release APK 29 | run: | 30 | chmod +x ./gradlew 31 | ./gradlew clean assembleProdRelease --no-build-cache --no-configuration-cache --no-daemon --rerun-tasks 32 | env: 33 | SIGNING_KEY_ALIAS: ${{ secrets.ALIAS }} 34 | SIGNING_KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }} 35 | SIGNING_STORE_PASSWORD: ${{ secrets.KEY_STORE_PASSWORD }} 36 | 37 | - name: Extract Version Name and Version Code 38 | run: | 39 | # Extract versionName and versionCode from build.gradle 40 | VERSION_NAME=$(cat app/build.gradle | grep -oP 'versionName "\K[^"]*') 41 | VERSION_CODE=$(cat app/build.gradle | grep -oP 'versionCode \K\d+') 42 | 43 | echo "Version Name: $VERSION_NAME" 44 | echo "Version Code: $VERSION_CODE" 45 | 46 | # Set these values as environment variables for later steps 47 | echo "VERSION_NAME=$VERSION_NAME" >> $GITHUB_ENV 48 | echo "VERSION_CODE=$VERSION_CODE" >> $GITHUB_ENV 49 | 50 | - name: Archive APKs 51 | uses: actions/upload-artifact@v4 52 | with: 53 | name: ${{ env.VERSION_NAME }} APKs 54 | path: app/build/outputs/apk/prod/release/app-prod-release.apk 55 | -------------------------------------------------------------------------------- /.github/workflows/build_release_apk.yml: -------------------------------------------------------------------------------- 1 | name: Build Release APK 2 | 3 | on: 4 | workflow_dispatch: # Allow manual triggering 5 | 6 | jobs: 7 | build: 8 | name: Build Release APK 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v4 14 | 15 | - name: Set up Java and Android SDK 16 | uses: actions/setup-java@v3 17 | with: 18 | java-version: '21' 19 | distribution: 'temurin' 20 | 21 | - name: Decode Keystore 22 | id: decode_keystore 23 | uses: timheuer/base64-to-file@v1 24 | with: 25 | fileName: 'keystore/key.jks' 26 | encodedString: ${{ secrets.SIGN_KEY }} 27 | 28 | - name: Build GitHub Release APK 29 | run: | 30 | chmod +x ./gradlew 31 | ./gradlew clean assembleProdRelease --no-build-cache --no-configuration-cache --no-daemon --rerun-tasks 32 | env: 33 | SIGNING_KEY_ALIAS: ${{ secrets.ALIAS }} 34 | SIGNING_KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }} 35 | SIGNING_STORE_PASSWORD: ${{ secrets.KEY_STORE_PASSWORD }} 36 | 37 | - name: Extract Version Name and Version Code 38 | run: | 39 | # Extract versionName and versionCode from build.gradle 40 | VERSION_NAME=$(cat app/build.gradle | grep -oP 'versionName "\K[^"]*') 41 | VERSION_CODE=$(cat app/build.gradle | grep -oP 'versionCode \K\d+') 42 | 43 | echo "Version Name: $VERSION_NAME" 44 | echo "Version Code: $VERSION_CODE" 45 | 46 | # Set these values as environment variables for later steps 47 | echo "VERSION_NAME=$VERSION_NAME" >> $GITHUB_ENV 48 | echo "VERSION_CODE=$VERSION_CODE" >> $GITHUB_ENV 49 | 50 | - name: Set Tag 51 | run: | 52 | TAG=$(echo ${{ env.VERSION_NAME }} | tr '[:upper:]' '[:lower:]') 53 | echo "TAG=${TAG}" >> $GITHUB_ENV 54 | echo "Tag: ${TAG}" # Print tag to console 55 | 56 | - name: Archive APKs 57 | uses: actions/upload-artifact@v4 58 | with: 59 | name: ${{ env.VERSION_NAME }} APKs 60 | path: app/build/outputs/apk/prod/release/app-prod-release.apk 61 | 62 | - name: Create GitHub Release 63 | uses: softprops/action-gh-release@v2 64 | with: 65 | files: | 66 | app/**/prod/release/*.apk 67 | name: ${{ env.VERSION_NAME }} # Use the original case for the release name 68 | tag_name: ${{ env.TAG }} # Use lowercase for the tag 69 | env: 70 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 71 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | /app/release/ 17 | /app/prod/release/* 18 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # GitHub Copilot persisted chat sessions 5 | /copilot/chatSessions 6 | -------------------------------------------------------------------------------- /.idea/AndroidProjectSystem.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/deploymentTargetDropDown.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /.idea/deploymentTargetSelector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/dictionaries/Hamza.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 10 | 13 | 14 | 16 | -------------------------------------------------------------------------------- /.idea/migrations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.imgbotconfig: -------------------------------------------------------------------------------- 1 | { 2 | "schedule": "monthly", // daily|weekly|monthly 3 | "ignoredFiles": [ 4 | "app/src/main/*", // ignore by folderpath 5 | ], 6 | "aggressiveCompression": "false", // true|false 7 | "compressWiki": "true", // true|false 8 | "minKBReduced": 500, // delay new prs until size reduction meets this threshold (default to 10) 9 | } 10 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /prod/release/app-prod-release.zip 3 | /play/release/app-play-release.aab 4 | /play/release/baselineProfiles/0/app-play-release.dm 5 | /play/release/baselineProfiles/1/app-play-release.dm 6 | /play/release/app-play-release.apk 7 | /play/release/output-metadata.json 8 | /dev/release/baselineProfiles/0/app-dev-release.dm 9 | /dev/release/baselineProfiles/1/app-dev-release.dm 10 | /dev/release/app-dev-release.apk 11 | /dev/release/output-metadata.json 12 | -------------------------------------------------------------------------------- /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 22 | 23 | -ignorewarnings 24 | -dontobfuscate 25 | 26 | # This is generated automatically by the Android Gradle plugin. 27 | -dontwarn javax.annotation.Nonnull 28 | -dontwarn javax.annotation.Nullable 29 | -dontwarn javax.annotation.concurrent.GuardedBy 30 | -dontwarn org.bouncycastle.cert.X509CertificateHolder 31 | -dontwarn org.bouncycastle.cert.jcajce.JcaX509CertificateConverter 32 | -dontwarn org.bouncycastle.cms.CMSException 33 | -dontwarn org.bouncycastle.cms.CMSSignedData 34 | -dontwarn org.bouncycastle.cms.SignerId 35 | -dontwarn org.bouncycastle.cms.SignerInformation 36 | -dontwarn org.bouncycastle.cms.SignerInformationStore 37 | -dontwarn org.bouncycastle.jce.provider.BouncyCastleProvider 38 | -dontwarn org.bouncycastle.util.Selector 39 | -dontwarn org.bouncycastle.util.Store 40 | -dontwarn org.conscrypt.Conscrypt 41 | -dontwarn org.conscrypt.OpenSSLProvider -------------------------------------------------------------------------------- /app/schemas/app.simple.peri.database.instances.TagsDatabase/1.json: -------------------------------------------------------------------------------- 1 | { 2 | "formatVersion": 1, 3 | "database": { 4 | "version": 1, 5 | "identityHash": "88d7a4b07350f3aef9f605e3960c71f6", 6 | "entities": [ 7 | { 8 | "tableName": "tags", 9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `sum` TEXT, PRIMARY KEY(`name`))", 10 | "fields": [ 11 | { 12 | "fieldPath": "name", 13 | "columnName": "name", 14 | "affinity": "TEXT", 15 | "notNull": true 16 | }, 17 | { 18 | "fieldPath": "sum", 19 | "columnName": "sum", 20 | "affinity": "TEXT", 21 | "notNull": false 22 | } 23 | ], 24 | "primaryKey": { 25 | "autoGenerate": false, 26 | "columnNames": [ 27 | "name" 28 | ] 29 | }, 30 | "indices": [], 31 | "foreignKeys": [] 32 | } 33 | ], 34 | "views": [], 35 | "setupQueries": [ 36 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", 37 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '88d7a4b07350f3aef9f605e3960c71f6')" 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/schemas/app.simple.peri.database.instances.TagsDatabase/2.json: -------------------------------------------------------------------------------- 1 | { 2 | "formatVersion": 1, 3 | "database": { 4 | "version": 2, 5 | "identityHash": "a2a3451597f9113c956a175427784873", 6 | "entities": [ 7 | { 8 | "tableName": "tags", 9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `ids` TEXT NOT NULL, PRIMARY KEY(`name`))", 10 | "fields": [ 11 | { 12 | "fieldPath": "name", 13 | "columnName": "name", 14 | "affinity": "TEXT", 15 | "notNull": true 16 | }, 17 | { 18 | "fieldPath": "sum", 19 | "columnName": "ids", 20 | "affinity": "TEXT", 21 | "notNull": true 22 | } 23 | ], 24 | "primaryKey": { 25 | "autoGenerate": false, 26 | "columnNames": [ 27 | "name" 28 | ] 29 | } 30 | } 31 | ], 32 | "setupQueries": [ 33 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", 34 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a2a3451597f9113c956a175427784873')" 35 | ] 36 | } 37 | } -------------------------------------------------------------------------------- /app/schemas/app.simple.peri.database.instances.TagsDatabase/3.json: -------------------------------------------------------------------------------- 1 | { 2 | "formatVersion": 1, 3 | "database": { 4 | "version": 3, 5 | "identityHash": "a2a3451597f9113c956a175427784873", 6 | "entities": [ 7 | { 8 | "tableName": "tags", 9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `ids` TEXT NOT NULL, PRIMARY KEY(`name`))", 10 | "fields": [ 11 | { 12 | "fieldPath": "name", 13 | "columnName": "name", 14 | "affinity": "TEXT", 15 | "notNull": true 16 | }, 17 | { 18 | "fieldPath": "sum", 19 | "columnName": "ids", 20 | "affinity": "TEXT", 21 | "notNull": true 22 | } 23 | ], 24 | "primaryKey": { 25 | "autoGenerate": false, 26 | "columnNames": [ 27 | "name" 28 | ] 29 | } 30 | } 31 | ], 32 | "setupQueries": [ 33 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", 34 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a2a3451597f9113c956a175427784873')" 35 | ] 36 | } 37 | } -------------------------------------------------------------------------------- /app/schemas/app.simple.peri.database.instances.WallpaperDatabase/6.json: -------------------------------------------------------------------------------- 1 | { 2 | "formatVersion": 1, 3 | "database": { 4 | "version": 6, 5 | "identityHash": "5cf0a1dbafcccdb7f980cb894e46ddc1", 6 | "entities": [ 7 | { 8 | "tableName": "wallpapers", 9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT, `uri` TEXT NOT NULL, `md5` TEXT NOT NULL, `prominentColor` INTEGER NOT NULL, `width` INTEGER, `height` INTEGER, `dateModified` INTEGER NOT NULL, `size` INTEGER NOT NULL, `uri_hashcode` INTEGER NOT NULL, `isSelected` INTEGER NOT NULL, PRIMARY KEY(`md5`))", 10 | "fields": [ 11 | { 12 | "fieldPath": "name", 13 | "columnName": "name", 14 | "affinity": "TEXT", 15 | "notNull": false 16 | }, 17 | { 18 | "fieldPath": "uri", 19 | "columnName": "uri", 20 | "affinity": "TEXT", 21 | "notNull": true 22 | }, 23 | { 24 | "fieldPath": "md5", 25 | "columnName": "md5", 26 | "affinity": "TEXT", 27 | "notNull": true 28 | }, 29 | { 30 | "fieldPath": "prominentColor", 31 | "columnName": "prominentColor", 32 | "affinity": "INTEGER", 33 | "notNull": true 34 | }, 35 | { 36 | "fieldPath": "width", 37 | "columnName": "width", 38 | "affinity": "INTEGER", 39 | "notNull": false 40 | }, 41 | { 42 | "fieldPath": "height", 43 | "columnName": "height", 44 | "affinity": "INTEGER", 45 | "notNull": false 46 | }, 47 | { 48 | "fieldPath": "dateModified", 49 | "columnName": "dateModified", 50 | "affinity": "INTEGER", 51 | "notNull": true 52 | }, 53 | { 54 | "fieldPath": "size", 55 | "columnName": "size", 56 | "affinity": "INTEGER", 57 | "notNull": true 58 | }, 59 | { 60 | "fieldPath": "uriHashcode", 61 | "columnName": "uri_hashcode", 62 | "affinity": "INTEGER", 63 | "notNull": true 64 | }, 65 | { 66 | "fieldPath": "isSelected", 67 | "columnName": "isSelected", 68 | "affinity": "INTEGER", 69 | "notNull": true 70 | } 71 | ], 72 | "primaryKey": { 73 | "autoGenerate": false, 74 | "columnNames": [ 75 | "md5" 76 | ] 77 | }, 78 | "indices": [], 79 | "foreignKeys": [] 80 | } 81 | ], 82 | "views": [], 83 | "setupQueries": [ 84 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", 85 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '5cf0a1dbafcccdb7f980cb894e46ddc1')" 86 | ] 87 | } 88 | } -------------------------------------------------------------------------------- /app/schemas/app.simple.peri.database.instances.WallpaperDatabase/9.json: -------------------------------------------------------------------------------- 1 | { 2 | "formatVersion": 1, 3 | "database": { 4 | "version": 9, 5 | "identityHash": "c119ac5fab1f40ad7d352c977c29c77d", 6 | "entities": [ 7 | { 8 | "tableName": "wallpapers", 9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT, `uri` TEXT NOT NULL, `file_path` TEXT NOT NULL, `id` TEXT NOT NULL, `prominentColor` INTEGER NOT NULL, `width` INTEGER, `height` INTEGER, `dateModified` INTEGER NOT NULL, `size` INTEGER NOT NULL, `folder_id` INTEGER NOT NULL, `isSelected` INTEGER NOT NULL, PRIMARY KEY(`id`))", 10 | "fields": [ 11 | { 12 | "fieldPath": "name", 13 | "columnName": "name", 14 | "affinity": "TEXT", 15 | "notNull": false 16 | }, 17 | { 18 | "fieldPath": "uri", 19 | "columnName": "uri", 20 | "affinity": "TEXT", 21 | "notNull": true 22 | }, 23 | { 24 | "fieldPath": "filePath", 25 | "columnName": "file_path", 26 | "affinity": "TEXT", 27 | "notNull": true 28 | }, 29 | { 30 | "fieldPath": "id", 31 | "columnName": "id", 32 | "affinity": "TEXT", 33 | "notNull": true 34 | }, 35 | { 36 | "fieldPath": "prominentColor", 37 | "columnName": "prominentColor", 38 | "affinity": "INTEGER", 39 | "notNull": true 40 | }, 41 | { 42 | "fieldPath": "width", 43 | "columnName": "width", 44 | "affinity": "INTEGER", 45 | "notNull": false 46 | }, 47 | { 48 | "fieldPath": "height", 49 | "columnName": "height", 50 | "affinity": "INTEGER", 51 | "notNull": false 52 | }, 53 | { 54 | "fieldPath": "dateModified", 55 | "columnName": "dateModified", 56 | "affinity": "INTEGER", 57 | "notNull": true 58 | }, 59 | { 60 | "fieldPath": "size", 61 | "columnName": "size", 62 | "affinity": "INTEGER", 63 | "notNull": true 64 | }, 65 | { 66 | "fieldPath": "folderID", 67 | "columnName": "folder_id", 68 | "affinity": "INTEGER", 69 | "notNull": true 70 | }, 71 | { 72 | "fieldPath": "isSelected", 73 | "columnName": "isSelected", 74 | "affinity": "INTEGER", 75 | "notNull": true 76 | } 77 | ], 78 | "primaryKey": { 79 | "autoGenerate": false, 80 | "columnNames": [ 81 | "id" 82 | ] 83 | }, 84 | "indices": [], 85 | "foreignKeys": [] 86 | } 87 | ], 88 | "views": [], 89 | "setupQueries": [ 90 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", 91 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c119ac5fab1f40ad7d352c977c29c77d')" 92 | ] 93 | } 94 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/app/simple/peri/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri 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("app.simple.waller", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/dev/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Peristyle (Dev) 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/main/ic_next-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/ic_next-playstore.png -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/activities/association/WallpaperAssociationActivity.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.activities.association 2 | 3 | import android.graphics.BitmapFactory 4 | import android.os.Bundle 5 | import androidx.activity.compose.setContent 6 | import androidx.compose.foundation.layout.fillMaxSize 7 | import androidx.compose.material3.Surface 8 | import androidx.compose.ui.Modifier 9 | import androidx.documentfile.provider.DocumentFile 10 | import androidx.lifecycle.lifecycleScope 11 | import androidx.navigation.compose.rememberNavController 12 | import app.simple.peri.extensions.BaseComponentActivity 13 | import app.simple.peri.preferences.SharedPreferences 14 | import app.simple.peri.ui.screens.Wallpaper 15 | import app.simple.peri.ui.theme.PeristyleTheme 16 | import kotlinx.coroutines.Dispatchers 17 | import kotlinx.coroutines.launch 18 | import kotlinx.coroutines.withContext 19 | import java.io.File 20 | import java.io.FileOutputStream 21 | import java.io.InputStream 22 | import app.simple.peri.models.Wallpaper as ModelWallpaper 23 | 24 | class WallpaperAssociationActivity : BaseComponentActivity() { 25 | 26 | override fun onCreate(savedInstanceState: Bundle?) { 27 | super.onCreate(savedInstanceState) 28 | SharedPreferences.init(applicationContext) 29 | 30 | lifecycleScope.launch(Dispatchers.IO) { 31 | val wallpaper = ModelWallpaper() 32 | contentResolver.openInputStream(intent.data!!)?.use { inputStream -> 33 | val documentFile = DocumentFile.fromSingleUri(this@WallpaperAssociationActivity, intent.data!!) 34 | wallpaper.filePath = copyFileToCache(inputStream, documentFile!!.name!!).absolutePath 35 | } 36 | 37 | wallpaper.uri = intent.data.toString() 38 | wallpaper.name = wallpaper.getFile().name 39 | wallpaper.dateModified = wallpaper.getFile().lastModified() 40 | wallpaper.size = wallpaper.getFile().length() 41 | 42 | val options = BitmapFactory.Options() 43 | options.inJustDecodeBounds = true 44 | BitmapFactory.decodeFile(wallpaper.filePath, options) 45 | wallpaper.width = options.outWidth 46 | wallpaper.height = options.outHeight 47 | 48 | withContext(Dispatchers.Main) { 49 | setContent { 50 | val navController = rememberNavController() 51 | PeristyleTheme { 52 | Surface( 53 | modifier = Modifier.fillMaxSize() 54 | ) { 55 | Wallpaper(navController, wallpaper) 56 | } 57 | } 58 | } 59 | } 60 | } 61 | } 62 | 63 | private fun copyFileToCache(inputStream: InputStream, fileName: String): File { 64 | val cacheDir = cacheDir 65 | val cacheFile = File(cacheDir, fileName) 66 | inputStream.use { input -> 67 | FileOutputStream(cacheFile).use { output -> 68 | input.copyTo(output) 69 | } 70 | } 71 | 72 | return cacheFile 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/activities/main/ComposePreferencesActivity.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.activities.main 2 | 3 | import android.os.Bundle 4 | import androidx.activity.compose.setContent 5 | import androidx.compose.foundation.layout.fillMaxSize 6 | import androidx.compose.material3.Surface 7 | import androidx.compose.ui.Modifier 8 | import app.simple.peri.extensions.BaseComponentActivity 9 | import app.simple.peri.preferences.SharedPreferences 10 | import app.simple.peri.ui.screens.Settings 11 | import app.simple.peri.ui.theme.PeristyleTheme 12 | 13 | class ComposePreferencesActivity : BaseComponentActivity() { 14 | 15 | override fun onCreate(savedInstanceState: Bundle?) { 16 | super.onCreate(savedInstanceState) 17 | SharedPreferences.init(applicationContext) 18 | 19 | setContent { 20 | PeristyleTheme { 21 | Surface( 22 | modifier = Modifier.fillMaxSize() 23 | ) { 24 | Settings() 25 | } 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/application/PeriApplication.java: -------------------------------------------------------------------------------- 1 | package app.simple.peri.application; 2 | 3 | import android.app.Application; 4 | 5 | import com.google.android.material.color.DynamicColors; 6 | 7 | public class PeriApplication extends Application { 8 | 9 | @Override 10 | public void onCreate() { 11 | super.onCreate(); 12 | DynamicColors.applyToActivitiesIfAvailable(this); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/constants/Misc.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.constants 2 | 3 | object Misc { 4 | const val BLUR_TIMES = 4 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/crash/Utils.java: -------------------------------------------------------------------------------- 1 | package app.simple.peri.crash; 2 | 3 | import android.annotation.SuppressLint; 4 | 5 | import java.io.BufferedReader; 6 | import java.io.File; 7 | import java.io.FileReader; 8 | import java.io.FileWriter; 9 | import java.io.IOException; 10 | import java.text.SimpleDateFormat; 11 | import java.util.Date; 12 | 13 | public class Utils { 14 | public static void create(String text, File path) { 15 | try { 16 | FileWriter writer = new FileWriter(path); 17 | writer.write(text); 18 | writer.close(); 19 | } catch (IOException ignored) { 20 | } 21 | } 22 | 23 | @SuppressLint ("SimpleDateFormat") 24 | public static String getTimeStamp() { 25 | return new SimpleDateFormat("yyyyMMdd_HH-mm").format(new Date()); 26 | } 27 | 28 | public static String read(File file) { 29 | BufferedReader buf = null; 30 | try { 31 | buf = new BufferedReader(new FileReader(file)); 32 | 33 | StringBuilder stringBuilder = new StringBuilder(); 34 | String line; 35 | while ((line = buf.readLine()) != null) { 36 | stringBuilder.append(line).append("\n"); 37 | } 38 | 39 | return stringBuilder.toString().trim(); 40 | } catch (IOException ignored) { 41 | } finally { 42 | try { 43 | if (buf != null) { 44 | buf.close(); 45 | } 46 | } catch (IOException e) { 47 | e.printStackTrace(); 48 | } 49 | } 50 | return null; 51 | } 52 | 53 | public static Throwable getCause(Throwable e) { 54 | Throwable cause; 55 | Throwable result = e; 56 | 57 | while (null != (cause = result.getCause()) && (result != cause)) { 58 | result = cause; 59 | } 60 | return result; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/data/Page.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.data 2 | 3 | data class Page( 4 | val id: Int, 5 | val isVisible: Boolean 6 | ) -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/database/converters/IDListConverter.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.database.converters 2 | 3 | import androidx.room.TypeConverter 4 | 5 | class IDListConverter { 6 | @TypeConverter 7 | fun fromIDList(md5List: HashSet?): String { 8 | return md5List?.joinToString(",") ?: "" 9 | } 10 | 11 | @TypeConverter 12 | fun toIDList(md5String: String): HashSet { 13 | return md5String.split(",").toHashSet() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/database/dao/EffectsDao.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.database.dao 2 | 3 | import androidx.room.Dao 4 | import androidx.room.Delete 5 | import androidx.room.Insert 6 | import androidx.room.OnConflictStrategy 7 | import androidx.room.Query 8 | import app.simple.peri.models.Effect 9 | 10 | @Dao 11 | interface EffectsDao { 12 | @Query("SELECT * FROM effects") 13 | fun getAllEffects(): List 14 | 15 | @Query("SELECT * FROM effects WHERE id = :id") 16 | fun getEffectById(id: Int): Effect 17 | 18 | @Insert(onConflict = OnConflictStrategy.REPLACE) 19 | fun insertEffect(effect: Effect) 20 | 21 | @Delete 22 | fun deleteEffect(effect: Effect) 23 | 24 | @Query("DELETE FROM effects") 25 | fun deleteAllEffects() 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/database/dao/TagsDao.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.database.dao 2 | 3 | import androidx.room.Dao 4 | import androidx.room.Delete 5 | import androidx.room.Insert 6 | import androidx.room.OnConflictStrategy 7 | import androidx.room.Query 8 | import app.simple.peri.models.Tag 9 | 10 | @Dao 11 | interface TagsDao { 12 | @Query("SELECT * FROM tags") 13 | fun getAllTags(): List 14 | 15 | @Query("SELECT * FROM tags WHERE name = :id") 16 | fun getTagByID(id: String): Tag 17 | 18 | /** 19 | * Get all tag names whose sum contains the given md5 20 | * 21 | * @param id The md5 to search for 22 | */ 23 | @Query("SELECT name FROM tags WHERE ids LIKE '%' || :id || '%'") 24 | fun getTagNamesByID(id: String): List 25 | 26 | @Query("SELECT EXISTS(SELECT 1 FROM tags WHERE name = :id)") 27 | fun isTagExists(id: String): Boolean 28 | 29 | @Insert(onConflict = OnConflictStrategy.REPLACE) 30 | fun insertTag(tag: Tag) 31 | 32 | @Delete 33 | fun deleteTag(tag: Tag) 34 | 35 | @Query("DELETE FROM tags") 36 | fun deleteAllTags() 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/database/instances/EffectsDatabase.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.database.instances 2 | 3 | import android.content.Context 4 | import androidx.room.Database 5 | import androidx.room.Room 6 | import androidx.room.RoomDatabase 7 | import app.simple.peri.database.dao.EffectsDao 8 | import app.simple.peri.models.Effect 9 | import app.simple.peri.utils.ConditionUtils.invert 10 | 11 | @Database(entities = [Effect::class], version = 2) 12 | abstract class EffectsDatabase : RoomDatabase() { 13 | abstract fun effectsDao(): EffectsDao 14 | 15 | companion object { 16 | private const val DATABASE_NAME = "effects" 17 | private var instance: EffectsDatabase? = null 18 | 19 | @Synchronized 20 | fun getInstance(context: Context): EffectsDatabase? { 21 | kotlin.runCatching { 22 | if (instance!!.isOpen.invert()) { 23 | instance = Room.databaseBuilder(context, EffectsDatabase::class.java, DATABASE_NAME) 24 | .build() 25 | } 26 | }.getOrElse { 27 | instance = Room.databaseBuilder(context, EffectsDatabase::class.java, DATABASE_NAME).build() 28 | } 29 | 30 | return instance 31 | } 32 | 33 | fun destroy() { 34 | instance?.close() 35 | instance = null 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/database/instances/LastHomeWallpapersDatabase.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.database.instances 2 | 3 | import android.content.Context 4 | import androidx.room.Database 5 | import androidx.room.Room 6 | import androidx.room.RoomDatabase 7 | import app.simple.peri.database.dao.WallpaperDao 8 | import app.simple.peri.models.Wallpaper 9 | import app.simple.peri.utils.ConditionUtils.invert 10 | 11 | @Database(entities = [Wallpaper::class], version = 9) 12 | abstract class LastHomeWallpapersDatabase : RoomDatabase() { 13 | 14 | abstract fun wallpaperDao(): WallpaperDao 15 | 16 | companion object { 17 | private const val DB_NAME = "wallpapers_last_random_home" 18 | 19 | private var instance: LastHomeWallpapersDatabase? = null 20 | 21 | @Synchronized 22 | fun getInstance(context: Context): LastHomeWallpapersDatabase? { 23 | kotlin.runCatching { 24 | if (instance!!.isOpen.invert()) { 25 | instance = Room.databaseBuilder(context, LastHomeWallpapersDatabase::class.java, DB_NAME) 26 | .build() 27 | } 28 | }.getOrElse { 29 | instance = Room.databaseBuilder(context, LastHomeWallpapersDatabase::class.java, DB_NAME) 30 | .build() 31 | } 32 | 33 | return instance 34 | } 35 | 36 | @Synchronized 37 | fun wipeDatabase(context: Context) { 38 | kotlin.runCatching { 39 | instance?.clearAllTables() 40 | }.getOrElse { 41 | Room.databaseBuilder(context, LastHomeWallpapersDatabase::class.java, DB_NAME) 42 | .build() 43 | .clearAllTables() 44 | } 45 | } 46 | 47 | @Synchronized 48 | fun destroyInstance() { 49 | instance = null 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/database/instances/LastLockWallpapersDatabase.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.database.instances 2 | 3 | import android.content.Context 4 | import androidx.room.Database 5 | import androidx.room.Room 6 | import androidx.room.RoomDatabase 7 | import app.simple.peri.database.dao.WallpaperDao 8 | import app.simple.peri.models.Wallpaper 9 | import app.simple.peri.utils.ConditionUtils.invert 10 | 11 | @Database(entities = [Wallpaper::class], version = 9) 12 | 13 | abstract class LastLockWallpapersDatabase : RoomDatabase() { 14 | abstract fun wallpaperDao(): WallpaperDao 15 | 16 | companion object { 17 | private const val DB_NAME = "wallpapers_last_random_lock" 18 | 19 | private var instance: LastLockWallpapersDatabase? = null 20 | 21 | @Synchronized 22 | fun getInstance(context: Context): LastLockWallpapersDatabase? { 23 | kotlin.runCatching { 24 | if (instance!!.isOpen.invert()) { 25 | instance = Room.databaseBuilder(context, LastLockWallpapersDatabase::class.java, DB_NAME) 26 | 27 | .build() 28 | } 29 | }.getOrElse { 30 | instance = Room.databaseBuilder(context, LastLockWallpapersDatabase::class.java, DB_NAME) 31 | .build() 32 | } 33 | 34 | return instance 35 | } 36 | 37 | @Synchronized 38 | fun wipeDatabase(context: Context) { 39 | kotlin.runCatching { 40 | instance?.clearAllTables() 41 | }.getOrElse { 42 | Room.databaseBuilder(context, LastLockWallpapersDatabase::class.java, DB_NAME) 43 | .build() 44 | .clearAllTables() 45 | } 46 | } 47 | 48 | @Synchronized 49 | fun destroyInstance() { 50 | instance = null 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/database/instances/LastWallpapersDatabase.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.database.instances 2 | 3 | import android.content.Context 4 | import androidx.room.Database 5 | import androidx.room.Room 6 | import androidx.room.RoomDatabase 7 | import app.simple.peri.database.dao.WallpaperDao 8 | import app.simple.peri.models.Wallpaper 9 | import app.simple.peri.utils.ConditionUtils.invert 10 | 11 | @Database(entities = [Wallpaper::class], version = 9) 12 | abstract class LastWallpapersDatabase : RoomDatabase() { 13 | 14 | abstract fun wallpaperDao(): WallpaperDao 15 | 16 | companion object { 17 | private const val DB_NAME = "wallpapers_last_random" 18 | 19 | private var instance: LastWallpapersDatabase? = null 20 | 21 | @Synchronized 22 | fun getInstance(context: Context): LastWallpapersDatabase? { 23 | kotlin.runCatching { 24 | if (instance!!.isOpen.invert()) { 25 | instance = Room.databaseBuilder(context, LastWallpapersDatabase::class.java, DB_NAME) 26 | 27 | .build() 28 | } 29 | }.getOrElse { 30 | instance = Room.databaseBuilder(context, LastWallpapersDatabase::class.java, DB_NAME) 31 | .build() 32 | } 33 | 34 | return instance 35 | } 36 | 37 | @Synchronized 38 | fun wipeDatabase(context: Context) { 39 | kotlin.runCatching { 40 | instance?.clearAllTables() 41 | }.getOrElse { 42 | Room.databaseBuilder(context, LastWallpapersDatabase::class.java, DB_NAME) 43 | .build() 44 | .clearAllTables() 45 | } 46 | } 47 | 48 | @Synchronized 49 | fun destroyInstance() { 50 | instance = null 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/database/instances/TagsDatabase.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.database.instances 2 | 3 | import android.content.Context 4 | import androidx.room.Database 5 | import androidx.room.Room 6 | import androidx.room.RoomDatabase 7 | import app.simple.peri.database.dao.TagsDao 8 | import app.simple.peri.database.migrations.TagsMigration 9 | import app.simple.peri.models.Tag 10 | import app.simple.peri.utils.ConditionUtils.invert 11 | 12 | @Database( 13 | entities = [Tag::class], 14 | version = 3, 15 | ) 16 | abstract class TagsDatabase : RoomDatabase() { 17 | abstract fun tagsDao(): TagsDao 18 | 19 | companion object { 20 | private const val DATABASE_NAME = "tags" 21 | private var instance: TagsDatabase? = null 22 | 23 | @Synchronized 24 | fun getInstance(context: Context): TagsDatabase? { 25 | kotlin.runCatching { 26 | if (instance!!.isOpen.invert()) { 27 | instance = Room.databaseBuilder(context, TagsDatabase::class.java, DATABASE_NAME) 28 | .addMigrations(TagsMigration(2, 3)) 29 | .build() 30 | } 31 | }.getOrElse { 32 | instance = Room.databaseBuilder(context, TagsDatabase::class.java, DATABASE_NAME) 33 | .addMigrations(TagsMigration(2, 3)) 34 | .build() 35 | } 36 | 37 | return instance 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/database/instances/WallpaperDatabase.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.database.instances 2 | 3 | import android.content.Context 4 | import androidx.room.Database 5 | import androidx.room.Room 6 | import androidx.room.RoomDatabase 7 | import app.simple.peri.database.dao.WallpaperDao 8 | import app.simple.peri.models.Wallpaper 9 | import app.simple.peri.utils.ConditionUtils.invert 10 | 11 | @Database(entities = [Wallpaper::class], version = 9) 12 | abstract class WallpaperDatabase : RoomDatabase() { 13 | abstract fun wallpaperDao(): WallpaperDao 14 | 15 | companion object { 16 | private const val DATABASE_NAME = "wallpapers" 17 | private var instance: WallpaperDatabase? = null 18 | 19 | @Synchronized 20 | fun getInstance(context: Context): WallpaperDatabase? { 21 | kotlin.runCatching { 22 | if (instance!!.isOpen.invert()) { 23 | instance = Room.databaseBuilder(context, WallpaperDatabase::class.java, DATABASE_NAME) 24 | 25 | .build() 26 | } 27 | }.getOrElse { 28 | instance = Room.databaseBuilder(context, WallpaperDatabase::class.java, DATABASE_NAME) 29 | .build() 30 | } 31 | 32 | return instance 33 | } 34 | 35 | fun destroyInstance() { 36 | if (instance?.isOpen == true) { 37 | instance?.close() 38 | } 39 | instance = null 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/database/migrations/TagsMigration.java: -------------------------------------------------------------------------------- 1 | package app.simple.peri.database.migrations; 2 | 3 | import android.database.sqlite.SQLiteException; 4 | 5 | import androidx.room.migration.Migration; 6 | import androidx.sqlite.db.SupportSQLiteDatabase; 7 | 8 | public class TagsMigration extends Migration { 9 | public TagsMigration(int startVersion, int endVersion) { 10 | super(startVersion, endVersion); 11 | } 12 | 13 | @Override 14 | public void migrate(SupportSQLiteDatabase database) { 15 | try { 16 | // Create the new table with correct schema 17 | database.execSQL("CREATE TABLE IF NOT EXISTS `tags_new` (" + 18 | "`name` TEXT NOT NULL, " + 19 | "`ids` TEXT NOT NULL, " + 20 | "PRIMARY KEY(`name`))"); 21 | 22 | // Copy the data from the old table to the new one 23 | database.execSQL("INSERT INTO `tags_new` (`name`, `ids`) " + 24 | "SELECT `name`, IFNULL(`ids`, '') FROM `tags`"); 25 | 26 | // Remove the old table 27 | database.execSQL("DROP TABLE `tags`"); 28 | 29 | // Rename new table to original name 30 | database.execSQL("ALTER TABLE `tags_new` RENAME TO `tags`"); 31 | } catch (SQLiteException e) { 32 | // Something failed, recreate the table 33 | database.execSQL("DROP TABLE IF EXISTS `tags`"); 34 | database.execSQL("DROP TABLE IF EXISTS `tags_new`"); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/extensions/BaseComponentActivity.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.extensions 2 | 3 | import android.os.Bundle 4 | import android.os.StrictMode 5 | import androidx.activity.ComponentActivity 6 | 7 | abstract class BaseComponentActivity : ComponentActivity() { 8 | override fun onCreate(savedInstanceState: Bundle?) { 9 | super.onCreate(savedInstanceState) 10 | actionBar?.hide() 11 | 12 | StrictMode.setVmPolicy(StrictMode.VmPolicy.Builder() 13 | .detectAll() 14 | .penaltyLog() 15 | .build()) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/extensions/CompressorViewModel.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.extensions 2 | 3 | import android.app.Application 4 | import android.graphics.Bitmap 5 | import androidx.lifecycle.AndroidViewModel 6 | import androidx.lifecycle.viewModelScope 7 | import app.simple.peri.models.Wallpaper 8 | import app.simple.peri.utils.FileUtils.toFile 9 | import id.zelory.compressor.Compressor 10 | import id.zelory.compressor.constraint.destination 11 | import id.zelory.compressor.constraint.format 12 | import id.zelory.compressor.constraint.quality 13 | import id.zelory.compressor.constraint.resolution 14 | import kotlinx.coroutines.Dispatchers 15 | import kotlinx.coroutines.launch 16 | import kotlinx.coroutines.withContext 17 | import java.io.File 18 | 19 | abstract class CompressorViewModel(application: Application) : AndroidViewModel(application) { 20 | fun compressWallpaper(wallpaper: Wallpaper, onSuccess: (Wallpaper) -> Unit) { 21 | viewModelScope.launch(Dispatchers.IO) { 22 | val file = wallpaper.filePath.toFile() 23 | 24 | // Compress the file 25 | Compressor.compress(getApplication(), file) { 26 | destination(file) 27 | quality(60) 28 | resolution(wallpaper.width!!, wallpaper.height!!) 29 | format(getFormat(wallpaper.name!!)) 30 | } 31 | 32 | val wallpaper1 = onCompressionDone(wallpaper, file) 33 | 34 | withContext(Dispatchers.Main) { 35 | onSuccess(wallpaper1) 36 | } 37 | 38 | clearResidue() 39 | } 40 | } 41 | 42 | fun reduceResolution(wallpaper: Wallpaper, onSuccess: (Wallpaper) -> Unit) { 43 | viewModelScope.launch(Dispatchers.IO) { 44 | val context = getApplication() 45 | val file = wallpaper.filePath.toFile() 46 | 47 | // Compress the file 48 | Compressor.compress(context, file) { 49 | destination(file) 50 | quality(100) 51 | resolution(wallpaper.width!!.div(2), wallpaper.height!!.div(2)) 52 | format(getFormat(wallpaper.name!!)) 53 | } 54 | 55 | val wallpaper1 = onCompressionDone(wallpaper, file) 56 | 57 | withContext(Dispatchers.Main) { 58 | onSuccess(wallpaper1) 59 | } 60 | 61 | clearResidue() 62 | } 63 | } 64 | 65 | private fun getFormat(name: String): Bitmap.CompressFormat { 66 | @Suppress("DEPRECATION") 67 | return when (name.lowercase().substringAfterLast(".")) { 68 | "jpg" -> Bitmap.CompressFormat.JPEG 69 | "jpeg" -> Bitmap.CompressFormat.JPEG 70 | "png" -> Bitmap.CompressFormat.PNG 71 | else -> Bitmap.CompressFormat.WEBP 72 | } 73 | } 74 | 75 | private fun clearResidue() { 76 | val cacheDir = getApplication().cacheDir 77 | cacheDir.listFiles()?.forEach { 78 | if (it.absolutePath.contains("/compressor/")) { 79 | it.delete() 80 | } 81 | } 82 | } 83 | 84 | abstract fun onCompressionDone(wallpaper: Wallpaper, file: File): Wallpaper 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/extensions/DoubleTapListener.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.extensions 2 | 3 | import android.view.GestureDetector 4 | import android.view.MotionEvent 5 | 6 | @Suppress("ConvertSecondaryConstructorToPrimary") 7 | class DoubleTapListener : GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener { 8 | 9 | private val onDoubleTapCallback: (MotionEvent) -> Boolean 10 | 11 | constructor(onDoubleTapCallback: (MotionEvent) -> Boolean) { 12 | this.onDoubleTapCallback = onDoubleTapCallback 13 | } 14 | 15 | override fun onDoubleTap(e: MotionEvent): Boolean { 16 | return onDoubleTapCallback(e) 17 | } 18 | 19 | // No-op implementations for other methods 20 | override fun onDown(e: MotionEvent): Boolean = false 21 | override fun onShowPress(e: MotionEvent) {} 22 | override fun onSingleTapUp(e: MotionEvent): Boolean = false 23 | override fun onScroll(e1: MotionEvent?, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean = false 24 | override fun onLongPress(e: MotionEvent) {} 25 | override fun onFling(e1: MotionEvent?, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean = false 26 | override fun onSingleTapConfirmed(e: MotionEvent): Boolean = false 27 | override fun onDoubleTapEvent(e: MotionEvent): Boolean = false 28 | } -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/factories/FolderViewModelFactory.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.factories 2 | 3 | import androidx.lifecycle.ViewModel 4 | import androidx.lifecycle.ViewModelProvider 5 | import androidx.lifecycle.viewmodel.CreationExtras 6 | import app.simple.peri.models.Folder 7 | import app.simple.peri.viewmodels.FolderDataViewModel 8 | 9 | class FolderViewModelFactory(private val hashCode: Folder) : ViewModelProvider.Factory { 10 | override fun create(modelClass: Class, extras: CreationExtras): T { 11 | val application = extras[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY]!! 12 | @Suppress("UNCHECKED_CAST") 13 | return FolderDataViewModel(application, hashCode) as T 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/factories/TagsViewModelFactory.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.factories 2 | 3 | import androidx.lifecycle.ViewModel 4 | import androidx.lifecycle.ViewModelProvider 5 | import androidx.lifecycle.viewmodel.CreationExtras 6 | import app.simple.peri.viewmodels.TagsViewModel 7 | 8 | class TagsViewModelFactory(private val md5: String? = null, 9 | private val tag: String? = null) : ViewModelProvider.Factory { 10 | 11 | override fun create(modelClass: Class, extras: CreationExtras): T { 12 | val application = extras[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY]!! 13 | @Suppress("UNCHECKED_CAST") 14 | return TagsViewModel(application, md5, tag) as T 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/glide/effect/Effect.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.glide.effect 2 | 3 | import android.content.Context 4 | import app.simple.peri.models.Effect 5 | import app.simple.peri.models.Wallpaper 6 | 7 | class Effect(val context: Context, val effect: Effect, val wallpaper: Wallpaper) { 8 | override fun hashCode(): Int { 9 | return effect.hashCode() + wallpaper.filePath.hashCode() 10 | } 11 | 12 | override fun equals(other: Any?): Boolean { 13 | if (this === other) return true 14 | if (javaClass != other?.javaClass) return false 15 | 16 | other as app.simple.peri.glide.effect.Effect 17 | 18 | if (context != other.context) return false 19 | if (effect != other.effect) return false 20 | if (wallpaper != other.wallpaper) return false 21 | 22 | return true 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/glide/effect/EffectLoader.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.glide.effect 2 | 3 | import android.graphics.Bitmap 4 | import com.bumptech.glide.load.Options 5 | import com.bumptech.glide.load.model.ModelLoader 6 | import com.bumptech.glide.load.model.ModelLoaderFactory 7 | import com.bumptech.glide.load.model.MultiModelLoaderFactory 8 | import com.bumptech.glide.signature.ObjectKey 9 | 10 | class EffectLoader : ModelLoader { 11 | override fun handles(model: Effect): Boolean { 12 | return true 13 | } 14 | 15 | override fun buildLoadData(model: Effect, width: Int, height: Int, options: Options): ModelLoader.LoadData? { 16 | return ModelLoader.LoadData(ObjectKey(model), EffectsFetcher(model)) 17 | } 18 | 19 | internal class Factory : ModelLoaderFactory { 20 | override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader { 21 | return EffectLoader() 22 | } 23 | 24 | override fun teardown() { 25 | /* no-op */ 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/glide/folders/ContextFolder.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.glide.folders 2 | 3 | import android.content.Context 4 | import app.simple.peri.models.Folder 5 | 6 | class ContextFolder(val folder: Folder, val context: Context) { 7 | override fun hashCode(): Int { 8 | return folder.hashCode() 9 | } 10 | 11 | override fun equals(other: Any?): Boolean { 12 | return other is ContextFolder 13 | && other.folder.hashcode == folder.hashcode 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/glide/folders/FolderLoader.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.glide.folders 2 | 3 | import android.graphics.Bitmap 4 | import com.bumptech.glide.load.Options 5 | import com.bumptech.glide.load.model.ModelLoader 6 | import com.bumptech.glide.load.model.ModelLoaderFactory 7 | import com.bumptech.glide.load.model.MultiModelLoaderFactory 8 | import com.bumptech.glide.signature.ObjectKey 9 | 10 | class FolderLoader : ModelLoader { 11 | override fun buildLoadData(model: ContextFolder, width: Int, height: Int, options: Options): ModelLoader.LoadData { 12 | return ModelLoader.LoadData(ObjectKey(model), FolderFetcher(model)) 13 | } 14 | 15 | override fun handles(model: ContextFolder): Boolean { 16 | return true 17 | } 18 | 19 | internal class Factory : ModelLoaderFactory { 20 | override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader { 21 | return FolderLoader() 22 | } 23 | 24 | override fun teardown() { 25 | /* no-op */ 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/glide/modules/EffectModule.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.glide.modules 2 | 3 | import android.content.Context 4 | import android.graphics.Bitmap 5 | import app.simple.peri.glide.effect.Effect 6 | import app.simple.peri.glide.effect.EffectLoader 7 | import com.bumptech.glide.Glide 8 | import com.bumptech.glide.Registry 9 | import com.bumptech.glide.annotation.GlideModule 10 | import com.bumptech.glide.module.LibraryGlideModule 11 | 12 | @GlideModule 13 | class EffectModule : LibraryGlideModule() { 14 | override fun registerComponents(context: Context, glide: Glide, registry: Registry) { 15 | registry.append(Effect::class.java, Bitmap::class.java, EffectLoader.Factory()) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/glide/modules/FolderModule.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.glide.modules 2 | 3 | import android.content.Context 4 | import android.graphics.Bitmap 5 | import app.simple.peri.glide.folders.ContextFolder 6 | import app.simple.peri.glide.folders.FolderLoader 7 | import com.bumptech.glide.Glide 8 | import com.bumptech.glide.Registry 9 | import com.bumptech.glide.annotation.GlideModule 10 | import com.bumptech.glide.module.LibraryGlideModule 11 | 12 | @GlideModule 13 | class FolderModule : LibraryGlideModule() { 14 | override fun registerComponents(context: Context, glide: Glide, registry: Registry) { 15 | registry.append(ContextFolder::class.java, Bitmap::class.java, FolderLoader.Factory()) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/glide/modules/TagModule.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.glide.modules 2 | 3 | import android.content.Context 4 | import android.graphics.Bitmap 5 | import app.simple.peri.glide.tags.ContextTag 6 | import app.simple.peri.glide.tags.TagsLoader 7 | import com.bumptech.glide.Glide 8 | import com.bumptech.glide.Registry 9 | import com.bumptech.glide.annotation.GlideModule 10 | import com.bumptech.glide.module.LibraryGlideModule 11 | 12 | @GlideModule 13 | class TagModule : LibraryGlideModule() { 14 | override fun registerComponents(context: Context, glide: Glide, registry: Registry) { 15 | registry.append(ContextTag::class.java, Bitmap::class.java, TagsLoader.Factory()) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/glide/modules/WallpaperModule.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.glide.modules 2 | 3 | import android.content.Context 4 | import android.graphics.Bitmap 5 | import app.simple.peri.glide.wallpaper.Wallpaper 6 | import app.simple.peri.glide.wallpaper.WallpaperLoader 7 | import com.bumptech.glide.Glide 8 | import com.bumptech.glide.GlideBuilder 9 | import com.bumptech.glide.Registry 10 | import com.bumptech.glide.annotation.GlideModule 11 | import com.bumptech.glide.load.DecodeFormat 12 | import com.bumptech.glide.load.engine.DiskCacheStrategy 13 | import com.bumptech.glide.load.resource.bitmap.BitmapTransitionOptions 14 | import com.bumptech.glide.load.resource.bitmap.Downsampler 15 | import com.bumptech.glide.module.AppGlideModule 16 | import com.bumptech.glide.request.RequestOptions 17 | 18 | @GlideModule 19 | class WallpaperModule : AppGlideModule() { 20 | override fun isManifestParsingEnabled(): Boolean { 21 | return false 22 | } 23 | 24 | override fun applyOptions(context: Context, builder: GlideBuilder) { 25 | builder.setDefaultTransitionOptions(Bitmap::class.java, BitmapTransitionOptions.withCrossFade()) 26 | builder.setDefaultRequestOptions( 27 | RequestOptions() 28 | .format(DecodeFormat.PREFER_ARGB_8888) 29 | .set(Downsampler.ALLOW_HARDWARE_CONFIG, false) 30 | .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC) 31 | ) 32 | } 33 | 34 | override fun registerComponents(context: Context, glide: Glide, registry: Registry) { 35 | registry.append(Wallpaper::class.java, Bitmap::class.java, WallpaperLoader.Factory()) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/glide/tags/ContextTag.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.glide.tags 2 | 3 | import android.content.Context 4 | 5 | class ContextTag( 6 | val tag: app.simple.peri.models.Tag, 7 | val context: Context 8 | ) { 9 | override fun equals(other: Any?): Boolean { 10 | if (other is ContextTag) { 11 | return tag == other.tag && tag.sum?.count() == other.tag.sum?.count() 12 | } 13 | 14 | return false 15 | } 16 | 17 | override fun hashCode(): Int { 18 | return tag.hashCode() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/glide/tags/TagsLoader.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.glide.tags 2 | 3 | import android.graphics.Bitmap 4 | import com.bumptech.glide.load.Options 5 | import com.bumptech.glide.load.model.ModelLoader 6 | import com.bumptech.glide.load.model.ModelLoaderFactory 7 | import com.bumptech.glide.load.model.MultiModelLoaderFactory 8 | import com.bumptech.glide.signature.ObjectKey 9 | 10 | class TagsLoader : ModelLoader { 11 | override fun buildLoadData(model: ContextTag, width: Int, height: Int, options: Options): ModelLoader.LoadData { 12 | return ModelLoader.LoadData(ObjectKey(model), TagsFetcher(model)) 13 | } 14 | 15 | override fun handles(model: ContextTag): Boolean { 16 | return true 17 | } 18 | 19 | internal class Factory : ModelLoaderFactory { 20 | override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader { 21 | return TagsLoader() 22 | } 23 | 24 | override fun teardown() { 25 | /* no-op */ 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/glide/transitions/ZoomInTransitionFactory.java: -------------------------------------------------------------------------------- 1 | // ZoomInTransitionFactory.java 2 | package app.simple.peri.glide.transitions; 3 | 4 | import android.graphics.drawable.Drawable; 5 | 6 | import com.bumptech.glide.load.DataSource; 7 | import com.bumptech.glide.request.transition.Transition; 8 | import com.bumptech.glide.request.transition.TransitionFactory; 9 | import com.bumptech.glide.request.transition.ViewPropertyTransition; 10 | 11 | public class ZoomInTransitionFactory implements TransitionFactory { 12 | private final ViewPropertyTransition.Animator animator; 13 | 14 | public ZoomInTransitionFactory() { 15 | this.animator = view -> { 16 | view.setScaleX(0.8f); 17 | view.setScaleY(0.8f); 18 | view.animate().scaleX(1f).scaleY(1f).setDuration(300).start(); 19 | }; 20 | } 21 | 22 | @Override 23 | public Transition build(DataSource dataSource, boolean isFirstResource) { 24 | return new ViewPropertyTransition <>(animator); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/glide/transitions/ZoomOut.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.glide.transitions 2 | 3 | import android.util.Log 4 | import androidx.compose.animation.core.Animatable 5 | import androidx.compose.animation.core.AnimationSpec 6 | import androidx.compose.animation.core.AnimationVector1D 7 | import androidx.compose.animation.core.CubicBezierEasing 8 | import androidx.compose.animation.core.Easing 9 | import androidx.compose.animation.core.VectorConverter 10 | import androidx.compose.animation.core.tween 11 | import androidx.compose.ui.graphics.drawscope.scale 12 | import com.bumptech.glide.integration.compose.DrawPainter 13 | import com.bumptech.glide.integration.compose.Transition 14 | 15 | val LinearOutVerySlowInEasing: Easing = CubicBezierEasing(0.0f, 0.0f, 0.0f, 1.0f) 16 | 17 | class ZoomOut( 18 | private val animationSpec: AnimationSpec 19 | ) : Transition.Factory { 20 | override fun build(): Transition = ZoomOutImpl(animationSpec) 21 | 22 | companion object : Transition.Factory { 23 | override fun build(): Transition = 24 | ZoomOutImpl(animationSpec = tween(400, easing = LinearOutVerySlowInEasing)) 25 | } 26 | 27 | override fun equals(other: Any?): Boolean { 28 | if (other is ZoomOut) { 29 | return animationSpec == other.animationSpec 30 | } 31 | return false 32 | } 33 | 34 | override fun hashCode(): Int { 35 | return animationSpec.hashCode() 36 | } 37 | } 38 | 39 | internal class ZoomOutImpl( 40 | private val animationSpec: AnimationSpec 41 | ) : Transition { 42 | 43 | private companion object { 44 | const val INITIAL_SCALE = 0.75f 45 | const val FINAL_SCALE = 1F 46 | } 47 | 48 | private val animatable: Animatable = 49 | Animatable(INITIAL_SCALE, Float.VectorConverter, FINAL_SCALE) 50 | 51 | override suspend fun transition(invalidate: () -> Unit) { 52 | try { 53 | animatable.animateTo(FINAL_SCALE, animationSpec) 54 | invalidate() 55 | } finally { 56 | animatable.snapTo(FINAL_SCALE) 57 | invalidate() 58 | } 59 | } 60 | 61 | override suspend fun stop() { 62 | animatable.stop() 63 | } 64 | 65 | override val drawPlaceholder: DrawPainter = { painter, size, alpha, colorFilter -> 66 | with(painter) { 67 | scale(animatable.value) { 68 | val normalizedAlpha = (animatable.value - 0.75f) / (1f - 0.75f) 69 | draw(size, normalizedAlpha, colorFilter) 70 | } 71 | } 72 | } 73 | 74 | override val drawCurrent: DrawPainter = { painter, size, alpha, colorFilter -> 75 | with(painter) { 76 | scale(animatable.value) { 77 | val normalizedAlpha = (animatable.value - 0.75f) / (1f - 0.75f) 78 | draw(size, normalizedAlpha, colorFilter) 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/glide/wallpaper/Wallpaper.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.glide.wallpaper 2 | 3 | import android.content.Context 4 | import app.simple.peri.models.Wallpaper 5 | 6 | class Wallpaper( 7 | val wallpaper: Wallpaper, 8 | val context: Context) { 9 | 10 | override fun equals(other: Any?): Boolean { 11 | if (other is Wallpaper) { 12 | return wallpaper == other 13 | } 14 | return false 15 | } 16 | 17 | override fun hashCode(): Int { 18 | return wallpaper.hashCode() 19 | } 20 | } -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/glide/wallpaper/WallpaperLoader.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.glide.wallpaper 2 | 3 | import android.graphics.Bitmap 4 | import com.bumptech.glide.load.Options 5 | import com.bumptech.glide.load.model.ModelLoader 6 | import com.bumptech.glide.load.model.ModelLoaderFactory 7 | import com.bumptech.glide.load.model.MultiModelLoaderFactory 8 | import com.bumptech.glide.signature.ObjectKey 9 | 10 | class WallpaperLoader : ModelLoader { 11 | override fun buildLoadData(model: Wallpaper, width: Int, height: Int, options: Options): ModelLoader.LoadData? { 12 | return ModelLoader.LoadData(ObjectKey(model), WallpaperFetcher(model)) 13 | } 14 | 15 | override fun handles(model: Wallpaper): Boolean { 16 | return true 17 | } 18 | 19 | internal class Factory : ModelLoaderFactory { 20 | override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader { 21 | return WallpaperLoader() 22 | } 23 | 24 | override fun teardown() { 25 | /* no-op */ 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/interfaces/WallpaperCallbacks.java: -------------------------------------------------------------------------------- 1 | package app.simple.peri.interfaces; 2 | 3 | import android.view.View; 4 | 5 | import androidx.constraintlayout.widget.ConstraintLayout; 6 | import app.simple.peri.models.Wallpaper; 7 | 8 | public interface WallpaperCallbacks { 9 | void onWallpaperClicked(Wallpaper wallpaper, int position, ConstraintLayout constraintLayout); 10 | 11 | void onWallpaperLongClicked(Wallpaper wallpaper, int position, View view); 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/math/Ratio.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.math 2 | 3 | import app.simple.peri.models.Ratio 4 | 5 | object Ratio { 6 | 7 | fun greatestCommonDivisor(a: Int, b: Int): Int { 8 | return if (b == 0) a else greatestCommonDivisor(b, a % b) 9 | } 10 | 11 | fun greatestCommonDivisor(a: Long, b: Long): Long { 12 | return if (b == 0L) a else greatestCommonDivisor(b, a % b) 13 | } 14 | 15 | fun greatestCommonDivisor(a: Float, b: Float): Float { 16 | return if (b == 0f) a else greatestCommonDivisor(b, a % b) 17 | } 18 | 19 | fun greatestCommonDivisor(a: Double, b: Double): Double { 20 | return if (b == 0.0) a else greatestCommonDivisor(b, a % b) 21 | } 22 | 23 | fun calculateAspectRatio(width: Int, height: Int): Ratio { 24 | val gcd = greatestCommonDivisor(width, height) 25 | val ratioWidth = width / gcd 26 | val ratioHeight = height / gcd 27 | return Ratio(ratioWidth.toFloat(), ratioHeight.toFloat()) 28 | } 29 | 30 | fun calculateAspectRatio(width: Long, height: Long): Ratio { 31 | val gcd = greatestCommonDivisor(width, height) 32 | val ratioWidth = width / gcd 33 | val ratioHeight = height / gcd 34 | return Ratio(ratioWidth.toFloat(), ratioHeight.toFloat()) 35 | } 36 | 37 | fun calculateAspectRatio(width: Float, height: Float): Ratio { 38 | val gcd = greatestCommonDivisor(width, height) 39 | val ratioWidth = width / gcd 40 | val ratioHeight = height / gcd 41 | return Ratio(ratioWidth, ratioHeight) 42 | } 43 | 44 | fun calculateAspectRatio(width: Double, height: Double): Ratio { 45 | val gcd = greatestCommonDivisor(width, height) 46 | val ratioWidth = width / gcd 47 | val ratioHeight = height / gcd 48 | return Ratio(ratioWidth.toFloat(), ratioHeight.toFloat()) 49 | } 50 | } -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/models/DisplayDimension.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.models 2 | 3 | import android.content.Context 4 | import android.os.Build 5 | import android.util.Log 6 | import android.view.WindowInsets 7 | import android.view.WindowManager 8 | 9 | data class DisplayDimension(var width: Int, var height: Int) { 10 | fun getAspectRatio(): Float { 11 | return if (width > 0 && height > 0) { 12 | width.toFloat() / height.toFloat() 13 | } else { 14 | 1f 15 | } 16 | } 17 | 18 | fun getAspectRatio(context: Context): Float { 19 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 20 | val displayMetrics = context.resources.displayMetrics 21 | val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager 22 | val windowInsets = windowManager.currentWindowMetrics.windowInsets 23 | val insets = windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.statusBars()) 24 | 25 | width = displayMetrics.widthPixels 26 | height = displayMetrics.heightPixels + insets.top 27 | Log.i("DisplayDimension", "Width: $width, Height: $height") 28 | return width.toFloat() / height.toFloat() 29 | } else { 30 | val displayMetrics = context.resources.displayMetrics 31 | width = displayMetrics.widthPixels 32 | height = displayMetrics.heightPixels 33 | Log.i("DisplayDimension", "Width: $width, Height: $height") 34 | return width.toFloat() / height.toFloat() 35 | } 36 | } 37 | 38 | fun getReducedWidth() = width / REDUCER 39 | fun getReducedHeight() = height / REDUCER 40 | 41 | companion object { 42 | const val REDUCER = 5 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/models/LiveWallpaperInfo.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.models 2 | 3 | import android.content.pm.ResolveInfo 4 | import android.graphics.drawable.Drawable 5 | 6 | data class LiveWallpaperInfo( 7 | val name: String, 8 | val icon: Drawable, 9 | val resolveInfo: ResolveInfo 10 | ) 11 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/models/PostWallpaperData.java: -------------------------------------------------------------------------------- 1 | package app.simple.peri.models; 2 | 3 | public class PostWallpaperData { 4 | 5 | private long oldSize = 0; 6 | private long newSize = 0; 7 | private int oldWidth = 0; 8 | private int oldHeight = 0; 9 | private int newWidth = 0; 10 | private int newHeight = 0; 11 | private String path = ""; 12 | 13 | public PostWallpaperData() { 14 | } 15 | 16 | public PostWallpaperData(long oldSize, long newSize, int oldWidth, int oldHeight, int newWidth, int newHeight, String path) { 17 | this.oldSize = oldSize; 18 | this.newSize = newSize; 19 | this.oldWidth = oldWidth; 20 | this.oldHeight = oldHeight; 21 | this.newWidth = newWidth; 22 | this.newHeight = newHeight; 23 | this.path = path; 24 | } 25 | 26 | public long getOldSize() { 27 | return oldSize; 28 | } 29 | 30 | public void setOldSize(long oldSize) { 31 | this.oldSize = oldSize; 32 | } 33 | 34 | public long getNewSize() { 35 | return newSize; 36 | } 37 | 38 | public void setNewSize(long newSize) { 39 | this.newSize = newSize; 40 | } 41 | 42 | public int getOldWidth() { 43 | return oldWidth; 44 | } 45 | 46 | public void setOldWidth(int oldWidth) { 47 | this.oldWidth = oldWidth; 48 | } 49 | 50 | public int getOldHeight() { 51 | return oldHeight; 52 | } 53 | 54 | public void setOldHeight(int oldHeight) { 55 | this.oldHeight = oldHeight; 56 | } 57 | 58 | public int getNewWidth() { 59 | return newWidth; 60 | } 61 | 62 | public void setNewWidth(int newWidth) { 63 | this.newWidth = newWidth; 64 | } 65 | 66 | public int getNewHeight() { 67 | return newHeight; 68 | } 69 | 70 | public void setNewHeight(int newHeight) { 71 | this.newHeight = newHeight; 72 | } 73 | 74 | public String getPath() { 75 | return path; 76 | } 77 | 78 | public void setPath(String path) { 79 | this.path = path; 80 | } 81 | 82 | public float getNewAspectRatio() { 83 | return (float) newWidth / newHeight; 84 | } 85 | 86 | public float getOldAspectRatio() { 87 | return (float) oldWidth / oldHeight; 88 | } 89 | 90 | @Override 91 | public String toString() { 92 | return "PostWallpaperData{" + 93 | "oldSize=" + oldSize + 94 | ", newSize=" + newSize + 95 | ", oldWidth=" + oldWidth + 96 | ", oldHeight=" + oldHeight + 97 | ", newWidth=" + newWidth + 98 | ", newHeight=" + newHeight + 99 | ", path='" + path + '\'' + 100 | '}'; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/models/Ratio.java: -------------------------------------------------------------------------------- 1 | package app.simple.peri.models; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | public class Ratio { 6 | 7 | private final float horizontal; 8 | private final float vertical; 9 | 10 | public Ratio(float horizontal, float vertical) { 11 | this.horizontal = horizontal; 12 | this.vertical = vertical; 13 | } 14 | 15 | public float getHorizontal() { 16 | return horizontal; 17 | } 18 | 19 | public float getVertical() { 20 | return vertical; 21 | } 22 | 23 | @NonNull 24 | @Override 25 | public String toString() { 26 | return "Ratio{" + 27 | "horizontal=" + horizontal + 28 | ", vertical=" + vertical + 29 | '}'; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/models/Tag.java: -------------------------------------------------------------------------------- 1 | package app.simple.peri.models; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | import java.util.HashSet; 7 | import java.util.Objects; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.room.ColumnInfo; 11 | import androidx.room.Entity; 12 | import androidx.room.PrimaryKey; 13 | import androidx.room.TypeConverters; 14 | import app.simple.peri.database.converters.IDListConverter; 15 | 16 | @Entity (tableName = "tags") 17 | public class Tag implements Parcelable { 18 | @PrimaryKey 19 | @NonNull 20 | @ColumnInfo (name = "name") 21 | private String name; 22 | 23 | @ColumnInfo (name = "ids") 24 | @TypeConverters (IDListConverter.class) 25 | @NonNull 26 | private HashSet sum = new HashSet <>(); 27 | 28 | public Tag(@NonNull String name, @NonNull HashSet sum) { 29 | this.name = name; 30 | this.sum = new HashSet <>(sum); 31 | } 32 | 33 | protected Tag(Parcel in) { 34 | name = Objects.requireNonNull(in.readString()); 35 | } 36 | 37 | @Override 38 | public void writeToParcel(Parcel dest, int flags) { 39 | dest.writeString(name); 40 | } 41 | 42 | @Override 43 | public int describeContents() { 44 | return 0; 45 | } 46 | 47 | public static final Creator CREATOR = new Creator <>() { 48 | @Override 49 | public Tag createFromParcel(Parcel in) { 50 | return new Tag(in); 51 | } 52 | 53 | @Override 54 | public Tag[] newArray(int size) { 55 | return new Tag[size]; 56 | } 57 | }; 58 | 59 | @NonNull 60 | public String getName() { 61 | return name; 62 | } 63 | 64 | public void setName(@NonNull String name) { 65 | this.name = name; 66 | } 67 | 68 | public HashSet getSum() { 69 | return sum; 70 | } 71 | 72 | public void setSum(HashSet sum) { 73 | this.sum = sum; 74 | } 75 | 76 | public void addSum(String sum) { 77 | this.sum.add(sum); 78 | } 79 | 80 | @NonNull 81 | @Override 82 | public String toString() { 83 | return "Tag{" + 84 | ", tag='" + name + '\'' + 85 | ", sum=" + sum + 86 | '}'; 87 | } 88 | 89 | @Override 90 | public boolean equals(Object o) { 91 | if (this == o) { 92 | return true; 93 | } 94 | if (o == null || getClass() != o.getClass()) { 95 | return false; 96 | } 97 | 98 | Tag tag1 = (Tag) o; 99 | 100 | if (!Objects.equals(name, tag1.name)) { 101 | return false; 102 | } 103 | return Objects.equals(sum, tag1.sum); 104 | } 105 | 106 | @Override 107 | public int hashCode() { 108 | int result = name.hashCode(); 109 | result = 31 * result + (sum != null ? sum.hashCode() : 0); 110 | return result; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/preferences/CrashPreferences.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.preferences 2 | 3 | import android.annotation.SuppressLint 4 | 5 | @SuppressLint("UseKtx") 6 | object CrashPreferences { 7 | 8 | private const val CRASH_TIMESTAMP = "crash_timestamp" 9 | private const val CRASH_MESSAGE = "crash_message" 10 | private const val CRASH_CAUSE = "crashCause" 11 | 12 | const val CRASH_TIMESTAMP_EMPTY_DEFAULT = -1L 13 | 14 | // ---------------------------------------------------------------------------------------------------------- // 15 | 16 | fun saveCrashLog(value: Long): Boolean { 17 | return SharedPreferences.getSharedPreferences().edit().putLong(CRASH_TIMESTAMP, value).commit() 18 | } 19 | 20 | fun getCrashLog(): Long { 21 | return SharedPreferences.getSharedPreferences().getLong(CRASH_TIMESTAMP, CRASH_TIMESTAMP_EMPTY_DEFAULT) 22 | } 23 | 24 | // ---------------------------------------------------------------------------------------------------------- // 25 | 26 | fun saveMessage(value: String?): Boolean { 27 | return SharedPreferences.getSharedPreferences().edit().putString(CRASH_MESSAGE, value).commit() 28 | } 29 | 30 | fun getMessage(): String? { 31 | return SharedPreferences.getSharedPreferences().getString(CRASH_MESSAGE, null) 32 | } 33 | 34 | // ---------------------------------------------------------------------------------------------------------- // 35 | 36 | fun saveCause(value: String?): Boolean { 37 | return SharedPreferences.getSharedPreferences().edit().putString(CRASH_CAUSE, value).commit() 38 | } 39 | 40 | fun getCause(): String? { 41 | return SharedPreferences.getSharedPreferences().getString(CRASH_CAUSE, null) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/preferences/SharedPreferences.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.preferences 2 | 3 | import android.content.Context 4 | import android.content.SharedPreferences 5 | import app.simple.peri.utils.ConditionUtils.isNull 6 | 7 | object SharedPreferences { 8 | 9 | private const val PREFERENCES = "Preferences" 10 | private var sharedPreferences: SharedPreferences? = null 11 | 12 | fun init(context: Context) { 13 | if (sharedPreferences.isNull()) { 14 | sharedPreferences = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE) 15 | } 16 | } 17 | 18 | /** 19 | * Singleton to hold reference of SharedPreference. 20 | * Call [init] first before making a instance request 21 | * 22 | * @see init 23 | * @throws NullPointerException 24 | */ 25 | fun getSharedPreferences(): SharedPreferences { 26 | return sharedPreferences ?: throw NullPointerException() 27 | } 28 | 29 | fun registerSharedPreferencesListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) { 30 | getSharedPreferences().registerOnSharedPreferenceChangeListener(listener) 31 | } 32 | 33 | fun unregisterListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) { 34 | getSharedPreferences().unregisterOnSharedPreferenceChangeListener(listener) 35 | } 36 | 37 | /** 38 | * Use this function to register shared preference change listener if 39 | * the current context has [SharedPreferences.OnSharedPreferenceChangeListener] 40 | * implemented. 41 | */ 42 | fun SharedPreferences.OnSharedPreferenceChangeListener.registerSharedPreferenceChangeListener() { 43 | registerSharedPreferencesListener(this) 44 | } 45 | 46 | /** 47 | * Use this function to unregister shared preference change listener if 48 | * the current context has [SharedPreferences.OnSharedPreferenceChangeListener] 49 | * implemented. 50 | */ 51 | fun SharedPreferences.OnSharedPreferenceChangeListener.unregisterSharedPreferenceChangeListener() { 52 | unregisterListener(this) 53 | } 54 | 55 | /** 56 | * Singleton to hold reference of SharedPreference. 57 | * 58 | * @see init 59 | */ 60 | fun getSharedPreferences(context: Context): SharedPreferences { 61 | kotlin.runCatching { 62 | return sharedPreferences ?: throw NullPointerException() 63 | }.getOrElse { 64 | init(context) 65 | return sharedPreferences!! 66 | } 67 | } 68 | 69 | fun getSharedPreferencesPath(context: Context): String { 70 | return context.applicationInfo.dataDir + "/shared_prefs/" + PREFERENCES + ".xml" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/receivers/BootReceiver.java: -------------------------------------------------------------------------------- 1 | package app.simple.peri.receivers; 2 | 3 | import android.app.AlarmManager; 4 | import android.app.PendingIntent; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.util.Log; 8 | import android.widget.Toast; 9 | 10 | import app.simple.peri.BuildConfig; 11 | import app.simple.peri.preferences.MainPreferences; 12 | import app.simple.peri.preferences.SharedPreferences; 13 | import app.simple.peri.services.AutoWallpaperService; 14 | 15 | import static android.content.Context.ALARM_SERVICE; 16 | 17 | public class BootReceiver extends android.content.BroadcastReceiver { 18 | @Override 19 | public void onReceive(Context context, Intent intent) { 20 | SharedPreferences.INSTANCE.init(context.getApplicationContext()); 21 | 22 | if (intent.getAction() != null) { 23 | if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) { 24 | try { 25 | setAutoWallpaperAlarm(context); 26 | 27 | if (BuildConfig.DEBUG) { 28 | Toast.makeText(context, "Peristyle: Auto wallpaper enabled", Toast.LENGTH_SHORT).show(); 29 | } 30 | 31 | Log.d("BootReceiver", "Boot completed action received, auto wallpaper enabled"); 32 | } catch (Exception e) { 33 | if (BuildConfig.DEBUG) { 34 | Toast.makeText(context, "Peristyle: Error setting auto wallpaper", Toast.LENGTH_SHORT).show(); 35 | } 36 | 37 | Log.e("BootReceiver", "Error setting auto wallpaper", e); 38 | } 39 | } 40 | } 41 | } 42 | 43 | private void setAutoWallpaperAlarm(Context context) { 44 | AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE); 45 | Intent intent = new Intent(context.getApplicationContext(), AutoWallpaperService.class); 46 | PendingIntent pendingIntent = PendingIntent.getService(context.getApplicationContext(), 0, intent, PendingIntent.FLAG_IMMUTABLE); 47 | 48 | // Cancel any existing alarms 49 | alarmManager.cancel(pendingIntent); 50 | 51 | if (Integer.parseInt(MainPreferences.INSTANCE.getAutoWallpaperInterval()) > 0) { 52 | int interval = Integer.parseInt(MainPreferences.INSTANCE.getAutoWallpaperInterval()); 53 | alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent); 54 | Log.d("MainActivity", "Auto wallpaper alarm set for every " + MainPreferences.INSTANCE.getAutoWallpaperInterval() + " ms"); 55 | } else { 56 | Log.d("MainActivity", "Auto wallpaper alarm cancelled"); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/receivers/CopyActionReceiver.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.receivers 2 | 3 | import android.app.NotificationManager 4 | import android.content.BroadcastReceiver 5 | import android.content.ClipData 6 | import android.content.ClipboardManager 7 | import android.content.Context 8 | import android.content.Intent 9 | import android.widget.Toast 10 | import app.simple.peri.abstraction.AbstractComposeAutoWallpaperService 11 | import app.simple.peri.utils.WallpaperServiceNotification 12 | 13 | class CopyActionReceiver : BroadcastReceiver() { 14 | override fun onReceive(context: Context, intent: Intent) { 15 | if (intent.action == AbstractComposeAutoWallpaperService.ACTION_COPY_ERROR_MESSAGE) { 16 | val message = intent.getStringExtra(AbstractComposeAutoWallpaperService.EXTRA_ERROR_MESSAGE) 17 | val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager 18 | val clip = ClipData.newPlainText("Error Message", message) 19 | clipboard.setPrimaryClip(clip) 20 | Toast.makeText(context, "Error message copied to clipboard", Toast.LENGTH_SHORT).show() 21 | 22 | val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager 23 | notificationManager.cancel(WallpaperServiceNotification.ERROR_NOTIFICATION_ID) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/repository/WallpaperRepository.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.repository 2 | 3 | import app.simple.peri.database.dao.WallpaperDao 4 | import app.simple.peri.models.Wallpaper 5 | import kotlinx.coroutines.flow.Flow 6 | 7 | class WallpaperRepository(private val wallpaperDao: WallpaperDao) { 8 | fun getAllWallpapers(): Flow> = wallpaperDao.getWallpapersFlow() 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/services/NextWallpaperTileService.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.services 2 | 3 | import android.content.Intent 4 | import android.service.quicksettings.TileService 5 | 6 | class NextWallpaperTileService : TileService() { 7 | 8 | override fun onClick() { 9 | super.onClick() 10 | val intent = Intent(applicationContext, AutoWallpaperService::class.java) 11 | intent.action = AutoWallpaperService.ACTION_NEXT_WALLPAPER 12 | applicationContext.startService(intent) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/ui/commons/AnimatedCircularProgress.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.ui.commons 2 | 3 | import androidx.activity.ComponentActivity 4 | import androidx.activity.compose.LocalActivity 5 | import androidx.compose.animation.core.animateFloatAsState 6 | import androidx.compose.foundation.Canvas 7 | import androidx.compose.foundation.layout.size 8 | import androidx.compose.runtime.Composable 9 | import androidx.compose.runtime.collectAsState 10 | import androidx.compose.runtime.getValue 11 | import androidx.compose.ui.Modifier 12 | import androidx.compose.ui.geometry.Offset 13 | import androidx.compose.ui.geometry.Size 14 | import androidx.compose.ui.graphics.Brush 15 | import androidx.compose.ui.graphics.Color 16 | import androidx.compose.ui.graphics.drawscope.Stroke 17 | import androidx.compose.ui.unit.dp 18 | import androidx.lifecycle.viewmodel.compose.viewModel 19 | import app.simple.peri.utils.CommonUtils.toSeconds 20 | import app.simple.peri.viewmodels.HomeScreenViewModel 21 | 22 | @Composable 23 | fun AnimatedCircularProgress(modifier: Modifier = Modifier) { 24 | val homeScreenViewModel: HomeScreenViewModel = viewModel( 25 | LocalActivity.current as ComponentActivity 26 | ) 27 | 28 | val progress = homeScreenViewModel.countDownFlow 29 | .collectAsState(initial = HomeScreenViewModel.RANDOM_WALLPAPER_DELAY).value.toFloat().toSeconds() 30 | .div(HomeScreenViewModel.RANDOM_WALLPAPER_DELAY.toFloat().toSeconds()) 31 | .coerceIn(0f, 1f) 32 | 33 | val animatedProgress by animateFloatAsState(targetValue = progress, label = "") 34 | 35 | Canvas(modifier = modifier.size(32.dp)) { 36 | val strokeWidth = 4.dp.toPx() 37 | val radius = size.minDimension / 2 - strokeWidth / 2 38 | val center = Offset(size.width / 2, size.height / 2) 39 | 40 | drawCircle( 41 | brush = Brush.linearGradient( 42 | colors = listOf(Color.Red, Color.Yellow, Color.Green) 43 | ), 44 | center = center, 45 | radius = radius, 46 | style = Stroke(width = strokeWidth) 47 | ) 48 | 49 | drawArc( 50 | brush = Brush.linearGradient( 51 | colors = listOf(Color.Cyan, Color.Magenta, Color.Blue) 52 | ), 53 | startAngle = -90f, 54 | sweepAngle = 360 * animatedProgress, 55 | useCenter = false, 56 | topLeft = Offset(center.x - radius, center.y - radius), 57 | size = Size(radius * 2, radius * 2), 58 | style = Stroke(width = strokeWidth) 59 | ) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/ui/commons/CircularCountdownProgress.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.ui.commons 2 | 3 | import androidx.activity.ComponentActivity 4 | import androidx.activity.compose.LocalActivity 5 | import androidx.compose.foundation.layout.size 6 | import androidx.compose.material3.CircularProgressIndicator 7 | import androidx.compose.material3.MaterialTheme 8 | import androidx.compose.runtime.Composable 9 | import androidx.compose.runtime.collectAsState 10 | import androidx.compose.ui.Modifier 11 | import androidx.compose.ui.graphics.Color 12 | import androidx.compose.ui.unit.dp 13 | import androidx.lifecycle.viewmodel.compose.viewModel 14 | import app.simple.peri.utils.CommonUtils.toSeconds 15 | import app.simple.peri.viewmodels.HomeScreenViewModel 16 | 17 | @Composable 18 | fun CircularCountdownProgress(modifier: Modifier = Modifier) { 19 | val homeScreenViewModel: HomeScreenViewModel = viewModel( 20 | LocalActivity.current as ComponentActivity 21 | ) 22 | 23 | val progress = homeScreenViewModel.countDownFlow 24 | .collectAsState(initial = HomeScreenViewModel.RANDOM_WALLPAPER_DELAY).value.toFloat().toSeconds() 25 | .div(HomeScreenViewModel.RANDOM_WALLPAPER_DELAY.toFloat().toSeconds()) 26 | .coerceIn(0f, 1f) 27 | 28 | CircularProgressIndicator( 29 | progress = { progress }, 30 | modifier = modifier 31 | .size(32.dp), 32 | color = MaterialTheme.colorScheme.primary, 33 | strokeWidth = 4.dp, 34 | gapSize = 0.dp, 35 | trackColor = Color.Transparent 36 | ) 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/ui/commons/DisplayDimension.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.ui.commons 2 | 3 | import android.util.Log 4 | import android.view.ViewTreeObserver 5 | import androidx.compose.runtime.Composable 6 | import androidx.compose.runtime.DisposableEffect 7 | import androidx.compose.ui.platform.LocalView 8 | import app.simple.peri.ui.screens.displayDimension 9 | 10 | @Composable 11 | fun InitDisplayDimension() { 12 | val view = LocalView.current 13 | 14 | DisposableEffect(view) { 15 | val observer = view.viewTreeObserver 16 | val listener = object : ViewTreeObserver.OnGlobalLayoutListener { 17 | override fun onGlobalLayout() { 18 | if (observer.isAlive) { 19 | observer.removeOnGlobalLayoutListener(this) 20 | displayDimension.width = view.width 21 | displayDimension.height = view.height 22 | Log.i("InitDisplayDimension", "Width: ${displayDimension.width}, Height: ${displayDimension.height}") 23 | } 24 | } 25 | } 26 | observer.addOnGlobalLayoutListener(listener) 27 | 28 | onDispose { 29 | observer.removeOnGlobalLayoutListener(listener) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/ui/commons/Effect.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.ui.commons 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Parcelable 6 | import androidx.activity.compose.rememberLauncherForActivityResult 7 | import androidx.activity.result.contract.ActivityResultContracts 8 | import androidx.compose.runtime.Composable 9 | import androidx.compose.runtime.LaunchedEffect 10 | import androidx.compose.ui.platform.LocalContext 11 | import androidx.core.content.IntentCompat 12 | import app.simple.peri.activities.main.EffectsActivity 13 | import app.simple.peri.models.Effect 14 | import app.simple.peri.models.Wallpaper 15 | 16 | @Composable 17 | fun LaunchEffectActivity(wallpaper: Wallpaper, onEffect: (Effect) -> Unit, onCanceled: () -> Unit) { 18 | val context = LocalContext.current 19 | val launcher = rememberLauncherForActivityResult( 20 | contract = ActivityResultContracts.StartActivityForResult() 21 | ) { result -> 22 | if (result.resultCode == Activity.RESULT_OK) { 23 | val effect = IntentCompat.getParcelableExtra(result.data!!, "effect", Effect::class.java) 24 | onEffect(effect!!) 25 | } else { 26 | onCanceled() 27 | } 28 | } 29 | 30 | // Launch the effect activity 31 | LaunchedEffect(Unit) { 32 | val intent = Intent(context, EffectsActivity::class.java) 33 | intent.putExtra("wallpaper", wallpaper as Parcelable) 34 | launcher.launch(intent) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/ui/commons/Permission.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.ui.commons 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.util.Log 6 | import androidx.activity.compose.rememberLauncherForActivityResult 7 | import androidx.activity.result.contract.ActivityResultContracts 8 | import androidx.compose.runtime.Composable 9 | import androidx.compose.runtime.LaunchedEffect 10 | import androidx.compose.ui.platform.LocalContext 11 | import app.simple.peri.activities.main.PathChooserActivity 12 | 13 | @Composable 14 | fun FolderBrowser(onCancel: () -> Unit, onStorageGranted: (String) -> Unit) { 15 | val context = LocalContext.current 16 | val launcher = rememberLauncherForActivityResult( 17 | contract = ActivityResultContracts.StartActivityForResult() 18 | ) { result -> 19 | if (result.resultCode == Activity.RESULT_OK) { 20 | val chosenPath = result.data?.getStringExtra("chosen_path") 21 | ?: return@rememberLauncherForActivityResult 22 | Log.i("PathChooserActivity", "Chosen path: $chosenPath") 23 | onStorageGranted(chosenPath) 24 | } else { 25 | onCancel() 26 | } 27 | } 28 | 29 | // Launch the directory selection intent 30 | LaunchedEffect(Unit) { 31 | val intent = Intent(context, PathChooserActivity::class.java) 32 | launcher.launch(intent) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/ui/commons/TextWithIcon.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.ui.commons 2 | 3 | import androidx.compose.foundation.layout.Row 4 | import androidx.compose.foundation.layout.Spacer 5 | import androidx.compose.foundation.layout.size 6 | import androidx.compose.material3.Icon 7 | import androidx.compose.material3.MaterialTheme 8 | import androidx.compose.material3.Text 9 | import androidx.compose.runtime.Composable 10 | import androidx.compose.ui.Alignment 11 | import androidx.compose.ui.Modifier 12 | import androidx.compose.ui.graphics.Color 13 | import androidx.compose.ui.graphics.vector.ImageVector 14 | import androidx.compose.ui.unit.dp 15 | 16 | @Composable 17 | fun TextWithIcon(imageVector: ImageVector, tint: Color, text: String, modifier: Modifier) { 18 | Row( 19 | modifier = modifier 20 | ) { 21 | Icon( 22 | imageVector = imageVector, 23 | contentDescription = null, 24 | modifier = Modifier 25 | .size(16.dp) 26 | .align(Alignment.CenterVertically), 27 | tint = tint 28 | ) 29 | Spacer( 30 | modifier = Modifier.size(4.dp) 31 | ) 32 | Text( 33 | text = text, 34 | style = MaterialTheme.typography.bodySmall, 35 | modifier = Modifier.align(Alignment.CenterVertically) 36 | ) 37 | } 38 | } -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/ui/commons/VignetteImage.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.ui.commons 2 | 3 | import androidx.compose.foundation.ExperimentalFoundationApi 4 | import androidx.compose.foundation.combinedClickable 5 | import androidx.compose.foundation.layout.Box 6 | import androidx.compose.foundation.layout.fillMaxSize 7 | import androidx.compose.runtime.Composable 8 | import androidx.compose.ui.Modifier 9 | import androidx.compose.ui.draw.drawWithContent 10 | import androidx.compose.ui.graphics.BlendMode 11 | import androidx.compose.ui.graphics.Brush 12 | import androidx.compose.ui.graphics.Color 13 | import androidx.compose.ui.graphics.ColorFilter 14 | import androidx.compose.ui.layout.ContentScale 15 | import me.saket.telephoto.zoomable.glide.ZoomableGlideImage 16 | 17 | @OptIn(ExperimentalFoundationApi::class) 18 | @Composable 19 | fun VignetteImage( 20 | model: Any, 21 | contentDescription: String?, 22 | modifier: Modifier = Modifier, 23 | contentScale: ContentScale = ContentScale.Crop, 24 | colorFilter: ColorFilter? = null, 25 | onClick: () -> Unit = {}, 26 | onLongClick: () -> Unit = {} 27 | ) { 28 | Box( 29 | modifier = modifier 30 | .fillMaxSize() 31 | .drawWithContent { 32 | drawContent() 33 | drawRect( 34 | brush = Brush.radialGradient( 35 | colors = listOf(Color.Transparent, Color.Black), 36 | center = center, 37 | radius = size.minDimension / 2 38 | ), 39 | blendMode = BlendMode.Multiply 40 | ) 41 | } 42 | .combinedClickable( 43 | onClick = onClick, 44 | onLongClick = onLongClick 45 | ) 46 | ) { 47 | ZoomableGlideImage( 48 | model = model, 49 | contentDescription = contentDescription, 50 | modifier = Modifier.fillMaxSize(), 51 | contentScale = contentScale, 52 | colorFilter = colorFilter 53 | ) { 54 | it 55 | .disallowHardwareConfig() 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/ui/constants/DialogConstants.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.ui.constants 2 | 3 | import androidx.compose.ui.unit.sp 4 | 5 | val DIALOG_TITLE_FONT_SIZE = 18.sp 6 | val DIALOG_OPTION_FONT_SIZE = 16.sp 7 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/ui/dialogs/common/PleaseWaitDialog.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.ui.dialogs.common 2 | 3 | import androidx.compose.foundation.layout.Row 4 | import androidx.compose.foundation.layout.Spacer 5 | import androidx.compose.foundation.layout.padding 6 | import androidx.compose.foundation.layout.width 7 | import androidx.compose.material3.AlertDialog 8 | import androidx.compose.material3.CircularProgressIndicator 9 | import androidx.compose.material3.MaterialTheme 10 | import androidx.compose.material3.Text 11 | import androidx.compose.runtime.Composable 12 | import androidx.compose.ui.Modifier 13 | import androidx.compose.ui.res.stringResource 14 | import androidx.compose.ui.unit.dp 15 | import androidx.compose.ui.window.DialogProperties 16 | import app.simple.peri.R 17 | 18 | @Composable 19 | fun PleaseWaitDialog(stateText: String = stringResource(id = R.string.please_wait), onDismissRequest: () -> Unit) { 20 | AlertDialog( 21 | onDismissRequest = { onDismissRequest() }, 22 | title = { }, 23 | text = { 24 | Row( 25 | modifier = Modifier.padding(top = 8.dp), 26 | verticalAlignment = androidx.compose.ui.Alignment.CenterVertically 27 | ) { 28 | CircularProgressIndicator( 29 | strokeWidth = 6.dp, 30 | color = MaterialTheme.colorScheme.primary 31 | ) 32 | Spacer(modifier = Modifier.width(16.dp)) 33 | Text(stateText) 34 | } 35 | }, 36 | confirmButton = { 37 | 38 | }, 39 | dismissButton = { 40 | 41 | }, 42 | properties = DialogProperties( 43 | dismissOnBackPress = false, 44 | dismissOnClickOutside = false 45 | ) 46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/ui/dialogs/common/ShowWarningDialog.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.ui.dialogs.common 2 | 3 | import androidx.compose.material3.AlertDialog 4 | import androidx.compose.material3.Button 5 | import androidx.compose.material3.Text 6 | import androidx.compose.runtime.Composable 7 | import androidx.compose.ui.platform.LocalContext 8 | 9 | @Composable 10 | fun ShowWarningDialog(title: String, warning: String, onDismiss: () -> Unit) { 11 | val context = LocalContext.current 12 | 13 | AlertDialog( 14 | onDismissRequest = onDismiss, 15 | title = { 16 | Text(text = title) 17 | }, 18 | text = { 19 | Text(text = warning) 20 | }, 21 | confirmButton = { 22 | Button( 23 | onClick = onDismiss 24 | ) { 25 | Text(text = context.getString(android.R.string.ok)) 26 | } 27 | } 28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/ui/dialogs/common/SureDialog.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.ui.dialogs.common 2 | 3 | import androidx.compose.foundation.layout.Column 4 | import androidx.compose.material3.AlertDialog 5 | import androidx.compose.material3.Button 6 | import androidx.compose.material3.MaterialTheme 7 | import androidx.compose.material3.Text 8 | import androidx.compose.runtime.Composable 9 | import androidx.compose.ui.res.stringResource 10 | import androidx.compose.ui.unit.sp 11 | import app.simple.peri.R 12 | 13 | @Composable 14 | fun SureDialog( 15 | title: String = stringResource(R.string.delete), 16 | message: String, 17 | onSure: () -> Unit, 18 | onDismiss: () -> Unit 19 | ) { 20 | AlertDialog( 21 | onDismissRequest = { onDismiss() }, 22 | title = { 23 | Text(text = title) 24 | }, 25 | text = { 26 | Column { 27 | Text( 28 | text = message, 29 | fontSize = 14.sp, 30 | color = MaterialTheme.colorScheme.secondary, 31 | lineHeight = 16.sp 32 | ) 33 | } 34 | }, 35 | confirmButton = { 36 | Button(onClick = { onSure() }) { 37 | Text(stringResource(id = R.string.yes)) 38 | } 39 | }, 40 | dismissButton = { 41 | Button(onClick = { onDismiss() }) { 42 | Text(stringResource(id = R.string.no)) 43 | } 44 | }, 45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/ui/dialogs/livewallpapers/LiveWallpapersMenu.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.ui.dialogs.livewallpapers 2 | 3 | import androidx.compose.foundation.layout.Column 4 | import androidx.compose.foundation.layout.fillMaxWidth 5 | import androidx.compose.material3.AlertDialog 6 | import androidx.compose.material3.Button 7 | import androidx.compose.material3.ButtonDefaults 8 | import androidx.compose.material3.MaterialTheme 9 | import androidx.compose.material3.Text 10 | import androidx.compose.runtime.Composable 11 | import androidx.compose.ui.Modifier 12 | import androidx.compose.ui.graphics.Color 13 | import androidx.compose.ui.res.stringResource 14 | import androidx.compose.ui.text.font.FontWeight 15 | import androidx.compose.ui.text.style.TextAlign 16 | import app.simple.peri.R 17 | import app.simple.peri.models.LiveWallpaperInfo 18 | import app.simple.peri.ui.constants.DIALOG_OPTION_FONT_SIZE 19 | 20 | @Composable 21 | fun LiveWallpapersMenu(liveWallpaperInfo: LiveWallpaperInfo? = null, onDismiss: () -> Unit, onOptionSelected: (String) -> Unit) { 22 | val options = listOf( 23 | stringResource(R.string.delete) 24 | ) 25 | 26 | AlertDialog( 27 | title = { 28 | Text( 29 | text = liveWallpaperInfo?.name ?: "", 30 | ) 31 | }, 32 | onDismissRequest = { onDismiss() }, 33 | text = { 34 | Column { 35 | options.forEach { option -> 36 | Button( 37 | onClick = { 38 | onOptionSelected(option) 39 | onDismiss() 40 | }, 41 | colors = ButtonDefaults.buttonColors( 42 | containerColor = Color.Transparent, 43 | contentColor = MaterialTheme.colorScheme.onSurface 44 | ), 45 | modifier = Modifier.fillMaxWidth() 46 | ) { 47 | Text( 48 | text = option, 49 | color = MaterialTheme.colorScheme.onSurface, 50 | modifier = Modifier.fillMaxWidth(), 51 | textAlign = TextAlign.Center, 52 | fontWeight = FontWeight.Bold, 53 | fontSize = DIALOG_OPTION_FONT_SIZE 54 | ) 55 | } 56 | } 57 | } 58 | }, 59 | confirmButton = { 60 | Button( 61 | onClick = { 62 | onDismiss() 63 | } 64 | ) { 65 | Text(text = stringResource(R.string.close)) 66 | } 67 | }, 68 | ) 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/ui/dialogs/settings/ShowInureAppManagerDialog.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.ui.dialogs.settings 2 | 3 | import android.content.Intent 4 | import androidx.compose.foundation.layout.Column 5 | import androidx.compose.foundation.layout.fillMaxWidth 6 | import androidx.compose.material3.AlertDialog 7 | import androidx.compose.material3.Button 8 | import androidx.compose.material3.Text 9 | import androidx.compose.runtime.Composable 10 | import androidx.compose.ui.platform.LocalContext 11 | import androidx.compose.ui.res.stringResource 12 | import androidx.compose.ui.window.DialogProperties 13 | import androidx.core.net.toUri 14 | import app.simple.peri.R 15 | 16 | private const val INURE_GITHUB_URL = "https://github.com/Hamza417/Inure" 17 | private const val INURE_PLAY_STORE_URL = "https://play.google.com/store/apps/details?id=app.simple.inure.play" 18 | private const val INURE_F_DROID_URL = "https://f-droid.org/packages/app.simple.inure" 19 | private const val INURE_IZZY_URL = "https://apt.izzysoft.de/fdroid/index/apk/app.simple.inure/" 20 | 21 | @Composable 22 | fun ShowInureAppManagerDialog(onDismiss: () -> Unit) { 23 | val context = LocalContext.current 24 | val list = listOf("GitHub", "Play Store", "F-Droid", "IzzyOnDroid") 25 | 26 | AlertDialog( 27 | onDismissRequest = { 28 | onDismiss() 29 | }, 30 | title = { Text(text = stringResource(id = R.string.inure_app_manager)) }, 31 | text = { 32 | Column( 33 | modifier = androidx.compose.ui.Modifier.fillMaxWidth(), 34 | horizontalAlignment = androidx.compose.ui.Alignment.CenterHorizontally 35 | ) { 36 | list.forEachIndexed { index, item -> 37 | Button( 38 | modifier = androidx.compose.ui.Modifier.fillMaxWidth(), 39 | onClick = { 40 | val url = when (index) { 41 | 0 -> INURE_GITHUB_URL 42 | 1 -> INURE_PLAY_STORE_URL 43 | 2 -> INURE_F_DROID_URL 44 | 3 -> INURE_IZZY_URL 45 | else -> INURE_GITHUB_URL 46 | } 47 | val intent = Intent(Intent.ACTION_VIEW, url.toUri()) 48 | context.startActivity(intent) 49 | }) { 50 | Text(text = item) 51 | } 52 | } 53 | } 54 | }, 55 | confirmButton = { 56 | Button( 57 | onClick = { 58 | onDismiss() 59 | } 60 | ) { 61 | Text(text = stringResource(id = R.string.close)) 62 | } 63 | }, 64 | properties = DialogProperties(dismissOnClickOutside = true) 65 | ) 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/ui/dialogs/settings/ShowPositionalDialog.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.ui.dialogs.settings 2 | 3 | import android.content.Intent 4 | import android.net.Uri 5 | import androidx.compose.foundation.layout.Column 6 | import androidx.compose.foundation.layout.fillMaxWidth 7 | import androidx.compose.material3.AlertDialog 8 | import androidx.compose.material3.Button 9 | import androidx.compose.material3.Text 10 | import androidx.compose.runtime.Composable 11 | import androidx.compose.ui.platform.LocalContext 12 | import androidx.compose.ui.res.stringResource 13 | import androidx.compose.ui.window.DialogProperties 14 | import app.simple.peri.R 15 | 16 | private const val POSITIONAL_GITHUB_URL = "https://github.com/Hamza417/Positional" 17 | private const val POSITIONAL_PLAY_STORE_URL = "https://play.google.com/store/apps/details?id=app.simple.positional" 18 | 19 | @Composable 20 | fun ShowPositionalDialog(onDismiss: () -> Unit) { 21 | val context = LocalContext.current 22 | val list = listOf("GitHub", "Play Store") 23 | 24 | AlertDialog( 25 | onDismissRequest = { onDismiss() }, 26 | title = { Text(text = stringResource(id = R.string.positional)) }, 27 | text = { 28 | Column( 29 | modifier = androidx.compose.ui.Modifier.fillMaxWidth(), 30 | horizontalAlignment = androidx.compose.ui.Alignment.CenterHorizontally 31 | ) { 32 | list.forEachIndexed { index, item -> 33 | Button( 34 | modifier = androidx.compose.ui.Modifier.fillMaxWidth(), 35 | onClick = { 36 | val url = when (index) { 37 | 0 -> POSITIONAL_GITHUB_URL 38 | 1 -> POSITIONAL_PLAY_STORE_URL 39 | else -> POSITIONAL_GITHUB_URL 40 | } 41 | val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) 42 | context.startActivity(intent) 43 | onDismiss() 44 | }) { 45 | Text(text = item) 46 | } 47 | } 48 | } 49 | }, 50 | confirmButton = { 51 | Button( 52 | onClick = { 53 | onDismiss() 54 | } 55 | ) { 56 | Text(text = stringResource(id = R.string.close)) 57 | } 58 | }, 59 | properties = DialogProperties(dismissOnClickOutside = true) 60 | ) 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/ui/nav/Routes.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.ui.nav 2 | 3 | object Routes { 4 | const val SETUP = "setup" 5 | const val HOME = "home" 6 | const val LIST = "list" 7 | const val WALLPAPER = "wallpaper" 8 | const val SETTINGS = "settings" 9 | const val WALLPAPERS_LIST = "wallpapers" 10 | const val AUTO_WALLPAPER = "auto_wallpaper" 11 | const val LIVE_AUTO_WALLPAPER = "live_auto_wallpaper" 12 | const val TAGS = "tags" 13 | const val TAGGED_WALLPAPERS = "tagged_wallpapers" 14 | const val FOLDERS = "folders" 15 | const val LIVE_WALLPAPERS = "live_wallpapers" 16 | 17 | const val WALLPAPER_ARG = "wallpaper_arg" 18 | const val FOLDER_ARG = "folder_arg" 19 | const val TAG_ARG = "tag_arg" 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/ui/settings/SkipColumn.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.ui.settings 2 | 3 | import DescriptionPreference 4 | import SecondaryHeader 5 | import SwitchPreference 6 | import androidx.compose.runtime.Composable 7 | import androidx.compose.ui.res.stringResource 8 | import androidx.compose.ui.unit.dp 9 | import app.simple.peri.R 10 | import app.simple.peri.preferences.MainComposePreferences 11 | 12 | @Composable 13 | fun SkipColumn() { 14 | SecondaryHeader(title = stringResource(R.string.skip)) 15 | DescriptionPreference(description = stringResource(R.string.skip_when_condition_summary)) 16 | 17 | SwitchPreference( 18 | title = stringResource(R.string.skip_when_portrait), 19 | checked = MainComposePreferences.getDontChangeWhenPortrait(), 20 | topPadding = 4.dp 21 | ) { 22 | MainComposePreferences.setDontChangeWhenPortrait(it) 23 | } 24 | 25 | SwitchPreference( 26 | title = stringResource(R.string.skip_when_landscape), 27 | checked = MainComposePreferences.getDontChangeWhenLandscape(), 28 | topPadding = 4.dp 29 | ) { 30 | MainComposePreferences.setDontChangeWhenLandscape(it) 31 | } 32 | 33 | SwitchPreference( 34 | title = stringResource(R.string.skip_when_low_battery), 35 | checked = MainComposePreferences.getDontChangeWhenLowBattery(), 36 | topPadding = 4.dp 37 | ) { 38 | MainComposePreferences.setDontChangeWhenLowBattery(it) 39 | } 40 | } -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/ui/theme/Color.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.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 | 9 | val Purple40 = Color(0xFF6650a4) 10 | val PurpleGrey40 = Color(0xFF625b71) 11 | val Pink40 = Color(0xFF7D5260) 12 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/ui/theme/Typography.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.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 | // Set of Material typography styles to start with 10 | val Typography = Typography( 11 | bodyLarge = TextStyle( 12 | fontFamily = FontFamily.Default, 13 | fontWeight = FontWeight.Normal, 14 | fontSize = 16.sp, 15 | lineHeight = 24.sp, 16 | letterSpacing = 0.5.sp 17 | ), 18 | bodySmall = TextStyle( 19 | fontFamily = FontFamily.Default, 20 | fontWeight = FontWeight.Normal, 21 | fontSize = 14.sp, 22 | lineHeight = 20.sp, 23 | letterSpacing = 0.25.sp 24 | ), 25 | ) 26 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/utils/BatteryUtils.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.utils 2 | 3 | import android.content.Context 4 | import android.os.BatteryManager 5 | 6 | object BatteryUtils { 7 | 8 | private const val LOW_BATTERY_THRESHOLD = 20 9 | 10 | fun Context.getBatteryPercentage(): Int { 11 | val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager 12 | return batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) 13 | } 14 | 15 | fun Context.isLowBattery(): Boolean { 16 | return getBatteryPercentage() <= LOW_BATTERY_THRESHOLD 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/utils/CommonUtils.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.utils 2 | 3 | import kotlinx.coroutines.flow.MutableStateFlow 4 | 5 | object CommonUtils { 6 | 7 | /** 8 | * Execute a block of code with a boolean scope flag. What it does is set the flag to true 9 | * before executing the block, and then set it back to false after the block is done. 10 | */ 11 | inline fun withBooleanScope(scopeFlag: MutableStateFlow, block: () -> T): T { 12 | scopeFlag.value = true 13 | return try { 14 | block() 15 | } finally { 16 | scopeFlag.value = false 17 | } 18 | } 19 | 20 | fun Float.toSeconds(): Float { 21 | return this / 1000f 22 | } 23 | 24 | fun Long.toSeconds(): Long { 25 | return this / 1000 26 | } 27 | 28 | fun Int.toSeconds(): Int { 29 | return this / 1000 30 | } 31 | 32 | fun Double.toSeconds(): Double { 33 | return this / 1000 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/utils/ConditionUtils.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.utils 2 | 3 | @Suppress("unused") 4 | object ConditionUtils { 5 | /** 6 | * Quickly performs a null safety check 7 | * of a potential null object that has 8 | * no way to initialize but to throw an 9 | * exception. This approach is unsafe 10 | * and should not be used with conditional 11 | * statements 12 | * 13 | * Requires casting to the original object 14 | * 15 | * @throws UninitializedPropertyAccessException 16 | * @return [Any] 17 | */ 18 | fun Any?.asNotNull(): Any { 19 | return this ?: throw UninitializedPropertyAccessException() 20 | } 21 | 22 | /** 23 | * Check if an object is null 24 | * 25 | * @return true if null 26 | */ 27 | fun Any?.isNull(): Boolean { 28 | return this == null 29 | } 30 | 31 | /** 32 | * Check if an object is null 33 | * 34 | * @return true if not null 35 | */ 36 | fun Any?.isNotNull(): Boolean { 37 | return this != null 38 | } 39 | 40 | /** 41 | * Checks if a number is 0 42 | * 43 | * @return [Boolean] 44 | */ 45 | fun Number.isZero(): Boolean { 46 | return this == 0 47 | } 48 | 49 | /** 50 | * Checks if a number is not 0 51 | * 52 | * @return [Boolean] 53 | */ 54 | fun Number.isNotZero(): Boolean { 55 | return this != 0 56 | } 57 | 58 | /** 59 | * Check is a number is equal to another number 60 | * 61 | * @return [Boolean] 62 | */ 63 | fun Number.isEqualTo(number: Number): Boolean { 64 | return this == number 65 | } 66 | 67 | /** 68 | * Inverts the current boolean 69 | * 70 | * @return [Boolean] 71 | */ 72 | fun Boolean.invert(): Boolean { 73 | return !this 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/utils/DoubleTapDetector.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.utils 2 | 3 | import android.content.Context 4 | import android.view.GestureDetector 5 | import android.view.MotionEvent 6 | 7 | class DoubleTapDetector( 8 | context: Context, 9 | private val onDoubleTapListener: (MotionEvent) -> Unit 10 | ) { 11 | private val gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() { 12 | override fun onDoubleTap(e: MotionEvent): Boolean { 13 | onDoubleTapListener(e) 14 | return true 15 | } 16 | }) 17 | 18 | fun onTouchEvent(event: MotionEvent) { 19 | gestureDetector.onTouchEvent(event) 20 | } 21 | } -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/utils/ListUtils.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.utils 2 | 3 | object ListUtils { 4 | fun List.deepEquals(other: List) = 5 | size == other.size && asSequence() 6 | .mapIndexed { index, element -> element == other[index] } 7 | .all { it } 8 | } -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/utils/ParcelUtils.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.utils 2 | 3 | import android.content.Intent 4 | import android.os.Build.VERSION.SDK_INT 5 | import android.os.Bundle 6 | import android.os.Parcelable 7 | 8 | @Suppress("unused") 9 | object ParcelUtils { 10 | inline fun Intent.parcelable(key: String): T? = when { 11 | SDK_INT >= 33 -> getParcelableExtra(key, T::class.java) 12 | else -> @Suppress("DEPRECATION") getParcelableExtra(key) as? T 13 | } 14 | 15 | inline fun Bundle.parcelable(key: String): T? = when { 16 | SDK_INT >= 33 -> getParcelable(key, T::class.java) 17 | else -> @Suppress("DEPRECATION") getParcelable(key) as? T 18 | } 19 | 20 | inline fun Bundle.serializable(key: String): T? = when { 21 | SDK_INT >= 33 -> getSerializable(key, T::class.java) 22 | else -> @Suppress("DEPRECATION") getSerializable(key) as? T 23 | } 24 | 25 | inline fun Bundle.parcelable(key: String, default: T): T = when { 26 | SDK_INT >= 33 -> getParcelable(key, T::class.java) ?: default 27 | else -> @Suppress("DEPRECATION") getParcelable(key) as? T ?: default 28 | } 29 | 30 | inline fun Bundle.parcelable(key: String, default: () -> T): T = when { 31 | SDK_INT >= 33 -> getParcelable(key, T::class.java) ?: default() 32 | else -> @Suppress("DEPRECATION") getParcelable(key) as? T ?: default() 33 | } 34 | 35 | inline fun Bundle.parcelableArrayList(key: String): ArrayList? = when { 36 | SDK_INT >= 33 -> getParcelableArrayList(key, T::class.java) 37 | else -> @Suppress("DEPRECATION") getParcelableArrayList(key) 38 | } 39 | 40 | inline fun Intent.parcelableArrayList(key: String): ArrayList? = when { 41 | SDK_INT >= 33 -> getParcelableArrayListExtra(key, T::class.java) 42 | else -> @Suppress("DEPRECATION") getParcelableArrayListExtra(key) 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/utils/PermissionUtils.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.utils 2 | 3 | import android.Manifest 4 | import android.annotation.SuppressLint 5 | import android.content.Context 6 | import android.content.Intent 7 | import android.content.pm.PackageManager 8 | import android.net.Uri 9 | import android.os.Build 10 | import android.os.Environment 11 | import android.os.PowerManager 12 | import android.provider.Settings 13 | import androidx.annotation.RequiresApi 14 | import androidx.core.app.NotificationManagerCompat 15 | import androidx.core.content.ContextCompat 16 | 17 | object PermissionUtils { 18 | 19 | /** 20 | * return true if in App's Battery settings "Not optimized" and false if "Optimizing battery use" 21 | */ 22 | fun Context.isBatteryOptimizationDisabled(): Boolean { 23 | return (getSystemService(Context.POWER_SERVICE) as PowerManager) 24 | .isIgnoringBatteryOptimizations(packageName) 25 | } 26 | 27 | @SuppressLint("BatteryLife") 28 | fun Context.requestIgnoreBatteryOptimizations() { 29 | val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager 30 | if (!powerManager.isIgnoringBatteryOptimizations(packageName)) { 31 | val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).apply { 32 | data = Uri.parse("package:$packageName") 33 | } 34 | startActivity(intent) 35 | } 36 | } 37 | 38 | fun checkStoragePermission(context: Context): Boolean { 39 | return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 40 | Environment.isExternalStorageManager() 41 | } else { 42 | ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED 43 | } 44 | } 45 | 46 | @RequiresApi(Build.VERSION_CODES.TIRAMISU) 47 | fun checkMediaImagesPermission(context: Context): Boolean { 48 | return ContextCompat.checkSelfPermission(context, Manifest.permission.READ_MEDIA_IMAGES) == PackageManager.PERMISSION_GRANTED 49 | } 50 | 51 | @RequiresApi(Build.VERSION_CODES.TIRAMISU) 52 | fun checkNotificationPermission(context: Context): Boolean { 53 | return NotificationManagerCompat.from(context).areNotificationsEnabled() 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/utils/ProcessUtils.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.utils 2 | 3 | import android.app.ActivityManager 4 | import android.content.Context 5 | import kotlinx.coroutines.CancellationException 6 | import kotlinx.coroutines.Job 7 | 8 | object ProcessUtils { 9 | fun MutableSet.cancelAll(cause: String) { 10 | forEach { it.cancel(CancellationException(cause)) } 11 | clear() 12 | } 13 | 14 | @Suppress("DEPRECATION") 15 | fun Context.isServiceRunning(serviceClass: Class<*>): Boolean { 16 | val activityManager = this.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager 17 | 18 | /** 19 | * "As of Build. VERSION_CODES. O, this method is no longer available 20 | * to third party applications. For backwards compatibility, it will still 21 | * return the caller's own services." 22 | * 23 | * If we are querying my app's services, this method will work just fine. 24 | */ 25 | val services = activityManager.getRunningServices(Int.MAX_VALUE) 26 | for (service in services) { 27 | if (serviceClass.name == service.service.className) { 28 | return true 29 | } 30 | } 31 | 32 | return false 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/utils/ServiceUtils.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.utils 2 | 3 | import android.app.ActivityManager 4 | import android.content.Context 5 | import app.simple.peri.services.LiveAutoWallpaperService 6 | 7 | object ServiceUtils { 8 | fun isWallpaperServiceRunning(context: Context): Boolean { 9 | val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager 10 | @Suppress("DEPRECATION") val services = manager.getRunningServices(Integer.MAX_VALUE) 11 | return services.any { it.service.className == LiveAutoWallpaperService::class.java.name } 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/utils/StringUtils.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.utils 2 | 3 | object StringUtils { 4 | 5 | fun String?.endsWithAny(vararg strings: String): Boolean { 6 | strings.forEach { 7 | if (this?.endsWith(it) == true) { 8 | return true 9 | } 10 | } 11 | return false 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/utils/WallpaperSort.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.utils 2 | 3 | import app.simple.peri.models.Wallpaper 4 | import app.simple.peri.preferences.MainPreferences 5 | 6 | object WallpaperSort { 7 | 8 | const val NAME = "name" 9 | const val DATE = "date" 10 | const val SIZE = "size" 11 | const val WIDTH = "width" 12 | const val HEIGHT = "height" 13 | 14 | const val ASC = "asc" 15 | const val DESC = "desc" 16 | 17 | fun ArrayList.getSortedList() { 18 | when (MainPreferences.getSort()) { 19 | NAME -> sortByName() 20 | DATE -> sortByDate() 21 | SIZE -> sortBySize() 22 | WIDTH -> sortByWidth() 23 | HEIGHT -> sortByHeight() 24 | } 25 | } 26 | 27 | fun List.getSortedList(): List { 28 | val sortedList = ArrayList(this) // Copy the list 29 | sortedList.getSortedList() 30 | return sortedList 31 | } 32 | 33 | private fun ArrayList.sortByName() { 34 | if (isOrderAsc()) { 35 | sortBy { it.name } 36 | } else { 37 | sortByDescending { it.name } 38 | } 39 | } 40 | 41 | private fun ArrayList.sortByDate() { 42 | if (isOrderAsc()) { 43 | sortBy { it.dateModified } 44 | } else { 45 | sortByDescending { it.dateModified } 46 | } 47 | } 48 | 49 | private fun ArrayList.sortBySize() { 50 | if (isOrderAsc()) { 51 | sortBy { it.size } 52 | } else { 53 | sortByDescending { it.size } 54 | } 55 | } 56 | 57 | private fun ArrayList.sortByWidth() { 58 | if (isOrderAsc()) { 59 | sortBy { it.width } 60 | } else { 61 | sortByDescending { it.width } 62 | } 63 | } 64 | 65 | private fun ArrayList.sortByHeight() { 66 | if (isOrderAsc()) { 67 | sortBy { it.height } 68 | } else { 69 | sortByDescending { it.height } 70 | } 71 | } 72 | 73 | private fun isOrderAsc(): Boolean { 74 | return MainPreferences.getOrder() == ASC 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/viewmodels/EffectsViewModel.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.viewmodels 2 | 3 | import android.app.Application 4 | import androidx.lifecycle.AndroidViewModel 5 | import androidx.lifecycle.LiveData 6 | import androidx.lifecycle.MutableLiveData 7 | import androidx.lifecycle.viewModelScope 8 | import app.simple.peri.database.instances.EffectsDatabase 9 | import app.simple.peri.models.Effect 10 | import kotlinx.coroutines.Dispatchers 11 | import kotlinx.coroutines.launch 12 | import kotlinx.coroutines.withContext 13 | 14 | class EffectsViewModel(application: Application) : AndroidViewModel(application) { 15 | 16 | private val effects: MutableLiveData> by lazy { 17 | MutableLiveData>().also { 18 | viewModelScope.launch(Dispatchers.IO) { 19 | val effectsDatabase = EffectsDatabase.getInstance(application)!! 20 | it.postValue(effectsDatabase.effectsDao().getAllEffects()) 21 | } 22 | } 23 | } 24 | 25 | fun getEffects(): LiveData> { 26 | return effects 27 | } 28 | 29 | fun deleteEffect(effect: Effect, onDeleted: () -> Unit) { 30 | viewModelScope.launch(Dispatchers.IO) { 31 | val effectsDatabase = EffectsDatabase.getInstance(getApplication())!! 32 | effectsDatabase.effectsDao().deleteEffect(effect) 33 | effects.postValue(effectsDatabase.effectsDao().getAllEffects()) 34 | 35 | withContext(Dispatchers.Main) { 36 | onDeleted() 37 | } 38 | } 39 | } 40 | 41 | override fun onCleared() { 42 | super.onCleared() 43 | EffectsDatabase.destroy() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/viewmodels/StateViewModel.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.viewmodels 2 | 3 | import android.app.Application 4 | import androidx.compose.runtime.getValue 5 | import androidx.compose.runtime.mutableFloatStateOf 6 | import androidx.compose.runtime.mutableStateOf 7 | import androidx.compose.runtime.setValue 8 | import androidx.lifecycle.AndroidViewModel 9 | import androidx.lifecycle.viewModelScope 10 | import app.simple.peri.database.instances.EffectsDatabase 11 | import app.simple.peri.models.Effect 12 | import app.simple.peri.models.Folder 13 | import app.simple.peri.models.Tag 14 | import app.simple.peri.models.Wallpaper 15 | import kotlinx.coroutines.Dispatchers 16 | import kotlinx.coroutines.launch 17 | import kotlinx.coroutines.withContext 18 | 19 | class StateViewModel(application: Application) : AndroidViewModel(application) { 20 | 21 | var wallpaper by mutableStateOf(null) 22 | var tag by mutableStateOf(null) 23 | var folder by mutableStateOf(null) 24 | var blurValue by mutableFloatStateOf(0f) // 0F..25F 25 | var brightnessValue by mutableFloatStateOf(0f) // -255F..255F 26 | var contrastValue by mutableFloatStateOf(1f) // 0F..10F 27 | var saturationValue by mutableFloatStateOf(1f) // 0F..2F 28 | var hueValueRed by mutableFloatStateOf(0f) // 0F..360F 29 | var hueValueGreen by mutableFloatStateOf(0f) // 0F..360F 30 | var hueValueBlue by mutableFloatStateOf(0f) // 0F..360F 31 | var scaleValueRed by mutableFloatStateOf(1f) // 0F..1F 32 | var scaleValueGreen by mutableFloatStateOf(1f) // 0F..1F 33 | var scaleValueBlue by mutableFloatStateOf(1f) // 0F..1F 34 | 35 | fun saveEffectInDatabase(effect: Effect, onEffectSaved: () -> Unit) { 36 | viewModelScope.launch(Dispatchers.IO) { 37 | val effectDao = EffectsDatabase.getInstance(getApplication())?.effectsDao() 38 | effectDao?.insertEffect(effect) 39 | 40 | withContext(Dispatchers.Main) { 41 | onEffectSaved() 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/widgets/NextWallpaper.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.widgets 2 | 3 | import android.app.PendingIntent 4 | import android.appwidget.AppWidgetManager 5 | import android.appwidget.AppWidgetProvider 6 | import android.content.Context 7 | import android.content.Intent 8 | import android.util.Log 9 | import android.widget.RemoteViews 10 | import app.simple.peri.R 11 | import app.simple.peri.services.AutoWallpaperService 12 | 13 | open class NextWallpaper : AppWidgetProvider() { 14 | 15 | override fun onUpdate(context: Context?, appWidgetManager: AppWidgetManager?, appWidgetIds: IntArray?) { 16 | super.onUpdate(context, appWidgetManager, appWidgetIds) 17 | Log.d(TAG, "onUpdate") 18 | 19 | // Loop through all widget instances 20 | appWidgetIds?.forEach { appWidgetId -> 21 | val intent = Intent(context, AutoWallpaperService::class.java) 22 | intent.action = AutoWallpaperService.ACTION_NEXT_WALLPAPER 23 | val pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) 24 | 25 | // Get the layout for the App Widget and attach an on-click listener to the button 26 | val views = RemoteViews(context?.packageName, getLayoutID()) 27 | views.setOnClickPendingIntent(getButtonID(), pendingIntent) 28 | 29 | // Log a message when the widget is clicked 30 | Log.d(TAG, "Widget clicked") 31 | 32 | // Tell the AppWidgetManager to perform an update on the current App Widget 33 | appWidgetManager?.updateAppWidget(appWidgetId, views) 34 | } 35 | } 36 | 37 | open fun getLayoutID(): Int { 38 | return R.layout.widget_next_wallpaper 39 | } 40 | 41 | open fun getButtonID(): Int { 42 | return R.id.widget_next_wallpaper 43 | } 44 | 45 | companion object { 46 | private const val TAG = "NextWallpaperWidget" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/widgets/NextWallpaperWidget.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.widgets 2 | 3 | import app.simple.peri.R 4 | 5 | class NextWallpaperWidget : NextWallpaper() { 6 | override fun getLayoutID(): Int { 7 | return R.layout.widget_next_wallpaper 8 | } 9 | 10 | override fun getButtonID(): Int { 11 | return R.id.widget_next_wallpaper 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/app/simple/peri/widgets/NextWallpaperWidgetTransparent.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri.widgets 2 | 3 | import app.simple.peri.R 4 | 5 | class NextWallpaperWidgetTransparent : NextWallpaper() { 6 | override fun getLayoutID(): Int { 7 | return R.layout.widget_next_wallpaper_transparent 8 | } 9 | 10 | override fun getButtonID(): Int { 11 | return R.id.widget_next_wallpaper 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/inure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/drawable-nodpi/inure.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/positional.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/drawable-nodpi/positional.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_copy_all.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_fast_forward.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_next_foreground.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_peristyle.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_share.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/swap_vert.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/widget_next_wallpaper.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/widget_next_wallpaper_transparent.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_next.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_next_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_next.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-hdpi/ic_next.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_next_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-hdpi/ic_next_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_next.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-mdpi/ic_next.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_next_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-mdpi/ic_next_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_next.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-xhdpi/ic_next.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_next_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-xhdpi/ic_next_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_next.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-xxhdpi/ic_next.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_next_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-xxhdpi/ic_next_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_next.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-xxxhdpi/ic_next.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_next_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/app/src/main/res/mipmap-xxxhdpi/ic_next_round.webp -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #000000 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/ic_next_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #000000 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/non_translatable_strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Peristyle 4 | Inure App Manager 5 | Positional 6 | An elegant and beautiful premium Android app manager for both rooted and non-rooted devices and a built-in terminal, analytics panel and an independent custom theme engine, developed with purely custom APIs created for this app. 7 | An elegant and colorful location information app for Android with Compass, Clock, Level, Sun, Moon, Trail Marker and many other features. 8 | GitHub 9 | Play Store 10 | Wallpaper Manager API 11 | 12 | -------------------------------------------------------------------------------- /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/live_auto_wallpaper.xml: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/xml/provider_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | 12 | 15 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/xml/widget_next_wallpaper.xml: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/xml/widget_next_wallpaper_transparent.xml: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /app/src/test/java/app/simple/peri/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package app.simple.peri 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: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | plugins { 3 | id 'com.android.application' version '8.10.1' apply false 4 | id 'com.android.library' version '8.10.1' apply false 5 | id 'org.jetbrains.kotlin.android' version '2.0.20' apply false 6 | id 'com.google.devtools.ksp' version '2.0.20-1.0.25' apply false 7 | id 'org.jetbrains.kotlin.plugin.compose' version '2.0.20' apply false 8 | } 9 | -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | files: 2 | - source: /app/src/main/res/values/strings.xml 3 | translation: /app/src/main/res/values-%android_code%/%original_file_name% 4 | translate_content: 0 5 | translate_attributes: 0 6 | 7 | - source: /fastlane/metadata/android/en-US/full_description.txt 8 | translation: /fastlane/metadata/android/%locale%/full_description.txt 9 | translate_content: 1 10 | translate_attributes: 0 11 | 12 | - source: /fastlane/metadata/android/en-US/short_description.txt 13 | translation: /fastlane/metadata/android/%locale%/short_description.txt 14 | translate_content: 1 15 | translate_attributes: 0 16 | -------------------------------------------------------------------------------- /fastlane/metadata/android/ar-SA/full_description.txt: -------------------------------------------------------------------------------- 1 | تم إنشاء Peristyle ليكون تطبيق إدارة وتصفح خلفيات في غاية البساطة والتطور لأجهزة Android. إنه يحل مشكلة وجود الكثير من الميزات والتطبيقات الثقيلة والحصول على الحد الأدنى من دعم الخلفيات المخزنة محليًا. ماذا لو كنت ترغب/ين فقط في تطبيق يسمح لك بتصفح وتحديد الخلفيات المخزنة محليًا ويتيح لك إدارة وتعيين الخلفيات من هناك؟ إذًا Peristyle لك :) 2 | 3 | الميزات: 4 | 5 | - معمارية بسيطة، تصفح الخلفيات واستخدام إدارة الخلفيات في النظام لتعيينها كخلفية. 6 | - دعم تعدد المجلدات. 7 | - القدرة على تعيين وسوم لأي خلفية. 8 | - يمكن مسح مجلدات .nomedia، مفيدة إذا كنت ترغب/ين في الحفاظ على خلفياتك بعيدةً عن المعرض. 9 | - تطبيق فلاتر الألوان والضبابية على أي خلفية ديناميكيًا قبل التطبيق. 10 | - رسوم متحركة بسيطة ولكن جميلة مع التحسينات المناسبة. 11 | - ضغط وتقليل الصور بالمرة. 12 | - لا إعلانات ولا تعقب ولا تحليلات ولا أذونات إنترنت ولا أذونات غير ضرورية. 13 | - دعم التغيير التلقائي للخلفيات مع المجلدات والوسوم المخصصة لكل شاشة. 14 | - تغيير خلفية الشاشة باستخدام خلفيات التطبيق الحية 15 | - تحرير وتطبيق الفلاتر على الخلفيات بلا خسارة جودة آنيًا. 16 | - منتقي خلفيات حية مدمج. 17 | - دعم الوضع الداكن. 18 | - واجهة استخدام زجاجية مستندة إلى تأثيرات ضبابية وظلال كاوية آنية. 19 | - سمة ألوان Material You. 20 | - بناء قابل للنسخ بالكامل. 21 | - معمارية برمجية خالية من التحميل. 22 | -------------------------------------------------------------------------------- /fastlane/metadata/android/ar-SA/short_description.txt: -------------------------------------------------------------------------------- 1 | تطبيق إدارة خلفيات بسيط مع دعم آلية الخلفيات وتعدد المجلدات. 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/full_description.txt: -------------------------------------------------------------------------------- 1 | Peristyle wurde als ebenso einfacher wie durchdachter Hintergrundbild-Manager und -Browser für Android entwickelt. Er löst die Problematik komplexer und überladener Apps mit mangelhafter Unterstützung für lokal gespeicherte Hintergrundbilder. Was wäre, wenn Du nur eine App brauchst, um Deine lokal gespeicherten Hintergrundbilder zu durchstöbern, auszuwählen und sie von dort zu verwalten und anzuwenden? Dann ist Peristyle das Richtige für Dich :) 2 | 3 | Merkmale: 4 | 5 | - Einfache Architektur: durchsuche Hintergrundbilder und verwende die Hintergrund-Verwaltung des Systems, um sie festzulegen. 6 | - Unterstützung unterschiedlicher Ordner. 7 | - Möglichkeit, jedem Hintergrund Tags zuzuordnen. 8 | - Kann .nomedia-Verzeichnisse durchsuchen; nützlich, um Hintergrundbilder von der Galerie fernzuhalten. 9 | - Unschärfe und Farbfilter dynamisch auf jedes Hintergrundbild anwenden, bevor es festgelegt wird. 10 | - Einfache aber schöne Animationen mit den richtigen Optimierungen. 11 | - Komprimiere oder verkleinerte Bilder ganz nebenbei. 12 | - Keine Werbung, kein Tracking, keine Analytics, kein Internet-Zugriff, keine unnötigen Berechtigungen. 13 | - Unterstützt automatische Hintergrund-Änderung mit dedizierten Ordnern und Tags für jeden Bildschirm. 14 | - Hintergrund-Änderung mittels des Live-Hintergrunds der App 15 | - Bearbeite Hintergrundbilder verlustfrei und wende Filter in Echtzeit an. 16 | - Integrierte Live-Hintergrundauswahl. 17 | - Unterstützung von Dunklem Design. 18 | - Glasmorphe Benutzeroberfläche, basierend auf Echtzeit-Unschärfeeffekten und kausalen Schatten. 19 | - Material You-Farbthema. 20 | - Vollständig reproduzierbarer Build. 21 | - Ladefreie Software-Architektur. 22 | -------------------------------------------------------------------------------- /fastlane/metadata/android/de-DE/short_description.txt: -------------------------------------------------------------------------------- 1 | Einfache Hintergrundverwaltungs-App mit Auto-Hintergrund- und Mehrfachordner-Unterstützung. 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/107.txt: -------------------------------------------------------------------------------- 1 | - HD image viewer 2 | - Option to disable details -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/122.txt: -------------------------------------------------------------------------------- 1 | - Fixed various color filter issues 2 | - Fixed filter dialog blur not working 3 | - Added blur filter -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/123.txt: -------------------------------------------------------------------------------- 1 | - Fixed staggered grid not updating it's layout after a wallpaper is removed in dynamic spans 2 | - Fixed top elements names overlapping with status bar 3 | - Updated dynamic colors for preferences icons -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/124.txt: -------------------------------------------------------------------------------- 1 | - Fixed dynamic colors not applying 2 | - Fixed preference framework issues -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/126.txt: -------------------------------------------------------------------------------- 1 | - Added option to adjust hue -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/127.txt: -------------------------------------------------------------------------------- 1 | - Sliders should now show exact values 2 | - Removed native codes from the project -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/129.txt: -------------------------------------------------------------------------------- 1 | - Added monochrome icon support 2 | - Added Auto Wallpaper Changer -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/130.txt: -------------------------------------------------------------------------------- 1 | - Added 5, 15, and 30 intervals in auto wallpaper changer (#15) 2 | - Updated auto wallpaper cropper algorithm 3 | - Fixed various issues with auto wallpaper changer 4 | - Added crop wallpaper for auto wallpaper 5 | - Added boot completed receiver for auto wallpaper 6 | - Option to use separate wallpaper for lockscreen -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/131.txt: -------------------------------------------------------------------------------- 1 | - Fixed various issues with Auto Wallpaper 2 | - Fixed Auto Wallpaper setting pixelated wallpapers 3 | - Fixed some crashes in Auto Wallpaper framework -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/132.txt: -------------------------------------------------------------------------------- 1 | - Permissive auto wallpaper warning 2 | - Updated settings interface 3 | - Major improvements in animations framework -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/133.txt: -------------------------------------------------------------------------------- 1 | - Landscape orientation support 2 | - Fixed animations issues -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/134.txt: -------------------------------------------------------------------------------- 1 | - Added option to set un-cropped wallpaper on wallpaper screen 2 | - Switch style preferences instead of check box 3 | - Removed settings toolbar due to UI inconsistencies -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/136.txt: -------------------------------------------------------------------------------- 1 | - Added a consistent loader that refreshes wallpaper automatically 2 | - Removed swipe down to refresh 3 | - Make sure the animating view have only one animation pipeline working on it 4 | - Added multilevel subdirectory tree support 5 | - Fixed wallpaper not setting for lock screen in some devices 6 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/137.txt: -------------------------------------------------------------------------------- 1 | - Option to prevent setting wallpaper when device is sleeping 2 | - Added intent support to run AutoWallpaperService using other apps 3 | - Added option to specify which screen to set wallpaper to for Auto Wallpaper 4 | - Improved wallpaper service to reduce wallpaper load time 5 | - Better loading status 6 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/138.txt: -------------------------------------------------------------------------------- 1 | - Added toggle to switch between original and crop bounds 2 | - Fixed loader states 3 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/139.txt: -------------------------------------------------------------------------------- 1 | - Added option to reduce motions in the app 2 | - More info in Library Stats 3 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/140.txt: -------------------------------------------------------------------------------- 1 | - Added battery optimization permission 2 | - Fixed blurry wallpaper issue 3 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/141.txt: -------------------------------------------------------------------------------- 1 | - Disabled crop wallpaper popup for fitting images 2 | - Fixed crash when blur radius is too low 3 | - Fixed incorrect screen measurements 4 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/142.txt: -------------------------------------------------------------------------------- 1 | - Added Turkish translation (thanks to @mikropsoft) 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/143.txt: -------------------------------------------------------------------------------- 1 | - Added option to export edited wallpapers 2 | - Added option to edit wallpaper externally 3 | - EXIF orientation correction 4 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/144.txt: -------------------------------------------------------------------------------- 1 | - Added transparent next wallpaper widget 2 | - Various improvements and bug fixes 3 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/145.txt: -------------------------------------------------------------------------------- 1 | - Added icon for exceeding wallpapers 2 | - Removed zoom animation 3 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/146.txt: -------------------------------------------------------------------------------- 1 | - Add next wallpaper quick tiles 2 | - Add tweaks in settings 3 | - Add option to ignore .dot files 4 | - Add option to ignore sub-folders 5 | - Add French translations (Thanks to ppp987) 6 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/147.txt: -------------------------------------------------------------------------------- 1 | - Added option to set wallpapers linearly 2 | - Added realtime crash monitor 3 | - Fixes crash on enabling biometric lock 4 | - Added set as wallpaper option to set wallpaper from file managers 5 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/148.txt: -------------------------------------------------------------------------------- 1 | - Fixed inclusion of non-image files in the database 2 | - Added polish translations (thanks to @tama10) 3 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/149.txt: -------------------------------------------------------------------------------- 1 | - Added Simplified Chinese translations (thanks to @shanzhaxiaok) 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/150.txt: -------------------------------------------------------------------------------- 1 | - Added Vietnamese translations (thanks to @xeus0000) 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/151.txt: -------------------------------------------------------------------------------- 1 | - Fix multiple loading session issue 2 | - Added app Telegram group link 3 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/152.txt: -------------------------------------------------------------------------------- 1 | - Show system wallpaper in the main list 2 | - Allows critical permissions to be granted from Preferences screen 3 | - Polaroid design for current wallpaper card 4 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/153.txt: -------------------------------------------------------------------------------- 1 | - Remove round corners from polaroids 2 | - Added lock screen wallpaper in the main list 3 | - Fixed wallpaper dimensions when two spans is selected 4 | - Fixed crash while opening an image from file manager 5 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/154.txt: -------------------------------------------------------------------------------- 1 | - Add 3 and 7 days interval options 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/200.txt: -------------------------------------------------------------------------------- 1 | - Total UI overhaul based completely on Jetpack Compose 2 | - Added option to assign tags to wallpapers 3 | - Add direct image based shadow 4 | - MD5 Checksum based ids and prominent color based wallpaper shadows 5 | - Glassmorphic card based interface 6 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/201.txt: -------------------------------------------------------------------------------- 1 | - Fix blur not applying 2 | - Added header in lists with count 3 | - Fix interface overlapping status and navigation bar 4 | - Add more menus for Tags an Wallpapers 5 | - Fix loading indicators not showing 6 | - Tags thumbnails now shows according to the device aspect ratio 7 | - Various fixes and interface improvements 8 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/202.txt: -------------------------------------------------------------------------------- 1 | - Added multi folder support 2 | - Added tags and folder assignment for each screen auto wallpaper 3 | - Added sort and order in the Settings 4 | - Added selection in the main list 5 | - Various interface changes 6 | - Add Spanish and Chinese Traditional translations 7 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/203.txt: -------------------------------------------------------------------------------- 1 | - Slide and Zoom on wallpaper screen 2 | - Fixed the permission flow crashing in Android 9 3 | - Fixed no READ_MEDIA_IMAGES permission causes crash in Android 15 4 | - Fixed various issues with setup interface 5 | - Fixed Auto Wallpaper not changing wallpaper correctly 6 | - Added no lockscreen wallpaper hint for < Android 13 devices 7 | - Added basic transition animations 8 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/204.txt: -------------------------------------------------------------------------------- 1 | - Fix auto wallpaper applying wallpapers on both screens 2 | - Fix Folders screen flickering on every launch 3 | - Fix various UI issues 4 | 5 | Peristyle is stable now 6 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/205.txt: -------------------------------------------------------------------------------- 1 | - Fixed the looping home screen after the first setup 2 | - Added custom effects for each screen in Auto Wallpaper 3 | - Reduce animation time 4 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/300.txt: -------------------------------------------------------------------------------- 1 | - Added hue and saturation in wallpaper 2 | - Added hue and saturation in auto wallpaper 3 | - Added live wallpaper picker 4 | - Ability to uninstall live wallpapers 5 | - Fixed lost scroll state in wallpaper list 6 | - Long pressing buttons on home will show context tooltip 7 | - Updated home UI 8 | - Added Arabic translations 9 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/310.txt: -------------------------------------------------------------------------------- 1 | - Add option to add or remove nomedia from folders 2 | - Add folder visibility indicator 3 | - Hide card when click on wallpaper 4 | - Hide details card when edit dialog is opened 5 | - Added reset button in effects dialog 6 | - Main effects dialog is now semi transparent 7 | - Added option to clear image cache 8 | - Added option to remove a folder 9 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/320.txt: -------------------------------------------------------------------------------- 1 | - Added toggle to disable checksum calculation 2 | - Fixed various loading issues 3 | - Fixed invalid effects on final image 4 | - Fixed various UI issues on dark mode 5 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/330.txt: -------------------------------------------------------------------------------- 1 | - Added option to compress or reduce image on the fly 2 | - Fixed auto wallpaper effects not working properly 3 | - Added German translations 4 | - Removed telegram group links from the app 5 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/331.txt: -------------------------------------------------------------------------------- 1 | - Fixed crashes caused by NaN in aspect ratio 2 | - Italian translations 3 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/340.txt: -------------------------------------------------------------------------------- 1 | - Added a random wallpaper page on home screen 2 | - Added crossfade animation to all image thumbnails 3 | - Added a proper clear cache dialog 4 | - Added realtime database updates. 5 | - Images will load in realtime in the lists 6 | - Fix header wrapping the long text even with available space 7 | - Minor fixes 8 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/400.txt: -------------------------------------------------------------------------------- 1 | - Added option to move the header to the bottom 2 | - Added option to load original aspect ratio for thumbnails 3 | - Added option to select grid spans separately for each orientation 4 | - Added option to export edited wallpaper 5 | - Added separate RGB hue sliders 6 | - Added auto wallpaper notification with delete and send button 7 | - Added system wallpaper changed detection mechanism 8 | - Improved effects and cropping algorithms 9 | - Fixed selection menu issue 10 | - Fixed wallpaper effects state loss 11 | - Fixed loading folders taking up a long time 12 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/500.txt: -------------------------------------------------------------------------------- 1 | This is a destructive update meaning after update any of the previous data will be lost. If you want to keep the 2 | previous data, please do not update to this version. 3 | 4 | Read why? here: https://github.com/Hamza417/Peristyle/releases/tag/v5.0.0 5 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/510.txt: -------------------------------------------------------------------------------- 1 | Read the complete changelogs here: https://github.com/Hamza417/Peristyle/releases/latest 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/520.txt: -------------------------------------------------------------------------------- 1 | Read the complete changelogs here: https://github.com/Hamza417/Peristyle/releases/latest 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/600.txt: -------------------------------------------------------------------------------- 1 | Read the complete changelogs here: https://github.com/Hamza417/Peristyle/releases/latest 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/610.txt: -------------------------------------------------------------------------------- 1 | Read the complete changelogs here: https://github.com/Hamza417/Peristyle/releases/latest 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/620.txt: -------------------------------------------------------------------------------- 1 | Read the complete changelogs here: https://github.com/Hamza417/Peristyle/releases/latest 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/630.txt: -------------------------------------------------------------------------------- 1 | Read the complete changelogs here: https://github.com/Hamza417/Peristyle/releases/latest 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/640.txt: -------------------------------------------------------------------------------- 1 | Read the complete changelogs here: https://github.com/Hamza417/Peristyle/releases/latest 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/700.txt: -------------------------------------------------------------------------------- 1 | Read the complete changelogs here: https://github.com/Hamza417/Peristyle/releases/latest 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/704.txt: -------------------------------------------------------------------------------- 1 | Read the complete changelogs here: https://github.com/Hamza417/Peristyle/releases/latest 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/810.txt: -------------------------------------------------------------------------------- 1 | Read the complete changelogs here: https://github.com/Hamza417/Peristyle/releases/latest 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/820.txt: -------------------------------------------------------------------------------- 1 | Read the complete changelogs here: https://github.com/Hamza417/Peristyle/releases/latest 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/830.txt: -------------------------------------------------------------------------------- 1 | Read the complete changelogs here: https://github.com/Hamza417/Peristyle/releases/latest 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/840.txt: -------------------------------------------------------------------------------- 1 | Read the complete changelogs here: https://github.com/Hamza417/Peristyle/releases/latest 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/850.txt: -------------------------------------------------------------------------------- 1 | Read the complete changelogs here: https://github.com/Hamza417/Peristyle/releases/latest 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/changelogs/860.txt: -------------------------------------------------------------------------------- 1 | Read the complete changelogs here: https://github.com/Hamza417/Peristyle/releases/latest 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/full_description.txt: -------------------------------------------------------------------------------- 1 | Peristyle is created to be extremely simple and sophisticated wallpaper manager and browser app for Android. It solves the problem of having too many features and bloated apps and having very minimal support for locally stored wallpapers. What if you just wanted an app that allows you to browse and select your own locally stored wallpapers and lets you manage and set wallpapers from there? then Peristyle is for you :) 2 | 3 | Features: 4 | 5 | - Simple architecture, browse wallpapers and use system wallpaper manager to set them as wallpaper. 6 | - Multiple folders support. 7 | - Ability to assign Tags to any wallpaper. 8 | - Can scan .nomedia directories, useful if you want to keep your wallpapers away from gallery. 9 | - Apply blur and color filters dynamically on any wallpaper before applying. 10 | - Simple yet pretty animations with proper optimizations. 11 | - Compress or reduce images on the fly. 12 | - No ads, no tracking, no analytics, no internet permissions, no unnecessary permissions. 13 | - Auto wallpaper change support with dedicated folders and tags for each screens. 14 | - Change wallpaper using app's live wallpaper 15 | - Edit and apply filters on wallpapers losslessly in realtime. 16 | - Built-in live wallpaper picker. 17 | - Dark mode support. 18 | - Glassmorphic UI based on realtime blur effects and caustic shadows. 19 | - Material You color theme. 20 | - Fully reproducible build. 21 | - Zero loading software architecture. 22 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/fastlane/metadata/android/en-US/images/icon.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/fastlane/metadata/android/en-US/images/phoneScreenshots/01.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/fastlane/metadata/android/en-US/images/phoneScreenshots/02.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/fastlane/metadata/android/en-US/images/phoneScreenshots/03.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/fastlane/metadata/android/en-US/images/phoneScreenshots/04.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/fastlane/metadata/android/en-US/images/phoneScreenshots/05.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/fastlane/metadata/android/en-US/images/phoneScreenshots/06.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/fastlane/metadata/android/en-US/images/phoneScreenshots/07.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/fastlane/metadata/android/en-US/images/phoneScreenshots/08.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/fastlane/metadata/android/en-US/images/phoneScreenshots/09.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/fastlane/metadata/android/en-US/images/phoneScreenshots/10.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/fastlane/metadata/android/en-US/images/phoneScreenshots/11.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/images/phoneScreenshots/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/fastlane/metadata/android/en-US/images/phoneScreenshots/12.png -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/short_description.txt: -------------------------------------------------------------------------------- 1 | Simple wallpaper manager app with Auto Wallpaper and Multi Folder support. 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/en-US/title: -------------------------------------------------------------------------------- 1 | Peristyle -------------------------------------------------------------------------------- /fastlane/metadata/android/pl-PL/full_description.txt: -------------------------------------------------------------------------------- 1 | Peristyle zostało stworzone, by być bardzo prostą oraz łatwą w obsłudze aplikacją do porządkowania, oraz wybierania tapet na system Android. Rozwiązuje problem związany ze zbyt dużą ilością funkcji czy też programów zza dużym rozmiarem, czy także minimalnej kompatybilności z tapetami znajdującymi się na urządzeniu. Chciałbyś/łabyś aplikację, która pozwala na wybieranie oraz przeglądanie tapet prosto z pamięci urządzenia, i na zarządzanie nimi? Więc Peristyle jest strzałem w dziesiątkę. :) 2 | 3 | Funkcje: 4 | 5 | Prosta architektura do przeglądania oraz używania systemowego menadżera tapet do ustawienia ich. 6 | - Obsługa wielu folderów jednocześnie. 7 | - Dodawanie tagów do każdej tapety. 8 | - Skanowanie folderów typu .nomedia. Przydatne, jeśli chcesz, by twoje tapety nie były w galerii zdjęć na urządzeniu. 9 | - Dodawanie efektu rozmycia i filtrów kolorów do wybranej tapety tuż przed ustawieniem jej. 10 | - Proste i przyjazne dla oka zoptymalizowane animacje. 11 | - Kompresja i zmniejszanie rozmiaru pliku tapety. 12 | - Brak reklam, śledzenia, analiz oraz dostępu do internetu czy niepotrzebnych uprawnień. 13 | - Automatyczna zmiana tapety z obsługą wybranych folderów oraz tagów. 14 | - Zmień tapetę używając żywej tapety aplikacji 15 | - Edytuj i zastosuj filtry na tapetach w czasie rzeczywistym. 16 | - Wbudowany menedżer tapet animowanych. 17 | - Ciemny motyw. 18 | - Interfejs w stylu Glass, oparty na efektach rozmycia oraz cieni. 19 | - Materiał w kolorze motywu. 20 | - Budowa w pełni odtwarzalna. 21 | - Zero ładowania architektury oprogramowania. 22 | -------------------------------------------------------------------------------- /fastlane/metadata/android/pl-PL/short_description.txt: -------------------------------------------------------------------------------- 1 | Prosty menedżer tapet z funkcją tapet animowanych oraz z obsługą kilku folderów naraz. 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/ru-RU/full_description.txt: -------------------------------------------------------------------------------- 1 | Peristyle создан для того, чтобы быть очень простым и продвинутым менеджером обоев для Android. Оно решает проблему слишком большой функциональности и раздутых приложений и имеет очень минимальную поддержку локально сохраненных обоев. Что если вы просто хотите приложение которое позволяет просматривать и выбирать собственные локальные обои и позволяет вам управлять и устанавливать обои оттуда? Тогда Peristyle для вас :) 2 | 3 | Возможности: 4 | 5 | - Простая архитектура, просмотр обоев и использование системного менеджера обоев для их установки в качестве обоев. 6 | - Поддержка нескольких папок. 7 | - Возможность присвоения меток любым обоям. 8 | - Может сканировать папки .nomedia, это полезно, если вы хотите сохранить свои обои из галереи. 9 | - Динамически применять размытие и цветовые фильтры на любых обоях перед применением. 10 | - Простая, но красивая анимация с надлежащей оптимизацией. 11 | - Сжатие или уменьшение изображений на лету. 12 | - Без рекламы, без отслеживания, анализа и доступа к интернету, без лишних разрешений. 13 | - Автоматическая смена обоев с помощью выделенных папок и меток для каждого экрана. 14 | - Изменить обои, используя живые обои приложения 15 | - Редактируйте и применяйте фильтры к обоям без потерь в режиме реального времени. 16 | - Встроенный выбор обоев на живую. 17 | - Поддержка тёмного режима. 18 | - Стекломорфический интерфейс, основанный на эффектах размытия в реальном времени и каустической тени. 19 | - Material You цветовая тема. 20 | - Полностью воспроизводимая сборка. 21 | - Архитектура программного обеспечения с нулевой загрузкой. 22 | -------------------------------------------------------------------------------- /fastlane/metadata/android/ru-RU/short_description.txt: -------------------------------------------------------------------------------- 1 | Простой менеджер обоев с поддержкой автообоев и множественных папок. 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/tr-TR/full_description.txt: -------------------------------------------------------------------------------- 1 | Peristyle, Android için son derece basit ve sofistike bir duvar kağıdı yöneticisi ve tarayıcı uygulaması olarak oluşturuldu. Çok fazla özelliğe ve şişirilmiş uygulamalara sahip olma sorununu ve yerel olarak depolanan duvar kağıtları için çok az destek sunulmasını çözer. Çok fazla özelliğe ve şişirilmiş uygulamalara sahip olma sorununu ve yerel olarak depolanan duvar kağıtları için çok az destek sunulmasını çözer. Ya sadece kendi yerel olarak depolanan duvar kağıtlarınızı taramanıza ve seçmenize olanak tanıyan, bunları yönetmenize ve duvar kağıdı olarak ayarlamanıza izin veren bir uygulama isteseydiniz? O zaman Peristyle tam size göre :) 2 | 3 | Özellikler: 4 | 5 | - Basit mimari, duvar kağıtlarını tarayın ve sistem duvar kağıdı yöneticisini kullanarak bunları duvar kağıdı olarak ayarlayın. 6 | - Birden fazla klasör desteği. 7 | - Herhangi bir duvar kağıdına etiket atama yeteneği. 8 | - **.nomedia** dizinlerini tarayabilir, duvar kağıtlarınızı galeriden uzak tutmak istiyorsanız kullanışlıdır. 9 | - Uygulamadan önce herhangi bir duvar kağıdına bulanıklık ve renk filtreleri dinamik olarak uygulayın. 10 | - Uygun optimizasyonlarla basit ama hoş animasyonlar. 11 | - Görselleri anında sıkıştırma veya boyutlarını küçültme. 12 | - Reklam yok, izleme yok, analiz yok, internet izinleri yok, gereksiz izinler yok. 13 | - Özel klasörler ve her ekran için etiketlerle otomatik duvar kağıdı değiştirme desteği. 14 | - Uygulamanın canlı duvar kağıdını kullanarak duvar kağıdını değiştirin 15 | - Duvar kağıtlarını gerçek zamanlı olarak kayıpsız şekilde düzenleyin ve filtreler uygulayın. 16 | - Dahili canlı duvar kağıdı seçici. 17 | - Karanlık mod desteği. 18 | - Gerçek zamanlı bulanıklık efektleri ve ışık kırılmalarına dayalı cam benzeri kullanıcı arayüzü. 19 | - Material You renk teması. 20 | - Tamamen yeniden üretilebilir (reproducible) yapı. 21 | - Sıfır yükleme yazılım mimarisi. 22 | -------------------------------------------------------------------------------- /fastlane/metadata/android/tr-TR/short_description.txt: -------------------------------------------------------------------------------- 1 | Otomatik Duvar Kağıdı ve Çoklu Klasör desteğine sahip basit duvar kağıdı yöneticisi uygulaması. 2 | -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/full_description.txt: -------------------------------------------------------------------------------- 1 | 开发Peristyle是想打造一款适用于安卓系统的极简且精致的壁纸管理与浏览应用程序。 它解决了功能过多、应用臃肿以及对本地存储壁纸的支持极少的问题。 如果您只想要一款允许您浏览并选择自己本地存储的壁纸,还能从这里管理和设置壁纸的应用程序,该怎么做呢? 那么Peristyle就非常适合你 :) 2 | 3 | 特点: 4 | 5 | - 架构简约,可浏览壁纸,使用系统壁纸管理器将其设置为壁纸 。 6 | - 支持多个文件夹。 7 | - 能够给任何壁纸分配标签。 8 | - 可以扫描.nomedia目录,如果您想让壁纸不显示在图库中,该功能很有用。 9 | - 应用壁纸前可对任何壁纸动态应用模糊和色彩滤镜。 10 | - 具有简单而精美的动画,已经过适当优化。 11 | - 即时压缩或缩小图像。 12 | - 没有广告,不会跟踪,不会分析数据,不需要连接网络,也不获取不必要的权限。 13 | - 支持自动更换壁纸,为每个屏幕设置专用文件夹和标签 。 14 | - 内置实时壁纸选取器。 15 | - 支持深色模式。 16 | - 具有基于实时模糊效果和焦散阴影的玻璃拟态用户界面。 17 | - Material You 风格主题和颜色。 18 | -------------------------------------------------------------------------------- /fastlane/metadata/android/zh-CN/short_description.txt: -------------------------------------------------------------------------------- 1 | 简单的壁纸管理器应用程序,支持自动切换壁纸和多文件夹功能。 2 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## For more details on how to configure your build environment visit 2 | # http://www.gradle.org/docs/current/userguide/build_environment.html 3 | # 4 | # Specifies the JVM arguments used for the daemon process. 5 | # The setting is particularly useful for tweaking memory settings. 6 | # Default value: -Xmx1024m -XX:MaxPermSize=256m 7 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 8 | # 9 | # When configured, Gradle will run in incubating parallel mode. 10 | # This option should only be used with decoupled projects. For more details, visit 11 | # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects 12 | # org.gradle.parallel=true 13 | #Mon Oct 28 22:09:10 IST 2024 14 | android.nonTransitiveRClass=true 15 | android.useAndroidX=true 16 | kotlin.code.style=official 17 | org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M" -Dfile.encoding\=UTF-8 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Jul 18 21:36:32 IST 2023 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /screenshots/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/screenshots/01.png -------------------------------------------------------------------------------- /screenshots/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/screenshots/02.png -------------------------------------------------------------------------------- /screenshots/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/screenshots/03.png -------------------------------------------------------------------------------- /screenshots/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/screenshots/04.png -------------------------------------------------------------------------------- /screenshots/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/screenshots/05.png -------------------------------------------------------------------------------- /screenshots/06.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamza417/Peristyle/66d1b4a47f2fa1c83a9855e58cf972ba18b3565a/screenshots/06.gif -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | gradlePluginPortal() 6 | maven { 7 | url "https://jitpack.io" 8 | } 9 | } 10 | } 11 | 12 | dependencyResolutionManagement { 13 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 14 | repositories { 15 | google() 16 | mavenCentral() 17 | maven { 18 | url "https://jitpack.io" 19 | } 20 | } 21 | } 22 | 23 | rootProject.name = "Peristyle" 24 | include ':app' 25 | --------------------------------------------------------------------------------