diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 1af01d6f7..000000000 --- a/.editorconfig +++ /dev/null @@ -1,11 +0,0 @@ -# -# SPDX-FileCopyrightText: 2025 The Calyx Institute -# SPDX-License-Identifier: GPL-3.0-or-later -# - -root = true - -[*.{kt,kts}] -ktlint_code_style = android_studio -ktlint_function_naming_ignore_when_annotated_with = Composable -ktlint_standard_class-signature = disabled diff --git a/.gitignore b/.gitignore index 00b27ca70..7abcc84e1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,3 @@ -# -# SPDX-FileCopyrightText: 2021-2025 Aurora OSS -# SPDX-License-Identifier: GPL-3.0-or-later -# - # Built application files *.apk *.ap_ @@ -41,10 +36,9 @@ gradle-app.setting *.zip app/release/* +app/beta/* +app/alpha/* app/nightly/* -app/vanilla/* -app/huawei/* -app/preload/* #Exclude signing configurations & keystore @@ -53,3 +47,7 @@ signing.properties .kotlin/* +# Next.js +.next/ +out/ +node_modules/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7b4d95a18..311883b8d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,35 +1,22 @@ -# -# SPDX-FileCopyrightText: 2021-2025 Aurora OSS -# SPDX-FileCopyrightText: 2023-2025 The Calyx Institute -# SPDX-License-Identifier: GPL-3.0-or-later -# - variables: PACKAGE_VERSION: "continuous" - DEBUG_BINARY: "com.aurora.store.vanilla.debug_${CI_COMMIT_SHORT_SHA}.apk" - DEBUG_BINARY_PATH: "app/build/outputs/apk/vanilla/debug/app-vanilla-debug.apk" + DEBUG_BINARY: "com.aurora.store.debug_${CI_COMMIT_SHORT_SHA}.apk" + DEBUG_BINARY_PATH: "app/build/outputs/apk/debug/app-debug.apk" PACKAGE_REGISTRY_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/debug/${PACKAGE_VERSION}" stages: - build -- lint - upload +- release -assembleVanillaDebug: +assembleDebug: stage: build image: theimpulson/gitlab-ci-android:latest script: - - './gradlew assembleVanillaDebug' + - './gradlew assembleDebug' artifacts: paths: - $DEBUG_BINARY_PATH - - 'app/schemas/com.aurora.store.data.room.AuroraDatabase/' - -lintChecks: - stage: lint - image: theimpulson/gitlab-ci-android:latest - script: - - './gradlew ktlintCheck' uploadDebug: stage: upload diff --git a/.gitlab/issue_templates/Bug-Report.md b/.gitlab/issue_templates/Bug-Report.md index 09b8abe86..55dc5bc6a 100644 --- a/.gitlab/issue_templates/Bug-Report.md +++ b/.gitlab/issue_templates/Bug-Report.md @@ -3,7 +3,7 @@ https://auroraoss.com/guides/wiki-home/ - Provide a general summary of the issue in the Title above. - Check if your issue or something similar has been reported before (if yes upvote/comment there) -- If you are on latest stable release, please also check if the issue is reproducible on the latest nightly build from here: https://auroraoss.com/files/AuroraStore/Nightly +- If you are on latest stable release, please also check if the issue is reproducible on the latest nightly build from here: https://auroraoss.com/AuroraStore/Nightly/ - Make sure you have read [wiki](https://gitlab.com/AuroraOSS/AuroraStore/-/wikis/home) especially FAQs - If you did not know already, everything between " diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 000000000..5825da5b6 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,55 @@ +# JMODS Architecture + +This document outlines the modern, modular Clean Architecture implemented for the JMODS app store. + +## Core Principles + +- **Clean Architecture**: Strict separation of concerns into Data, Domain, and Presentation layers. +- **Modularization**: High-cohesion, low-coupling modules to improve build times and maintainability. +- **Offline-First**: Reliable access to app metadata using local persistence (Room). +- **Reactive UI**: State-driven UI built with Jetpack Compose and Kotlin Flow. + +## Tech Stack + +- **UI**: Jetpack Compose, Material 3 +- **Dependency Injection**: Hilt +- **Persistence**: Room (SQL), DataStore (Preferences) +- **Network**: OkHttp, Kotlinx Serialization +- **Image Loading**: Coil 3 +- **Navigation**: Type-Safe Navigation (Compose) +- **Background Tasks**: WorkManager + +## Module Structure + +The project is divided into several logical layers and modules within `jmods-android/`: + +### 1. Presentation Layer (Features & UI) + +- **:jmods:core-ui**: Shared design system. Contains the `JMODSTheme`, common Compose components (e.g., `AppCard`, `JModsTopBar`), and UI utilities. +- **:jmods:feature-home**: Discovery screen. Displays categorized app lists and hero sections. +- **:jmods:feature-details**: App details screen. Shows descriptions, versions, and installation options. +- **:jmods:feature-categories**: Category browsing screen. + +### 2. Domain Layer (Business Logic) + +- **:jmods:core-domain**: The heart of the app. Contains: + - **Models**: Plain Kotlin classes representing the business entities (e.g., `App`). + - **UseCases**: Granular business logic (e.g., `GetAppsUseCase`, `GetAppDetailsUseCase`). + - **Repository Interfaces**: Definitions for data operations. + +### 3. Data Layer (Implementation) + +- **:jmods:core-data**: Implements Repository interfaces. Orchestrates between local and remote sources using a "cache-then-network" strategy. +- **:jmods:core-database**: Room-based local persistence. Stores app metadata for offline access and performance. +- **:jmods:core-network**: Remote data source. +- **:jmods:core-auth**: Authentication management. +- **:jmods:core-installer**: Handles APK installation and uninstallation logic. + +### 4. Infrastructure + +- **:jmods:core-navigation**: Defines type-safe routes and destination models. +- **:jmods:app**: The main entry point for the Android application. + +## Web Storefront + +The repository also includes a high-performance web storefront built with **Next.js 16**, **React 19**, and **Tailwind CSS 4**, located in the `app/` directory. diff --git a/CHANGELOG b/CHANGELOG index 46b207b87..8bfd9179b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,48 +1,3 @@ -Changelog : v4.8.1 (73) -• Fix login issues -• Minor bug fixes and improvements -• Translation updates - -Changelog: v4.8.0 (72) -• Minimum supported Android version is now Android 6.0 -• Switched to Material3 Expressive theme -• Improved support for wide-screen devices -• Fixed an issue where Hebrew language wasn't set properly with per-app language -• Restored search filters functionality - -Changelog : v4.7.5 (71) -• Fix app install issue on huawei devices -• Translation updates - -Changelog : v4.7.4 (70) -• Do not prompt for microG installs on non-huawei builds -• Translation updates - -Changelog : v4.7.3 (69) -• Add capability to install microG bundle on Huawei devices -• Minor bug fixes and improvements -• Translation updates - -Changelog : v4.7.2 (68) -• Switch to new APIs for searching and installing apps -• Search filter is no longer available, will be added back later -• Fix crash on navigating to app details page -• Fix crash on spoofing locale -• Translation updates - -Changelog : v4.7.1 (67) -• Target Android 16 -• Fix bug with opening links to apps -• Support opening the app's detail page from app info settings -• Translation updates - -Changelog : v4.7.0 (66) -• New app compatibility ratings powered by Plexus -• Improvements to blacklist manager -• Ability to change auto-update restrictions -• Minor bug fixes and improvements -• Translation updates; additional strings localized - Changelog : v4.6.4 (65) • Fixed issues with shared library installation for apps like Chrome and WebView • Support for login into personal account using microG diff --git a/DISCLAIMER.md b/DISCLAIMER.md index 6c02fe178..5c23dc25a 100644 --- a/DISCLAIMER.md +++ b/DISCLAIMER.md @@ -31,7 +31,7 @@ You are to hold yourself responsible by installing **Aurora Store** from other s The following sources are the only official links we provide: -- **F-Droid:** https://f-droid.org/packages/com.aurora.store/ +- **F-Droid:** https://f-droid.org/en/packages/com.aurora.store/ - **AuroraOSS Website:** https://auroraoss.com/downloads.php - **Official Telegram Channel:** https://t.me/AuroraOfficial - **GitLab:** https://gitlab.com/AuroraOSS/AuroraStore/-/releases diff --git a/LATEST_LEARNINGS.md b/LATEST_LEARNINGS.md new file mode 100644 index 000000000..f54bc04d8 --- /dev/null +++ b/LATEST_LEARNINGS.md @@ -0,0 +1,21 @@ +# JMods Architecture Enhancements - Learnings + +## Core Persistent Strategy +- Implemented a **Cache-First** strategy in `AppRepositoryImpl`. +- The repository emits cached data from Room immediately before fetching from the network. +- This ensures a fast, responsive UI and allows the app to function offline. + +## Modularization & UI Consistency +- Created a `:jmods:core-ui` module to centralize the Design System. +- Feature modules (`feature-home`, `feature-details`) now depend on `core-ui` for shared components like `AppCard` and the global theme. +- This structure reduces code duplication and ensures visual consistency across the entire app. + +## Build System & Compatibility +- Standardized all modules to use **Java 21** and **Gradle 8.12**. +- Successfully integrated **Room** with **KSP** in a multi-module environment. +- Navigating between modules using Type-Safe Navigation (`kotlinx-serialization`) is working seamlessly within the `NavHost` in the `app` module. + +## Next Steps +- Implement actual APK downloading and installation in `:core-installer`. +- Integrate the real `gplayapi` into `:core-network`. +- Add unit tests for the Repository and UseCases. diff --git a/LICENSE b/LICENSE index d97330910..aa5e99924 100644 --- a/LICENSE +++ b/LICENSE @@ -631,8 +631,7 @@ to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - - Copyright (C) 2025 Rahul Patel + Copyright (C) 2021, Rahul Kumar Patel This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -652,7 +651,7 @@ Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - Copyright (C) 2025 Rahul Patel + AuroraStore Copyright (C) 2019, Rahul Kumar Patel This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. diff --git a/LICENSES/Apache-2.0.txt b/LICENSES/Apache-2.0.txt deleted file mode 100644 index 137069b82..000000000 --- a/LICENSES/Apache-2.0.txt +++ /dev/null @@ -1,73 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - - (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - - You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/LICENSES/CC0-1.0.txt b/LICENSES/CC0-1.0.txt deleted file mode 100644 index 0e259d42c..000000000 --- a/LICENSES/CC0-1.0.txt +++ /dev/null @@ -1,121 +0,0 @@ -Creative Commons Legal Code - -CC0 1.0 Universal - - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE - LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN - ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS - INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES - REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS - PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM - THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED - HEREUNDER. - -Statement of Purpose - -The laws of most jurisdictions throughout the world automatically confer -exclusive Copyright and Related Rights (defined below) upon the creator -and subsequent owner(s) (each and all, an "owner") of an original work of -authorship and/or a database (each, a "Work"). - -Certain owners wish to permanently relinquish those rights to a Work for -the purpose of contributing to a commons of creative, cultural and -scientific works ("Commons") that the public can reliably and without fear -of later claims of infringement build upon, modify, incorporate in other -works, reuse and redistribute as freely as possible in any form whatsoever -and for any purposes, including without limitation commercial purposes. -These owners may contribute to the Commons to promote the ideal of a free -culture and the further production of creative, cultural and scientific -works, or to gain reputation or greater distribution for their Work in -part through the use and efforts of others. - -For these and/or other purposes and motivations, and without any -expectation of additional consideration or compensation, the person -associating CC0 with a Work (the "Affirmer"), to the extent that he or she -is an owner of Copyright and Related Rights in the Work, voluntarily -elects to apply CC0 to the Work and publicly distribute the Work under its -terms, with knowledge of his or her Copyright and Related Rights in the -Work and the meaning and intended legal effect of CC0 on those rights. - -1. Copyright and Related Rights. A Work made available under CC0 may be -protected by copyright and related or neighboring rights ("Copyright and -Related Rights"). Copyright and Related Rights include, but are not -limited to, the following: - - i. the right to reproduce, adapt, distribute, perform, display, - communicate, and translate a Work; - ii. moral rights retained by the original author(s) and/or performer(s); -iii. publicity and privacy rights pertaining to a person's image or - likeness depicted in a Work; - iv. rights protecting against unfair competition in regards to a Work, - subject to the limitations in paragraph 4(a), below; - v. rights protecting the extraction, dissemination, use and reuse of data - in a Work; - vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal - protection of databases, and under any national implementation - thereof, including any amended or successor version of such - directive); and -vii. other similar, equivalent or corresponding rights throughout the - world based on applicable law or treaty, and any national - implementations thereof. - -2. Waiver. To the greatest extent permitted by, but not in contravention -of, applicable law, Affirmer hereby overtly, fully, permanently, -irrevocably and unconditionally waives, abandons, and surrenders all of -Affirmer's Copyright and Related Rights and associated claims and causes -of action, whether now known or unknown (including existing as well as -future claims and causes of action), in the Work (i) in all territories -worldwide, (ii) for the maximum duration provided by applicable law or -treaty (including future time extensions), (iii) in any current or future -medium and for any number of copies, and (iv) for any purpose whatsoever, -including without limitation commercial, advertising or promotional -purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each -member of the public at large and to the detriment of Affirmer's heirs and -successors, fully intending that such Waiver shall not be subject to -revocation, rescission, cancellation, termination, or any other legal or -equitable action to disrupt the quiet enjoyment of the Work by the public -as contemplated by Affirmer's express Statement of Purpose. - -3. Public License Fallback. Should any part of the Waiver for any reason -be judged legally invalid or ineffective under applicable law, then the -Waiver shall be preserved to the maximum extent permitted taking into -account Affirmer's express Statement of Purpose. In addition, to the -extent the Waiver is so judged Affirmer hereby grants to each affected -person a royalty-free, non transferable, non sublicensable, non exclusive, -irrevocable and unconditional license to exercise Affirmer's Copyright and -Related Rights in the Work (i) in all territories worldwide, (ii) for the -maximum duration provided by applicable law or treaty (including future -time extensions), (iii) in any current or future medium and for any number -of copies, and (iv) for any purpose whatsoever, including without -limitation commercial, advertising or promotional purposes (the -"License"). The License shall be deemed effective as of the date CC0 was -applied by Affirmer to the Work. Should any part of the License for any -reason be judged legally invalid or ineffective under applicable law, such -partial invalidity or ineffectiveness shall not invalidate the remainder -of the License, and in such case Affirmer hereby affirms that he or she -will not (i) exercise any of his or her remaining Copyright and Related -Rights in the Work or (ii) assert any associated claims and causes of -action with respect to the Work, in either case contrary to Affirmer's -express Statement of Purpose. - -4. Limitations and Disclaimers. - - a. No trademark or patent rights held by Affirmer are waived, abandoned, - surrendered, licensed or otherwise affected by this document. - b. Affirmer offers the Work as-is and makes no representations or - warranties of any kind concerning the Work, express, implied, - statutory or otherwise, including without limitation warranties of - title, merchantability, fitness for a particular purpose, non - infringement, or the absence of latent or other defects, accuracy, or - the present or absence of errors, whether or not discoverable, all to - the greatest extent permissible under applicable law. - c. Affirmer disclaims responsibility for clearing rights of other persons - that may apply to the Work or any use thereof, including without - limitation any person's Copyright and Related Rights in the Work. - Further, Affirmer disclaims responsibility for obtaining any necessary - consents, permissions or other rights required for any use of the - Work. - d. Affirmer understands and acknowledges that Creative Commons is not a - party to this document and has no duty or obligation with respect to - this CC0 or use of the Work. diff --git a/LICENSES/GPL-3.0-or-later.txt b/LICENSES/GPL-3.0-or-later.txt deleted file mode 100644 index f6cdd22a6..000000000 --- a/LICENSES/GPL-3.0-or-later.txt +++ /dev/null @@ -1,232 +0,0 @@ -GNU GENERAL PUBLIC LICENSE -Version 3, 29 June 2007 - -Copyright © 2007 Free Software Foundation, Inc. - -Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - -Preamble - -The GNU General Public License is a free, copyleft license for software and other kinds of works. - -The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. - -When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. - -To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. - -For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. - -Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. - -For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. - -Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. - -Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. - -The precise terms and conditions for copying, distribution and modification follow. - -TERMS AND CONDITIONS - -0. Definitions. - -“This License” refers to version 3 of the GNU General Public License. - -“Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. - -“The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations. - -To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work. - -A “covered work” means either the unmodified Program or a work based on the Program. - -To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. - -To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. - -An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. - -1. Source Code. -The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work. - -A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. - -The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. - -The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. - -The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. - -The Corresponding Source for a work in source code form is that same work. - -2. Basic Permissions. -All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. - -You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. - -Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. - -3. Protecting Users' Legal Rights From Anti-Circumvention Law. -No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. - -When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. - -4. Conveying Verbatim Copies. -You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. - -You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. - -5. Conveying Modified Source Versions. -You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”. - - c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. - -A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. - -6. Conveying Non-Source Forms. -You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: - - a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. - - d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. - -A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. - -A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. - -“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. - -If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). - -The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. - -Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. - -7. Additional Terms. -“Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. - -When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. - -Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or authors of the material; or - - e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. - -All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. - -If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. - -Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. - -8. Termination. -You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). - -However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. - -Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. - -Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. - -9. Acceptance Not Required for Having Copies. -You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. - -10. Automatic Licensing of Downstream Recipients. -Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. - -An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. - -You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. - -11. Patents. -A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”. - -A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. - -Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. - -In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. - -If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. - -If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. - -A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. - -Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. - -12. No Surrender of Others' Freedom. -If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. - -13. Use with the GNU Affero General Public License. -Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. - -14. Revised Versions of this License. -The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. - -If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. - -Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. - -15. Disclaimer of Warranty. -THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - -16. Limitation of Liability. -IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -17. Interpretation of Sections 15 and 16. -If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - -If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”. - -You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . - -The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . diff --git a/README.md b/README.md index 188b71f9e..e249a05b5 100644 --- a/README.md +++ b/README.md @@ -1,118 +1,39 @@ -# Aurora Store +# JMODS — Private Android App Store -Aurora Store enables you to search and download apps from the official Google Play store. You can check app descriptions, screenshots, updates, reviews, and download the APK directly from Google Play to your device. +JMODS is a modern, privacy-focused Android app store. It enables you to search, discover, and install apps privately without tracking or the need for a Google account. -To use Aurora Store, log in using Google Play account, when you first open and configure Aurora Store. +## Project Structure -Unlike a traditional app store, Aurora Store does not own, license or distribute any apps. All apps, app descriptions, screenshots and other content in Aurora Store are directly accessed, downloaded and/or displayed from Google Play. +This repository is a monorepo containing: -Aurora Store works exactly like a door or a browser, allowing you to log in to your Google Play account and find the apps from Google Play. - -*_Please note that Aurora Store does not have any approval, sponsorship or authorization from Google, Google Play, any apps downloaded through Aurora Store or any app developers; neither does Aurora Store have any affiliation, cooperation or connection with them._* - -[Get it on F-Droid](https://f-droid.org/packages/com.aurora.store/) -[Get it on IzzyOnDroid](https://apt.izzysoft.de/fdroid/index/apk/com.aurora.store) +- **jmods-android/**: A modern Android application built with Jetpack Compose, Hilt, and Clean Architecture. +- **app/**: A high-performance web storefront built with Next.js 16 and React 19. ## Features -- FOSS: Has GPLv3 licence -- Beautiful design: Built upon latest Material 3 guidelines -- Account login: You can login with either personal or an anonymous account -- Device & Locale spoofing: Change your device and/or locale to access geo locked apps -- [Exodus Privacy](https://exodus-privacy.eu.org/) integration: Instantly see trackers in app -- [Plexus](https://plexus.techlore.tech/) integration: Instantly see app compatibility without Google Play Services or with microG -- Updates blacklisting: Ignore updates for specific apps -- Download manager -- Manual downloads: allows you to download older version of apps, provided - - The APKs are available with Google - - You know the version codes for older versions - -## Limitations - -- The underlying API used is reversed engineered from the Google Play Store, changes on side may break it. -- Provides only base minimum features - - Can not download or update paid apps. - - Can not update apps/games with [Play Asset Delivery](https://developer.android.com/guide/playcore/asset-delivery) -- Multiple in-app features are not available if logged in as Anonymous. - - Library - - Purchase History - - Editor's choice - - Beta Programs - - Review Add/Update -- Token dispenser server is not super reliable, downtimes are expected. - -## Downloads - -Please only download the latest stable releases from one of these sources: - -- [Official website](https://auroraoss.com/) -- [GitLab Releases](https://gitlab.com/AuroraOSS/AuroraStore/-/releases) -- [IzzyOnDroid](https://apt.izzysoft.de/fdroid/index/apk/com.aurora.store) (reproducible) -- [F-Droid](https://f-droid.org/packages/com.aurora.store/) (signed by F-Droid, [more details](https://f-droid.org/docs/Signing_Process/)) -- [App Gallery](https://appgallery.huawei.com/app/C110907863) (limited to certain countries) - -You can also get latest debug builds signed with AOSP test keys for testing latest changes from our [GitLab Package Registry](https://gitlab.com/AuroraOSS/AuroraStore/-/packages/24103616). - -## Certificate Fingerprints - -- SHA1: 94:42:75:D7:59:8B:C0:3E:48:85:06:06:42:25:A7:19:90:A2:22:02 -- SHA256: 4C:62:61:57:AD:02:BD:A3:40:1A:72:63:55:5F:68:A7:96:63:FC:3E:13:A4:D4:36:9A:12:57:09:41:AA:28:0F - -## Support - -Aurora Store v4 is still in on-going development! Bugs are to be expected! Any bug reports are appreciated. -Please visit [Aurora Wiki](https://gitlab.com/AuroraOSS/AuroraStore/-/wikis/home) for FAQs. - -- [Telegram](https://t.me/AuroraSupport) -- [XDA Developers](https://forum.xda-developers.com/t/app-5-0-aurora-store-open-source-google-play-client.3739733/) - -## Permissions - -- `android.permission.INTERNET` to download and install/update apps from the Google Play servers -- `android.permission.ACCESS_NETWORK_STATE` to check internet availability -- `android.permission.FOREGROUND_SERVICE` to download apps without interruption -- `android.permission.FOREGROUND_SERVICE_DATA_SYNC` to download apps without interruption -- `android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS` to auto-update apps without interruption (optional) -- `android.permission.MANAGE_EXTERNAL_STORAGE` to access the OBB directory to download APK expansion files for games or large apps -- `android.permission.READ_EXTERNAL_STORAGE` to access the OBB directory to download APK expansion files for games or large apps -- `android.permission.WRITE_EXTERNAL_STORAGE` to access the OBB directory to download APK expansion files for games or large apps -- `android.permission.QUERY_ALL_PACKAGES` to check updates for all installed apps -- `android.permission.REQUEST_INSTALL_PACKAGES` to install and update apps -- `android.permission.REQUEST_DELETE_PACKAGES` to uninstall apps -- `android.permission.ENFORCE_UPDATE_OWNERSHIP` to silently update apps -- `android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION` to silently update apps -- `android.permission.POST_NOTIFICATIONS` to notify user about ongoing downloads, available updates, and errors (optional) -- `android.permission.USE_CREDENTIALS` to allow users to sign into their personal Google account via microG - -## Screenshots - - - - - - -## Translations - -Don't see your preferred language? Click on the widget below to help translate Aurora Store! - - - Translation status - - -## Donations +- **Privacy First**: No tracking, no ads, and no mandatory Google accounts. +- **Modern UI**: Clean Material 3 design on Android and a responsive Tailwind CSS 4 web interface. +- **Modular Architecture**: Built for maintainability and scalability. +- **Offline-First**: Metadata caching with Room persistence. +- **Privacy Audit**: Built-in tracker and permission analysis. -You can support Aurora Store's development financially via options below. For more options, checkout the **About** page within the Aurora Store. +## Getting Started -[![Liberapay](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/whyorean) - - PayPal - +### Android App +To build the Android application: +```bash +./gradlew :jmods:app:assembleDebug +``` -## Project references +### Web Storefront +To run the web storefront locally: +```bash +npm install +npm run dev # Runs on http://localhost:3001 +``` -Aurora Store is based on these projects +## Architecture +See [ARCHITECTURE.md](ARCHITECTURE.md) for a detailed breakdown of the technical design. -- [YalpStore](https://github.com/yeriomin/YalpStore) -- [AppCrawler](https://github.com/Akdeniz/google-play-crawler) -- [Raccoon](https://github.com/onyxbits/raccoon4) -- [SAI](https://github.com/Aefyr/SAI) +## License +Licensed under the MIT License. diff --git a/REUSE.toml b/REUSE.toml deleted file mode 100644 index 3a2e51d73..000000000 --- a/REUSE.toml +++ /dev/null @@ -1,39 +0,0 @@ -# -# SPDX-FileCopyrightText: 2025 The Calyx Institute -# SPDX-License-Identifier: GPL-3.0-or-later -# - -# This file describes the licensing and copyright situation for files that -# cannot be annotated directly, for example because of being simply -# uncommentable. Unless this is the case, a file should be annotated directly. -# -# This follows the REUSE specification: https://reuse.software/spec-3.3/#reusetoml - -version = 1 - -[[annotations]] -path = [ - ".gitlab/**", - "fastlane/**", - "CHANGELOG", - "README.md", - "DISCLAIMER.md", - "POLICY.md", - "updates.json", - "app/schemas/**", - "app/testkey.jks", - "app/src/main/**/*.png", - "app/src/main/res/resources.properties", -] -precedence = "aggregate" -SPDX-FileCopyrightText = [ - "2021-2025 Aurora OSS", - "2023-2025 The Calyx Institute" -] -SPDX-License-Identifier = "GPL-3.0-or-later" - -[[annotations]] -path = "gradle/wrapper/**" -precedence = "aggregate" -SPDX-FileCopyrightText = "2007-2023 Gradle, Inc." -SPDX-License-Identifier = "Apache-2.0" diff --git a/app/.gitignore b/app/.gitignore index d79cd808f..42afabfd2 100644 --- a/app/.gitignore +++ b/app/.gitignore @@ -1,6 +1 @@ -# -# SPDX-FileCopyrightText: 2021 Aurora OSS -# SPDX-License-Identifier: GPL-3.0-or-later -# - -/build +/build \ No newline at end of file diff --git a/app/app/[packageName]/page.tsx b/app/app/[packageName]/page.tsx new file mode 100644 index 000000000..45c736cee --- /dev/null +++ b/app/app/[packageName]/page.tsx @@ -0,0 +1,294 @@ +import { Navbar } from '@/components/navbar' +import { getAppByPackageName } from '@/lib/mock-data' +import { notFound } from 'next/navigation' +import Image from 'next/image' +import { + Download, + Shield, + ShieldCheck, + AlertTriangle, + Package, + Calendar, + HardDrive, + Cpu, + GitBranch, + ExternalLink, + ChevronLeft, + Info +} from 'lucide-react' +import Link from 'next/link' +import { CategoryBadge } from '@/components/category-badge' +import { StarRating } from '@/components/star-rating' +import { formatBytes, formatDate, formatRatingCount } from '@/lib/format' + +interface AppDetailsPageProps { + params: Promise<{ packageName: string }> +} + +export default async function AppDetailsPage({ params }: AppDetailsPageProps) { + const { packageName } = await params + const app = getAppByPackageName(packageName) + + if (!app) { + notFound() + } + + const dangerousPermissions = app.permissions.filter((p) => p.dangerous) + const safePermissions = app.permissions.filter((p) => !p.dangerous) + + return ( + <> + +
+ + + Back to Browse + + + {/* Header Section */} +
+
+
+ +
+ +
+
+

+ {app.name} +

+ {app.isOpenSource && ( + + Open Source + + )} +
+

{app.developer}

+
+ +
+ + {app.rating.average.toFixed(1)} + ({formatRatingCount(app.rating.count)} reviews) +
+
+ + {app.downloads} + downloads +
+
+
+
+ +
+ + + {app.isOpenSource && app.sourceUrl && ( + + + )} +
+
+ +
+
+
+

+ + About this app +

+

{app.longDescription}

+
+ + {/* Enhanced Permissions & Trackers UI */} +
+
+

+ + Permissions +

+ {app.permissions.length === 0 ? ( +
+ + No permissions required. +
+ ) : ( +
+ {dangerousPermissions.length > 0 && ( +
+

Sensitive Access

+
+ {dangerousPermissions.map((perm) => ( +
+
+ + {perm.name} +
+

{perm.description}

+
+ ))} +
+
+ )} + {safePermissions.length > 0 && ( +
+

Standard Access

+
+ {safePermissions.map((perm) => ( +
+ +
+ {perm.name} +

{perm.description}

+
+
+ ))} +
+
+ )} +
+ )} +
+ +
+

+ + Privacy Audit +

+ {app.trackers.length === 0 ? ( +
+
+ +
+

Clean App

+

No known trackers or ads detected in this version.

+
+ ) : ( +
+
+ +

{app.trackers.length} trackers detected

+
+
+ {app.trackers.map((tracker) => ( +
+ {tracker.name} + + Details + +
+ ))} +
+
+ )} +
+
+
+ +
+
+

+ Technical Specs +

+
+
+
+ + Version +
+
{app.version.versionName}
+
+
+
+ + Size +
+
{formatBytes(app.version.sizeBytes)}
+
+
+
+ + Architecture +
+
universal
+
+
+
+ + Requirement +
+
Android {app.version.minSdk}+
+
+
+
+ + Released +
+
{formatDate(app.version.uploadDate)}
+
+
+
+ + {app.version.changelog && ( +
+

+ {"What's New"} +

+
+ {app.version.changelog} +
+
+ )} + +
+

+ Package ID +

+

{app.packageName}

+
+
+
+
+ +
+
+

J MODS

+

The high-performance, private app store for Android.

+
+ Browse + Categories + Privacy +
+
+
+ + ) +} diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 032c125dc..b650da77f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,14 +1,24 @@ /* - * SPDX-FileCopyrightText: 2021-2025 Rahul Kumar Patel - * SPDX-FileCopyrightText: 2022-2025 The Calyx Institute - * SPDX-FileCopyrightText: 2023 grrfe - * SPDX-License-Identifier: GPL-3.0-or-later + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * Copyright (C) 2022, The Calyx Institute + * Copyright (C) 2023, grrfe + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * */ -@file:OptIn(KspExperimental::class) - -import com.android.build.api.dsl.ApplicationExtension -import com.google.devtools.ksp.KspExperimental import java.util.Properties plugins { @@ -16,7 +26,6 @@ plugins { alias(libs.plugins.jetbrains.kotlin.android) alias(libs.plugins.jetbrains.kotlin.compose) alias(libs.plugins.jetbrains.kotlin.parcelize) - alias(libs.plugins.jetbrains.kotlin.serialization) alias(libs.plugins.google.ksp) alias(libs.plugins.androidx.navigation) alias(libs.plugins.ktlint) @@ -24,49 +33,26 @@ plugins { alias(libs.plugins.hilt.android.plugin) } -val lastCommitHash = providers.exec { - commandLine("git", "rev-parse", "--short", "HEAD") -}.standardOutput.asText.map { it.trim() } - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(21) - } -} - kotlin { - compilerOptions { - freeCompilerArgs.addAll( - "-Xannotation-default-target=param-property" - ) - optIn.addAll( - "androidx.compose.material3.ExperimentalMaterial3Api", - "androidx.compose.material3.ExperimentalMaterial3ExpressiveApi", - "androidx.compose.foundation.layout.ExperimentalLayoutApi", - "androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi", - "coil3.annotation.ExperimentalCoilApi" - ) - } + jvmToolchain(21) } -configure { +android { namespace = "com.aurora.store" - compileSdk = 36 + compileSdk = 35 defaultConfig { applicationId = "com.aurora.store" - minSdk = 23 - targetSdk = 36 + minSdk = 21 + targetSdk = 35 - versionCode = 73 - versionName = "4.8.1" + versionCode = 65 + versionName = "4.6.4" testInstrumentationRunner = "com.aurora.store.HiltInstrumentationTestRunner" testInstrumentationRunnerArguments["disableAnalytics"] = "true" buildConfigField("String", "EXODUS_API_KEY", "\"bbe6ebae4ad45a9cbacb17d69739799b8df2c7ae\"") - - missingDimensionStrategy("device", "vanilla") } signingConfigs { @@ -108,7 +94,6 @@ configure { register("nightly") { initWith(getByName("release")) applicationIdSuffix = ".nightly" - versionNameSuffix = "-${lastCommitHash.get()}" } debug { @@ -117,32 +102,20 @@ configure { } } - flavorDimensions += "device" - - productFlavors { - create("vanilla") { - isDefault = true - dimension = "device" - } - - create("huawei") { - dimension = "device" - versionNameSuffix = "-hw" - } - - // This flavor is only for preloaded devices / users who push the app to system - create("preload") { - dimension = "device" - versionNameSuffix = "-preload" - } - } - buildFeatures { buildConfig = true viewBinding = true aidl = true compose = true } + kotlinOptions { + jvmTarget = JavaVersion.VERSION_21.toString() + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 + } lint { lintConfig = file("lint.xml") @@ -158,54 +131,27 @@ configure { } } -androidComponents { - beforeVariants(selector().all()) { variant -> - val flavour = variant.flavorName - if ((flavour == "huawei" || flavour == "preload") && variant.buildType == "nightly") { - variant.enable = false - } - } -} - -ksp { - arg("room.schemaLocation", "$projectDir/schemas") -} - -ktlint { - android = true - verbose = true -} - dependencies { - // Google's Goodies + //Google's Goodies implementation(libs.google.android.material) + implementation(libs.google.gson) implementation(libs.google.protobuf.javalite) - // AndroidX + //AndroidX implementation(libs.androidx.core.ktx) implementation(libs.androidx.browser) implementation(libs.androidx.lifecycle.viewmodel.ktx) - implementation(libs.androidx.lifecycle.navigation3) + implementation(libs.androidx.lifecycle.process) + implementation(libs.androidx.navigation.fragment.ktx) + implementation(libs.androidx.navigation.ui.ktx) implementation(libs.androidx.preference.ktx) implementation(libs.androidx.swiperefreshlayout) implementation(libs.androidx.viewpager2) implementation(libs.androidx.work.runtime.ktx) - implementation(libs.androidx.paging.runtime) - - implementation(libs.androidx.adaptive.core) - implementation(libs.androidx.adaptive.navigation) - implementation(libs.androidx.adaptive.layout) - implementation(libs.androidx.paging.compose) - implementation(libs.androidx.navigation3.runtime) - implementation(libs.androidx.navigation3.ui) - implementation(libs.kotlinx.serialization.json) - implementation(libs.androidx.navigation.fragment.ktx) - implementation(libs.androidx.navigation.ui.ktx) implementation(libs.androidx.activity.compose) implementation(platform(libs.androidx.compose.bom)) - implementation(libs.androidx.material3) implementation(libs.androidx.ui) implementation(libs.androidx.ui.graphics) @@ -215,28 +161,28 @@ dependencies { debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) - // Coil + //Coil implementation(libs.coil.kt) implementation(libs.coil.compose) implementation(libs.coil.network) - // Shimmer + //Shimmer implementation(libs.facebook.shimmer) - // Epoxy + //Epoxy implementation(libs.airbnb.epoxy.android) ksp(libs.airbnb.epoxy.processor) - // HTTP Clients + //HTTP Clients implementation(libs.squareup.okhttp) - // Lib-SU + //Lib-SU implementation(libs.github.topjohnwu.libsu) - // GPlayApi + //GPlayApi implementation(libs.auroraoss.gplayapi) - // Shizuku + //Shizuku compileOnly(libs.rikka.hidden.stub) implementation(libs.rikka.tools.refine.runtime) implementation(libs.rikka.shizuku.api) @@ -244,7 +190,7 @@ dependencies { implementation(libs.lsposed.hiddenapibypass) - // Test + //Test testImplementation(libs.junit) testImplementation(libs.androidx.junit) testImplementation(libs.google.truth) @@ -252,26 +198,22 @@ dependencies { androidTestImplementation(libs.google.truth) androidTestImplementation(libs.androidx.espresso.core) - // Hilt + //Hilt ksp(libs.hilt.android.compiler) ksp(libs.hilt.androidx.compiler) - implementation(libs.androidx.hilt.viewmodel) implementation(libs.hilt.android.core) implementation(libs.hilt.androidx.work) kspAndroidTest(libs.hilt.android.compiler) androidTestImplementation(libs.hilt.android.testing) - // Room + //Room ksp(libs.androidx.room.compiler) implementation(libs.androidx.room.ktx) implementation(libs.androidx.room.runtime) - implementation(libs.androidx.room.paging) implementation(libs.process.phoenix) - "huaweiImplementation"(libs.huawei.hms.coreservice) - // LeakCanary debugImplementation(libs.squareup.leakcanary.android) } diff --git a/app/categories/page.tsx b/app/categories/page.tsx new file mode 100644 index 000000000..fecf8b04a --- /dev/null +++ b/app/categories/page.tsx @@ -0,0 +1,50 @@ +import { Navbar } from '@/components/navbar' +import { ALL_CATEGORIES } from '@/lib/mock-data' +import Link from 'next/link' +import { LayoutGrid, Shield, MessageCircle, Gamepad2, Wrench, PlayCircle, Lock, Wallet, HeartPulse } from 'lucide-react' + +const CATEGORY_ICONS: Record = { + 'Productivity': LayoutGrid, + 'Social': MessageCircle, + 'Games': Gamepad2, + 'Tools': Wrench, + 'Media': PlayCircle, + 'Security': Lock, + 'Finance': Wallet, + 'Health': HeartPulse, +} + +export default function CategoriesPage() { + return ( + <> + +
+
+

Categories

+

Explore apps by their function and use case.

+
+ +
+ {ALL_CATEGORIES.map((cat) => { + const Icon = CATEGORY_ICONS[cat] || LayoutGrid + return ( + +
+ +
+
+

{cat}

+

Browse apps

+
+ + ) + })} +
+
+ + ) +} diff --git a/app/globals.css b/app/globals.css new file mode 100644 index 000000000..6bb1aa851 --- /dev/null +++ b/app/globals.css @@ -0,0 +1,49 @@ +@import "tailwindcss"; + +@theme { + --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif; + --color-background: var(--background); + --color-foreground: var(--foreground); +} + +:root { + --background: #f9fafb; + --foreground: #111827; +} + +@media (prefers-color-scheme: dark) { + :root { + --background: #030712; + --foreground: #f9fafb; + } +} + +@layer base { + body { + @apply bg-background text-foreground; + -webkit-tap-highlight-color: transparent; + } +} + +@layer utilities { + .pb-safe { + padding-bottom: env(safe-area-inset-bottom); + } + + .scrollbar-hide::-webkit-scrollbar { + display: none; + } + .scrollbar-hide { + -ms-overflow-style: none; + scrollbar-width: none; + } +} + +/* Ensure minimum touch target sizes */ +button, a { + @apply min-h-[44px] min-w-[44px]; +} + +/* Override for small inline elements if needed */ +.min-h-0 { min-height: 0; } +.min-w-0 { min-width: 0; } diff --git a/app/layout.tsx b/app/layout.tsx new file mode 100644 index 000000000..a16cb8b56 --- /dev/null +++ b/app/layout.tsx @@ -0,0 +1,39 @@ +import type { Metadata, Viewport } from 'next' +import { Suspense } from 'react' +import { Inter } from 'next/font/google' +import { BottomNav } from '@/components/bottom-nav' +import './globals.css' + +const inter = Inter({ subsets: ['latin'] }) + +export const metadata: Metadata = { + title: 'J MODS — Open-source Android App Store', + description: + 'Browse, search, and sideload Android apps privately. J MODS is an open-source Google Play alternative with no tracking.', + keywords: ['android', 'app store', 'jmods', 'open source', 'sideload', 'apk'], +} + +export const viewport: Viewport = { + themeColor: '#2563eb', + width: 'device-width', + initialScale: 1, + maximumScale: 1, + userScalable: false, +} + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode +}>) { + return ( + + + }> + {children} + + + + + ) +} diff --git a/app/lint.xml b/app/lint.xml index 0cea46327..171a4f24a 100644 --- a/app/lint.xml +++ b/app/lint.xml @@ -1,12 +1,6 @@ - - diff --git a/app/page.tsx b/app/page.tsx new file mode 100644 index 000000000..678751842 --- /dev/null +++ b/app/page.tsx @@ -0,0 +1,188 @@ +'use client' + +import { useState, use } from 'react' +import { Navbar } from '@/components/navbar' +import { SearchHero } from '@/components/home/search-hero' +import { FeaturedBanner } from '@/components/home/featured-banner' +import { AppGridSection } from '@/components/home/app-grid-section' +import { Drawer } from '@/components/ui/drawer' +import { Player } from '@/components/ui/player' +import { + MOCK_APPS, + getFeaturedApps, + getAppsByCategory, + searchApps, + getRecentlyAddedApps, +} from '@/lib/mock-data' + +interface HomePageProps { + searchParams: Promise<{ q?: string; category?: string }> +} + +export default function HomePage({ searchParams }: HomePageProps) { + const { q, category } = use(searchParams) + const [isPlayerOpen, setIsPlayerOpen] = useState(false) + const [isDrawerOpen, setIsDrawerOpen] = useState(false) + + const featuredApps = getFeaturedApps() + const primaryFeatured = featuredApps[0] + const recentlyAdded = getRecentlyAddedApps() + + let displayApps = MOCK_APPS + let sectionTitle = 'Recommended for you' + let sectionDescription: string | undefined + + if (q) { + displayApps = searchApps(q) + sectionTitle = `Results for "${q}"` + } else if (category) { + displayApps = getAppsByCategory(category) + sectionTitle = category + } + + const isFiltered = Boolean(q || category) + + return ( + <> + +
+ {!isFiltered && } + +
+ {!isFiltered && primaryFeatured && ( +
+
+

Featured

+ +
+
+ {featuredApps.map((app) => ( + + ))} +
+
+ )} + + + + {!isFiltered && recentlyAdded.length > 0 && ( +
+ +
+ )} + +
+ +
+ + {!isFiltered && ( +
+
+ {(['Tools', 'Security', 'Media'] as const).map((cat) => { + const apps = getAppsByCategory(cat) + if (apps.length === 0) return null + return ( + + ) + })} +
+
+ )} +
+
+ + setIsPlayerOpen(false)} + title="J MODS Community Radio" + subtitle="Live stream" + /> + + setIsDrawerOpen(false)} + title="Quick Settings" + > +
+
+
+

Automatic Updates

+

Keep your apps at the latest version

+
+
+
+
+
+
+
+

Anonymous Mode

+

Protect your identity while browsing

+
+
+
+
+
+ +
+ + +
+
+
+
+

J MODS

+

+ Open-source Android app store. Privacy first, no tracking, no Google account needed. +

+
+ +
+
+ © {new Date().getFullYear()} J MODS. All rights reserved. +
+
+
+ + ) +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 38c09a2c3..855f7b111 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -1,9 +1,3 @@ -# -# SPDX-FileCopyrightText: 2021-2025 Rahul Kumar Patel -# SPDX-FileCopyrightText: 2023-2025 The Calyx Institute -# SPDX-License-Identifier: GPL-3.0-or-later -# - # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle.kts. @@ -130,9 +124,3 @@ -keep class * extends androidx.viewbinding.ViewBinding { *; } - -# Keep Huawei specific classes and methods --keep class com.huawei.** { *; } --dontwarn com.huawei.** --keep class com.hihonor.** { *; } --dontwarn com.hihonor.** diff --git a/app/schemas/com.aurora.store.data.room.AuroraDatabase/5.json b/app/schemas/com.aurora.store.data.room.AuroraDatabase/5.json deleted file mode 100644 index 9dcbe5a0f..000000000 --- a/app/schemas/com.aurora.store.data.room.AuroraDatabase/5.json +++ /dev/null @@ -1,284 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 5, - "identityHash": "d5da6e54113409ba811bafebc85632e6", - "entities": [ - { - "tableName": "download", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`packageName` TEXT NOT NULL, `versionCode` INTEGER NOT NULL, `offerType` INTEGER NOT NULL, `isInstalled` INTEGER NOT NULL, `displayName` TEXT NOT NULL, `iconURL` TEXT NOT NULL, `size` INTEGER NOT NULL, `id` INTEGER NOT NULL, `downloadStatus` TEXT NOT NULL, `progress` INTEGER NOT NULL, `speed` INTEGER NOT NULL, `timeRemaining` INTEGER NOT NULL, `totalFiles` INTEGER NOT NULL, `downloadedFiles` INTEGER NOT NULL, `fileList` TEXT NOT NULL, `sharedLibs` TEXT NOT NULL, `targetSdk` INTEGER NOT NULL, `downloadedAt` INTEGER NOT NULL, PRIMARY KEY(`packageName`))", - "fields": [ - { - "fieldPath": "packageName", - "columnName": "packageName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "versionCode", - "columnName": "versionCode", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "offerType", - "columnName": "offerType", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isInstalled", - "columnName": "isInstalled", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "displayName", - "columnName": "displayName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "iconURL", - "columnName": "iconURL", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "size", - "columnName": "size", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "downloadStatus", - "columnName": "downloadStatus", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "progress", - "columnName": "progress", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "speed", - "columnName": "speed", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "timeRemaining", - "columnName": "timeRemaining", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "totalFiles", - "columnName": "totalFiles", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "downloadedFiles", - "columnName": "downloadedFiles", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "fileList", - "columnName": "fileList", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "sharedLibs", - "columnName": "sharedLibs", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "targetSdk", - "columnName": "targetSdk", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "downloadedAt", - "columnName": "downloadedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "packageName" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "favourite", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`packageName` TEXT NOT NULL, `displayName` TEXT NOT NULL, `iconURL` TEXT NOT NULL, `added` INTEGER NOT NULL, `mode` TEXT NOT NULL, PRIMARY KEY(`packageName`))", - "fields": [ - { - "fieldPath": "packageName", - "columnName": "packageName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "displayName", - "columnName": "displayName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "iconURL", - "columnName": "iconURL", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "added", - "columnName": "added", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "mode", - "columnName": "mode", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "packageName" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "update", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`packageName` TEXT NOT NULL, `versionCode` INTEGER NOT NULL, `versionName` TEXT NOT NULL, `displayName` TEXT NOT NULL, `iconURL` TEXT NOT NULL, `changelog` TEXT NOT NULL, `id` INTEGER NOT NULL, `developerName` TEXT NOT NULL, `size` INTEGER NOT NULL, `updatedOn` TEXT NOT NULL, `hasValidCert` INTEGER NOT NULL, `offerType` INTEGER NOT NULL, `fileList` TEXT NOT NULL, `sharedLibs` TEXT NOT NULL, `targetSdk` INTEGER NOT NULL, PRIMARY KEY(`packageName`))", - "fields": [ - { - "fieldPath": "packageName", - "columnName": "packageName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "versionCode", - "columnName": "versionCode", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "versionName", - "columnName": "versionName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "displayName", - "columnName": "displayName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "iconURL", - "columnName": "iconURL", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "changelog", - "columnName": "changelog", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "developerName", - "columnName": "developerName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "size", - "columnName": "size", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "updatedOn", - "columnName": "updatedOn", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "hasValidCert", - "columnName": "hasValidCert", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "offerType", - "columnName": "offerType", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "fileList", - "columnName": "fileList", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "sharedLibs", - "columnName": "sharedLibs", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "targetSdk", - "columnName": "targetSdk", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "packageName" - ] - }, - "indices": [], - "foreignKeys": [] - } - ], - "views": [], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd5da6e54113409ba811bafebc85632e6')" - ] - } -} \ No newline at end of file diff --git a/app/schemas/com.aurora.store.data.room.AuroraDatabase/6.json b/app/schemas/com.aurora.store.data.room.AuroraDatabase/6.json deleted file mode 100644 index 17fb39102..000000000 --- a/app/schemas/com.aurora.store.data.room.AuroraDatabase/6.json +++ /dev/null @@ -1,283 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 6, - "identityHash": "82935f33f6fe476bd752dd3643095d69", - "entities": [ - { - "tableName": "download", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`packageName` TEXT NOT NULL, `versionCode` INTEGER NOT NULL, `offerType` INTEGER NOT NULL, `isInstalled` INTEGER NOT NULL, `displayName` TEXT NOT NULL, `iconURL` TEXT NOT NULL, `size` INTEGER NOT NULL, `id` INTEGER NOT NULL, `downloadStatus` TEXT NOT NULL, `progress` INTEGER NOT NULL, `speed` INTEGER NOT NULL, `timeRemaining` INTEGER NOT NULL, `totalFiles` INTEGER NOT NULL, `downloadedFiles` INTEGER NOT NULL, `fileList` TEXT NOT NULL, `sharedLibs` TEXT NOT NULL, `targetSdk` INTEGER NOT NULL, `downloadedAt` INTEGER NOT NULL, `requiresGMS` INTEGER NOT NULL, PRIMARY KEY(`packageName`))", - "fields": [ - { - "fieldPath": "packageName", - "columnName": "packageName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "versionCode", - "columnName": "versionCode", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "offerType", - "columnName": "offerType", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isInstalled", - "columnName": "isInstalled", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "displayName", - "columnName": "displayName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "iconURL", - "columnName": "iconURL", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "size", - "columnName": "size", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "status", - "columnName": "downloadStatus", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "progress", - "columnName": "progress", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "speed", - "columnName": "speed", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "timeRemaining", - "columnName": "timeRemaining", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "totalFiles", - "columnName": "totalFiles", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "downloadedFiles", - "columnName": "downloadedFiles", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "fileList", - "columnName": "fileList", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "sharedLibs", - "columnName": "sharedLibs", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "targetSdk", - "columnName": "targetSdk", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "downloadedAt", - "columnName": "downloadedAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "requiresGMS", - "columnName": "requiresGMS", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "packageName" - ] - } - }, - { - "tableName": "favourite", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`packageName` TEXT NOT NULL, `displayName` TEXT NOT NULL, `iconURL` TEXT NOT NULL, `added` INTEGER NOT NULL, `mode` TEXT NOT NULL, PRIMARY KEY(`packageName`))", - "fields": [ - { - "fieldPath": "packageName", - "columnName": "packageName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "displayName", - "columnName": "displayName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "iconURL", - "columnName": "iconURL", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "added", - "columnName": "added", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "mode", - "columnName": "mode", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "packageName" - ] - } - }, - { - "tableName": "update", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`packageName` TEXT NOT NULL, `versionCode` INTEGER NOT NULL, `versionName` TEXT NOT NULL, `displayName` TEXT NOT NULL, `iconURL` TEXT NOT NULL, `changelog` TEXT NOT NULL, `id` INTEGER NOT NULL, `developerName` TEXT NOT NULL, `size` INTEGER NOT NULL, `updatedOn` TEXT NOT NULL, `hasValidCert` INTEGER NOT NULL, `offerType` INTEGER NOT NULL, `fileList` TEXT NOT NULL, `sharedLibs` TEXT NOT NULL, `targetSdk` INTEGER NOT NULL, PRIMARY KEY(`packageName`))", - "fields": [ - { - "fieldPath": "packageName", - "columnName": "packageName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "versionCode", - "columnName": "versionCode", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "versionName", - "columnName": "versionName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "displayName", - "columnName": "displayName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "iconURL", - "columnName": "iconURL", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "changelog", - "columnName": "changelog", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "developerName", - "columnName": "developerName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "size", - "columnName": "size", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "updatedOn", - "columnName": "updatedOn", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "hasValidCert", - "columnName": "hasValidCert", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "offerType", - "columnName": "offerType", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "fileList", - "columnName": "fileList", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "sharedLibs", - "columnName": "sharedLibs", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "targetSdk", - "columnName": "targetSdk", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "packageName" - ] - } - } - ], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '82935f33f6fe476bd752dd3643095d69')" - ] - } -} \ No newline at end of file diff --git a/app/src/androidTest/java/com/aurora/store/HiltInstrumentationTestRunner.kt b/app/src/androidTest/java/com/aurora/store/HiltInstrumentationTestRunner.kt index a720021cc..ad018c84c 100644 --- a/app/src/androidTest/java/com/aurora/store/HiltInstrumentationTestRunner.kt +++ b/app/src/androidTest/java/com/aurora/store/HiltInstrumentationTestRunner.kt @@ -5,11 +5,13 @@ import android.content.Context import androidx.test.runner.AndroidJUnitRunner import dagger.hilt.android.testing.HiltTestApplication -class HiltInstrumentationTestRunner : AndroidJUnitRunner() { +class HiltInstrumentationTestRunner: AndroidJUnitRunner() { override fun newApplication( cl: ClassLoader?, className: String?, context: Context? - ): Application = super.newApplication(cl, HiltTestApplication::class.java.name, context) + ): Application { + return super.newApplication(cl, HiltTestApplication::class.java.name, context) + } } diff --git a/app/src/androidTest/java/com/aurora/store/IsolatedTest.kt b/app/src/androidTest/java/com/aurora/store/IsolatedTest.kt deleted file mode 100644 index 103c98714..000000000 --- a/app/src/androidTest/java/com/aurora/store/IsolatedTest.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store - -import androidx.compose.runtime.Composable -import androidx.compose.ui.test.junit4.createComposeRule -import com.aurora.store.compose.theme.AuroraTheme -import org.junit.Rule - -/** - * Class that provides helper methods to test isolated composable - */ -abstract class IsolatedTest { - - @get:Rule - val composeTestRule = createComposeRule() - - /** - * Sets given composable as content with default theme - */ - fun setContent(content: @Composable () -> Unit) { - composeTestRule.setContent { - AuroraTheme(content = content) - } - } -} diff --git a/app/src/androidTest/java/com/aurora/store/compose/composable/ErrorTest.kt b/app/src/androidTest/java/com/aurora/store/compose/composable/ErrorTest.kt deleted file mode 100644 index 2cd0b9374..000000000 --- a/app/src/androidTest/java/com/aurora/store/compose/composable/ErrorTest.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.test.assertHasClickAction -import androidx.compose.ui.test.assertIsDisplayed -import androidx.compose.ui.test.assertIsNotEnabled -import androidx.compose.ui.test.onNodeWithText -import com.aurora.store.IsolatedTest -import com.aurora.store.R -import org.junit.Test - -class ErrorTest : IsolatedTest() { - - @Test - fun testErrorWithoutActionHandling() { - setContent { - Error( - painter = painterResource(R.drawable.ic_apps_outage), - message = "An error occurred!", - actionMessage = "Retry" - ) - } - - composeTestRule.onNodeWithText("Retry") - .assertIsDisplayed() - .assertHasClickAction() - .assertIsNotEnabled() - } -} diff --git a/app/src/androidTest/java/com/aurora/store/compose/composable/InfoTest.kt b/app/src/androidTest/java/com/aurora/store/compose/composable/InfoTest.kt deleted file mode 100644 index da51e9292..000000000 --- a/app/src/androidTest/java/com/aurora/store/compose/composable/InfoTest.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.test.assertHasClickAction -import androidx.compose.ui.test.assertIsDisplayed -import androidx.compose.ui.test.assertIsNotEnabled -import androidx.compose.ui.test.onNodeWithText -import androidx.compose.ui.text.AnnotatedString -import com.aurora.store.IsolatedTest -import com.aurora.store.R -import org.junit.Test - -class InfoTest : IsolatedTest() { - - @Test - fun testInfoWithoutClickHandling() { - setContent { - Info(title = AnnotatedString(text = stringResource(R.string.app_name))) - } - - composeTestRule.onNodeWithText("Aurora Store") - .assertIsDisplayed() - .assertHasClickAction() - .assertIsNotEnabled() - } -} diff --git a/app/src/androidTest/java/com/aurora/store/compose/composable/PermissionListItemTest.kt b/app/src/androidTest/java/com/aurora/store/compose/composable/PermissionListItemTest.kt deleted file mode 100644 index b0ff0e7fd..000000000 --- a/app/src/androidTest/java/com/aurora/store/compose/composable/PermissionListItemTest.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.runtime.Composable -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.test.assertIsDisplayed -import androidx.compose.ui.test.assertIsEnabled -import androidx.compose.ui.test.assertIsNotEnabled -import androidx.compose.ui.test.onNodeWithText -import com.aurora.store.IsolatedTest -import com.aurora.store.R -import com.aurora.store.data.model.Permission -import com.aurora.store.data.model.PermissionType -import org.junit.Test - -class PermissionListItemTest : IsolatedTest() { - - private val permission: Permission - @Composable - get() = Permission( - PermissionType.STORAGE_MANAGER, - stringResource(R.string.onboarding_permission_esm), - stringResource(R.string.onboarding_permission_esa_desc) - ) - - @Test - fun testPermissionNotGranted() { - setContent { - PermissionListItem(permission = permission.copy(isGranted = false)) - } - - composeTestRule.onNodeWithText("Grant") - .assertIsDisplayed() - .assertIsEnabled() - } - - @Test - fun testPermissionGranted() { - setContent { - PermissionListItem(permission = permission.copy(isGranted = true)) - } - - composeTestRule.onNodeWithText("Granted") - .assertIsDisplayed() - .assertIsNotEnabled() - } -} diff --git a/app/src/androidTest/java/com/aurora/store/compose/composable/TopAppBarTest.kt b/app/src/androidTest/java/com/aurora/store/compose/composable/TopAppBarTest.kt deleted file mode 100644 index 0dec80424..000000000 --- a/app/src/androidTest/java/com/aurora/store/compose/composable/TopAppBarTest.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.ui.test.assertIsDisplayed -import androidx.compose.ui.test.onNodeWithContentDescription -import androidx.compose.ui.test.onNodeWithText -import com.aurora.store.IsolatedTest -import org.junit.Test - -class TopAppBarTest : IsolatedTest() { - - @Test - fun testTitleWithNoNavigationAction() { - setContent { - TopAppBar(title = "About", onNavigateUp = null) - } - - composeTestRule.onNodeWithText("About") - .assertIsDisplayed() - - composeTestRule.onNodeWithContentDescription("Back") - .assertDoesNotExist() - } -} diff --git a/app/src/androidTest/java/com/aurora/store/compose/composable/app/AnimatedAppIconTest.kt b/app/src/androidTest/java/com/aurora/store/compose/composable/app/AnimatedAppIconTest.kt deleted file mode 100644 index c0dad41fe..000000000 --- a/app/src/androidTest/java/com/aurora/store/compose/composable/app/AnimatedAppIconTest.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable.app - -import androidx.compose.ui.semantics.ProgressBarRangeInfo -import androidx.compose.ui.test.assertIsDisplayed -import androidx.compose.ui.test.assertIsNotDisplayed -import androidx.compose.ui.test.assertRangeInfoEquals -import androidx.compose.ui.test.onNodeWithTag -import com.aurora.store.IsolatedTest -import org.junit.Test - -class AnimatedAppIconTest : IsolatedTest() { - - @Test - fun testAnimatedAppIconNoProgress() { - setContent { - AnimatedAppIcon( - iconUrl = "https://example.com/icon.png", - inProgress = false - ) - } - - composeTestRule.onNodeWithTag("progressIndicator") - .assertIsNotDisplayed() - } - - @Test - fun testAnimatedAppIconProgressAt0() { - setContent { - AnimatedAppIcon( - iconUrl = "https://example.com/icon.png", - progress = 0F, - inProgress = true - ) - } - - composeTestRule.onNodeWithTag("progressIndicator") - .assertIsDisplayed() - .assertRangeInfoEquals(ProgressBarRangeInfo.Indeterminate) - } - - @Test - fun testAnimatedAppIconProgressAt50() { - setContent { - AnimatedAppIcon( - iconUrl = "https://example.com/icon.png", - progress = 50F, - inProgress = true - ) - } - - composeTestRule.onNodeWithTag("progressIndicator") - .assertIsDisplayed() - .assertRangeInfoEquals(ProgressBarRangeInfo(0.5F, 0.00F..1.00F)) - } -} diff --git a/app/src/huawei/AndroidManifest.xml b/app/src/huawei/AndroidManifest.xml deleted file mode 100644 index ea1a0693d..000000000 --- a/app/src/huawei/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/app/src/huawei/java/com/aurora/store/data/receiver/InstallerStatusReceiver.kt b/app/src/huawei/java/com/aurora/store/data/receiver/InstallerStatusReceiver.kt deleted file mode 100644 index 8da5d47bf..000000000 --- a/app/src/huawei/java/com/aurora/store/data/receiver/InstallerStatusReceiver.kt +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2021, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - */ -package com.aurora.store.data.receiver - -import android.content.Context -import android.content.Intent -import android.content.pm.ApplicationInfo -import android.content.pm.PackageManager -import android.util.Log -import com.aurora.Constants.PACKAGE_NAME_APP_GALLERY -import com.aurora.extensions.TAG -import com.huawei.appgallery.coreservice.api.ApiClient -import com.huawei.appgallery.coreservice.api.ApiCode -import com.huawei.appgallery.coreservice.api.IConnectionResult -import com.huawei.appgallery.coreservice.api.PendingCall -import com.huawei.appgallery.coreservice.internal.framework.ipc.transport.data.BaseIPCRequest -import com.huawei.appgallery.coreservice.internal.framework.ipc.transport.data.BaseIPCResponse -import com.huawei.appmarket.framework.coreservice.Status -import com.huawei.appmarket.service.externalservice.distribution.thirdsilentinstall.SilentInstallRequest -import com.huawei.appmarket.service.externalservice.distribution.thirdsilentinstall.SilentInstallResponse -import dagger.hilt.android.AndroidEntryPoint - -@AndroidEntryPoint -class InstallerStatusReceiver : BaseInstallerStatusReceiver() { - - private lateinit var apiClient: ApiClient - - override fun onReceive(context: Context?, intent: Intent?) { - super.onReceive(context, intent) - } - - override fun doAppropriatePrompt(context: Context, intent: Intent, sessionId: Int) { - if (isHuaweiSilentInstallSupported(context)) { - Log.i( - TAG, - "Huawei silent install supported, proceeding with ApiClient connection" - ) - connectApiClient(context, intent, sessionId) - } else { - promptUser(context, intent) - } - } - - override fun postStatus(status: Int, packageName: String, extra: String?, context: Context) { - super.postStatus(status, packageName, extra, context) - - if (::apiClient.isInitialized && apiClient.isConnected) { - apiClient.disconnect() - } - } - - private fun connectApiClient(context: Context, intent: Intent, sessionId: Int) { - // Check if the ApiClient is already initialized and connected - if (::apiClient.isInitialized && apiClient.isConnected) { - Log.i(TAG, "ApiClient already connected, requesting silent install") - requestSilentInstall(context, intent, sessionId) - return - } - - apiClient = ApiClient.Builder(context.applicationContext) - .setHomeCountry("CN") - .addConnectionCallbacks(object : ApiClient.ConnectionCallback { - override fun onConnected() { - Log.i(TAG, "ApiClient connected") - requestSilentInstall(context, intent, sessionId) - } - - override fun onConnectionSuspended(cause: Int) { - Log.w(TAG, "ApiClient connection suspended: $cause") - } - - override fun onConnectionFailed(result: IConnectionResult?) { - Log.e(TAG, "ApiClient failed to connect with result: $result, prompting user") - promptUser(context, intent) - } - }) - .build() - - apiClient.connect() - } - - private fun requestSilentInstall(context: Context, intent: Intent, sessionId: Int) { - val request = SilentInstallRequest().apply { - setSessionId(sessionId) - } - - val pendingResult = PendingCall( - apiClient, - request - ) - - if (::apiClient.isInitialized && apiClient.isConnected) { - pendingResult.setCallback { handleIPCResponse(context, intent, it) } - } else { - Log.e(TAG, "ApiClient null or not connected") - promptUser(context, intent) - } - } - - private fun handleIPCResponse( - context: Context, - intent: Intent, - ipcResponse: Status - ) { - val response = ipcResponse.response - val statusCode = ipcResponse.statusCode - - when (response) { - is SilentInstallResponse -> { - Log.i(TAG, "IPC Response: ${ApiCode.getStatusCodeString(statusCode)}") - - if (statusCode != ApiCode.SUCCESS || response.result != ApiCode.SUCCESS) { - Log.e(TAG, "Silent install unavailable: $statusCode") - promptUser(context, intent) - } - } - - null -> { - Log.e(TAG, "IPC response is null.") - promptUser(context, intent) - } - - else -> { - Log.e(TAG, "Unexpected IPC response type: ${response.javaClass.name}") - promptUser(context, intent) - } - } - } - - private fun isHuaweiSilentInstallSupported(context: Context): Boolean = try { - val applicationInfo: ApplicationInfo = context.packageManager.getApplicationInfo( - PACKAGE_NAME_APP_GALLERY, - PackageManager.GET_META_DATA - ) - - val supportFunction = applicationInfo.metaData.getInt("appgallery_support_function") - Log.i(TAG, "Huawei silent install support function: $supportFunction") - - (supportFunction and (1 shl 5)) != 0 - } catch (_: Exception) { - false - } -} diff --git a/app/src/huawei/java/com/aurora/store/util/FlavouredUtil.kt b/app/src/huawei/java/com/aurora/store/util/FlavouredUtil.kt deleted file mode 100644 index 0a3a8d67e..000000000 --- a/app/src/huawei/java/com/aurora/store/util/FlavouredUtil.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.aurora.store.util - -import android.content.Context -import com.aurora.extensions.isHuawei - -object FlavouredUtil : IFlavouredUtil { - - override val defaultDispensers: Set = emptySet() - - override fun promptMicroGInstall(context: Context): Boolean = isHuawei && - PackageUtil.hasSupportedAppGallery(context) && - !PackageUtil.isMicroGBundleInstalled(context) -} diff --git a/app/src/huawei/java/com/huawei/appmarket/service/externalservice/distribution/thirdsilentinstall/SilentInstallRequest.java b/app/src/huawei/java/com/huawei/appmarket/service/externalservice/distribution/thirdsilentinstall/SilentInstallRequest.java deleted file mode 100644 index 49d4dc25d..000000000 --- a/app/src/huawei/java/com/huawei/appmarket/service/externalservice/distribution/thirdsilentinstall/SilentInstallRequest.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.huawei.appmarket.service.externalservice.distribution.thirdsilentinstall; - -import android.os.Parcel; -import android.os.Parcelable; - -import androidx.annotation.Keep; - -import com.huawei.appgallery.coreservice.internal.framework.ipc.transport.data.BaseIPCRequest; -import com.huawei.appgallery.coreservice.internal.support.parcelable.AutoParcelable; -import com.huawei.appgallery.coreservice.internal.support.parcelable.EnableAutoParcel; - -@Keep -public class SilentInstallRequest extends BaseIPCRequest { - public static final Parcelable.Creator CREATOR = new AutoParcelable.AutoCreator<>(SilentInstallRequest.class); - - public static final String METHOD = "method.requestSilentInstall"; - @EnableAutoParcel(1) - private int sessionId; - - @Override - public String getMethod() { - return METHOD; - } - - public int getSessionId() { - return sessionId; - } - - public void setSessionId(int sessionId) { - this.sessionId = sessionId; - } - - @Override - public void writeToParcel(Parcel parcel, int i) { - super.writeToParcel(parcel, i); - parcel.writeInt(sessionId); - } - - public void readFromParcel(Parcel source) { - this.sessionId = source.readInt(); - } - - public SilentInstallRequest() { - } - - protected SilentInstallRequest(Parcel in) { - this.sessionId = in.readInt(); - } - - @Override - public int describeContents() { - return 0; - } -} diff --git a/app/src/huawei/java/com/huawei/appmarket/service/externalservice/distribution/thirdsilentinstall/SilentInstallResponse.java b/app/src/huawei/java/com/huawei/appmarket/service/externalservice/distribution/thirdsilentinstall/SilentInstallResponse.java deleted file mode 100644 index ccf15f017..000000000 --- a/app/src/huawei/java/com/huawei/appmarket/service/externalservice/distribution/thirdsilentinstall/SilentInstallResponse.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.huawei.appmarket.service.externalservice.distribution.thirdsilentinstall; - -import android.os.Parcelable; - -import com.huawei.appgallery.coreservice.internal.framework.ipc.transport.data.BaseIPCResponse; -import com.huawei.appgallery.coreservice.internal.support.parcelable.AutoParcelable; -import com.huawei.appgallery.coreservice.internal.support.parcelable.EnableAutoParcel; - -public class SilentInstallResponse extends BaseIPCResponse { - - public static final Parcelable.Creator CREATOR = new AutoParcelable.AutoCreator<>(SilentInstallResponse.class); - - @EnableAutoParcel(1) - private int result; - - public int getResult() { - return this.result; - } - - public void setResult(int result) { - this.result = result; - } -} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e7d15f5ec..5873e2185 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -100,32 +100,16 @@ - - - - - - - - - - - SignalGraph --> SignalFrame\r\n\r\nWireless connectivity blankets the world. SignalFrame harnesses billions of detectable WiFi and Bluetooth signals to reveal the world through signals. Our SignalGraph™ platform enables a new generation of proximity services, and delivers unprecedented brand and product market intelligence.\r\n\r\nPowered by the SignalGraph™ — a purpose-built streaming data and analytics platform that applies machine learning over graph structures to reveal relationships in space and time within massive datasets.\r\n\r\nDocumentation: https://signalframe.com/privacy-policy.html", + "description": "SignalFrame (previously Wireless Registry)\r\n\r\nWireless Registry --> SignalGraph --> SignalFrame\r\n\r\nWireless connectivity blankets the world. SignalFrame harnesses billions of detectable WiFi and Bluetooth signals to reveal the world through signals. Our SignalGraph\u2122 platform enables a new generation of proximity services, and delivers unprecedented brand and product market intelligence.\r\n\r\nPowered by the SignalGraph\u2122 \u2014 a purpose-built streaming data and analytics platform that applies machine learning over graph structures to reveal relationships in space and time within massive datasets.\r\n\r\nDocumentation: https://signalframe.com/privacy-policy.html", "creation_date": "2021-01-24", "code_signature": "com.wirelessregistry.observersdk.", "network_signature": "", @@ -4291,8 +4292,8 @@ "network_signature": "api\\.myendpoint\\.io|bin5y4muil\\.execute-api\\.us-east-1\\.amazonaws\\.com|api\\.smartechmetrics\\.com", "website": "https://xmode.io/", "categories": [ - "Location", - "Analytics" + "Analytics", + "Location" ], "documentation": [] }, @@ -4305,8 +4306,8 @@ "network_signature": "", "website": "http://www.oneaudience.com/", "categories": [ - "Profiling", - "Analytics" + "Analytics", + "Profiling" ], "documentation": [] }, @@ -4330,10 +4331,10 @@ "network_signature": "sdk\\.predic\\.io", "website": "https://www.predic.io/", "categories": [ - "Advertisement", - "Analytics", + "Identification", "Location", - "Identification" + "Analytics", + "Advertisement" ], "documentation": [] }, @@ -4346,10 +4347,10 @@ "network_signature": "", "website": "https://adlocus.com", "categories": [ - "Location", - "Advertisement", + "Profiling", "Identification", - "Profiling" + "Advertisement", + "Location" ], "documentation": [] }, @@ -4369,7 +4370,7 @@ "360": { "id": 360, "name": "Admitad", - "description": "Admitad helps advertisers and publishers develop their online business around the world.\r\n\r\nHow affiliate marketing works\r\n\r\nYou choose publishers with suitable traffic and give them special affiliate links. They advertise your products and services and lead customers to you through those links. If a customer makes an order, you pay the publisher a commission. Only completed orders are taken into account: if the customer doesn’t buy a product or returns it, you pay nothing.", + "description": "Admitad helps advertisers and publishers develop their online business around the world.\r\n\r\nHow affiliate marketing works\r\n\r\nYou choose publishers with suitable traffic and give them special affiliate links. They advertise your products and services and lead customers to you through those links. If a customer makes an order, you pay the publisher a commission. Only completed orders are taken into account: if the customer doesn\u2019t buy a product or returns it, you pay nothing.", "creation_date": "2021-02-28", "code_signature": "ru.tachos.admitadstatisticsdk", "network_signature": ".*\\.admitad.com", @@ -4382,7 +4383,7 @@ "361": { "id": 361, "name": "AutoNavi / Amap", - "description": "AutoNavi Software Co., Ltd. (simplified Chinese: 高德软件有限公司; traditional Chinese: 高德軟件有限公司; pinyin: Gāodé Ruǎnjiàn Yǒuxiàn Gōngsī)) is a Chinese web mapping, navigation and location-based services provider, founded in 2001.\r\n\r\nAutoNavi was acquired by Alibaba Group in 2014.\r\n\r\nIt offers its map services at Amap.com and as the Amap mobile app. It is known as Gaode in Chinese. \r\n\r\nhttps://en.wikipedia.org/wiki/AutoNavi", + "description": "AutoNavi Software Co., Ltd. (simplified Chinese: \u9ad8\u5fb7\u8f6f\u4ef6\u6709\u9650\u516c\u53f8; traditional Chinese: \u9ad8\u5fb7\u8edf\u4ef6\u6709\u9650\u516c\u53f8; pinyin: G\u0101od\u00e9 Ru\u01cenji\u00e0n Y\u01d2uxi\u00e0n G\u014dngs\u012b)) is a Chinese web mapping, navigation and location-based services provider, founded in 2001.\r\n\r\nAutoNavi was acquired by Alibaba Group in 2014.\r\n\r\nIt offers its map services at Amap.com and as the Amap mobile app. It is known as Gaode in Chinese. \r\n\r\nhttps://en.wikipedia.org/wiki/AutoNavi", "creation_date": "2021-02-28", "code_signature": "com.amap.api", "network_signature": "grid\\.amap\\.com|tm\\.amap\\.com|mst[0-9]*\\.is\\.autonavi\\.com|mt[0-9]*\\.google\\.cn|abroad\\.apilocate\\.amap\\.com|apilocate\\.amap\\.com|restapi\\.amap\\.com|yuntuapi\\.amap\\.com|m5\\.amap\\.com|wb\\.amap\\.com|wb\\.amap\\.com|wb\\.amap\\.com|wb\\.amap\\.com|apiinit\\.amap\\.com|restapi\\.amap\\.com|logs\\.amap\\.com|cgicol\\.amap\\.com|lbs\\.amap\\.com|wap\\.amap\\.com", @@ -4479,8 +4480,8 @@ "network_signature": "", "website": "https://appodealstack.com/about/", "categories": [ - "Advertisement", - "Analytics" + "Analytics", + "Advertisement" ], "documentation": [] }, @@ -4584,8 +4585,8 @@ "network_signature": "", "website": "https://raygun.com", "categories": [ - "Analytics", - "Crash reporting" + "Crash reporting", + "Analytics" ], "documentation": [] }, @@ -4624,8 +4625,8 @@ "network_signature": "", "website": "https://www.tapresearch.com/", "categories": [ - "Profiling", - "Analytics" + "Analytics", + "Profiling" ], "documentation": [] }, @@ -4651,8 +4652,8 @@ "network_signature": "", "website": "http://www.thinkingdata.cn/", "categories": [ - "Identification", - "Analytics" + "Analytics", + "Identification" ], "documentation": [] }, @@ -4704,8 +4705,8 @@ "network_signature": "", "website": "http://www.yifants.cn/", "categories": [ - "Advertisement", - "Analytics" + "Analytics", + "Advertisement" ], "documentation": [] }, @@ -4731,11 +4732,11 @@ "network_signature": ".*\\.anvato\\.net", "website": "https://cloud.google.com/solutions/media-entertainment/?a=2", "categories": [ - "Location", - "Advertisement", - "Identification", + "Analytics", "Profiling", - "Analytics" + "Identification", + "Advertisement", + "Location" ], "documentation": [] }, @@ -4768,14 +4769,14 @@ "390": { "id": 390, "name": "CoolaData", - "description": "*We make it easy to track, capture and analyze each customer’s journey and turn them in actionable insights to improve engagement, retention and monetization. Built to collect data from any source. Cooladata’s big data infrastructure covers all components from tracking, managed data warehousing, and ETL – all the way to the visualization layer.*\r\n\r\nDocumentation: https://docs.cooladata.com/android/", + "description": "*We make it easy to track, capture and analyze each customer\u2019s journey and turn them in actionable insights to improve engagement, retention and monetization. Built to collect data from any source. Cooladata\u2019s big data infrastructure covers all components from tracking, managed data warehousing, and ETL \u2013 all the way to the visualization layer.*\r\n\r\nDocumentation: https://docs.cooladata.com/android/", "creation_date": "2021-03-12", "code_signature": "com.cooladata.android.", "network_signature": "", "website": "https://www.cooladata.com/", "categories": [ - "Profiling", - "Analytics" + "Analytics", + "Profiling" ], "documentation": [] }, @@ -4827,8 +4828,8 @@ "network_signature": "ipsws\\.indooratlas\\.com", "website": "http://www.indooratlas.com/", "categories": [ - "Location", - "Analytics" + "Analytics", + "Location" ], "documentation": [] }, @@ -4854,37 +4855,37 @@ "network_signature": "api-device\\.mocaplatform\\.com", "website": "https://www.mocaplatform.com/", "categories": [ - "Location", + "Analytics", "Profiling", - "Analytics" + "Location" ], "documentation": [] }, "397": { "id": 397, "name": "Point Inside", - "description": "## About\r\nSince 2009, Point Inside has been creating a foundation of indoor maps. We’re enabling location-centric, digital strategies across industries unlocking the power of the data driven enterprise", + "description": "## About\r\nSince 2009, Point Inside has been creating a foundation of indoor maps. We\u2019re enabling location-centric, digital strategies across industries unlocking the power of the data driven enterprise", "creation_date": "2021-03-12", "code_signature": "com.pointinside", "network_signature": "", "website": "https://www.pointinside.com/", "categories": [ - "Location", - "Analytics" + "Analytics", + "Location" ], "documentation": [] }, "398": { "id": 398, "name": "Proximi.io", - "description": "## About\r\nProximi.io is a developer platform offering you all the positioning technologies and all features in a simple solution. Enable outdoor and indoor positioning in your app through iBeacon, Eddystone beacons, IndoorAtlas geomagnetic positioning, Wi-Fi, GPS and cellular positioning. Proximi.io is truly technology-agnostic, and committed to supporting all of the major positioning technologies. In other words, you’ll be safe with us – no matter what technologies you want to use today or tomorrow. Add geofencing with top market quality background functionality for indoor or outdoor spaces. And top it all with wayfinding and location-based analytics.\r\n\r\n## Repositories\r\n* Maven: `https://bintray.com/proximi-io/proximiio-android/proximiio-android/2.7`\r\n* Artifact ID: `proximiiolibrary`\r\n* Group ID: `io.proximi.proximiiolibrary`\r\n\r\n## Additional links\r\nhttps://proximi.io/docs/android/ https://github.com/proximiio/proximiio-android-demo", + "description": "## About\r\nProximi.io is a developer platform offering you all the positioning technologies and all features in a simple solution. Enable outdoor and indoor positioning in your app through iBeacon, Eddystone beacons, IndoorAtlas geomagnetic positioning, Wi-Fi, GPS and cellular positioning. Proximi.io is truly technology-agnostic, and committed to supporting all of the major positioning technologies. In other words, you\u2019ll be safe with us \u2013 no matter what technologies you want to use today or tomorrow. Add geofencing with top market quality background functionality for indoor or outdoor spaces. And top it all with wayfinding and location-based analytics.\r\n\r\n## Repositories\r\n* Maven: `https://bintray.com/proximi-io/proximiio-android/proximiio-android/2.7`\r\n* Artifact ID: `proximiiolibrary`\r\n* Group ID: `io.proximi.proximiiolibrary`\r\n\r\n## Additional links\r\nhttps://proximi.io/docs/android/ https://github.com/proximiio/proximiio-android-demo", "creation_date": "2021-03-12", "code_signature": "io.proximi.proximiiolibrary", "network_signature": "api\\.proximi\\.fi", "website": "https://proximi.io/", "categories": [ - "Location", - "Analytics" + "Analytics", + "Location" ], "documentation": [] }, @@ -4921,9 +4922,9 @@ "network_signature": "", "website": "https://nicepeopleatwork.com/", "categories": [ - "Location", + "Analytics", "Profiling", - "Analytics" + "Location" ], "documentation": [] }, @@ -4936,10 +4937,10 @@ "network_signature": "", "website": "https://beintoo.com/", "categories": [ - "Location", - "Advertisement", + "Analytics", "Profiling", - "Analytics" + "Advertisement", + "Location" ], "documentation": [] }, @@ -4972,15 +4973,15 @@ "405": { "id": 405, "name": "Cifrasoft", - "description": "## About\r\n\r\nCifrasoft is a technological company developing ground-breaking solutions for acoustic connectivity, acoustic watermarking, audio fingerprinting and audio/video classification. Cifrasoft’s innovative solutions simplify user experience and bring interactivity to mobile e-commerce, mobile advertisement, second screen and social TV applications. Our technology has been successfully deployed in millions of smartphones, tablets, and other mobile devices. Cifrasoft’s growing IP portfolio and vast expertise in digital signal processing delivers competitive advantage to our customers and R&D partners.\r\n\r\n## Additional links\r\n\r\n* http://cifrasoft.com/secondscreen.html\r\n* https://addons.mozilla.org/en-US/firefox/addon/sound-login/\r\n* https://www.soundlogin.com/\r\n* http://svn.cifrasoft.com/ \r\n\r\n## Notes\r\n\r\npartnership with https://actv8me.com/", + "description": "## About\r\n\r\nCifrasoft is a technological company developing ground-breaking solutions for acoustic connectivity, acoustic watermarking, audio fingerprinting and audio/video classification. Cifrasoft\u2019s innovative solutions simplify user experience and bring interactivity to mobile e-commerce, mobile advertisement, second screen and social TV applications. Our technology has been successfully deployed in millions of smartphones, tablets, and other mobile devices. Cifrasoft\u2019s growing IP portfolio and vast expertise in digital signal processing delivers competitive advantage to our customers and R&D partners.\r\n\r\n## Additional links\r\n\r\n* http://cifrasoft.com/secondscreen.html\r\n* https://addons.mozilla.org/en-US/firefox/addon/sound-login/\r\n* https://www.soundlogin.com/\r\n* http://svn.cifrasoft.com/ \r\n\r\n## Notes\r\n\r\npartnership with https://actv8me.com/", "creation_date": "2021-05-07", "code_signature": "com.cifrasoft.", "network_signature": "\\.tele\\.fm", "website": "http://cifrasoft.com", "categories": [ - "Location", + "Identification", "Advertisement", - "Identification" + "Location" ], "documentation": [] }, @@ -4993,9 +4994,9 @@ "network_signature": "", "website": "https://flowsense.com.br/", "categories": [ - "Location", + "Analytics", "Profiling", - "Analytics" + "Location" ], "documentation": [] }, @@ -5021,8 +5022,8 @@ "network_signature": "", "website": "https://huq.io/", "categories": [ - "Location", - "Analytics" + "Analytics", + "Location" ], "documentation": [] }, @@ -5048,8 +5049,8 @@ "network_signature": "", "website": "https://mopinion.com", "categories": [ - "Profiling", - "Analytics" + "Analytics", + "Profiling" ], "documentation": [] }, @@ -5095,15 +5096,15 @@ "414": { "id": 414, "name": "Zendrive", - "description": "*We use over 180 billion miles of data analyzed, plus the sensors on your drivers’ smartphones, to measure and improve driving behavior. Our tools can detect collisions, predict risk, improve fuel efficiency, and more, and are easy to integrate in your app or phone.*", + "description": "*We use over 180 billion miles of data analyzed, plus the sensors on your drivers\u2019 smartphones, to measure and improve driving behavior. Our tools can detect collisions, predict risk, improve fuel efficiency, and more, and are easy to integrate in your app or phone.*", "creation_date": "2021-05-07", "code_signature": "com.zendrive.sdk.", "network_signature": "", "website": "https://www.zendrive.com/", "categories": [ - "Location", + "Analytics", "Profiling", - "Analytics" + "Location" ], "documentation": [] }, @@ -5172,8 +5173,8 @@ "network_signature": "", "website": "https://www.treasuredata.com/product/", "categories": [ - "Profiling", - "Analytics" + "Analytics", + "Profiling" ], "documentation": [ "https://docs.treasuredata.com/display/public/PD/Android+SDK", @@ -5183,14 +5184,14 @@ "420": { "id": 420, "name": "IBM Mobile Marketing (Acoustic)", - "description": "* Mobile push messaging\r\n* SMS and group chat marketing\r\n* Mobile analytics\r\n* Location-based marketing\r\n* AI-powered content management\r\n* Multichannel marketing\r\n\r\n* [Old documentation](https://www.ibm.com/digital-marketing/mobile-marketing)\r\n\r\nIBM Mobile Web Push (formerly Xtify Web Push)\r\n\r\nDynamically trigger near-real-time, one-to-one notifications for your mobile and tablet websites.\r\n\r\nIBM Mobile Push Notification (formerly Xtify® Mobile Push Notification)\r\n\r\nCreate notification campaigns that engage mobile app users at the optimal time and place.", + "description": "* Mobile push messaging\r\n* SMS and group chat marketing\r\n* Mobile analytics\r\n* Location-based marketing\r\n* AI-powered content management\r\n* Multichannel marketing\r\n\r\n* [Old documentation](https://www.ibm.com/digital-marketing/mobile-marketing)\r\n\r\nIBM Mobile Web Push (formerly Xtify Web Push)\r\n\r\nDynamically trigger near-real-time, one-to-one notifications for your mobile and tablet websites.\r\n\r\nIBM Mobile Push Notification (formerly Xtify\u00ae Mobile Push Notification)\r\n\r\nCreate notification campaigns that engage mobile app users at the optimal time and place.", "creation_date": "2021-10-09", "code_signature": "com.ibm.mce.sdk.|co.acoustic.mobile.push.sdk.|com.xtify.mce.sdk.|com.xtify.android.sdk.", "network_signature": "sdk6\\.ibm\\.xtify\\.com", "website": "https://acoustic.co/", "categories": [ - "Advertisement", - "Analytics" + "Analytics", + "Advertisement" ], "documentation": [] }, @@ -5203,8 +5204,8 @@ "network_signature": "", "website": "https://solar2d.com/", "categories": [ - "Advertisement", - "Analytics" + "Analytics", + "Advertisement" ], "documentation": [ "https://docs.coronalabs.com/" @@ -5299,9 +5300,9 @@ "network_signature": "", "website": "http://lotadata.com", "categories": [ - "Location", + "Analytics", "Profiling", - "Analytics" + "Location" ], "documentation": [] }, @@ -5323,7 +5324,7 @@ "431": { "id": 431, "name": "PlaytestCloud Event Tracking", - "description": "Players play your game at home on their own devices. PlayestCloud will capture their whole gameplay experience.\r\n\r\n*We record the players’ screen, their touches and what they have to say at all times.*", + "description": "Players play your game at home on their own devices. PlayestCloud will capture their whole gameplay experience.\r\n\r\n*We record the players\u2019 screen, their touches and what they have to say at all times.*", "creation_date": "2022-02-10", "code_signature": "com.playtestcloud.Analytics", "network_signature": "", @@ -5368,9 +5369,9 @@ "network_signature": "synerise\\.com", "website": "https://synerise.com", "categories": [ - "Advertisement", + "Profiling", "Identification", - "Profiling" + "Advertisement" ], "documentation": [] }, @@ -5383,10 +5384,10 @@ "network_signature": "", "website": "https://www.userexperior.com/", "categories": [ - "Location", - "Profiling", + "Crash reporting", "Analytics", - "Crash reporting" + "Profiling", + "Location" ], "documentation": [] }, @@ -5546,8 +5547,8 @@ "network_signature": "", "website": "https://yueying-docs.effirst.com/", "categories": [ - "Analytics", - "Crash reporting" + "Crash reporting", + "Analytics" ], "documentation": [] } diff --git a/app/src/main/java/com/aurora/Constants.kt b/app/src/main/java/com/aurora/Constants.kt index 09ca67e34..d87ddcd3b 100644 --- a/app/src/main/java/com/aurora/Constants.kt +++ b/app/src/main/java/com/aurora/Constants.kt @@ -24,7 +24,7 @@ object Constants { const val PARCEL_DOWNLOAD = "PARCEL_DOWNLOAD" const val URL_TOS = "https://play.google.com/about/play-terms/" - const val URL_LICENSE = "https://gitlab.com/AuroraOSS/AuroraStore/-/tree/master/LICENSES" + const val URL_LICENSE = "https://gitlab.com/AuroraOSS/AuroraStore/blob/master/LICENSE" const val URL_DISCLAIMER = "https://gitlab.com/AuroraOSS/AuroraStore/blob/master/DISCLAIMER.md" const val URL_POLICY = "https://gitlab.com/AuroraOSS/AuroraStore/-/blob/master/POLICY.md" @@ -50,7 +50,7 @@ object Constants { const val GITLAB_URL = "https://gitlab.com/AuroraOSS/AuroraStore" const val URL_DISPENSER = "https://auroraoss.com/api/auth" - // ACCOUNTS + //ACCOUNTS const val ACCOUNT_SIGNED_IN = "ACCOUNT_SIGNED_IN" const val ACCOUNT_TYPE = "ACCOUNT_TYPE" const val ACCOUNT_EMAIL_PLAIN = "ACCOUNT_EMAIL_PLAIN" @@ -62,16 +62,4 @@ object Constants { const val TOP_CHART_CATEGORY = "TOP_CHART_CATEGORY" const val JSON_MIME_TYPE = "application/json" - const val PROPERTIES_IMPORT_MIME_TYPE = "application/octet-stream" - const val PROPERTIES_EXPORT_MIME_TYPE = "text/x-java-properties" - - // PACKAGE NAMES - const val PACKAGE_NAME_GMS = "com.google.android.gms" - const val PACKAGE_NAME_PLAY_STORE = "com.android.vending" - const val PACKAGE_NAME_APP_GALLERY = "com.huawei.appmarket" - - // FLAVOURS - const val FLAVOUR_VANILLA = "vanilla" - const val FLAVOUR_HUAWEI = "huawei" - const val FLAVOUR_PRELOAD = "preload" } diff --git a/app/src/main/java/com/aurora/extensions/Any.kt b/app/src/main/java/com/aurora/extensions/Any.kt deleted file mode 100644 index 5b85ce29d..000000000 --- a/app/src/main/java/com/aurora/extensions/Any.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.extensions - -/** - * Simple extension method to provide logging TAG - */ -inline val T.TAG: String - get() = when { - T::class.java.isAnonymousClass -> T::class.java.name - else -> T::class.java.simpleName - } diff --git a/app/src/main/java/com/aurora/extensions/App.kt b/app/src/main/java/com/aurora/extensions/App.kt deleted file mode 100644 index bfc69e2c7..000000000 --- a/app/src/main/java/com/aurora/extensions/App.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.extensions - -import com.aurora.Constants.PACKAGE_NAME_GMS -import com.aurora.gplayapi.data.models.App - -fun App.requiresGMS() = dependencies.dependentPackages.contains(PACKAGE_NAME_GMS) diff --git a/app/src/main/java/com/aurora/extensions/Collection.kt b/app/src/main/java/com/aurora/extensions/Collection.kt index 8a4555473..efb6f5cf1 100644 --- a/app/src/main/java/com/aurora/extensions/Collection.kt +++ b/app/src/main/java/com/aurora/extensions/Collection.kt @@ -19,6 +19,18 @@ package com.aurora.extensions -import com.aurora.gplayapi.data.models.PlayFile +import com.aurora.gplayapi.data.models.File -fun List.requiresObbDir(): Boolean = this.any { it.type == PlayFile.Type.OBB } +fun MutableList.flushAndAdd(list: List) { + clear() + addAll(list) +} + +fun MutableSet.flushAndAdd(list: Set) { + clear() + addAll(list) +} + +fun List.requiresObbDir(): Boolean { + return this.any { it.type == File.FileType.OBB || it.type == File.FileType.PATCH } +} diff --git a/app/src/preload/java/com/aurora/store/view/ui/splash/SplashFragment.kt b/app/src/main/java/com/aurora/extensions/Commons.kt similarity index 71% rename from app/src/preload/java/com/aurora/store/view/ui/splash/SplashFragment.kt rename to app/src/main/java/com/aurora/extensions/Commons.kt index d965d10e4..e3ae62cee 100644 --- a/app/src/preload/java/com/aurora/store/view/ui/splash/SplashFragment.kt +++ b/app/src/main/java/com/aurora/extensions/Commons.kt @@ -17,9 +17,14 @@ * */ -package com.aurora.store.view.ui.splash +package com.aurora.extensions -import dagger.hilt.android.AndroidEntryPoint +import android.text.format.DateFormat +import java.util.Calendar +import java.util.Locale -@AndroidEntryPoint -class SplashFragment : BaseFlavouredSplashFragment() +fun Long.toDate(): String { + val calendar = Calendar.getInstance(Locale.getDefault()) + calendar.timeInMillis = this + return DateFormat.format("dd/MM/yy", calendar).toString() +} diff --git a/app/src/main/java/com/aurora/extensions/Context.kt b/app/src/main/java/com/aurora/extensions/Context.kt index 68d198803..510eb8db0 100644 --- a/app/src/main/java/com/aurora/extensions/Context.kt +++ b/app/src/main/java/com/aurora/extensions/Context.kt @@ -29,10 +29,10 @@ import android.content.pm.PackageManager import android.content.pm.verify.domain.DomainVerificationManager import android.content.pm.verify.domain.DomainVerificationUserState import android.graphics.Color +import android.net.Uri import android.os.Bundle import android.os.Environment import android.os.PowerManager -import android.provider.Settings import android.util.Log import android.util.TypedValue import android.view.LayoutInflater @@ -40,11 +40,9 @@ import androidx.browser.customtabs.CustomTabsIntent import androidx.core.app.ActivityCompat import androidx.core.app.ActivityOptionsCompat import androidx.core.content.getSystemService -import androidx.core.net.toUri import com.aurora.Constants -import com.aurora.store.ComposeActivity +import com.aurora.gplayapi.data.models.App import com.aurora.store.R -import com.aurora.store.compose.navigation.Screen private const val TAG = "Context" @@ -54,29 +52,18 @@ val Context.inflater: LayoutInflater fun Context.browse(url: String) { try { val customTabsIntent = CustomTabsIntent.Builder() - customTabsIntent.build().launchUrl(this, url.toUri()) + customTabsIntent.build().launchUrl(this, Uri.parse(url)) } catch (exception: Exception) { Log.e(TAG, "Failed to open custom tab", exception) } } -fun Context.appInfo(packageName: String) { - try { - val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { - data = "package:$packageName".toUri() - } - startActivity(intent) - } catch (exception: Exception) { - Log.e(TAG, "Failed to open app info", exception) - } -} - -fun Context.share(displayName: String, packageName: String) { +fun Context.share(app: App) { try { val sendIntent = Intent().apply { action = Intent.ACTION_SEND - putExtra(Intent.EXTRA_SUBJECT, displayName) - putExtra(Intent.EXTRA_TEXT, "${Constants.SHARE_URL}$packageName") + putExtra(Intent.EXTRA_SUBJECT, app.displayName) + putExtra(Intent.EXTRA_TEXT, "${Constants.SHARE_URL}${app.packageName}") type = "text/plain" } startActivity(Intent.createChooser(sendIntent, getString(R.string.action_share))) @@ -85,24 +72,11 @@ fun Context.share(displayName: String, packageName: String) { } } -fun Context.mailTo(email: String) { - try { - val sendIntent = Intent().apply { - action = Intent.ACTION_SENDTO - data = "mailto:".toUri() - putExtra(Intent.EXTRA_EMAIL, email) - } - startActivity(Intent.createChooser(sendIntent, getString(R.string.details_dev_email))) - } catch (exception: Exception) { - Log.e(TAG, "Failed to email", exception) - } -} - fun Context.openInfo(packageName: String) { try { val intent = Intent( "android.settings.APPLICATION_DETAILS_SETTINGS", - "package:$packageName".toUri() + Uri.parse("package:$packageName") ) startActivity(intent) } catch (exception: Exception) { @@ -112,20 +86,21 @@ fun Context.openInfo(packageName: String) { fun Context.open(className: Class, newTask: Boolean = false) { val intent = Intent(this, className) - if (newTask) { + if (newTask) intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK - } startActivity( intent, getEmptyActivityBundle() ) } -fun Context.getEmptyActivityBundle(): Bundle? = ActivityOptionsCompat.makeCustomAnimation( - this, - android.R.anim.fade_in, - android.R.anim.fade_out -).toBundle() +fun Context.getEmptyActivityBundle(): Bundle? { + return ActivityOptionsCompat.makeCustomAnimation( + this, + android.R.anim.fade_in, + android.R.anim.fade_out + ).toBundle() +} fun Context.copyToClipBoard(data: String?) { val clipboard = getSystemService() @@ -140,36 +115,41 @@ fun Context.getStyledAttributeColor(id: Int): Int { return styledAttr } -fun Context.isIgnoringBatteryOptimizations(): Boolean = - getSystemService()?.isIgnoringBatteryOptimizations(packageName) ?: true +fun Context.isIgnoringBatteryOptimizations(): Boolean { + return if (isMAndAbove) { + (getSystemService())?.isIgnoringBatteryOptimizations(packageName) ?: true + } else { + true + } +} -fun Context.areNotificationsEnabled(): Boolean = when { - isNAndAbove -> getSystemService()!!.areNotificationsEnabled() - else -> true +fun Context.areNotificationsEnabled(): Boolean { + return if (isNAndAbove) { + getSystemService()!!.areNotificationsEnabled() + } else { + true + } } -fun Context.checkManifestPermission(permission: String): Boolean = - ActivityCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED +fun Context.checkManifestPermission(permission: String): Boolean { + return ActivityCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED +} -fun Context.isExternalStorageAccessible(): Boolean = when { - isRAndAbove -> Environment.isExternalStorageManager() - else -> checkManifestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) +fun Context.isExternalStorageAccessible(): Boolean { + return if (isRAndAbove) { + Environment.isExternalStorageManager() + } else { + checkManifestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) + } } -fun Context.isDomainVerified(domain: String): Boolean = when { - isSAndAbove -> { +fun Context.isDomainVerified(domain: String): Boolean { + return if (isSAndAbove) { val domainVerificationManager = getSystemService() val userState = domainVerificationManager!!.getDomainVerificationUserState(packageName) val domainMap = userState?.hostToStateMap?.filterKeys { it == domain } domainMap?.values?.first() == DomainVerificationUserState.DOMAIN_STATE_SELECTED + } else { + true } - - else -> true -} - -fun Context.navigate(screen: Screen) { - val intent = Intent(this, ComposeActivity::class.java).apply { - putExtra(Screen.PARCEL_KEY, screen) - } - startActivity(intent) } diff --git a/app/src/main/java/com/aurora/extensions/Dialog.kt b/app/src/main/java/com/aurora/extensions/Dialog.kt index b3d7da3ad..5264efa14 100644 --- a/app/src/main/java/com/aurora/extensions/Dialog.kt +++ b/app/src/main/java/com/aurora/extensions/Dialog.kt @@ -53,6 +53,7 @@ fun Context.showDialog( negativeListener?.let { setNegativeButton(android.R.string.cancel, negativeListener) } + }.create() builder.show() @@ -62,3 +63,7 @@ fun Context.showDialog( fun Fragment.showDialog(@StringRes titleId: Int, @StringRes messageId: Int) { requireContext().showDialog(titleId, messageId) } + +fun Fragment.showDialog(title: String, message: String) { + requireContext().showDialog(title, message) +} diff --git a/app/src/main/java/com/aurora/extensions/InputStream.kt b/app/src/main/java/com/aurora/extensions/InputStream.kt index 4dc969a3d..69a444d45 100644 --- a/app/src/main/java/com/aurora/extensions/InputStream.kt +++ b/app/src/main/java/com/aurora/extensions/InputStream.kt @@ -1,36 +1,36 @@ package com.aurora.extensions import com.aurora.store.data.model.DownloadInfo -import java.io.InputStream -import java.io.OutputStream -import kotlin.concurrent.fixedRateTimer import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn +import java.io.InputStream +import java.io.OutputStream +import kotlin.concurrent.fixedRateTimer -fun InputStream.copyTo(out: OutputStream, streamSize: Long): Flow = flow { - var bytesCopied: Long = 0 - val buffer = ByteArray(DEFAULT_BUFFER_SIZE) - var bytes = read(buffer) - var lastTotalBytesRead: Long = 0 - var speed: Long = 0 - - @Suppress("KotlinConstantConditions") // False-positive for bytesCopied always being zero - val timer = fixedRateTimer("timer", true, 0L, 1000) { - val totalBytesRead = bytesCopied - speed = totalBytesRead - lastTotalBytesRead - lastTotalBytesRead = totalBytesRead - } +fun InputStream.copyTo(out: OutputStream, streamSize: Long): Flow { + return flow { + var bytesCopied: Long = 0 + val buffer = ByteArray(DEFAULT_BUFFER_SIZE) + var bytes = read(buffer) - while (bytes >= 0) { - out.write(buffer, 0, bytes) - out.flush() + var lastTotalBytesRead = 0L + var speed: Long = 0 + @Suppress("KotlinConstantConditions") // False-positive for bytesCopied always being zero + val timer = fixedRateTimer("timer", true, 0L, 1000) { + val totalBytesRead = bytesCopied + speed = totalBytesRead - lastTotalBytesRead + lastTotalBytesRead = totalBytesRead + } - bytesCopied += bytes - // Emit stream progress in percentage - emit(DownloadInfo((bytesCopied * 100 / streamSize).toInt(), bytes.toLong(), speed)) - bytes = read(buffer) - } - timer.cancel() -}.flowOn(Dispatchers.IO) + while (bytes >= 0) { + out.write(buffer, 0, bytes) + bytesCopied += bytes + // Emit stream progress in percentage + emit(DownloadInfo((bytesCopied * 100 / streamSize).toInt(), bytes.toLong(), speed)) + bytes = read(buffer) + } + timer.cancel() + }.flowOn(Dispatchers.IO) +} diff --git a/app/src/main/java/com/aurora/extensions/Intent.kt b/app/src/main/java/com/aurora/extensions/Intent.kt index 36134c1e2..c270615ab 100644 --- a/app/src/main/java/com/aurora/extensions/Intent.kt +++ b/app/src/main/java/com/aurora/extensions/Intent.kt @@ -19,25 +19,24 @@ package com.aurora.extensions +import android.content.Context import android.content.Intent -import android.net.UrlQuerySanitizer import android.os.Bundle -fun Intent.getPackageName(fallbackBundle: Bundle? = null): String? = when (action) { - Intent.ACTION_VIEW -> { - data?.getQueryParameter("id") - } +inline fun Context.newIntent(): Intent = + Intent(this, T::class.java) - Intent.ACTION_SEND -> { - val clipData = getStringExtra(Intent.EXTRA_TEXT).orEmpty() - UrlQuerySanitizer(clipData).getValue("id") - } +inline fun Context.newIntent(flags: Int): Intent { + val intent = newIntent() + intent.flags = flags + return intent +} - Intent.ACTION_SHOW_APP_INFO -> { - extras?.getString(Intent.EXTRA_PACKAGE_NAME) - } +inline fun Context.newIntent(extras: Bundle): Intent = + newIntent(0, extras) - else -> { - extras?.getString("packageName") ?: fallbackBundle?.getString("packageName") - } +inline fun Context.newIntent(flags: Int, extras: Bundle): Intent { + val intent = newIntent(flags) + intent.putExtras(extras) + return intent } diff --git a/app/src/main/java/com/aurora/extensions/Number.kt b/app/src/main/java/com/aurora/extensions/Number.kt index e1625da69..95396ec8a 100644 --- a/app/src/main/java/com/aurora/extensions/Number.kt +++ b/app/src/main/java/com/aurora/extensions/Number.kt @@ -21,5 +21,8 @@ package com.aurora.extensions import android.content.res.Resources +val Number.dp: Number + get() = (this.toFloat() / Resources.getSystem().displayMetrics.density).toInt() + val Number.px: Number - get() = (this.toFloat() * Resources.getSystem().displayMetrics.density).toInt() + get() = (this.toFloat() * Resources.getSystem().displayMetrics.density).toInt() \ No newline at end of file diff --git a/app/src/main/java/com/aurora/extensions/PackageInfo.kt b/app/src/main/java/com/aurora/extensions/PackageInfo.kt index 781b9bc39..9d3064488 100644 --- a/app/src/main/java/com/aurora/extensions/PackageInfo.kt +++ b/app/src/main/java/com/aurora/extensions/PackageInfo.kt @@ -1,39 +1,21 @@ package com.aurora.extensions -import android.content.pm.ApplicationInfo import android.content.pm.PackageInfo import android.content.pm.PackageManager -import android.os.Build import android.os.Process -import androidx.core.content.pm.PackageInfoCompat fun PackageInfo.isValidApp(packageManager: PackageManager): Boolean { if (this.applicationInfo == null || this.packageName.isEmpty()) return false - // Filter out core AOSP system apps - if (this.applicationInfo!!.flags and ApplicationInfo.FLAG_SYSTEM != 0) { - if (this.packageName.endsWith(".resources")) return false - if (this.applicationInfo!!.loadLabel(packageManager).startsWith(this.packageName)) { - return false - } - if (this.versionName?.endsWith("system image") == true) return false - if (this.versionName?.endsWith("-initial") == true) return false - if (this.versionName == Build.VERSION.RELEASE && - PackageInfoCompat.getLongVersionCode(this) == Build.VERSION.SDK_INT.toLong() - ) { - return false - } - } + // Most core AOSP system apps use their package name as label + if (this.applicationInfo!!.loadLabel(packageManager).startsWith(this.packageName)) return false return when { isQAndAbove -> { Process.isApplicationUid(this.applicationInfo!!.uid) && - !this.applicationInfo!!.isResourceOverlay && - !this.isApex + !this.applicationInfo!!.isResourceOverlay && !this.isApex } - isNAndAbove -> Process.isApplicationUid(this.applicationInfo!!.uid) - else -> this.versionName != null } } diff --git a/app/src/main/java/com/aurora/extensions/PackageManager.kt b/app/src/main/java/com/aurora/extensions/PackageManager.kt index 4d1497769..913946e1f 100644 --- a/app/src/main/java/com/aurora/extensions/PackageManager.kt +++ b/app/src/main/java/com/aurora/extensions/PackageManager.kt @@ -22,9 +22,6 @@ fun PackageManager.getUpdateOwnerPackageNameCompat(packageName: String): String? installSourceInfo.installingPackageName } - else -> { - @Suppress("DEPRECATION") - getInstallerPackageName(packageName) - } + else -> @Suppress("DEPRECATION") getInstallerPackageName(packageName) } } diff --git a/app/src/main/java/com/aurora/extensions/Paging.kt b/app/src/main/java/com/aurora/extensions/Paging.kt deleted file mode 100644 index 850b0bfd5..000000000 --- a/app/src/main/java/com/aurora/extensions/Paging.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.extensions - -import androidx.compose.runtime.Composable -import androidx.paging.PagingData -import androidx.paging.compose.LazyPagingItems -import androidx.paging.compose.collectAsLazyPagingItems -import kotlinx.coroutines.flow.flowOf - -/** - * Empty lazy paging item flow for optional methods - */ -@Composable -fun emptyPagingItems(): LazyPagingItems = - flowOf(PagingData.empty()).collectAsLazyPagingItems() diff --git a/app/src/main/java/com/aurora/extensions/Platform.kt b/app/src/main/java/com/aurora/extensions/Platform.kt index 4d28213a8..e75d762e6 100644 --- a/app/src/main/java/com/aurora/extensions/Platform.kt +++ b/app/src/main/java/com/aurora/extensions/Platform.kt @@ -24,6 +24,9 @@ import android.annotation.SuppressLint import android.os.Build import java.util.Locale +val isMAndAbove: Boolean + get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M + val isNAndAbove: Boolean get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N @@ -55,31 +58,31 @@ val isMIUI: Boolean get() = !getSystemProperty("ro.miui.ui.version.name").isNullOrBlank() val isHuawei: Boolean - get() = Build.MANUFACTURER.lowercase(Locale.getDefault()).contains("huawei") || - Build.HARDWARE.lowercase(Locale.getDefault()).contains("kirin") || - Build.HARDWARE.lowercase(Locale.getDefault()).contains("hi3") + get() = Build.MANUFACTURER.lowercase(Locale.getDefault()).contains("huawei") + || Build.HARDWARE.lowercase(Locale.getDefault()).contains("kirin") + || Build.HARDWARE.lowercase(Locale.getDefault()).contains("hi3") @get:SuppressLint("PrivateApi") val isMiuiOptimizationDisabled: Boolean get() { return if ("0" == getSystemProperty("persist.sys.miui_optimization")) { true - } else { - try { - Class.forName("android.miui.AppOpsUtils") - .getDeclaredMethod("isXOptMode") - .invoke(null) as Boolean - } catch (_: java.lang.Exception) { - false - } + } else try { + Class.forName("android.miui.AppOpsUtils") + .getDeclaredMethod("isXOptMode") + .invoke(null) as Boolean + } catch (_: java.lang.Exception) { + false } } @SuppressLint("PrivateApi") -private fun getSystemProperty(key: String): String? = try { - Class.forName("android.os.SystemProperties") - .getDeclaredMethod("get", String::class.java) - .invoke(null, key) as String -} catch (_: Exception) { - null +private fun getSystemProperty(key: String): String? { + return try { + Class.forName("android.os.SystemProperties") + .getDeclaredMethod("get", String::class.java) + .invoke(null, key) as String + } catch (e: Exception) { + null + } } diff --git a/app/src/main/java/com/aurora/extensions/SharedPreferences.kt b/app/src/main/java/com/aurora/extensions/SharedPreferences.kt deleted file mode 100644 index c4b67f361..000000000 --- a/app/src/main/java/com/aurora/extensions/SharedPreferences.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.extensions - -import android.content.SharedPreferences -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.callbackFlow -import kotlinx.coroutines.flow.stateIn - -/** - * Extension method to observe changes in shared preferences as a flow - */ -fun SharedPreferences.observeAsStateFlow( - key: String, - scope: CoroutineScope, - started: SharingStarted = SharingStarted.Eagerly, - initial: T, - valueProvider: () -> T -): StateFlow = callbackFlow { - val listener = - SharedPreferences.OnSharedPreferenceChangeListener { _, changedKey -> - if (changedKey == key) { - trySend(valueProvider()) - } - } - - // Emit the initial value - trySend(valueProvider()) - - registerOnSharedPreferenceChangeListener(listener) - awaitClose { - unregisterOnSharedPreferenceChangeListener(listener) - } -}.stateIn(scope, started, initial) diff --git a/app/src/main/java/com/aurora/extensions/Shimmer.kt b/app/src/main/java/com/aurora/extensions/Shimmer.kt deleted file mode 100644 index f0518a1ba..000000000 --- a/app/src/main/java/com/aurora/extensions/Shimmer.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.extensions - -import androidx.compose.animation.core.FastOutSlowInEasing -import androidx.compose.animation.core.RepeatMode -import androidx.compose.animation.core.animateFloat -import androidx.compose.animation.core.infiniteRepeatable -import androidx.compose.animation.core.rememberInfiniteTransition -import androidx.compose.animation.core.tween -import androidx.compose.foundation.background -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.composed -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.graphics.Brush -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.layout.onGloballyPositioned -import androidx.compose.ui.unit.IntSize - -/** - * Modifier for composable to play shimmer animation - * @param toShow Whether to play shimmer animation - */ -fun Modifier.shimmer(toShow: Boolean): Modifier = composed { - if (toShow) { - val shimmerColors = listOf( - Color.LightGray.copy(alpha = 0.6f), - Color.LightGray.copy(alpha = 0.2f), - Color.LightGray.copy(alpha = 0.6f) - ) - - var size by remember { mutableStateOf(IntSize.Zero) } - - val transition = rememberInfiniteTransition() - val transitionAnimation = transition.animateFloat( - initialValue = 0f, - targetValue = 1000f, - animationSpec = infiniteRepeatable( - animation = tween( - durationMillis = 1000, - easing = FastOutSlowInEasing - ), - repeatMode = RepeatMode.Reverse - ) - ) - background( - brush = Brush.linearGradient( - colors = shimmerColors, - start = Offset.Zero, - end = Offset(x = transitionAnimation.value, y = transitionAnimation.value) - ) - ).onGloballyPositioned { size = it.size } - } else { - Modifier - } -} diff --git a/app/src/main/java/com/aurora/extensions/Threading.kt b/app/src/main/java/com/aurora/extensions/Threading.kt index a0f6bb5d9..d7d94e7ba 100644 --- a/app/src/main/java/com/aurora/extensions/Threading.kt +++ b/app/src/main/java/com/aurora/extensions/Threading.kt @@ -22,6 +22,8 @@ package com.aurora.extensions import android.os.Handler import android.os.Looper +fun runAsync(action: () -> Unit) = Thread(Runnable(action)).start() + fun runOnUiThread(action: () -> Unit) { when { isMainThread() -> action.invoke() diff --git a/app/src/main/java/com/aurora/extensions/WindowAdaptiveInfo.kt b/app/src/main/java/com/aurora/extensions/WindowAdaptiveInfo.kt deleted file mode 100644 index 43b715beb..000000000 --- a/app/src/main/java/com/aurora/extensions/WindowAdaptiveInfo.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.extensions - -import androidx.compose.material3.adaptive.WindowAdaptiveInfo -import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.res.painterResource -import androidx.window.core.layout.WindowSizeClass -import com.aurora.store.R - -/** - * Whether the device width is compact or not - * - */ -val WindowAdaptiveInfo.isWindowCompact: Boolean - get() = !windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND) - -/** - * Returns navigation icon for adaptive screens such as extra pane - */ -val WindowAdaptiveInfo.adaptiveNavigationIcon: Painter - @Composable - get() = when { - isWindowCompact -> painterResource(R.drawable.ic_arrow_back) - else -> painterResource(R.drawable.ic_cancel) - } diff --git a/app/src/main/java/com/aurora/store/Aliases.kt b/app/src/main/java/com/aurora/store/Aliases.kt index 876b75126..f1f95ce43 100644 --- a/app/src/main/java/com/aurora/store/Aliases.kt +++ b/app/src/main/java/com/aurora/store/Aliases.kt @@ -8,7 +8,7 @@ import com.aurora.gplayapi.helpers.contracts.TopChartsContract typealias MR = com.google.android.material.R.attr -typealias TopChartStash = - MutableMap> +typealias TopChartStash = MutableMap> typealias HomeStash = MutableMap typealias CategoryStash = MutableMap> +typealias AppStreamStash = MutableMap diff --git a/app/src/main/java/com/aurora/store/AuroraApp.kt b/app/src/main/java/com/aurora/store/AuroraApp.kt index 650dd515d..5956437cf 100644 --- a/app/src/main/java/com/aurora/store/AuroraApp.kt +++ b/app/src/main/java/com/aurora/store/AuroraApp.kt @@ -22,9 +22,6 @@ package com.aurora.store import android.app.Application import android.content.Context -import android.util.Log.DEBUG -import android.util.Log.INFO -import androidx.compose.material3.ComposeMaterial3Flags import androidx.core.content.ContextCompat import androidx.hilt.work.HiltWorkerFactory import androidx.work.Configuration @@ -44,10 +41,11 @@ import com.aurora.store.util.PackageUtil import com.aurora.store.util.Preferences import com.google.android.material.color.DynamicColors import dagger.hilt.android.HiltAndroidApp -import javax.inject.Inject import kotlinx.coroutines.MainScope +import kotlinx.coroutines.cancel import okhttp3.OkHttpClient import org.lsposed.hiddenapibypass.HiddenApiBypass +import javax.inject.Inject @HiltAndroidApp class AuroraApp : Application(), Configuration.Provider, SingletonImageLoader.Factory { @@ -66,11 +64,12 @@ class AuroraApp : Application(), Configuration.Provider, SingletonImageLoader.Fa override val workManagerConfiguration: Configuration get() = Configuration.Builder() - .setMinimumLoggingLevel(if (BuildConfig.DEBUG) DEBUG else INFO) + .setMinimumLoggingLevel(android.util.Log.INFO) .setWorkerFactory(workerFactory) .build() companion object { + // Alternative to GlobalScope var scope = MainScope() private set @@ -79,7 +78,6 @@ class AuroraApp : Application(), Configuration.Provider, SingletonImageLoader.Fa } override fun onCreate() { - ComposeMaterial3Flags.isCheckboxStylingFixEnabled = true super.onCreate() // Set the app theme val themeStyle = Preferences.getInteger(this, Preferences.PREFERENCE_THEME_STYLE) @@ -91,14 +89,14 @@ class AuroraApp : Application(), Configuration.Provider, SingletonImageLoader.Fa // Required for Shizuku installer if (isPAndAbove) HiddenApiBypass.addHiddenApiExemptions("I", "L") - // Create Notification Channels + //Create Notification Channels NotificationUtil.createNotificationChannel(this) // Initialize Download and Update helpers to observe and trigger downloads downloadHelper.init() updateHelper.init() - // Register broadcast receiver for package install/uninstall + //Register broadcast receiver for package install/uninstall ContextCompat.registerReceiver( this, object : PackageManagerReceiver() {}, @@ -109,8 +107,16 @@ class AuroraApp : Application(), Configuration.Provider, SingletonImageLoader.Fa CommonUtil.cleanupInstallationSessions(applicationContext) } - override fun newImageLoader(context: Context): ImageLoader = ImageLoader(this).newBuilder() - .crossfade(true) - .components { add(OkHttpNetworkFetcherFactory(callFactory = okHttpClient)) } - .build() + override fun onLowMemory() { + super.onLowMemory() + scope.cancel("onLowMemory() called by system") + scope = MainScope() + } + + override fun newImageLoader(context: Context): ImageLoader { + return ImageLoader(this).newBuilder() + .crossfade(true) + .components { add(OkHttpNetworkFetcherFactory(callFactory = okHttpClient)) } + .build() + } } diff --git a/app/src/main/java/com/aurora/store/ComposeActivity.kt b/app/src/main/java/com/aurora/store/ComposeActivity.kt deleted file mode 100644 index ca687974c..000000000 --- a/app/src/main/java/com/aurora/store/ComposeActivity.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store - -import android.os.Bundle -import androidx.activity.ComponentActivity -import androidx.activity.compose.setContent -import androidx.activity.enableEdgeToEdge -import androidx.compose.runtime.CompositionLocalProvider -import androidx.core.content.IntentCompat -import com.aurora.store.compose.composition.LocalUI -import com.aurora.store.compose.composition.UI -import com.aurora.store.compose.navigation.NavDisplay -import com.aurora.store.compose.navigation.Screen -import com.aurora.store.compose.theme.AuroraTheme -import com.aurora.store.util.PackageUtil -import dagger.hilt.android.AndroidEntryPoint - -@AndroidEntryPoint -class ComposeActivity : ComponentActivity() { - - override fun onCreate(savedInstanceState: Bundle?) { - enableEdgeToEdge() - super.onCreate(savedInstanceState) - - // TODO: Change startDestination logic to mirror MainActivity - val startDestination = IntentCompat.getParcelableExtra( - intent, - Screen.PARCEL_KEY, - Screen::class.java - ) ?: Screen.Blacklist - - val localUI = when { - PackageUtil.isTv(this) -> UI.TV - else -> UI.DEFAULT - } - - setContent { - CompositionLocalProvider(LocalUI provides localUI) { - AuroraTheme { - NavDisplay(startDestination = startDestination) - } - } - } - } -} diff --git a/app/src/main/java/com/aurora/store/MainActivity.kt b/app/src/main/java/com/aurora/store/MainActivity.kt index 683f22517..988236dec 100644 --- a/app/src/main/java/com/aurora/store/MainActivity.kt +++ b/app/src/main/java/com/aurora/store/MainActivity.kt @@ -34,25 +34,26 @@ import androidx.lifecycle.lifecycleScope import androidx.navigation.FloatingWindow import androidx.navigation.fragment.NavHostFragment import androidx.navigation.ui.setupWithNavController +import com.aurora.extensions.isNAndAbove import com.aurora.store.data.model.NetworkStatus import com.aurora.store.data.receiver.MigrationReceiver import com.aurora.store.databinding.ActivityMainBinding -import com.aurora.store.util.PackageUtil import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences.PREFERENCE_DEFAULT_SELECTED_TAB import com.aurora.store.view.ui.sheets.NetworkDialogSheet +import com.aurora.store.util.PackageUtil import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.launch @AndroidEntryPoint class MainActivity : AppCompatActivity() { private val viewModel: MainViewModel by viewModels() - private lateinit var binding: ActivityMainBinding + private lateinit var B: ActivityMainBinding // TopLevelFragments private val topLevelFrags = listOf( @@ -69,11 +70,11 @@ class MainActivity : AppCompatActivity() { enableEdgeToEdge() super.onCreate(savedInstanceState) - binding = ActivityMainBinding.inflate(layoutInflater) - setContentView(binding.root) + B = ActivityMainBinding.inflate(layoutInflater) + setContentView(B.root) // Adjust root view's paddings for edgeToEdge display - ViewCompat.setOnApplyWindowInsetsListener(binding.root) { root, windowInsets -> + ViewCompat.setOnApplyWindowInsetsListener(B.root) { root, windowInsets -> val insets = windowInsets.getInsets(systemBars() or displayCutout() or ime()) root.setPadding(insets.left, insets.top, insets.right, 0) windowInsets @@ -83,7 +84,7 @@ class MainActivity : AppCompatActivity() { supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navController = navHostFragment.navController - if (!PackageUtil.isTv(this)) { + if (isNAndAbove && !PackageUtil.isTv(this)) { viewModel.networkProvider.status.onEach { networkStatus -> when (networkStatus) { NetworkStatus.AVAILABLE -> { @@ -96,6 +97,7 @@ class MainActivity : AppCompatActivity() { .commitAllowingStateLoss() } } + } NetworkStatus.UNAVAILABLE -> { @@ -109,7 +111,7 @@ class MainActivity : AppCompatActivity() { }.launchIn(AuroraApp.scope) } - binding.navView.setupWithNavController(navController) + B.navView.setupWithNavController(navController) // Handle quick exit from back actions val defaultTab = when (Preferences.getInteger(this, PREFERENCE_DEFAULT_SELECTED_TAB)) { @@ -136,8 +138,8 @@ class MainActivity : AppCompatActivity() { navController.addOnDestinationChangedListener { _, navDestination, _ -> if (navDestination !is FloatingWindow) { when (navDestination.id) { - in topLevelFrags -> binding.navView.visibility = View.VISIBLE - else -> binding.navView.visibility = View.GONE + in topLevelFrags -> B.navView.visibility = View.VISIBLE + else -> B.navView.visibility = View.GONE } } } @@ -145,7 +147,7 @@ class MainActivity : AppCompatActivity() { // Updates lifecycleScope.launch { viewModel.updateHelper.updates.collectLatest { list -> - binding.navView.getOrCreateBadge(R.id.updatesFragment).apply { + B.navView.getOrCreateBadge(R.id.updatesFragment).apply { isVisible = !list.isNullOrEmpty() number = list?.size ?: 0 } @@ -153,5 +155,7 @@ class MainActivity : AppCompatActivity() { } } - private fun isIntroDone(): Boolean = Preferences.getBoolean(this, Preferences.PREFERENCE_INTRO) + private fun isIntroDone(): Boolean { + return Preferences.getBoolean(this@MainActivity, Preferences.PREFERENCE_INTRO) + } } diff --git a/app/src/main/java/com/aurora/store/compose/composable/BlackListItem.kt b/app/src/main/java/com/aurora/store/compose/composable/BlackListItem.kt deleted file mode 100644 index 81a5bfd76..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/BlackListItem.kt +++ /dev/null @@ -1,118 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import android.graphics.Bitmap -import android.graphics.Color -import androidx.compose.foundation.Image -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredSize -import androidx.compose.material3.Checkbox -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.asImageBitmap -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.core.graphics.drawable.toBitmap -import androidx.core.graphics.drawable.toDrawable -import com.aurora.store.BuildConfig -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Composable for displaying package details in a list for blacklisting - * @param modifier The modifier to be applied to the composable - * @param icon Icon for the package - * @param displayName User-readable name of the package - * @param packageName Name of the package - * @param versionName versionName of the package - * @param versionCode versionCode of the package - * @param isChecked Whether the app is blacklisted - * @param isEnabled Whether this app is allowed to be blacklisted - * @param onClick Callback when the composable is clicked - */ -@Composable -fun BlackListItem( - modifier: Modifier = Modifier, - icon: Bitmap, - displayName: String, - packageName: String, - versionName: String, - versionCode: Long, - isChecked: Boolean = false, - isEnabled: Boolean = true, - onClick: () -> Unit = {} -) { - Row( - modifier = modifier - .fillMaxWidth() - .clickable(enabled = isEnabled, onClick = onClick) - .padding( - horizontal = dimensionResource(R.dimen.padding_medium), - vertical = dimensionResource(R.dimen.padding_xsmall) - ), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Row(modifier = Modifier.weight(1F)) { - Image( - bitmap = icon.asImageBitmap(), - contentDescription = null, - modifier = Modifier.requiredSize(dimensionResource(R.dimen.icon_size_medium)) - ) - Column( - modifier = Modifier.padding(horizontal = dimensionResource(R.dimen.margin_small)) - ) { - Text( - text = displayName, - style = MaterialTheme.typography.bodyMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = packageName, - style = MaterialTheme.typography.bodySmall, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = stringResource(R.string.version, versionName, versionCode), - style = MaterialTheme.typography.bodySmall, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - } - Checkbox(checked = isChecked, enabled = isEnabled, onCheckedChange = { onClick() }) - } -} - -@Preview(showBackground = true) -@Composable -private fun BlackListItemPreview() { - PreviewTemplate { - BlackListItem( - icon = Color.GRAY.toDrawable().toBitmap(56, 56), - displayName = LocalContext.current.getString(R.string.app_name), - packageName = BuildConfig.APPLICATION_ID, - versionName = BuildConfig.VERSION_NAME, - versionCode = BuildConfig.VERSION_CODE.toLong(), - isChecked = true, - isEnabled = false - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/ContainedLoadingIndicator.kt b/app/src/main/java/com/aurora/store/compose/composable/ContainedLoadingIndicator.kt deleted file mode 100644 index 9978a7876..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/ContainedLoadingIndicator.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredSize -import androidx.compose.material3.ContainedLoadingIndicator -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.semantics.stateDescription -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Composable to display an indeterminate loading indicator that fills all available screen - * @param modifier The modifier to be applied to the composable - */ -@Composable -fun ContainedLoadingIndicator(modifier: Modifier = Modifier) { - Box( - modifier = modifier - .fillMaxSize() - .padding(dimensionResource(R.dimen.padding_small)), - contentAlignment = Alignment.Center - ) { - val description = stringResource(R.string.loading) - ContainedLoadingIndicator( - modifier = Modifier - .requiredSize(dimensionResource(R.dimen.icon_size_small)) - .semantics { stateDescription = description } - ) - } -} - -@Preview(showBackground = true) -@Composable -private fun ContainedLoadingIndicatorPreview() { - PreviewTemplate { - ContainedLoadingIndicator() - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/DeviceListItem.kt b/app/src/main/java/com/aurora/store/compose/composable/DeviceListItem.kt deleted file mode 100644 index 0fb05fbd8..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/DeviceListItem.kt +++ /dev/null @@ -1,86 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Checkbox -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R - -/** - * Composable to display device details for spoofing in a list - * @param modifier The modifier to be applied to the composable - * @param userReadableName Name of the device, obtained through `UserReadableName` property - * @param manufacturer Name of the device manufacturer, obtained through `Build.MANUFACTURER` property - * @param androidVersionSdk Android version on the device, obtained through `Build.VERSION.SDK_INT` property - * @param platforms Platforms supported on the device, obtained through `Platforms` property - * @param isChecked If the device is selected - * @param onClick Callback when the composable is clicked - */ -@Composable -fun DeviceListItem( - modifier: Modifier = Modifier, - userReadableName: String, - manufacturer: String, - androidVersionSdk: String, - platforms: String, - isChecked: Boolean = false, - onClick: () -> Unit = {} -) { - Row( - modifier = modifier - .fillMaxWidth() - .clickable(onClick = { if (!isChecked) onClick() }) - .padding(dimensionResource(R.dimen.padding_small)), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween - ) { - Column(modifier = Modifier.weight(1F)) { - Text( - text = userReadableName, - style = MaterialTheme.typography.bodyLarge, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = stringResource(R.string.spoof_property, manufacturer, androidVersionSdk), - style = MaterialTheme.typography.bodyMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = platforms.replace(",\\s*".toRegex(), ", "), - style = MaterialTheme.typography.bodySmall - ) - } - Checkbox(checked = isChecked, onCheckedChange = { if (!isChecked) onClick() }) - } -} - -@Preview(showBackground = true) -@Composable -private fun DeviceListItemPreview() { - DeviceListItem( - userReadableName = "Google Pixel 7a", - manufacturer = "Google", - androidVersionSdk = "33", - platforms = "arm64-v8a", - isChecked = true - ) -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/DispenserListItem.kt b/app/src/main/java/com/aurora/store/compose/composable/DispenserListItem.kt deleted file mode 100644 index 20dd4cd57..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/DispenserListItem.kt +++ /dev/null @@ -1,78 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R - -/** - * Composable to display dispenser URL in a list - * @param modifier The modifier to be applied to the composable - * @param url URL of the dispenser - * @param onClick Callback when this URL is clicked - * @param onClear Callback when the clear button is clicked - */ -@Composable -fun DispenserListItem( - modifier: Modifier = Modifier, - url: String, - onClick: () -> Unit = {}, - onClear: () -> Unit = {} -) { - Row( - modifier = modifier - .fillMaxWidth() - .clickable(onClick = onClick) - .padding(dimensionResource(R.dimen.padding_small)), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Row( - modifier = Modifier.weight(1F), - horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_small)) - ) { - Icon( - painter = painterResource(R.drawable.ic_server), - contentDescription = null - ) - Text( - text = url, - style = MaterialTheme.typography.bodyLarge, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - TextButton(onClick = onClear) { - Text( - text = stringResource(R.string.remove), - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun DispenserListItemPreview() { - DispenserListItem(url = "https://auroraoss.com/api/auth") -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/DownloadListItem.kt b/app/src/main/java/com/aurora/store/compose/composable/DownloadListItem.kt deleted file mode 100644 index 21c4abddd..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/DownloadListItem.kt +++ /dev/null @@ -1,180 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import android.text.format.DateUtils -import android.text.format.Formatter -import androidx.compose.animation.AnimatedContent -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.fadeOut -import androidx.compose.animation.shrinkVertically -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredSize -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.composable.app.AnimatedAppIcon -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.data.model.DownloadStatus -import com.aurora.store.data.room.download.Download -import com.aurora.store.util.CommonUtil.getETAString -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch - -/** - * Composable to display details of a download in a list - * @param modifier The modifier to be applied to the composable - * @param download [Download] to display - * @param onClick Callback when this composable is clicked - */ -@Composable -fun DownloadListItem( - modifier: Modifier = Modifier, - download: Download, - onClick: () -> Unit = {}, - onClear: () -> Unit = {}, - onCancel: () -> Unit = {}, - onExport: () -> Unit = {}, - onInstall: () -> Unit = {}, - isExpanded: Boolean = false -) { - val progress = "${download.progress}%" - val speed = "${Formatter.formatShortFileSize(LocalContext.current, download.speed)}/s" - val eta = getETAString(LocalContext.current, download.timeRemaining) - - val coroutineScope = rememberCoroutineScope() - var isVisible by remember { mutableStateOf(true) } - var isExpanded by remember { mutableStateOf(isExpanded) } - - fun requestClear() { - coroutineScope.launch { - isVisible = false - delay(300) // Let the animation play - onClear() - } - } - - @Composable - fun ExpandedMenu() { - val context = LocalContext.current - Box(modifier = modifier) { - IconButton(onClick = { isExpanded = true }) { - Icon( - painter = painterResource(R.drawable.ic_more_vert), - contentDescription = stringResource(R.string.menu) - ) - } - DropdownMenu(expanded = isExpanded, onDismissRequest = { isExpanded = false }) { - DropdownMenuItem( - text = { Text(text = stringResource(R.string.action_cancel)) }, - onClick = onCancel, - enabled = download.isRunning - ) - DropdownMenuItem( - text = { Text(text = stringResource(R.string.action_install)) }, - onClick = onInstall, - enabled = download.canInstall(context) - ) - DropdownMenuItem( - text = { Text(text = stringResource(R.string.action_export)) }, - onClick = onExport, - enabled = download.canInstall(context) - ) - DropdownMenuItem( - text = { Text(text = stringResource(R.string.action_clear)) }, - onClick = ::requestClear, - enabled = !download.isRunning - ) - } - } - } - - AnimatedVisibility(visible = isVisible, exit = shrinkVertically() + fadeOut()) { - Row( - modifier = modifier - .fillMaxWidth() - .clickable(onClick = onClick) - .padding( - horizontal = dimensionResource(R.dimen.padding_medium), - vertical = dimensionResource(R.dimen.padding_small) - ), - horizontalArrangement = Arrangement.SpaceBetween - ) { - Row(modifier = Modifier.weight(1F)) { - AnimatedAppIcon( - modifier = Modifier.requiredSize(dimensionResource(R.dimen.icon_size_medium)), - iconUrl = download.iconURL, - inProgress = download.isRunning, - progress = download.progress.toFloat() - ) - Column( - modifier = Modifier - .padding(horizontal = dimensionResource(R.dimen.margin_small)) - ) { - Text( - text = download.displayName, - style = MaterialTheme.typography.bodyMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = stringResource(download.status.localized), - style = MaterialTheme.typography.bodySmall - ) - AnimatedContent(targetState = download.status) { status -> - Text( - style = MaterialTheme.typography.bodySmall, - text = if (status in DownloadStatus.running) { - "$progress • $speed • $eta" - } else { - DateUtils.formatDateTime( - LocalContext.current, - download.downloadedAt, - DateUtils.FORMAT_SHOW_DATE - ).toString() - } - ) - } - } - } - ExpandedMenu() - } - } -} - -@Preview(showBackground = true) -@Composable -private fun DownloadListItemPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - DownloadListItem(download = Download.fromApp(app), isExpanded = true) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/Error.kt b/app/src/main/java/com/aurora/store/compose/composable/Error.kt deleted file mode 100644 index 55793316a..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/Error.kt +++ /dev/null @@ -1,89 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredSize -import androidx.compose.material3.Button -import androidx.compose.material3.Icon -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Composable to show error message that fills all available screen - * @param modifier The modifier to be applied to the composable - * @param painter Painter to draw the icon - * @param message Message for error - * @param actionMessage Message to show on action button; defaults to null with button not visible - * @param onAction Callback when action button is clicked - */ -@Composable -fun Error( - modifier: Modifier = Modifier, - painter: Painter, - message: String, - actionMessage: String? = null, - onAction: (() -> Unit)? = null -) { - Column( - modifier = modifier - .fillMaxSize() - .padding(dimensionResource(R.dimen.padding_medium)), - verticalArrangement = Arrangement.spacedBy( - dimensionResource(R.dimen.margin_small), - Alignment.CenterVertically - ), - horizontalAlignment = Alignment.CenterHorizontally - ) { - Icon( - painter = painter, - contentDescription = null, - modifier = Modifier.requiredSize(dimensionResource(R.dimen.icon_size)) - ) - Text( - modifier = Modifier.fillMaxWidth(), - text = message, - textAlign = TextAlign.Center - ) - - if (actionMessage != null) { - Button(onClick = { if (onAction != null) onAction() }, enabled = onAction != null) { - Text( - text = actionMessage, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - } - } -} - -@Preview(showBackground = true) -@Composable -private fun ErrorPreview() { - PreviewTemplate { - Error( - painter = painterResource(R.drawable.ic_updates), - message = stringResource(R.string.details_no_updates), - actionMessage = stringResource(R.string.check_updates) - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/FavouriteListItem.kt b/app/src/main/java/com/aurora/store/compose/composable/FavouriteListItem.kt deleted file mode 100644 index 3820a20a1..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/FavouriteListItem.kt +++ /dev/null @@ -1,147 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import android.text.format.DateUtils -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.fadeOut -import androidx.compose.animation.shrinkVertically -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredSize -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import coil3.compose.AsyncImage -import coil3.request.ImageRequest -import coil3.request.crossfade -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.data.room.favourite.Favourite -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch - -/** - * Composable to display a favourite app in a list - * @param modifier The modifier to be applied to the composable - * @param favourite A [Favourite] app to display - * @param onClick Callback when this composable is clicked - * @param onClear Callback when the favourite button is clicked to remove the app from favourites - */ -@Composable -fun FavouriteListItem( - modifier: Modifier = Modifier, - favourite: Favourite, - onClick: () -> Unit = {}, - onClear: () -> Unit = {} -) { - val coroutineScope = rememberCoroutineScope() - var isVisible by remember { mutableStateOf(true) } - - fun requestClear() { - coroutineScope.launch { - isVisible = false - delay(300) // Let the animation play - onClear() - } - } - - AnimatedVisibility( - visible = isVisible, - exit = shrinkVertically() + fadeOut() - ) { - Row( - modifier = modifier - .fillMaxWidth() - .clickable(onClick = onClick) - .padding( - horizontal = dimensionResource(R.dimen.padding_medium), - vertical = dimensionResource(R.dimen.padding_xsmall) - ), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween - ) { - Row(modifier = Modifier.weight(1F)) { - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(favourite.iconURL) - .crossfade(true) - .build(), - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = Modifier - .requiredSize(dimensionResource(R.dimen.icon_size_medium)) - .clip(RoundedCornerShape(dimensionResource(R.dimen.radius_medium))) - ) - Column( - modifier = Modifier.padding( - horizontal = dimensionResource(R.dimen.margin_small) - ) - ) { - Text( - text = favourite.displayName, - style = MaterialTheme.typography.bodyMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = favourite.packageName, - style = MaterialTheme.typography.bodySmall, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = DateUtils.formatDateTime( - LocalContext.current, - favourite.added, - DateUtils.FORMAT_SHOW_DATE - ), - style = MaterialTheme.typography.bodySmall - ) - } - } - IconButton(onClick = { requestClear() }) { - Icon( - painter = painterResource(R.drawable.ic_favorite_checked), - contentDescription = stringResource(R.string.action_favourite) - ) - } - } - } -} - -@Preview(showBackground = true) -@Composable -private fun FavouriteListItemPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - FavouriteListItem(favourite = Favourite.fromApp(app, Favourite.Mode.MANUAL)) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/Header.kt b/app/src/main/java/com/aurora/store/compose/composable/Header.kt deleted file mode 100644 index edc58f094..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/Header.kt +++ /dev/null @@ -1,93 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Composable to display sticky header in list - * @param modifier The modifier to be applied to the composable - * @param title Title to display - * @param subtitle Optional subtitle to display - * @param onClick Callback when this composable is clicked - * @see TextDividerComposable - */ -@Composable -fun Header( - modifier: Modifier = Modifier, - title: String, - subtitle: String? = null, - onClick: (() -> Unit)? = null -) { - Row( - modifier = modifier - .fillMaxWidth() - .clip(RoundedCornerShape(dimensionResource(R.dimen.radius_small))) - .clickable(onClick = { if (onClick != null) onClick() }, enabled = onClick != null) - .padding( - horizontal = dimensionResource(R.dimen.padding_small), - vertical = dimensionResource(R.dimen.padding_xxsmall) - ), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Column( - modifier = Modifier.weight(1F), - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.padding_xsmall)) - ) { - Text( - text = title, - style = MaterialTheme.typography.titleMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - if (!subtitle.isNullOrBlank()) { - Text( - text = subtitle, - style = MaterialTheme.typography.bodyMedium - ) - } - } - if (onClick != null) { - Icon( - painter = painterResource(R.drawable.ic_arrow_right), - contentDescription = null - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun HeaderPreview() { - PreviewTemplate { - Header( - title = stringResource(R.string.details_privacy), - subtitle = stringResource(R.string.exodus_powered), - onClick = {} - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/Info.kt b/app/src/main/java/com/aurora/store/compose/composable/Info.kt deleted file mode 100644 index b18d6817e..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/Info.kt +++ /dev/null @@ -1,94 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.text.fromHtml -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Composable to show some information - * @param modifier The modifier to be applied to the composable - * @param title Title of the information - * @param description Information to show - * @param painter Optional painter to draw the icon - * @param titleColor Optional color for the title - * @param onClick Callback when this composable is clicked - */ -@Composable -fun Info( - modifier: Modifier = Modifier, - title: AnnotatedString, - description: AnnotatedString? = null, - painter: Painter? = null, - titleColor: Color = Color.Unspecified, - onClick: (() -> Unit)? = null -) { - Row( - modifier = modifier - .fillMaxWidth() - .clickable(onClick = { if (onClick != null) onClick() }, enabled = onClick != null) - .padding( - horizontal = dimensionResource(R.dimen.padding_small), - vertical = dimensionResource(R.dimen.padding_xxsmall) - ), - horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_normal)), - verticalAlignment = Alignment.CenterVertically - ) { - if (painter != null) Icon(painter = painter, contentDescription = null) - Column(modifier = Modifier.weight(1F)) { - Text( - text = title, - style = MaterialTheme.typography.bodyMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - color = titleColor - ) - if (!description.isNullOrBlank()) { - Text( - text = description, - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.secondary - ) - } - } - } -} - -@Preview(showBackground = true) -@Composable -private fun InfoPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - Info( - title = AnnotatedString(text = stringResource(R.string.details_dev_website)), - description = AnnotatedString.fromHtml(htmlString = app.developerWebsite), - painter = painterResource(R.drawable.ic_network) - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/InstallerListItem.kt b/app/src/main/java/com/aurora/store/compose/composable/InstallerListItem.kt deleted file mode 100644 index 0bc1752d2..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/InstallerListItem.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.RadioButton -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.data.installer.SessionInstaller -import com.aurora.store.data.model.InstallerInfo - -/** - * Composable to display installer details in a list - * @param modifier The modifier to be applied to the composable - * @param installerInfo A [InstallerInfo] object to display details - * @param isSelected Whether this installer is selected - * @param onClick Callback when this composable is clicked - */ -@Composable -fun InstallerListItem( - modifier: Modifier = Modifier, - installerInfo: InstallerInfo, - isSelected: Boolean = false, - onClick: () -> Unit = {} -) { - Row( - modifier = modifier - .fillMaxWidth() - .clickable(onClick = onClick) - .padding(dimensionResource(R.dimen.padding_small)), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Column(modifier = Modifier.weight(1F)) { - Text( - text = stringResource(installerInfo.title), - style = MaterialTheme.typography.bodyLarge, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = stringResource(installerInfo.subtitle), - style = MaterialTheme.typography.bodyMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = stringResource(installerInfo.description), - style = MaterialTheme.typography.bodySmall - ) - } - RadioButton(selected = isSelected, onClick = onClick) - } -} - -@Preview(showBackground = true) -@Composable -private fun InstallerListItemPreview() { - PreviewTemplate { - InstallerListItem(installerInfo = SessionInstaller.installerInfo, isSelected = true) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/LinkListItem.kt b/app/src/main/java/com/aurora/store/compose/composable/LinkListItem.kt deleted file mode 100644 index 54b1d1525..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/LinkListItem.kt +++ /dev/null @@ -1,108 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredSize -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.material3.VerticalDivider -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.ColorFilter -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import coil3.compose.AsyncImage -import coil3.request.ImageRequest -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.data.model.Link - -/** - * Composable to show link details in a list - * @param modifier The modifier to be applied to the composable - * @param link [Link] to show details - * @param onClick Callback when the composable is clicked - */ -@Composable -fun LinkListItem( - modifier: Modifier = Modifier, - link: Link, - onClick: () -> Unit = {}, - iconTint: Color? = null -) { - Row( - modifier = modifier - .fillMaxWidth() - .clickable(onClick = onClick) - .padding(dimensionResource(R.dimen.padding_medium)), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(link.icon) - .build(), - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = Modifier - .requiredSize(dimensionResource(R.dimen.icon_size_default)) - .clip(CircleShape), - colorFilter = if (iconTint != null) ColorFilter.tint(color = iconTint) else null - ) - VerticalDivider( - modifier = Modifier - .padding(horizontal = dimensionResource(R.dimen.margin_large)) - .width(dimensionResource(R.dimen.padding_xxsmall)) - .height(dimensionResource(R.dimen.height_header)) - ) - Column { - Text( - text = link.title, - style = MaterialTheme.typography.bodyLarge, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = link.subtitle, - style = MaterialTheme.typography.bodySmall, - maxLines = 2, - overflow = TextOverflow.Ellipsis - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun LinkListItemPreview() { - PreviewTemplate { - LinkListItem( - link = Link( - id = 0, - title = stringResource(R.string.title_about), - subtitle = stringResource(R.string.about_aurora_store_subtitle), - url = "https://auroraoss.com/", - icon = R.drawable.ic_menu_about - ) - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/LocaleListItem.kt b/app/src/main/java/com/aurora/store/compose/composable/LocaleListItem.kt deleted file mode 100644 index cebc413d8..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/LocaleListItem.kt +++ /dev/null @@ -1,76 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Checkbox -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import java.util.Locale - -/** - * Composable to display locale details in a list - * @param modifier The modifier to be applied to the composable - * @param displayName Display name of the locale - * @param displayLanguage Display name of the language in the locale - * @param isChecked Whether the locale is checked/selected - * @param onClick Callback when the composable is clicked - */ -@Composable -fun LocaleListItem( - modifier: Modifier = Modifier, - displayName: String, - displayLanguage: String, - isChecked: Boolean = false, - onClick: () -> Unit = {} -) { - Row( - modifier = modifier - .fillMaxWidth() - .clickable(onClick = { if (!isChecked) onClick() }) - .padding(dimensionResource(R.dimen.padding_small)), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween - ) { - Column(modifier = Modifier.weight(1F)) { - Text( - text = displayName, - style = MaterialTheme.typography.bodyLarge, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = displayLanguage, - style = MaterialTheme.typography.bodyMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - Checkbox(checked = isChecked, onCheckedChange = { if (!isChecked) onClick() }) - } -} - -@Preview(showBackground = true) -@Composable -private fun LocaleListItemPreview() { - LocaleListItem( - displayName = Locale.JAPANESE.displayName, - displayLanguage = Locale.JAPAN.getDisplayLanguage(Locale.JAPAN), - isChecked = true - ) -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/Logo.kt b/app/src/main/java/com/aurora/store/compose/composable/Logo.kt deleted file mode 100644 index 0727e638f..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/Logo.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.requiredSize -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import coil3.compose.AsyncImage -import coil3.request.ImageRequest -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Composable to show Aurora Store's logo - */ -@Composable -fun Logo(modifier: Modifier = Modifier) { - Column( - modifier = modifier.fillMaxSize(), - verticalArrangement = Arrangement.spacedBy( - dimensionResource(R.dimen.margin_small), - Alignment.CenterVertically - ), - horizontalAlignment = Alignment.CenterHorizontally - ) { - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(R.mipmap.ic_launcher) - .build(), - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = Modifier - .requiredSize(dimensionResource(R.dimen.icon_size_avatar)) - .clip(CircleShape) - ) - Text( - text = stringResource(R.string.app_name), - style = MaterialTheme.typography.titleLarge, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } -} - -@Preview(showBackground = true) -@Composable -private fun LogoPreview() { - PreviewTemplate { - Logo() - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/MicroG.kt b/app/src/main/java/com/aurora/store/compose/composable/MicroG.kt deleted file mode 100644 index 46878134f..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/MicroG.kt +++ /dev/null @@ -1,157 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Button -import androidx.compose.material3.Checkbox -import androidx.compose.material3.LinearProgressIndicator -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.util.fastForEach -import com.aurora.extensions.browse -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.data.model.Link -import com.aurora.store.viewmodel.onboarding.MicroGUIState - -/** - * Composable to display suggestion to install microG - * @param modifier Modifier for the composable - * @param onInstall Callback when user requests installing microG bundle - */ -@Composable -fun MicroG( - modifier: Modifier = Modifier, - uiState: MicroGUIState, - onInstall: () -> Unit = {}, - onTOSChecked: (Boolean) -> Unit = {} -) { - val context = LocalContext.current - var isChecked by rememberSaveable { mutableStateOf(false) } - val links = listOf( - Link( - id = 2, - title = stringResource(R.string.details_dev_website), - subtitle = stringResource(R.string.microg_website), - icon = R.drawable.ic_network, - url = "https://microG.org" - ), - Link( - id = 4, - title = stringResource(R.string.privacy_policy_title), - subtitle = stringResource(R.string.microg_privacy_policy), - icon = R.drawable.ic_privacy, - url = "https://microg.org/privacy.html" - ), - Link( - id = 5, - title = stringResource(R.string.menu_disclaimer), - subtitle = stringResource(R.string.microg_license_agreement), - icon = R.drawable.ic_disclaimer, - url = "https://raw.githubusercontent.com/microg/GmsCore/refs/heads/master/LICENSE" - ) - ) - - Column( - modifier = modifier - .fillMaxSize() - .padding( - horizontal = dimensionResource(R.dimen.padding_small), - vertical = dimensionResource(R.dimen.padding_xxsmall) - ), - verticalArrangement = Arrangement.SpaceBetween - ) { - Column( - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_xxsmall)) - ) { - Text( - text = stringResource(R.string.onboarding_gms_microg), - style = MaterialTheme.typography.bodyMedium - ) - - links.fastForEach { link -> - LinkListItem( - link = link, - onClick = { context.browse(link.url) }, - iconTint = MaterialTheme.colorScheme.primary - ) - } - } - - Column( - modifier = Modifier - .fillMaxWidth() - .padding(vertical = dimensionResource(R.dimen.padding_xlarge)), - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_small)) - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy( - dimensionResource(R.dimen.padding_small) - ) - ) { - Checkbox( - checked = isChecked, - onCheckedChange = { - isChecked = it - onTOSChecked(it) - }, - enabled = !uiState.isInstalled && !uiState.isDownloading - ) - Text( - text = stringResource(R.string.onboarding_gms_agreement), - style = MaterialTheme.typography.bodyMedium, - maxLines = 2, - overflow = TextOverflow.Ellipsis - ) - } - Button( - onClick = onInstall, - enabled = isChecked && !uiState.isDownloading && !uiState.isInstalled, - modifier = Modifier.fillMaxWidth() - ) { - Text( - text = if (uiState.isDownloading) { - stringResource(R.string.action_installing) - } else { - stringResource(R.string.action_install_microG) - } - ) - } - if (uiState.isDownloading) { - LinearProgressIndicator( - modifier = Modifier.fillMaxWidth() - ) - } - } - } -} - -@Preview(showBackground = true) -@Composable -private fun MicroGPreview() { - PreviewTemplate { - MicroG(uiState = MicroGUIState()) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/PageIndicator.kt b/app/src/main/java/com/aurora/store/compose/composable/PageIndicator.kt deleted file mode 100644 index 951af76a3..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/PageIndicator.kt +++ /dev/null @@ -1,86 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.animation.animateColorAsState -import androidx.compose.animation.core.animateDpAsState -import androidx.compose.animation.core.tween -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.semantics.stateDescription -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Pager indicator - * Adapted from [Pager in Compose](https://developer.android.com/jetpack/compose/layouts/pager#add-page) - * @param modifier The modifier to be applied to the composable - * @param totalPages Total number of pages - * @param currentPage Currently displayed page number - */ -@Composable -fun PageIndicator(modifier: Modifier = Modifier, totalPages: Int, currentPage: Int = 0) { - Row( - modifier = modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy( - dimensionResource(R.dimen.margin_xsmall), - Alignment.CenterHorizontally - ) - ) { - repeat(totalPages) { iteration -> - val page = stringResource(R.string.page, iteration) - val isSelected = currentPage == iteration - val color by animateColorAsState( - targetValue = if (isSelected) { - Color.DarkGray - } else { - Color.LightGray - }, - animationSpec = tween() - ) - val size by animateDpAsState( - targetValue = if (isSelected) { - dimensionResource(R.dimen.radius_normal) - } else { - dimensionResource(R.dimen.radius_small) - }, - animationSpec = tween() - ) - - Box( - modifier = modifier - .size(size) - .clip(CircleShape) - .background(color = color) - .semantics { stateDescription = page } - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun PageIndicatorPreview() { - PreviewTemplate { - PageIndicator(totalPages = 5) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/PermissionList.kt b/app/src/main/java/com/aurora/store/compose/composable/PermissionList.kt deleted file mode 100644 index 58ed92d28..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/PermissionList.kt +++ /dev/null @@ -1,177 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import android.Manifest -import android.annotation.SuppressLint -import android.content.Intent -import android.provider.Settings -import android.provider.Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS -import android.util.Log -import androidx.activity.compose.rememberLauncherForActivityResult -import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.LazyItemScope -import androidx.compose.foundation.lazy.items -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.datasource.LoremIpsum -import androidx.core.net.toUri -import com.aurora.extensions.isTAndAbove -import com.aurora.extensions.toast -import com.aurora.store.BuildConfig -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.data.model.Permission -import com.aurora.store.data.model.PermissionType -import com.aurora.store.data.providers.PermissionProvider.Companion.isGranted -import com.aurora.store.util.PackageUtil -import kotlin.random.Random - -private const val TAG = "PermissionsScreen" - -/** - * Composable to request known set of permissions - * @param modifier Modifier to apply to the composable - * @param permissions Set of known permissions to request from the user - * @param onPermissionCallback Callback when a permission is granted or denied - */ -@Composable -fun PermissionList( - modifier: Modifier = Modifier, - permissions: List, - header: (@Composable (LazyItemScope.(Int) -> Unit))? = null, - onPermissionCallback: (type: PermissionType) -> Unit = {} -) { - val context = LocalContext.current - var permissionRequested by rememberSaveable { mutableStateOf(null) } - - @SuppressLint("InlinedApi", "BatteryLife") - val intentMap = mapOf( - PermissionType.STORAGE_MANAGER to PackageUtil.getStorageManagerIntent(context), - PermissionType.INSTALL_UNKNOWN_APPS to PackageUtil.getInstallUnknownAppsIntent(), - PermissionType.DOZE_WHITELIST to Intent( - Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, - "package:${BuildConfig.APPLICATION_ID}".toUri() - ), - PermissionType.APP_LINKS to Intent( - ACTION_APP_OPEN_BY_DEFAULT_SETTINGS, - "package:${BuildConfig.APPLICATION_ID}".toUri() - ) - ) - - fun onResult() { - permissionRequested?.let { - if (!isGranted(context, it)) context.toast(R.string.permissions_denied) - onPermissionCallback(it) - } - } - - val intentLauncher = rememberLauncherForActivityResult( - contract = ActivityResultContracts.StartActivityForResult(), - onResult = { onResult() } - ) - val permissionLauncher = rememberLauncherForActivityResult( - contract = ActivityResultContracts.RequestPermission(), - onResult = { - when (permissionRequested) { - PermissionType.STORAGE_MANAGER -> { - intentLauncher.launch(intentMap[PermissionType.STORAGE_MANAGER]!!) - } - - else -> onResult() - } - } - ) - - fun requestPermission(type: PermissionType) { - try { - permissionRequested = type - when (type) { - PermissionType.EXTERNAL_STORAGE -> { - permissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) - } - - PermissionType.POST_NOTIFICATIONS -> { - if (isTAndAbove) { - permissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) - } - } - - PermissionType.STORAGE_MANAGER -> { - if (!isGranted(context, PermissionType.INSTALL_UNKNOWN_APPS)) { - context.toast(R.string.toast_permission_installer_required) - } else { - permissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) - } - } - - else -> { - val intent = intentMap[type] ?: return - intentLauncher.launch(intent) - } - } - } catch (exception: Exception) { - Log.e(TAG, "Error requesting permission", exception) - permissionRequested = null - } - } - - LazyColumn( - modifier = modifier.fillMaxSize(), - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_xxsmall)) - ) { - if (header != null) stickyHeader(content = header) - - permissions.sortedBy { it.optional } - .groupBy { permission -> permission.optional } - .forEach { (key, value) -> - stickyHeader { - TextDividerComposable( - title = if (!key) { - stringResource(R.string.item_required) - } else { - stringResource(R.string.item_optional) - } - ) - } - - items(items = value, key = { p -> p.type.name }) { permission -> - PermissionListItem( - permission = permission, - onAction = { requestPermission(permission.type) } - ) - } - } - } -} - -@Preview(showBackground = true) -@Composable -private fun PermissionListPreview() { - val permissions = PermissionType.entries.map { type -> - Permission( - type = type, - title = LoremIpsum(3).values.first(), - subtitle = LoremIpsum(7).values.first(), - optional = Random.nextBoolean(), - isGranted = Random.nextBoolean() - ) - } - PreviewTemplate { - PermissionList(permissions = permissions) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/PermissionListItem.kt b/app/src/main/java/com/aurora/store/compose/composable/PermissionListItem.kt deleted file mode 100644 index 1fc7e0760..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/PermissionListItem.kt +++ /dev/null @@ -1,86 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.data.model.Permission -import com.aurora.store.data.model.PermissionType - -/** - * Composable to display permission details in a list - * @param modifier The modifier to be applied to the composable - * @param permission [Permission] to display - * @param onAction Callback when the user clicks the action button - */ -@Composable -fun PermissionListItem( - modifier: Modifier = Modifier, - permission: Permission, - onAction: () -> Unit = {} -) { - Row( - modifier = modifier - .fillMaxWidth() - .padding(dimensionResource(R.dimen.padding_small)), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween - ) { - Column(modifier = Modifier.weight(1F)) { - Text( - text = permission.title, - style = MaterialTheme.typography.bodyLarge, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = permission.subtitle, - style = MaterialTheme.typography.bodySmall - ) - } - TextButton(onClick = onAction, enabled = !permission.isGranted) { - Text( - text = if (permission.isGranted) { - stringResource(R.string.action_granted) - } else { - stringResource(R.string.action_grant) - }, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun PermissionListItemPreview() { - PreviewTemplate { - PermissionListItem( - permission = Permission( - PermissionType.STORAGE_MANAGER, - stringResource(R.string.onboarding_permission_esm), - stringResource(R.string.onboarding_permission_esa_desc), - false - ) - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/SearchSuggestionListItem.kt b/app/src/main/java/com/aurora/store/compose/composable/SearchSuggestionListItem.kt deleted file mode 100644 index 2cb99b596..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/SearchSuggestionListItem.kt +++ /dev/null @@ -1,107 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredSize -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import coil3.compose.AsyncImage -import coil3.request.ImageRequest -import coil3.request.crossfade -import com.aurora.gplayapi.SearchSuggestEntry -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Composable for displaying search suggestions in a list - * @param modifier The modifier to be applied to the composable - * @param searchSuggestEntry A [SearchSuggestEntry] to display search suggestion - * @param onClick Callback when this composable is clicked - * @param onAction Callback when action button is clicked - */ -@Composable -fun SearchSuggestionListItem( - modifier: Modifier = Modifier, - searchSuggestEntry: SearchSuggestEntry, - onClick: (query: String) -> Unit = {}, - onAction: (query: String) -> Unit = {} -) { - Row( - modifier = modifier - .fillMaxWidth() - .clickable(onClick = { onClick(searchSuggestEntry.title) }) - .padding( - top = dimensionResource(R.dimen.padding_xsmall), - bottom = dimensionResource(R.dimen.padding_xsmall), - start = dimensionResource(R.dimen.padding_large), - end = dimensionResource(R.dimen.padding_xsmall) - ), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween - ) { - Row( - modifier = Modifier - .weight(1F) - .clickable(onClick = { onClick(searchSuggestEntry.title) }), - horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data( - if (searchSuggestEntry.hasImageContainer()) { - searchSuggestEntry.imageContainer.imageUrl - } else { - R.drawable.ic_search_suggestion - } - ) - .crossfade(true) - .build(), - contentDescription = null, - placeholder = painterResource(R.drawable.ic_search_suggestion), - contentScale = ContentScale.Crop, - modifier = Modifier.requiredSize(dimensionResource(R.dimen.icon_size_default)) - ) - Text( - text = searchSuggestEntry.title, - style = MaterialTheme.typography.bodyLarge, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - IconButton(onClick = { onAction(searchSuggestEntry.title) }) { - Icon( - painter = painterResource(R.drawable.ic_search_append), - contentDescription = null - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun SearchSuggestionListItemPreview() { - PreviewTemplate { - SearchSuggestionListItem( - searchSuggestEntry = SearchSuggestEntry.getDefaultInstance() - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/TextDividerComposable.kt b/app/src/main/java/com/aurora/store/compose/composable/TextDividerComposable.kt deleted file mode 100644 index 1c93f0b07..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/TextDividerComposable.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Composable to display a sticky header in a list - * @param modifier The modifier to be applied to the composable - * @param title Title to display - * @see Header - */ -@Composable -fun TextDividerComposable(modifier: Modifier = Modifier, title: String) { - Text( - modifier = modifier - .fillMaxWidth() - .padding(dimensionResource(R.dimen.padding_small)), - text = title.uppercase(), - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.primary, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) -} - -@Preview(showBackground = true) -@Composable -private fun TextDividerComposablePreview() { - PreviewTemplate { - TextDividerComposable(title = stringResource(R.string.item_optional)) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/TopAppBar.kt b/app/src/main/java/com/aurora/store/compose/composable/TopAppBar.kt deleted file mode 100644 index 02d5ace87..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/TopAppBar.kt +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable - -import androidx.compose.foundation.layout.RowScope -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * A top app bar composable to be used with Scaffold in different Screen - * @param modifier The modifier to be applied to the composable - * @param title Title of the screen - * @param navigationIcon Icon for the navigation button - * @param onNavigateUp Action when user clicks the navigation icon - * @param actions Actions to display on the top app bar (for e.g. menu) - */ -@Composable -fun TopAppBar( - modifier: Modifier = Modifier, - title: String? = null, - navigationIcon: Painter = painterResource(R.drawable.ic_arrow_back), - onNavigateUp: (() -> Unit)? = null, - actions: @Composable (RowScope.() -> Unit) = {} -) { - TopAppBar( - modifier = modifier, - title = { if (title != null) Text(text = title) }, - navigationIcon = { - if (onNavigateUp != null) { - IconButton(onClick = onNavigateUp) { - Icon( - painter = navigationIcon, - contentDescription = stringResource(R.string.action_back) - ) - } - } - }, - actions = actions - ) -} - -@Preview(showBackground = true) -@Composable -private fun TopAppBarPreview() { - PreviewTemplate { - TopAppBar( - title = stringResource(R.string.title_about), - onNavigateUp = {} - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/app/AnimatedAppIcon.kt b/app/src/main/java/com/aurora/store/compose/composable/app/AnimatedAppIcon.kt deleted file mode 100644 index b6d68c0d3..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/app/AnimatedAppIcon.kt +++ /dev/null @@ -1,122 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable.app - -import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.animation.core.tween -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.requiredSize -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.semantics.testTag -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import coil3.compose.AsyncImage -import coil3.request.ImageRequest -import coil3.request.crossfade -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Composable to show icon for an app that can be animated to also show install progress - * @param modifier The modifier to be applied to the composable - * @param iconUrl URL of the app icon - * @param progress Progress to show, for e.g. download or install - * @param inProgress Whether to show indeterminate or determinate progress bar - */ -@Composable -fun AnimatedAppIcon( - modifier: Modifier = Modifier, - iconUrl: String, - progress: Float = 0F, - inProgress: Boolean = false -) { - val animatedProgress by animateFloatAsState( - targetValue = progress, - animationSpec = tween(durationMillis = 300) - ) - val animatedScale by animateFloatAsState( - targetValue = if (inProgress) 0.75F else 1F, - animationSpec = tween(durationMillis = 300) - ) - val clip = when { - inProgress -> CircleShape - else -> RoundedCornerShape(dimensionResource(R.dimen.radius_medium)) - } - - Box(modifier = modifier, contentAlignment = Alignment.Center) { - if (inProgress) { - val indicatorModifier = Modifier - .fillMaxSize() - .semantics { testTag = "progressIndicator" } - if (animatedProgress > 0) { - CircularProgressIndicator( - modifier = indicatorModifier, - progress = { animatedProgress / 100 } - ) - } else { - CircularProgressIndicator(modifier = indicatorModifier) - } - } - - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(iconUrl) - .crossfade(true) - .build(), - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = Modifier - .fillMaxSize() - .graphicsLayer(scaleX = animatedScale, scaleY = animatedScale) - .clip(clip) - ) - } -} - -private class ProgressProvider : PreviewParameterProvider { - override val values: Sequence - get() = sequenceOf(0F, 50F) -} - -@Preview(showBackground = true) -@Composable -private fun AnimatedAppIconPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - AnimatedAppIcon( - modifier = Modifier.requiredSize(dimensionResource(R.dimen.icon_size_large)), - iconUrl = app.iconArtwork.url - ) - } -} - -@Preview(showBackground = true) -@Composable -private fun AnimatedAppIconPreview(@PreviewParameter(ProgressProvider::class) progress: Float) { - PreviewTemplate { - AnimatedAppIcon( - modifier = Modifier.requiredSize(dimensionResource(R.dimen.icon_size_large)), - iconUrl = "", - inProgress = true, - progress = progress - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/app/AppListItem.kt b/app/src/main/java/com/aurora/store/compose/composable/app/AppListItem.kt deleted file mode 100644 index 71eeaab29..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/app/AppListItem.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable.app - -import android.text.format.Formatter -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredSize -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import coil3.compose.AsyncImage -import coil3.request.ImageRequest -import coil3.request.crossfade -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Composable for displaying minimal app details in a horizontal-scrollable list - * @param modifier The modifier to be applied to the composable - * @param app [App] to display - * @param onClick Callback when the composable is clicked - * @see LargeAppListItem - */ -@Composable -fun AppListItem(modifier: Modifier = Modifier, app: App, onClick: () -> Unit = {}) { - val context = LocalContext.current - - Column( - modifier = modifier - .width(dimensionResource(R.dimen.icon_size_cluster)) - .clickable(onClick = onClick) - .padding(dimensionResource(R.dimen.padding_xsmall)) - ) { - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(app.iconArtwork.url) - .crossfade(true) - .build(), - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = Modifier - .requiredSize(dimensionResource(R.dimen.icon_size_cluster)) - .clip(RoundedCornerShape(dimensionResource(R.dimen.radius_medium))) - ) - Text( - text = app.displayName, - style = MaterialTheme.typography.bodySmall, - maxLines = 2, - overflow = TextOverflow.Ellipsis - ) - Text( - text = if (app.size > 0) { - Formatter.formatShortFileSize(context, app.size) - } else { - app.downloadString - }, - style = MaterialTheme.typography.bodySmall - ) - } -} - -@Preview(showBackground = true) -@Composable -private fun AppListItemPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - AppListItem(app = app) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/app/LargeAppListItem.kt b/app/src/main/java/com/aurora/store/compose/composable/app/LargeAppListItem.kt deleted file mode 100644 index 524e99a51..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/app/LargeAppListItem.kt +++ /dev/null @@ -1,112 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable.app - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredSize -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import coil3.compose.AsyncImage -import coil3.request.ImageRequest -import coil3.request.crossfade -import com.aurora.extensions.requiresGMS -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.util.CommonUtil - -/** - * Composable for displaying minimal app details in a vertical-scrollable list - * @param modifier The modifier to be applied to the composable - * @param app [App] to display - * @param onClick Callback when the composable is clicked - * @see AppListItem - */ -@Composable -fun LargeAppListItem(modifier: Modifier = Modifier, app: App, onClick: () -> Unit = {}) { - Row( - modifier = modifier - .fillMaxWidth() - .clickable(onClick = onClick) - .padding( - horizontal = dimensionResource(R.dimen.padding_medium), - vertical = dimensionResource(R.dimen.padding_small) - ) - ) { - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(app.iconArtwork.url) - .crossfade(true) - .build(), - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = Modifier - .requiredSize(dimensionResource(R.dimen.icon_size_medium)) - .clip(RoundedCornerShape(dimensionResource(R.dimen.radius_medium))) - ) - Column( - modifier = Modifier.padding(horizontal = dimensionResource(R.dimen.margin_small)) - ) { - Text( - text = app.displayName, - style = MaterialTheme.typography.bodyMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text(text = app.developerName, style = MaterialTheme.typography.bodySmall) - Text( - text = buildExtras(app).joinToString(separator = " • "), - style = MaterialTheme.typography.bodySmall - ) - } - } -} - -@Preview(showBackground = true) -@Composable -fun LargeAppListItemPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - LargeAppListItem(app = app) - } -} - -@Composable -private fun buildExtras(app: App): List = mutableListOf().apply { - add(if (app.size > 0) CommonUtil.addSiPrefix(app.size) else app.downloadString) - add("${app.labeledRating}★") - - if (app.isFree) { - add(stringResource(R.string.details_free)) - } else { - add(stringResource(R.string.details_paid)) - } - - if (app.containsAds) { - add(stringResource(R.string.details_contains_ads)) - } else { - add(stringResource(R.string.details_no_ads)) - } - - if (app.requiresGMS()) { - add(stringResource(R.string.details_gsf_dependent)) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/app/TagListItem.kt b/app/src/main/java/com/aurora/store/compose/composable/app/TagListItem.kt deleted file mode 100644 index 3fec81079..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/app/TagListItem.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable.app - -import androidx.compose.material3.FilterChip -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Composable to show a tag related to an app - * @param modifier The modifier to be applied to the composable - * @param label Label of the tag - * @param painter Painter to draw the icon - * @param onClick Callback when this composable is clicked - */ -@Composable -fun TagListItem( - modifier: Modifier = Modifier, - label: String, - painter: Painter, - onClick: () -> Unit = {} -) { - FilterChip( - modifier = modifier, - onClick = onClick, - label = { Text(text = label, style = MaterialTheme.typography.bodySmall) }, - leadingIcon = { Icon(painter = painter, contentDescription = label) }, - selected = true - ) -} - -@Preview(showBackground = true) -@Composable -private fun TagListItemPreview() { - PreviewTemplate { - TagListItem( - label = stringResource(R.string.details_free), - painter = painterResource(R.drawable.ic_paid) - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/details/ExodusListItem.kt b/app/src/main/java/com/aurora/store/compose/composable/details/ExodusListItem.kt deleted file mode 100644 index 124297da7..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/details/ExodusListItem.kt +++ /dev/null @@ -1,76 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable.details - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.extensions.browse -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.data.model.ExodusTracker - -/** - * Composable to display details about a tracker reported by Exodus Privacy - * @param modifier The modifier to be applied to the composable - * @param tracker Tracker to display details about - */ -@Composable -fun ExodusListItem(modifier: Modifier = Modifier, tracker: ExodusTracker) { - val context = LocalContext.current - Column( - modifier = modifier - .fillMaxWidth() - .clickable( - onClick = { context.browse(tracker.url) }, - enabled = tracker.url.isNotBlank() - ) - .padding(dimensionResource(R.dimen.padding_small)) - ) { - Text( - text = tracker.name, - style = MaterialTheme.typography.bodyMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = tracker.signature, - style = MaterialTheme.typography.bodySmall, - maxLines = 2, - overflow = TextOverflow.Ellipsis - ) - Text( - text = tracker.date, - style = MaterialTheme.typography.bodySmall, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } -} - -@Preview(showBackground = true) -@Composable -private fun ExodusListItemPreview() { - PreviewTemplate { - ExodusListItem( - tracker = ExodusTracker( - name = "Google Analytics", - signature = "com.google.android.apps.analytics.|com.google.analytics.", - date = "2017-09-24", - url = "http://www.google.com/analytics/" - ) - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/details/RatingListItem.kt b/app/src/main/java/com/aurora/store/compose/composable/details/RatingListItem.kt deleted file mode 100644 index 1731d9940..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/details/RatingListItem.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable.details - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.LinearProgressIndicator -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Composable to show a progress bar with rating for an app - * @param modifier The modifier to be applied to the composable - * @param label Label of the rating, for e.g. 5 - * @param rating Current rating, for e.g. 0.3 - */ -@Composable -fun RatingListItem(modifier: Modifier = Modifier, label: String, rating: Float) { - Row( - modifier = modifier - .fillMaxWidth() - .padding(horizontal = dimensionResource(R.dimen.padding_small)), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_small)) - ) { - Text( - text = label, - style = MaterialTheme.typography.bodyMedium, - fontWeight = FontWeight.Bold - ) - LinearProgressIndicator( - modifier = Modifier - .fillMaxWidth() - .height(dimensionResource(R.dimen.radius_small)), - progress = { rating } - ) - } -} - -@Preview(showBackground = true) -@Composable -private fun RatingListItemPreview() { - PreviewTemplate { - RatingListItem(label = "5", rating = 0.5F) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/details/ReviewListItem.kt b/app/src/main/java/com/aurora/store/compose/composable/details/ReviewListItem.kt deleted file mode 100644 index a4e6c4746..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/details/ReviewListItem.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable.details - -import android.text.format.DateUtils -import android.widget.RatingBar -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredSize -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.viewinterop.AndroidView -import coil3.compose.AsyncImage -import coil3.request.ImageRequest -import coil3.request.crossfade -import com.aurora.gplayapi.data.models.Review -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.compose.preview.ReviewPreviewProvider - -/** - * Composable for viewing a review about an app - * @param modifier The modifier to be applied to the composable - * @param review [Review] about an app - */ -@Composable -fun ReviewListItem(modifier: Modifier = Modifier, review: Review) { - Row( - modifier = modifier - .fillMaxWidth() - .padding( - horizontal = dimensionResource(R.dimen.padding_medium), - vertical = dimensionResource(R.dimen.padding_small) - ) - ) { - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(review.userPhotoUrl) - .crossfade(true) - .build(), - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = Modifier - .requiredSize(dimensionResource(R.dimen.icon_size_small)) - .clip(RoundedCornerShape(dimensionResource(R.dimen.radius_medium))) - ) - Column( - modifier = Modifier.padding(horizontal = dimensionResource(R.dimen.margin_small)) - ) { - Text( - text = review.userName, - style = MaterialTheme.typography.bodyMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = DateUtils.formatDateTime( - LocalContext.current, - review.timeStamp, - DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_SHOW_YEAR - ), - style = MaterialTheme.typography.bodySmall - ) - AndroidView( - factory = { context -> - RatingBar(context, null, android.R.attr.ratingBarStyleSmall) - }, - update = { view -> - view.rating = review.rating.toFloat() - } - ) - Text( - text = review.comment, - style = MaterialTheme.typography.bodySmall, - overflow = TextOverflow.Ellipsis - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun ReviewListItemPreview(@PreviewParameter(ReviewPreviewProvider::class) review: Review) { - PreviewTemplate { - ReviewListItem(review = review) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composable/details/ScreenshotListItem.kt b/app/src/main/java/com/aurora/store/compose/composable/details/ScreenshotListItem.kt deleted file mode 100644 index 0f6d49638..000000000 --- a/app/src/main/java/com/aurora/store/compose/composable/details/ScreenshotListItem.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composable.details - -import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.aspectRatio -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import coil3.compose.AsyncImagePainter -import coil3.compose.rememberAsyncImagePainter -import coil3.compose.rememberConstraintsSizeResolver -import coil3.request.ImageRequest -import coil3.request.crossfade -import com.aurora.extensions.shimmer -import com.aurora.gplayapi.data.models.App -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Composable to display a screenshot of an app - * @param modifier The modifier to be applied to the composable - * @param url URL of the screenshot - */ -@Composable -fun ScreenshotListItem(modifier: Modifier = Modifier, url: String) { - // See https://coil-kt.github.io/coil/compose/#rememberasyncimagepainter - val sizeResolver = rememberConstraintsSizeResolver() - val painter = rememberAsyncImagePainter( - model = ImageRequest.Builder(LocalContext.current) - .data(url) - .size(sizeResolver) - .crossfade(true) - .build() - ) - val state by painter.state.collectAsStateWithLifecycle() - val aspectRatioModifier = state.painter?.intrinsicSize?.let { intrinsicSize -> - val ratio = intrinsicSize.width / intrinsicSize.height - if (ratio.isNaN()) null else Modifier.aspectRatio(ratio = ratio) - } - - Image( - painter = painter, - contentDescription = null, - contentScale = ContentScale.Fit, - modifier = modifier - .shimmer(state is AsyncImagePainter.State.Loading) - .then(sizeResolver) - .then(aspectRatioModifier ?: Modifier) - ) -} - -@Preview -@Composable -private fun ScreenshotListItemPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - ScreenshotListItem(url = app.screenshots.firstOrNull()?.url ?: "") - } -} diff --git a/app/src/main/java/com/aurora/store/compose/composition/LocalUI.kt b/app/src/main/java/com/aurora/store/compose/composition/LocalUI.kt deleted file mode 100644 index ef15886a9..000000000 --- a/app/src/main/java/com/aurora/store/compose/composition/LocalUI.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.composition - -import androidx.compose.runtime.staticCompositionLocalOf - -/** - * Supported UI styles for different types of Android OS - */ -enum class UI { - - /** - * Targets Phone, Foldable, Tablets, Desktop - */ - DEFAULT, - - /** - * Targets TV - */ - TV -} - -/** - * CompositionLocal to provide information on which UI style should be used - */ -val LocalUI = staticCompositionLocalOf { UI.DEFAULT } diff --git a/app/src/main/java/com/aurora/store/compose/navigation/NavDisplay.kt b/app/src/main/java/com/aurora/store/compose/navigation/NavDisplay.kt deleted file mode 100644 index a40419114..000000000 --- a/app/src/main/java/com/aurora/store/compose/navigation/NavDisplay.kt +++ /dev/null @@ -1,160 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.navigation - -import android.content.Intent -import androidx.activity.compose.LocalActivity -import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalContext -import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator -import androidx.navigation.NavDeepLinkBuilder -import androidx.navigation3.runtime.NavKey -import androidx.navigation3.runtime.entryProvider -import androidx.navigation3.runtime.rememberNavBackStack -import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator -import androidx.navigation3.ui.NavDisplay -import com.aurora.store.MainActivity -import com.aurora.store.R -import com.aurora.store.compose.ui.about.AboutScreen -import com.aurora.store.compose.ui.accounts.AccountsScreen -import com.aurora.store.compose.ui.blacklist.BlacklistScreen -import com.aurora.store.compose.ui.commons.PermissionRationaleScreen -import com.aurora.store.compose.ui.details.AppDetailsScreen -import com.aurora.store.compose.ui.dev.DevProfileScreen -import com.aurora.store.compose.ui.dispenser.DispenserScreen -import com.aurora.store.compose.ui.downloads.DownloadsScreen -import com.aurora.store.compose.ui.favourite.FavouriteScreen -import com.aurora.store.compose.ui.installed.InstalledScreen -import com.aurora.store.compose.ui.onboarding.OnboardingScreen -import com.aurora.store.compose.ui.preferences.installation.InstallerScreen -import com.aurora.store.compose.ui.search.SearchScreen -import com.aurora.store.compose.ui.spoof.SpoofScreen - -/** - * Navigation display for compose screens - * @param startDestination Starting destination for the activity/app - */ -@Composable -fun NavDisplay(startDestination: NavKey) { - val backstack = rememberNavBackStack(startDestination) - - // TODO: Rework when migrating splash fragment to compose - val splashIntent = NavDeepLinkBuilder(LocalContext.current) - .setGraph(R.navigation.mobile_navigation) - .setDestination(R.id.splashFragment) - .setComponentName(MainActivity::class.java) - .createTaskStackBuilder() - .intents - .first() - .apply { addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK) } - - // TODO: Drop this logic once everything is in compose - val activity = LocalActivity.current - fun onNavigateUp() { - if (backstack.size == 1) activity?.finish() else backstack.removeLastOrNull() - } - - NavDisplay( - backStack = backstack, - entryDecorators = listOf( - rememberSaveableStateHolderNavEntryDecorator(), - rememberViewModelStoreNavEntryDecorator() - ), - entryProvider = entryProvider { - entry { - BlacklistScreen(onNavigateUp = ::onNavigateUp) - } - - entry { - SearchScreen(onNavigateUp = ::onNavigateUp) - } - - entry { screen -> - AppDetailsScreen( - packageName = screen.packageName, - onNavigateUp = ::onNavigateUp, - onNavigateToAppDetails = { packageName -> - backstack.add(Screen.AppDetails(packageName)) - } - ) - } - - entry { screen -> - DevProfileScreen( - developerId = screen.developerId, - onNavigateUp = ::onNavigateUp, - onNavigateToAppDetails = { packageName -> - backstack.add(Screen.AppDetails(packageName)) - } - ) - } - - entry { screen -> - PermissionRationaleScreen( - onNavigateUp = ::onNavigateUp, - requiredPermissions = screen.requiredPermissions - ) - } - - entry { - DownloadsScreen( - onNavigateUp = ::onNavigateUp, - onNavigateToAppDetails = { packageName -> - backstack.add(Screen.AppDetails(packageName)) - } - ) - } - - entry { - AccountsScreen( - onNavigateUp = ::onNavigateUp, - onNavigateToSplash = { activity?.startActivity(splashIntent) } - ) - } - - entry { - AboutScreen(onNavigateUp = ::onNavigateUp) - } - - entry { - FavouriteScreen( - onNavigateUp = ::onNavigateUp, - onNavigateToAppDetails = { packageName -> - backstack.add(Screen.AppDetails(packageName)) - } - ) - } - - entry { - OnboardingScreen() - } - - entry { - SpoofScreen( - onNavigateUp = ::onNavigateUp, - onNavigateToSplash = { activity?.startActivity(splashIntent) } - ) - } - - entry { - DispenserScreen(onNavigateUp = ::onNavigateUp) - } - - entry { - InstallerScreen(onNavigateUp = ::onNavigateUp) - } - - entry { - InstalledScreen( - onNavigateUp = ::onNavigateUp, - onNavigateToAppDetails = { packageName -> - backstack.add(Screen.AppDetails(packageName)) - } - ) - } - } - ) -} diff --git a/app/src/main/java/com/aurora/store/compose/navigation/Screen.kt b/app/src/main/java/com/aurora/store/compose/navigation/Screen.kt deleted file mode 100644 index 26d463ee3..000000000 --- a/app/src/main/java/com/aurora/store/compose/navigation/Screen.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.navigation - -import android.os.Parcelable -import androidx.navigation3.runtime.NavKey -import com.aurora.store.data.model.PermissionType -import kotlinx.parcelize.Parcelize -import kotlinx.serialization.Serializable - -/** - * Destinations for navigation in compose - */ -@Parcelize -@Serializable -sealed class Screen : NavKey, Parcelable { - - companion object { - const val PARCEL_KEY = "SCREEN" - } - - @Serializable - data object Blacklist : Screen() - - @Serializable - data class DevProfile(val developerId: String) : Screen() - - @Serializable - data class AppDetails(val packageName: String) : Screen() - - @Serializable - data object Search : Screen() - - @Serializable - data class PermissionRationale(val requiredPermissions: Set) : Screen() - - @Serializable - data object Downloads : Screen() - - @Serializable - data object Accounts : Screen() - - @Serializable - data object About : Screen() - - @Serializable - data object Favourite : Screen() - - @Serializable - data object Onboarding : Screen() - - @Serializable - data object Spoof : Screen() - - @Serializable - data object Dispenser : Screen() - - @Serializable - data object Installer : Screen() - - @Serializable - data object Installed : Screen() -} diff --git a/app/src/main/java/com/aurora/store/compose/preview/AppPreviewProvider.kt b/app/src/main/java/com/aurora/store/compose/preview/AppPreviewProvider.kt deleted file mode 100644 index e8991d781..000000000 --- a/app/src/main/java/com/aurora/store/compose/preview/AppPreviewProvider.kt +++ /dev/null @@ -1,88 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.preview - -import android.Manifest -import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.aurora.gplayapi.data.models.App -import com.aurora.gplayapi.data.models.Artwork -import com.aurora.gplayapi.data.models.Rating -import com.aurora.gplayapi.data.models.details.TestingProgram -import com.aurora.store.BuildConfig - -/** - * Preview provider for composable working with [App] - */ -class AppPreviewProvider : PreviewParameterProvider { - companion object { - private const val CHANGELOG = """ - • New app compatibility ratings powered by Plexus
- • Improvements to blacklist manager
- • Ability to change auto-update restrictions
- • Minor bug fixes and improvements
- • Translation updates; additional strings localized - """ - - private const val DESCRIPTION = """ -

Aurora Store is an unofficial, FOSS client to Google Play with an elegant design. Aurora Store allows users to download, update, and search for apps like the Play Store. It works perfectly fine with or without Google Play Services or microG.

- -

Features:

- -

• FOSS: Has GPLv3 licence
- • Beautiful design: Built upon latest Material 3 guidelines
- • Account login: You can login with either personal or an anonymous account
- • Device & Locale spoofing: Change your device and/or locale to access geo locked apps
- • Exodus Privacy integration: Instantly see trackers in app
- • Plexus integration: Instantly see app compatibility without Google Play Services or with microG
- • Updates blacklisting: Ignore updates for specific apps

- """ - } - - override val values: Sequence - get() = sequenceOf( - App( - packageName = BuildConfig.APPLICATION_ID, - displayName = "Aurora Store", - developerName = "Rahul Kumar Patel", - versionCode = BuildConfig.VERSION_CODE.toLong(), - versionName = BuildConfig.VERSION_NAME, - shortDescription = "An unofficial FOSS client to Google Play", - changes = CHANGELOG, - description = DESCRIPTION, - isFree = true, - containsAds = false, - isInstalled = true, - size = 7431013, - updatedOn = "Mar 17, 2025", - labeledRating = "4.3", - installs = 1000000000, - developerEmail = "rahul@auroraoss.com", - developerWebsite = "https://auroraoss.com/", - developerAddress = "330 N Midland Ave, Mumbai, India", - screenshots = MutableList(5) { Artwork(url = "$it") }, - testingProgram = TestingProgram( - isAvailable = true, - isSubscribed = false - ), - rating = Rating( - fiveStar = 201458104, - fourStar = 313829104, - threeStar = 204581672, - twoStar = 183746829, - oneStar = 96384291, - average = 4.4F, - abbreviatedLabel = "10 M" - ), - permissions = mutableListOf( - Manifest.permission.INTERNET, - Manifest.permission.ACCESS_NETWORK_STATE, - Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.WRITE_EXTERNAL_STORAGE - ), - privacyPolicyUrl = "https://gitlab.com/AuroraOSS/AuroraStore/" - ) - ) -} diff --git a/app/src/main/java/com/aurora/store/compose/preview/CoilPreviewProvider.kt b/app/src/main/java/com/aurora/store/compose/preview/CoilPreviewProvider.kt deleted file mode 100644 index a976ee99e..000000000 --- a/app/src/main/java/com/aurora/store/compose/preview/CoilPreviewProvider.kt +++ /dev/null @@ -1,18 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.preview - -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.toArgb -import coil3.ColorImage -import coil3.compose.AsyncImagePreviewHandler - -/** - * Preview provider for composable working with coil for loading remote images - */ -val coilPreviewProvider = AsyncImagePreviewHandler { - ColorImage(Color.Gray.toArgb()) -} diff --git a/app/src/main/java/com/aurora/store/compose/preview/FavouritePreviewProvider.kt b/app/src/main/java/com/aurora/store/compose/preview/FavouritePreviewProvider.kt deleted file mode 100644 index 104b0e3d4..000000000 --- a/app/src/main/java/com/aurora/store/compose/preview/FavouritePreviewProvider.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.preview - -import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import com.aurora.store.BuildConfig -import com.aurora.store.data.room.favourite.Favourite -import com.aurora.store.data.room.favourite.Favourite.Mode - -/** - * Preview provider for composable working with [Favourite] - */ -class FavouritePreviewProvider() : PreviewParameterProvider { - - override val values: Sequence - get() = sequenceOf( - Favourite( - packageName = BuildConfig.APPLICATION_ID, - displayName = "Aurora Store", - iconURL = "", - added = 0L, - mode = Mode.MANUAL - ) - ) -} diff --git a/app/src/main/java/com/aurora/store/compose/preview/PreviewTemplate.kt b/app/src/main/java/com/aurora/store/compose/preview/PreviewTemplate.kt deleted file mode 100644 index a5965deac..000000000 --- a/app/src/main/java/com/aurora/store/compose/preview/PreviewTemplate.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.preview - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import coil3.compose.LocalAsyncImagePreviewHandler -import com.aurora.store.compose.theme.AuroraTheme - -/** - * Template for previewing composable with default theme and remote image handling - */ -@Composable -fun PreviewTemplate(content: @Composable () -> Unit) { - AuroraTheme { - CompositionLocalProvider( - value = LocalAsyncImagePreviewHandler provides coilPreviewProvider, - content = content - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/preview/ReviewPreviewProvider.kt b/app/src/main/java/com/aurora/store/compose/preview/ReviewPreviewProvider.kt deleted file mode 100644 index e863323c3..000000000 --- a/app/src/main/java/com/aurora/store/compose/preview/ReviewPreviewProvider.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.preview - -import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import androidx.compose.ui.tooling.preview.datasource.LoremIpsum -import com.aurora.gplayapi.data.models.Review - -/** - * Preview provider for composable working with [Review] - */ -class ReviewPreviewProvider : PreviewParameterProvider { - - override val values: Sequence - get() = sequenceOf( - Review( - userName = "Rahul Kumar Patel", - timeStamp = 1745750879, - rating = 4, - comment = LoremIpsum(40).values.first() - ) - ) -} diff --git a/app/src/main/java/com/aurora/store/compose/theme/Color.kt b/app/src/main/java/com/aurora/store/compose/theme/Color.kt deleted file mode 100644 index 8e2d709a6..000000000 --- a/app/src/main/java/com/aurora/store/compose/theme/Color.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.theme - -import androidx.compose.ui.graphics.Color - -val warningColor = Color(0xFFFF7600) // Amber -val successColor = Color(0xFF1B8738) // Green diff --git a/app/src/main/java/com/aurora/store/compose/theme/Theme.kt b/app/src/main/java/com/aurora/store/compose/theme/Theme.kt deleted file mode 100644 index e797d772f..000000000 --- a/app/src/main/java/com/aurora/store/compose/theme/Theme.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024-2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.theme - -import android.os.Build -import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.material3.MaterialExpressiveTheme -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.darkColorScheme -import androidx.compose.material3.dynamicDarkColorScheme -import androidx.compose.material3.dynamicLightColorScheme -import androidx.compose.material3.lightColorScheme -import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.colorResource -import com.aurora.store.R -import com.aurora.store.util.Preferences - -/** - * App theme for Aurora Store based on [MaterialTheme] - */ -@Composable -fun AuroraTheme(content: @Composable () -> Unit) { - val context = LocalContext.current - val themeStyle = Preferences.getInteger(context, Preferences.PREFERENCE_THEME_STYLE) - val isDynamicColorSupported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S - - val lightScheme = if (isDynamicColorSupported) { - dynamicLightColorScheme(context) - } else { - lightColorScheme(primary = colorResource(id = R.color.colorAccent)) - } - - val darkScheme = if (isDynamicColorSupported) { - dynamicDarkColorScheme(context) - } else { - darkColorScheme(primary = colorResource(id = R.color.colorAccent)) - } - - val colorScheme = when (themeStyle) { - 1 -> lightScheme - 2 -> darkScheme - else -> if (isSystemInDarkTheme()) darkScheme else lightScheme - } - - MaterialExpressiveTheme(colorScheme = colorScheme, content = content) -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/about/AboutDialog.kt b/app/src/main/java/com/aurora/store/compose/ui/about/AboutDialog.kt deleted file mode 100644 index 7dbfefd5d..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/about/AboutDialog.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.about - -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Dialog for displaying information about Aurora Store - * @param onDismiss Callback on dismiss - */ -@Composable -fun AboutDialog(onDismiss: () -> Unit = {}) { - AlertDialog( - title = { Text(text = stringResource(R.string.about_aurora_store_title)) }, - text = { - Text(text = stringResource(R.string.about_aurora_store_summary)) - }, - onDismissRequest = onDismiss, - confirmButton = { - TextButton(onClick = onDismiss) { - Text(text = stringResource(android.R.string.ok)) - } - } - ) -} - -@Preview -@Composable -private fun AboutDialogPreview() { - PreviewTemplate { - AboutDialog() - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/about/AboutScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/about/AboutScreen.kt deleted file mode 100644 index a8c6d8ee0..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/about/AboutScreen.kt +++ /dev/null @@ -1,173 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.about - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredSize -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringArrayResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import coil3.compose.AsyncImage -import coil3.request.ImageRequest -import com.aurora.extensions.browse -import com.aurora.store.BuildConfig.VERSION_CODE -import com.aurora.store.BuildConfig.VERSION_NAME -import com.aurora.store.R -import com.aurora.store.compose.composable.LinkListItem -import com.aurora.store.compose.composable.TopAppBar -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.data.model.Link - -@Composable -fun AboutScreen(onNavigateUp: () -> Unit) { - var shouldShowAboutDialog by rememberSaveable { mutableStateOf(false) } - - if (shouldShowAboutDialog) { - AboutDialog(onDismiss = { shouldShowAboutDialog = false }) - } - - ScreenContent( - onNavigateUp = onNavigateUp, - onAboutAurora = { shouldShowAboutDialog = true } - ) -} - -@Composable -private fun ScreenContent(onNavigateUp: () -> Unit = {}, onAboutAurora: () -> Unit = {}) { - val context = LocalContext.current - - val linkURLS = stringArrayResource(R.array.link_urls) - val linkTitles = stringArrayResource(R.array.link_titles) - val linkSummary = stringArrayResource(R.array.link_subtitle) - val linkIcons = intArrayOf( - R.drawable.ic_about, - R.drawable.ic_help, - R.drawable.ic_xda, - R.drawable.ic_telegram, - R.drawable.ic_gitlab, - R.drawable.ic_fdroid, - R.drawable.ic_bitcoin_btc, - R.drawable.ic_bitcoin_bch, - R.drawable.ic_ethereum_eth, - R.drawable.ic_bhim, - R.drawable.ic_paypal, - R.drawable.ic_libera_pay - ) - - val links = linkURLS.mapIndexed { index, url -> - Link( - id = index, - title = linkTitles[index], - subtitle = linkSummary[index], - url = url, - icon = linkIcons[index] - ) - } - - Scaffold( - topBar = { - TopAppBar( - title = stringResource(R.string.title_about), - onNavigateUp = onNavigateUp - ) - } - ) { paddingValues -> - LazyColumn( - modifier = Modifier - .fillMaxSize() - .padding(paddingValues), - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_xxsmall)) - ) { - stickyHeader { - Surface(modifier = Modifier.fillMaxWidth()) { - BrandHeader() - } - } - items(items = links, key = { item -> item.id }) { link -> - LinkListItem( - link = link, - onClick = { - when (link.id) { - 0 -> onAboutAurora() - else -> context.browse(link.url) - } - } - ) - } - } - } -} - -@Composable -private fun BrandHeader() { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(dimensionResource(R.dimen.margin_medium)), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_xxsmall)) - ) { - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(R.mipmap.ic_launcher) - .build(), - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = Modifier - .requiredSize(dimensionResource(R.dimen.icon_size)) - .clip(CircleShape) - ) - Text( - text = stringResource(R.string.app_name), - style = MaterialTheme.typography.titleLarge, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = stringResource(R.string.version, VERSION_NAME, VERSION_CODE), - style = MaterialTheme.typography.bodyMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = stringResource(R.string.made_with_love, String(Character.toChars(0x2764))), - style = MaterialTheme.typography.bodyMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } -} - -@Preview -@Composable -private fun AboutScreenPreview() { - PreviewTemplate { - ScreenContent() - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/accounts/AccountsScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/accounts/AccountsScreen.kt deleted file mode 100644 index 60170750a..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/accounts/AccountsScreen.kt +++ /dev/null @@ -1,213 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.accounts - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredSize -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.AssistChip -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedButton -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import coil3.compose.AsyncImage -import coil3.request.ImageRequest -import coil3.request.crossfade -import com.aurora.Constants.URL_DISCLAIMER -import com.aurora.Constants.URL_LICENSE -import com.aurora.Constants.URL_TOS -import com.aurora.extensions.browse -import com.aurora.store.R -import com.aurora.store.compose.composable.TopAppBar -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.data.providers.AccountProvider -import com.aurora.store.viewmodel.accounts.AccountsViewModel - -@Composable -fun AccountsScreen( - onNavigateUp: () -> Unit, - onNavigateToSplash: () -> Unit, - viewModel: AccountsViewModel = hiltViewModel() -) { - val userProfile = viewModel.authProvider.authData?.userProfile - val avatar = when { - viewModel.authProvider.isAnonymous -> R.mipmap.ic_launcher - userProfile != null -> userProfile.artwork.url - else -> R.mipmap.ic_launcher - } - val name = when { - viewModel.authProvider.isAnonymous -> stringResource(R.string.account_anonymous) - userProfile != null -> userProfile.name - else -> stringResource(R.string.account_anonymous) - } - val email = when { - viewModel.authProvider.isAnonymous -> stringResource(R.string.account_anonymous_email) - userProfile != null -> userProfile.email - else -> stringResource(R.string.account_anonymous_email) - } - - val context = LocalContext.current - var shouldShowLogoutDialog by rememberSaveable { mutableStateOf(false) } - - if (shouldShowLogoutDialog) { - LogoutDialog( - onConfirm = { - shouldShowLogoutDialog = false - AccountProvider.logout(context) - onNavigateToSplash() - }, - onDismiss = { shouldShowLogoutDialog = false } - ) - } - - ScreenContent( - onNavigateUp = onNavigateUp, - avatar = avatar, - name = name, - email = email, - onLogout = { shouldShowLogoutDialog = true } - ) -} - -@Composable -private fun ScreenContent( - avatar: Any = R.mipmap.ic_launcher, - name: String = stringResource(R.string.account_anonymous), - email: String = stringResource(R.string.account_anonymous_email), - onNavigateUp: () -> Unit = {}, - onLogout: () -> Unit = {} -) { - Scaffold( - topBar = { - TopAppBar( - title = stringResource(R.string.title_account_manager), - onNavigateUp = onNavigateUp - ) - } - ) { paddingValues -> - Column( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - .padding(vertical = dimensionResource(R.dimen.padding_medium)), - verticalArrangement = Arrangement.SpaceBetween - ) { - AssistHeader() - - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .crossfade(true) - .data(avatar) - .build(), - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = Modifier - .requiredSize(dimensionResource(R.dimen.icon_size_avatar)) - .clip(CircleShape) - ) - Text( - text = name, - style = MaterialTheme.typography.titleLarge, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = email, - style = MaterialTheme.typography.bodyMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - - Column( - modifier = Modifier - .fillMaxWidth() - .padding(bottom = dimensionResource(R.dimen.height_bottom_adj)), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - Text( - text = stringResource(R.string.account_logout), - style = MaterialTheme.typography.bodyMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - OutlinedButton(onClick = onLogout) { - Icon( - painter = painterResource(R.drawable.ic_logout), - contentDescription = null - ) - Spacer(modifier = Modifier.width(dimensionResource(R.dimen.padding_xsmall))) - Text( - text = stringResource(R.string.action_logout) - ) - } - } - } - } -} - -@Composable -private fun AssistHeader() { - val context = LocalContext.current - val links = mapOf( - R.string.menu_terms to URL_TOS, - R.string.menu_disclaimer to URL_DISCLAIMER, - R.string.menu_license to URL_LICENSE - ) - - LazyRow( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = dimensionResource(R.dimen.padding_medium)), - horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_normal)) - ) { - items(items = links.keys.toList(), key = { item -> item }) { label -> - AssistChip( - onClick = { context.browse(links.getValue(label)) }, - label = { Text(text = stringResource(label)) } - ) - } - } -} - -@Preview -@Composable -private fun AccountsScreenPreview() { - PreviewTemplate { - ScreenContent() - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/accounts/LogoutDialog.kt b/app/src/main/java/com/aurora/store/compose/ui/accounts/LogoutDialog.kt deleted file mode 100644 index e6a6f5ad4..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/accounts/LogoutDialog.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.accounts - -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Dialog for confirming log out - * @param onConfirm Callback on confirmation - * @param onDismiss Callback on dismiss - */ -@Composable -fun LogoutDialog(onConfirm: () -> Unit = {}, onDismiss: () -> Unit = {}) { - AlertDialog( - title = { Text(text = stringResource(R.string.action_logout_confirmation_title)) }, - text = { - Text(text = stringResource(R.string.action_logout_confirmation_message)) - }, - onDismissRequest = onDismiss, - confirmButton = { - TextButton(onClick = onConfirm) { - Text(text = stringResource(android.R.string.ok)) - } - }, - dismissButton = { - TextButton(onClick = onDismiss) { - Text(text = stringResource(android.R.string.cancel)) - } - } - ) -} - -@Preview -@Composable -private fun LogoutDialogPreview() { - PreviewTemplate { - LogoutDialog() - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/blacklist/BlacklistScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/blacklist/BlacklistScreen.kt deleted file mode 100644 index 7687e1527..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/blacklist/BlacklistScreen.kt +++ /dev/null @@ -1,250 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.blacklist - -import android.content.pm.PackageInfo -import android.net.Uri -import androidx.activity.compose.rememberLauncherForActivityResult -import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.text.input.clearText -import androidx.compose.foundation.text.input.rememberTextFieldState -import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd -import androidx.compose.material3.AppBarWithSearch -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.Scaffold -import androidx.compose.material3.SearchBarDefaults -import androidx.compose.material3.Text -import androidx.compose.material3.rememberSearchBarState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.snapshotFlow -import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusRequester -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.core.content.pm.PackageInfoCompat -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.aurora.Constants -import com.aurora.extensions.toast -import com.aurora.store.R -import com.aurora.store.compose.composable.BlackListItem -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.compose.ui.blacklist.menu.BlacklistMenu -import com.aurora.store.compose.ui.blacklist.menu.MenuItem -import com.aurora.store.util.PackageUtil -import com.aurora.store.viewmodel.blacklist.BlacklistViewModel -import java.util.Calendar -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.launch - -@Composable -fun BlacklistScreen(onNavigateUp: () -> Unit, viewModel: BlacklistViewModel = hiltViewModel()) { - val context = LocalContext.current - val packages by viewModel.filteredPackages.collectAsStateWithLifecycle() - - ScreenContent( - packages = packages, - onNavigateUp = onNavigateUp, - isPackageBlacklisted = { pkgName -> pkgName in viewModel.blacklist }, - isPackageFiltered = { pkgInfo -> viewModel.isFiltered(pkgInfo) }, - onBlacklistImport = { uri -> - viewModel.importBlacklist(uri) - context.toast(R.string.toast_black_import_success) - }, - onBlacklistExport = { uri -> - viewModel.exportBlacklist(uri) - context.toast(R.string.toast_black_export_success) - }, - onBlacklist = { packageName -> viewModel.blacklist(packageName) }, - onBlacklistAll = { viewModel.blacklistAll() }, - onWhitelist = { packageName -> viewModel.whitelist(packageName) }, - onWhitelistAll = { viewModel.whitelistAll() }, - onSearch = { query -> viewModel.search(query) } - ) -} - -@Composable -private fun ScreenContent( - packages: List? = null, - onNavigateUp: () -> Unit = {}, - isPackageBlacklisted: (packageName: String) -> Boolean = { false }, - isPackageFiltered: (packageInfo: PackageInfo) -> Boolean = { false }, - onBlacklistImport: (uri: Uri) -> Unit = {}, - onBlacklistExport: (uri: Uri) -> Unit = {}, - onBlacklist: (packageName: String) -> Unit = {}, - onBlacklistAll: () -> Unit = {}, - onWhitelist: (packageName: String) -> Unit = {}, - onWhitelistAll: () -> Unit = {}, - onSearch: (query: String) -> Unit = {} -) { - val context = LocalContext.current - val textFieldState = rememberTextFieldState() - val searchBarState = rememberSearchBarState() - val focusRequester = remember { FocusRequester() } - val coroutineScope = rememberCoroutineScope() - - val docImportLauncher = rememberLauncherForActivityResult( - contract = ActivityResultContracts.OpenDocument(), - onResult = { - if (it != null) { - onBlacklistImport(it) - } else { - context.toast(R.string.toast_black_import_failed) - } - } - ) - val docExportLauncher = rememberLauncherForActivityResult( - contract = ActivityResultContracts.CreateDocument(Constants.JSON_MIME_TYPE), - onResult = { - if (it != null) { - onBlacklistExport(it) - } else { - context.toast(R.string.toast_black_export_failed) - } - } - ) - - LaunchedEffect(key1 = textFieldState) { - snapshotFlow { textFieldState.text.toString() } - .collectLatest { query -> onSearch(query) } - } - - @Composable - fun SetupMenu() { - BlacklistMenu { menuItem -> - when (menuItem) { - MenuItem.SELECT_ALL -> onBlacklistAll() - - MenuItem.REMOVE_ALL -> onWhitelistAll() - - MenuItem.IMPORT -> { - docImportLauncher.launch(arrayOf(Constants.JSON_MIME_TYPE)) - } - - MenuItem.EXPORT -> { - docExportLauncher.launch( - "aurora_store_apps_${Calendar.getInstance().time.time}.json" - ) - } - } - } - } - - fun onRequestSearch(query: String) { - textFieldState.setTextAndPlaceCursorAtEnd(query.trim()) - coroutineScope.launch { searchBarState.animateToCollapsed() } - onSearch(textFieldState.text.toString()) - } - - @Composable - fun SearchBar() { - val inputField = @Composable { - SearchBarDefaults.InputField( - modifier = Modifier.focusRequester(focusRequester), - searchBarState = searchBarState, - textFieldState = textFieldState, - onSearch = { query -> onRequestSearch(query) }, - placeholder = { - Text( - text = stringResource(R.string.search_hint), - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - }, - leadingIcon = { - Icon( - painter = painterResource(R.drawable.ic_round_search), - contentDescription = stringResource(R.string.action_search) - ) - }, - trailingIcon = { - if (textFieldState.text.isNotBlank()) { - IconButton( - onClick = { - textFieldState.clearText() - focusRequester.requestFocus() - } - ) { - Icon( - painter = painterResource(R.drawable.ic_cancel), - contentDescription = stringResource(R.string.action_clear) - ) - } - } - } - ) - } - - AppBarWithSearch( - state = searchBarState, - inputField = inputField, - navigationIcon = { - IconButton(onClick = onNavigateUp) { - Icon( - painter = painterResource(R.drawable.ic_arrow_back), - contentDescription = stringResource(R.string.action_back) - ) - } - }, - actions = { if (!packages.isNullOrEmpty()) SetupMenu() } - ) - } - - Scaffold(topBar = { SearchBar() }) { paddingValues -> - LazyColumn( - modifier = Modifier - .fillMaxWidth() - .padding(paddingValues), - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_xxsmall)) - ) { - items(items = packages ?: emptyList(), key = { p -> p.packageName.hashCode() }) { pkg -> - val isBlacklisted = isPackageBlacklisted(pkg.packageName) - val isFiltered = isPackageFiltered(pkg) - BlackListItem( - icon = PackageUtil.getIconForPackage(context, pkg.packageName)!!, - displayName = pkg.applicationInfo!!.loadLabel( - context.packageManager - ).toString(), - packageName = pkg.packageName, - versionName = pkg.versionName!!, - versionCode = PackageInfoCompat.getLongVersionCode(pkg), - isChecked = isBlacklisted || isFiltered, - isEnabled = !isFiltered, - onClick = { - if (isBlacklisted) { - onWhitelist(pkg.packageName) - } else { - onBlacklist(pkg.packageName) - } - } - ) - } - } - } -} - -@Preview -@Composable -private fun BlacklistScreenPreview() { - PreviewTemplate { - ScreenContent() - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/blacklist/menu/BlacklistMenu.kt b/app/src/main/java/com/aurora/store/compose/ui/blacklist/menu/BlacklistMenu.kt deleted file mode 100644 index b5493ff19..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/blacklist/menu/BlacklistMenu.kt +++ /dev/null @@ -1,78 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.blacklist.menu - -import androidx.compose.foundation.layout.Box -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Menu for the blacklist screen - * @param modifier The modifier to be applied to the composable - * @param onMenuItemClicked Callback when a menu item has been clicked - * @see MenuItem - */ -@Composable -fun BlacklistMenu( - modifier: Modifier = Modifier, - isExpanded: Boolean = false, - onMenuItemClicked: (menuItem: MenuItem) -> Unit = {} -) { - var expanded by remember { mutableStateOf(isExpanded) } - fun onClick(menuItem: MenuItem) { - onMenuItemClicked(menuItem) - expanded = false - } - - Box(modifier = modifier) { - IconButton(onClick = { expanded = true }) { - Icon( - painter = painterResource(R.drawable.ic_more_vert), - contentDescription = stringResource(R.string.menu) - ) - } - DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) { - DropdownMenuItem( - text = { Text(text = stringResource(R.string.action_select_all)) }, - onClick = { onClick(MenuItem.SELECT_ALL) } - ) - DropdownMenuItem( - text = { Text(text = stringResource(R.string.action_remove_all)) }, - onClick = { onClick(MenuItem.REMOVE_ALL) } - ) - DropdownMenuItem( - text = { Text(text = stringResource(R.string.action_import)) }, - onClick = { onClick(MenuItem.IMPORT) } - ) - DropdownMenuItem( - text = { Text(text = stringResource(R.string.action_export)) }, - onClick = { onClick(MenuItem.EXPORT) } - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun BlacklistMenuPreview() { - PreviewTemplate { - BlacklistMenu(isExpanded = true) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/blacklist/menu/MenuItem.kt b/app/src/main/java/com/aurora/store/compose/ui/blacklist/menu/MenuItem.kt deleted file mode 100644 index 49d313d12..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/blacklist/menu/MenuItem.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.blacklist.menu - -/** - * Valid menu items for the purpose of handling clicks - */ -enum class MenuItem { - SELECT_ALL, - REMOVE_ALL, - IMPORT, - EXPORT -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/commons/PermissionRationaleScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/commons/PermissionRationaleScreen.kt deleted file mode 100644 index 5dcd3f69a..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/commons/PermissionRationaleScreen.kt +++ /dev/null @@ -1,93 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.commons - -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Scaffold -import androidx.compose.material3.adaptive.WindowAdaptiveInfo -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.pluralStringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.datasource.LoremIpsum -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.aurora.extensions.adaptiveNavigationIcon -import com.aurora.store.R -import com.aurora.store.compose.composable.PermissionList -import com.aurora.store.compose.composable.TopAppBar -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.data.model.Permission -import com.aurora.store.data.model.PermissionType -import com.aurora.store.viewmodel.commons.PermissionRationaleViewModel -import kotlin.random.Random - -/** - * Screen to request specific set of permissions expected to be used during installing an app - */ -@Composable -fun PermissionRationaleScreen( - requiredPermissions: Set = emptySet(), - onNavigateUp: () -> Unit, - onPermissionCallback: (type: PermissionType) -> Unit = {}, - viewModel: PermissionRationaleViewModel = hiltViewModel() -) { - val permissions by viewModel.permissions.collectAsStateWithLifecycle() - - ScreenContent( - onNavigateUp = onNavigateUp, - permissions = permissions - .filter { it.type in requiredPermissions } - .map { permission -> permission.copy(optional = false) }, - onPermissionCallback = { type -> - viewModel.refreshPermissionsList() - onPermissionCallback(type) - } - ) -} - -@Composable -private fun ScreenContent( - permissions: List = emptyList(), - onNavigateUp: () -> Unit = {}, - onPermissionCallback: (type: PermissionType) -> Unit = {}, - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() -) { - Scaffold( - topBar = { - TopAppBar( - title = pluralStringResource(R.plurals.permissions_required, permissions.size), - navigationIcon = windowAdaptiveInfo.adaptiveNavigationIcon, - onNavigateUp = onNavigateUp - ) - } - ) { paddingValues -> - PermissionList( - modifier = Modifier.padding(paddingValues), - permissions = permissions, - onPermissionCallback = onPermissionCallback - ) - } -} - -@Preview -@Composable -private fun PermissionsScreenPreview() { - val permissions = PermissionType.entries.map { type -> - Permission( - type = type, - title = LoremIpsum(3).values.first(), - subtitle = LoremIpsum(7).values.first(), - optional = Random.nextBoolean(), - isGranted = Random.nextBoolean() - ) - } - PreviewTemplate { - ScreenContent(permissions = permissions) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/AppDetailsScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/details/AppDetailsScreen.kt deleted file mode 100644 index 7ee852ea5..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/AppDetailsScreen.kt +++ /dev/null @@ -1,555 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details - -import android.content.ActivityNotFoundException -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.Icon -import androidx.compose.material3.Scaffold -import androidx.compose.material3.adaptive.WindowAdaptiveInfo -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.material3.adaptive.layout.AdaptStrategy -import androidx.compose.material3.adaptive.layout.AnimatedPane -import androidx.compose.material3.adaptive.layout.PaneAdaptedValue -import androidx.compose.material3.adaptive.layout.SupportingPaneScaffoldDefaults -import androidx.compose.material3.adaptive.layout.SupportingPaneScaffoldRole -import androidx.compose.material3.adaptive.layout.calculatePaneScaffoldDirective -import androidx.compose.material3.adaptive.navigation.NavigableSupportingPaneScaffold -import androidx.compose.material3.adaptive.navigation.rememberSupportingPaneScaffoldNavigator -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.tooling.preview.PreviewScreenSizes -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation3.runtime.NavKey -import com.aurora.extensions.appInfo -import com.aurora.extensions.requiresGMS -import com.aurora.extensions.requiresObbDir -import com.aurora.extensions.share -import com.aurora.extensions.toast -import com.aurora.gplayapi.data.models.App -import com.aurora.gplayapi.data.models.Review -import com.aurora.gplayapi.data.models.datasafety.Report as DataSafetyReport -import com.aurora.store.R -import com.aurora.store.compose.composable.ContainedLoadingIndicator -import com.aurora.store.compose.composable.Error -import com.aurora.store.compose.composable.Header -import com.aurora.store.compose.composable.TopAppBar -import com.aurora.store.compose.composable.app.LargeAppListItem -import com.aurora.store.compose.navigation.Screen -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.compose.ui.commons.PermissionRationaleScreen -import com.aurora.store.compose.ui.details.composable.Actions -import com.aurora.store.compose.ui.details.composable.Changelog -import com.aurora.store.compose.ui.details.composable.Compatibility -import com.aurora.store.compose.ui.details.composable.DataSafety -import com.aurora.store.compose.ui.details.composable.Details -import com.aurora.store.compose.ui.details.composable.DeveloperDetails -import com.aurora.store.compose.ui.details.composable.Privacy -import com.aurora.store.compose.ui.details.composable.RatingAndReviews -import com.aurora.store.compose.ui.details.composable.Screenshots -import com.aurora.store.compose.ui.details.composable.Tags -import com.aurora.store.compose.ui.details.composable.Testing -import com.aurora.store.compose.ui.details.menu.AppDetailsMenu -import com.aurora.store.compose.ui.details.menu.MenuItem -import com.aurora.store.compose.ui.details.navigation.ExtraScreen -import com.aurora.store.compose.ui.dev.DevProfileScreen -import com.aurora.store.data.installer.AppInstaller -import com.aurora.store.data.model.AppState -import com.aurora.store.data.model.PermissionType -import com.aurora.store.data.model.Report -import com.aurora.store.data.model.Scores -import com.aurora.store.data.providers.PermissionProvider.Companion.isPermittedToInstall -import com.aurora.store.util.FlavouredUtil -import com.aurora.store.util.PackageUtil -import com.aurora.store.util.ShortcutManagerUtil -import com.aurora.store.viewmodel.details.AppDetailsViewModel -import kotlin.random.Random -import kotlinx.coroutines.launch - -@Composable -fun AppDetailsScreen( - packageName: String, - onNavigateUp: () -> Unit, - onNavigateToAppDetails: (packageName: String) -> Unit, - viewModel: AppDetailsViewModel = hiltViewModel(key = packageName), - forceSinglePane: Boolean = false -) { - val context = LocalContext.current - - val app by viewModel.app.collectAsStateWithLifecycle() - val state by viewModel.state.collectAsStateWithLifecycle() - val featuredReviews by viewModel.featuredReviews.collectAsStateWithLifecycle() - val favorite by viewModel.favourite.collectAsStateWithLifecycle() - val exodusReport by viewModel.exodusReport.collectAsStateWithLifecycle() - val dataSafetyReport by viewModel.dataSafetyReport.collectAsStateWithLifecycle() - val plexusScores by viewModel.plexusScores.collectAsStateWithLifecycle() - val suggestions by viewModel.suggestions.collectAsStateWithLifecycle() - - LaunchedEffect(key1 = packageName) { viewModel.fetchAppDetails(packageName) } - - when (state) { - is AppState.Loading -> ScreenContentLoading(onNavigateUp = onNavigateUp) - - is AppState.Error -> { - ScreenContentError( - onNavigateUp = onNavigateUp, - message = (state as AppState.Error).message - ) - } - - else -> { - ScreenContentApp( - app = app!!, - featuredReviews = featuredReviews, - suggestions = suggestions, - isFavorite = favorite, - isAnonymous = viewModel.authProvider.isAnonymous, - state = state, - plexusScores = plexusScores, - dataSafetyReport = dataSafetyReport, - exodusReport = exodusReport, - onNavigateUp = onNavigateUp, - onNavigateToAppDetails = onNavigateToAppDetails, - onDownload = { requestedApp -> viewModel.enqueueDownload(requestedApp) }, - onFavorite = { viewModel.toggleFavourite(app!!) }, - onCancelDownload = { viewModel.cancelDownload(app!!) }, - onUninstall = { AppInstaller.uninstall(context, packageName) }, - onOpen = { - try { - context.startActivity( - PackageUtil.getLaunchIntent(context, packageName) - ) - } catch (_: ActivityNotFoundException) { - context.toast(context.getString(R.string.unable_to_open)) - } - }, - onTestingSubscriptionChange = { subscribe -> - viewModel.updateTestingProgramStatus(packageName, subscribe) - }, - forceSinglePane = forceSinglePane - ) - } - } -} - -/** - * Composable to show progress while fetching app details - */ -@Composable -private fun ScreenContentLoading(onNavigateUp: () -> Unit = {}) { - Scaffold( - topBar = { TopAppBar(onNavigateUp = onNavigateUp) } - ) { paddingValues -> - ContainedLoadingIndicator(modifier = Modifier.padding(paddingValues)) - } -} - -/** - * Composable to display errors related to fetching app details - */ -@Composable -private fun ScreenContentError(onNavigateUp: () -> Unit = {}, message: String? = null) { - Scaffold( - topBar = { TopAppBar(onNavigateUp = onNavigateUp) } - ) { paddingValues -> - Error( - modifier = Modifier.padding(paddingValues), - painter = painterResource(R.drawable.ic_apps_outage), - message = message ?: stringResource(R.string.toast_app_unavailable) - ) - } -} - -/** - * Composable to display app details and suggestions - */ -@Composable -private fun ScreenContentApp( - app: App, - featuredReviews: List = emptyList(), - suggestions: List = emptyList(), - isFavorite: Boolean = false, - isAnonymous: Boolean = true, - state: AppState = AppState.Unavailable, - plexusScores: Scores? = null, - dataSafetyReport: DataSafetyReport? = null, - exodusReport: Report? = null, - onNavigateUp: () -> Unit = {}, - onNavigateToAppDetails: (packageName: String) -> Unit = {}, - onDownload: (requestedApp: App) -> Unit = {}, - onFavorite: () -> Unit = {}, - onCancelDownload: () -> Unit = {}, - onUninstall: () -> Unit = {}, - onOpen: () -> Unit = {}, - onTestingSubscriptionChange: (subscribe: Boolean) -> Unit = {}, - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo(), - forceSinglePane: Boolean = false -) { - val context = LocalContext.current - var scaffoldDirective = calculatePaneScaffoldDirective(windowAdaptiveInfo) - - if (forceSinglePane) { - scaffoldDirective = scaffoldDirective.copy(maxHorizontalPartitions = 1) - } - - val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator( - scaffoldDirective = scaffoldDirective, - adaptStrategies = SupportingPaneScaffoldDefaults.adaptStrategies( - supportingPaneAdaptStrategy = AdaptStrategy.Hide - ) - ) - val coroutineScope = rememberCoroutineScope() - val shouldShowMenuOnMainPane = scaffoldNavigator - .scaffoldValue[SupportingPaneScaffoldRole.Supporting] == PaneAdaptedValue.Hidden - - fun onNavigateBack() { - coroutineScope.launch { - scaffoldNavigator.navigateBack() - } - } - - fun showExtraPane(screen: NavKey) { - coroutineScope.launch { - scaffoldNavigator.navigateTo(SupportingPaneScaffoldRole.Extra, screen) - } - } - - fun onInstall(requestedApp: App = app, ignoreMicroG: Boolean = false) { - if (isPermittedToInstall(context, app)) { - val shouldPromptMicroGInstall = app.requiresGMS() && - FlavouredUtil.promptMicroGInstall(context) - - if (shouldPromptMicroGInstall && !ignoreMicroG) { - showExtraPane(ExtraScreen.MicroG) - } else { - onDownload(requestedApp) - onNavigateBack() - } - } else { - val requiredPermissions = setOfNotNull( - PermissionType.INSTALL_UNKNOWN_APPS, - if (app.fileList.requiresObbDir()) PermissionType.STORAGE_MANAGER else null, - if (app.fileList.requiresObbDir()) PermissionType.EXTERNAL_STORAGE else null - ) - showExtraPane(Screen.PermissionRationale(requiredPermissions = requiredPermissions)) - } - } - - @Composable - fun SetupMenu() { - AppDetailsMenu(isFavorite = isFavorite, state = state) { menuItem -> - when (menuItem) { - MenuItem.FAVORITE -> onFavorite() - - MenuItem.MANUAL_DOWNLOAD -> { - showExtraPane(ExtraScreen.ManualDownload) - } - - MenuItem.SHARE -> context.share(app.displayName, app.packageName) - - MenuItem.APP_INFO -> context.appInfo(app.packageName) - - MenuItem.ADD_TO_HOME -> { - ShortcutManagerUtil.requestPinShortcut(context, app.packageName) - } - } - } - } - - @Composable - fun SetupActions() { - when (state) { - is AppState.Queued, - is AppState.Purchasing, - is AppState.Downloading -> { - Actions( - primaryActionDisplayName = stringResource(R.string.action_open), - secondaryActionDisplayName = stringResource(R.string.action_cancel), - isPrimaryActionEnabled = false, - onSecondaryAction = onCancelDownload - ) - } - - is AppState.Updatable -> { - Actions( - primaryActionDisplayName = stringResource(R.string.action_update), - secondaryActionDisplayName = stringResource(R.string.action_uninstall), - onPrimaryAction = ::onInstall, - onSecondaryAction = onUninstall - ) - } - - is AppState.Installed -> { - Actions( - primaryActionDisplayName = stringResource(R.string.action_open), - secondaryActionDisplayName = stringResource(R.string.action_uninstall), - onPrimaryAction = onOpen, - onSecondaryAction = onUninstall, - isPrimaryActionEnabled = PackageUtil - .getLaunchIntent(context, app.packageName) != null - ) - } - - else -> { - val primaryActionName = if (state is AppState.Archived) { - stringResource(R.string.action_unarchive) - } else { - if (app.isFree) stringResource(R.string.action_install) else app.price - } - - Actions( - primaryActionDisplayName = primaryActionName, - secondaryActionDisplayName = stringResource(R.string.title_manual_download), - onPrimaryAction = ::onInstall, - onSecondaryAction = { showExtraPane(ExtraScreen.ManualDownload) } - ) - } - } - } - - @Composable - fun MainPane() { - Scaffold( - topBar = { - TopAppBar( - onNavigateUp = onNavigateUp, - actions = { if (shouldShowMenuOnMainPane) SetupMenu() } - ) - } - ) { paddingValues -> - Column( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - .verticalScroll(rememberScrollState()) - .padding(dimensionResource(R.dimen.padding_medium)), - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - Details( - app = app, - state = state, - onNavigateToDetailsDevProfile = { showExtraPane(Screen.DevProfile(it)) } - ) - - SetupActions() - - Tags(app = app) - Changelog(changelog = app.changes) - Header( - title = stringResource(R.string.details_more_about_app), - subtitle = app.shortDescription, - onClick = { showExtraPane(ExtraScreen.More) } - ) - - Screenshots( - screenshots = app.screenshots, - onNavigateToScreenshot = { showExtraPane(ExtraScreen.Screenshot(it)) } - ) - - RatingAndReviews( - rating = app.rating, - featuredReviews = featuredReviews, - onNavigateToDetailsReview = { showExtraPane(ExtraScreen.Review) } - ) - - if (!isAnonymous && app.testingProgram?.isAvailable == true) { - Testing( - isSubscribed = app.testingProgram!!.isSubscribed, - onTestingSubscriptionChange = onTestingSubscriptionChange - ) - } - - Compatibility(needsGms = app.requiresGMS(), plexusScores = plexusScores) - - Header( - title = stringResource(R.string.details_permission), - subtitle = if (app.permissions.isNotEmpty()) { - stringResource(R.string.permissions_requested, app.permissions.size) - } else { - stringResource(R.string.details_no_permission) - }, - onClick = if (app.permissions.isNotEmpty()) { - { showExtraPane(ExtraScreen.Permission) } - } else { - null - } - ) - - if (dataSafetyReport != null) { - DataSafety(report = dataSafetyReport, privacyPolicyUrl = app.privacyPolicyUrl) - } - - Privacy( - report = exodusReport, - onNavigateToDetailsExodus = if (exodusReport?.id != -1) { - { showExtraPane(ExtraScreen.Exodus) } - } else { - null - } - ) - - DeveloperDetails( - address = app.developerAddress, - website = app.developerWebsite, - email = app.developerEmail - ) - } - } - } - - @Composable - fun SupportingPane() { - Scaffold( - topBar = { - TopAppBar(actions = { if (!shouldShowMenuOnMainPane) SetupMenu() }) - } - ) { paddingValues -> - Column( - modifier = Modifier - .fillMaxSize() - .padding(paddingValues) - ) { - Row( - modifier = Modifier.padding(dimensionResource(R.dimen.margin_medium)), - verticalAlignment = Alignment.CenterVertically - ) { - Icon( - painter = painterResource(R.drawable.ic_suggestions), - contentDescription = null - ) - Header(title = stringResource(R.string.pref_ui_similar_apps)) - } - LazyColumn( - modifier = Modifier - .fillMaxSize() - .padding(vertical = dimensionResource(R.dimen.padding_medium)) - ) { - items(items = suggestions, key = { item -> item.id }) { app -> - LargeAppListItem( - app = app, - onClick = { onNavigateToAppDetails(app.packageName) } - ) - } - } - } - } - } - - @Composable - fun ExtraPane(screen: NavKey) = when (screen) { - is ExtraScreen.Review -> ReviewScreen( - packageName = app.packageName, - onNavigateUp = ::onNavigateBack - ) - - is ExtraScreen.Exodus -> ExodusScreen( - packageName = app.packageName, - onNavigateUp = ::onNavigateBack - ) - - is ExtraScreen.More -> MoreScreen( - packageName = app.packageName, - onNavigateUp = ::onNavigateBack, - onNavigateToAppDetails = onNavigateToAppDetails - ) - - is ExtraScreen.Permission -> PermissionScreen( - packageName = app.packageName, - onNavigateUp = ::onNavigateBack - ) - - is ExtraScreen.Screenshot -> ScreenshotScreen( - packageName = app.packageName, - index = screen.index, - onNavigateUp = ::onNavigateBack - ) - - is ExtraScreen.ManualDownload -> ManualDownloadScreen( - packageName = app.packageName, - onNavigateUp = ::onNavigateBack, - onRequestInstall = { requestedApp -> onInstall(requestedApp) } - ) - - is ExtraScreen.MicroG -> MicroGScreen( - packageName = app.packageName, - onNavigateUp = ::onNavigateBack, - onIgnore = { onInstall(ignoreMicroG = it) } - ) - - is Screen.DevProfile -> DevProfileScreen( - publisherId = app.developerName, - onNavigateUp = ::onNavigateBack, - onNavigateToAppDetails = { onNavigateToAppDetails(it) } - ) - - is Screen.PermissionRationale -> PermissionRationaleScreen( - onNavigateUp = ::onNavigateBack, - requiredPermissions = screen.requiredPermissions, - onPermissionCallback = { onInstall() } - ) - - else -> {} - } - - NavigableSupportingPaneScaffold( - navigator = scaffoldNavigator, - mainPane = { AnimatedPane { MainPane() } }, - supportingPane = { AnimatedPane { SupportingPane() } }, - extraPane = { - scaffoldNavigator.currentDestination?.contentKey?.let { screen -> - AnimatedPane { ExtraPane(screen) } - } - } - ) -} - -@PreviewScreenSizes -@Composable -private fun AppDetailsScreenPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - ScreenContentApp( - app = app, - isAnonymous = false, - suggestions = List(10) { app.copy(id = Random.nextInt()) } - ) - } -} - -@Preview -@Composable -private fun AppDetailsScreenPreviewLoading() { - PreviewTemplate { - ScreenContentLoading() - } -} - -@Preview -@Composable -private fun AppDetailsScreenPreviewError() { - PreviewTemplate { - ScreenContentError() - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/ExodusScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/details/ExodusScreen.kt deleted file mode 100644 index 15aaa715c..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/ExodusScreen.kt +++ /dev/null @@ -1,195 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details - -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.material3.FloatingActionButton -import androidx.compose.material3.Icon -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Surface -import androidx.compose.material3.adaptive.WindowAdaptiveInfo -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.aurora.Constants.EXODUS_REPORT_URL -import com.aurora.Constants.EXODUS_SUBMIT_PAGE -import com.aurora.extensions.adaptiveNavigationIcon -import com.aurora.extensions.browse -import com.aurora.extensions.isWindowCompact -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.composable.Error -import com.aurora.store.compose.composable.Header -import com.aurora.store.compose.composable.TopAppBar -import com.aurora.store.compose.composable.details.ExodusListItem -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.data.model.ExodusTracker -import com.aurora.store.data.model.Report -import com.aurora.store.viewmodel.details.AppDetailsViewModel -import com.aurora.store.viewmodel.details.ExodusViewModel - -@Composable -fun ExodusScreen( - packageName: String, - onNavigateUp: () -> Unit, - appDetailsViewModel: AppDetailsViewModel = hiltViewModel(key = packageName), - exodusViewModel: ExodusViewModel = hiltViewModel(key = "$packageName/exodus"), - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() -) { - val context = LocalContext.current - - val app by appDetailsViewModel.app.collectAsStateWithLifecycle() - val report by appDetailsViewModel.exodusReport.collectAsStateWithLifecycle() - val trackers by exodusViewModel.trackers.collectAsStateWithLifecycle() - - LaunchedEffect(key1 = Unit) { - report?.let { exodusViewModel.getExodusTrackersFromReport(it) } - } - - val topAppBarTitle = when { - windowAdaptiveInfo.isWindowCompact -> app!!.displayName - else -> stringResource(R.string.details_privacy) - } - - when (report) { - null -> { - ScreenContentError( - topAppBarTitle = topAppBarTitle, - onNavigateUp = onNavigateUp, - onRequestAnalysis = { context.browse("${EXODUS_SUBMIT_PAGE}${app!!.packageName}") } - ) - } - - else -> { - ScreenContentReport( - topAppBarTitle = topAppBarTitle, - report = report, - trackers = trackers, - onNavigateUp = onNavigateUp, - onRequestAnalysis = { context.browse("${EXODUS_SUBMIT_PAGE}${app!!.packageName}") } - ) - } - } -} - -@Composable -private fun ScreenContentReport( - topAppBarTitle: String? = null, - report: Report? = null, - trackers: List = emptyList(), - onNavigateUp: () -> Unit = {}, - onRequestAnalysis: () -> Unit = {}, - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() -) { - val context = LocalContext.current - - Scaffold( - topBar = { - TopAppBar( - title = topAppBarTitle, - navigationIcon = windowAdaptiveInfo.adaptiveNavigationIcon, - onNavigateUp = onNavigateUp - ) - }, - floatingActionButton = { - FloatingActionButton(onClick = onRequestAnalysis) { - Icon( - painter = painterResource(R.drawable.ic_scan), - contentDescription = stringResource(R.string.action_request_analysis) - ) - } - } - ) { paddingValues -> - LazyColumn( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - .padding(horizontal = dimensionResource(R.dimen.padding_medium)) - ) { - stickyHeader { - Surface(modifier = Modifier.fillMaxWidth()) { - Header( - title = if (report?.trackers.isNullOrEmpty()) { - stringResource(R.string.exodus_no_tracker) - } else { - stringResource( - R.string.exodus_report_trackers, - report.trackers.size, - report.version - ) - }, - subtitle = stringResource(R.string.exodus_view_report), - onClick = { context.browse(EXODUS_REPORT_URL + report!!.id) } - ) - } - } - - items(items = trackers, key = { item -> item.id }) { tracker -> - ExodusListItem(tracker = tracker) - } - } - } -} - -/** - * Composable to display errors related to fetching app details - */ -@Composable -private fun ScreenContentError( - topAppBarTitle: String? = null, - onNavigateUp: () -> Unit = {}, - onRequestAnalysis: () -> Unit = {}, - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() -) { - Scaffold( - topBar = { - TopAppBar( - title = topAppBarTitle, - navigationIcon = windowAdaptiveInfo.adaptiveNavigationIcon, - onNavigateUp = onNavigateUp - ) - } - ) { paddingValues -> - Error( - modifier = Modifier.padding(paddingValues), - painter = painterResource(R.drawable.ic_disclaimer), - message = stringResource(R.string.failed_to_fetch_report), - actionMessage = stringResource(R.string.action_request_analysis), - onAction = onRequestAnalysis - ) - } -} - -@Preview -@Composable -private fun ExodusScreenPreviewReport(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - ScreenContentReport(topAppBarTitle = app.displayName) - } -} - -@Preview -@Composable -private fun ExodusScreenPreviewError(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - ScreenContentError(topAppBarTitle = app.displayName) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/ManualDownloadScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/details/ManualDownloadScreen.kt deleted file mode 100644 index 1d49f31d7..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/ManualDownloadScreen.kt +++ /dev/null @@ -1,225 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.imePadding -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredSize -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material3.Button -import androidx.compose.material3.ContainedLoadingIndicator -import androidx.compose.material3.FilledTonalButton -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState -import androidx.compose.material3.Text -import androidx.compose.material3.adaptive.WindowAdaptiveInfo -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusRequester -import androidx.compose.ui.platform.LocalFocusManager -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.text.TextRange -import androidx.compose.ui.text.input.KeyboardType -import androidx.compose.ui.text.input.TextFieldValue -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.unit.dp -import androidx.core.text.isDigitsOnly -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.aurora.extensions.adaptiveNavigationIcon -import com.aurora.extensions.isWindowCompact -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.composable.Info -import com.aurora.store.compose.composable.TopAppBar -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.data.model.AppState -import com.aurora.store.viewmodel.details.AppDetailsViewModel -import kotlinx.coroutines.android.awaitFrame -import kotlinx.coroutines.launch - -@Composable -fun ManualDownloadScreen( - packageName: String, - onNavigateUp: () -> Unit, - onRequestInstall: (requestedApp: App) -> Unit, - viewModel: AppDetailsViewModel = hiltViewModel(key = packageName), - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() -) { - val app by viewModel.app.collectAsStateWithLifecycle() - val state by viewModel.state.collectAsStateWithLifecycle() - val topAppBarTitle = when { - windowAdaptiveInfo.isWindowCompact -> app!!.displayName - else -> stringResource(R.string.title_manual_download) - } - - ScreenContent( - state = state, - topAppBarTitle = topAppBarTitle, - currentVersionCode = app!!.versionCode, - onNavigateUp = onNavigateUp, - onRequestInstall = { versionCode -> - val requestedApp = app!!.copy( - versionCode = versionCode, - dependencies = app!!.dependencies.copy( - dependentLibraries = app!!.dependencies.dependentLibraries.map { lib -> - lib.copy(versionCode = versionCode) - } - ) - ) - onRequestInstall(requestedApp) - } - ) -} - -@Composable -private fun ScreenContent( - state: AppState = AppState.Unavailable, - topAppBarTitle: String? = null, - currentVersionCode: Long = 0L, - onNavigateUp: () -> Unit = {}, - onRequestInstall: (versionCode: Long) -> Unit = {}, - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() -) { - val coroutineScope = rememberCoroutineScope() - val snackBarHostState = remember { SnackbarHostState() } - val errorMessage = stringResource(R.string.manual_download_version_error) - - val focusManager = LocalFocusManager.current - val focusRequester = remember { FocusRequester() } - var versionCode by remember { - val initText = currentVersionCode.toString() - mutableStateOf(TextFieldValue(text = initText, selection = TextRange(initText.length))) - } - - LaunchedEffect(focusRequester) { - awaitFrame() - focusRequester.requestFocus() - } - - Scaffold( - modifier = Modifier.imePadding(), - topBar = { - TopAppBar( - title = topAppBarTitle, - navigationIcon = windowAdaptiveInfo.adaptiveNavigationIcon, - onNavigateUp = onNavigateUp - ) - }, - snackbarHost = { SnackbarHost(hostState = snackBarHostState) } - ) { paddingValues -> - Column( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - .padding(dimensionResource(R.dimen.padding_medium)), - verticalArrangement = Arrangement.SpaceBetween - ) { - Column( - modifier = Modifier.fillMaxWidth(), - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - Info( - painter = painterResource(R.drawable.ic_download_manager), - title = AnnotatedString(text = stringResource(R.string.manual_download_hint)) - ) - OutlinedTextField( - modifier = Modifier - .fillMaxWidth() - .focusRequester(focusRequester), - enabled = !state.inProgress(), - value = versionCode, - onValueChange = { - if (it.text.isDigitsOnly()) { - versionCode = it - } else { - coroutineScope.launch { snackBarHostState.showSnackbar(errorMessage) } - } - }, - shape = RoundedCornerShape(10.dp), - singleLine = true, - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), - keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - trailingIcon = { - if (state.inProgress()) { - ContainedLoadingIndicator( - modifier = Modifier - .requiredSize(dimensionResource(R.dimen.icon_size_default)) - ) - } - } - ) - } - - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy( - dimensionResource(R.dimen.padding_medium) - ) - ) { - FilledTonalButton( - modifier = Modifier.weight(1F), - onClick = onNavigateUp - ) { - Text( - text = stringResource(R.string.action_close), - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - - Button( - modifier = Modifier.weight(1F), - enabled = !state.inProgress(), - onClick = { - onRequestInstall(versionCode.text.toLong()) - focusManager.clearFocus() - } - ) { - Text( - text = stringResource(R.string.action_install), - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - } - } - } -} - -@Preview -@Composable -private fun ManualDownloadScreenPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - ScreenContent( - topAppBarTitle = app.displayName, - currentVersionCode = app.versionCode - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/MicroGScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/details/MicroGScreen.kt deleted file mode 100644 index 0f6408f23..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/MicroGScreen.kt +++ /dev/null @@ -1,160 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.Button -import androidx.compose.material3.FilledTonalButton -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.adaptive.WindowAdaptiveInfo -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.aurora.extensions.adaptiveNavigationIcon -import com.aurora.extensions.isWindowCompact -import com.aurora.extensions.toast -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.composable.MicroG -import com.aurora.store.compose.composable.TopAppBar -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.data.model.PermissionType -import com.aurora.store.data.providers.PermissionProvider -import com.aurora.store.viewmodel.details.AppDetailsViewModel -import com.aurora.store.viewmodel.onboarding.MicroGUIState -import com.aurora.store.viewmodel.onboarding.MicroGViewModel - -@Composable -fun MicroGScreen( - packageName: String, - onNavigateUp: () -> Unit, - onIgnore: (Boolean) -> Unit, - appDetailsViewModel: AppDetailsViewModel = hiltViewModel(key = packageName), - viewModel: MicroGViewModel = hiltViewModel(), - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() -) { - val app by appDetailsViewModel.app.collectAsStateWithLifecycle() - val topAppBarTitle = when { - windowAdaptiveInfo.isWindowCompact -> app!!.displayName - else -> stringResource(R.string.onboarding_title_gsf) - } - - ScreenContent( - topAppBarTitle = topAppBarTitle, - uiState = viewModel.uiState, - onNavigateUp = onNavigateUp, - onInstall = { viewModel.downloadMicroG() }, - onIgnore = onIgnore - ) -} - -@Composable -private fun ScreenContent( - topAppBarTitle: String? = null, - uiState: MicroGUIState = MicroGUIState(), - onNavigateUp: () -> Unit = {}, - onInstall: () -> Unit = {}, - onIgnore: (Boolean) -> Unit = {}, - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() -) { - val context = LocalContext.current - - Scaffold( - topBar = { - TopAppBar( - title = topAppBarTitle, - navigationIcon = windowAdaptiveInfo.adaptiveNavigationIcon, - onNavigateUp = onNavigateUp - ) - } - ) { paddingValues -> - Column( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - .padding(dimensionResource(R.dimen.padding_medium)) - .verticalScroll(rememberScrollState()), - verticalArrangement = Arrangement.SpaceBetween - ) { - MicroG( - modifier = Modifier.weight(1F), - onInstall = { - when { - PermissionProvider.isGranted( - context, - PermissionType.INSTALL_UNKNOWN_APPS - ) -> { - onInstall() - } - - else -> context.toast(R.string.permissions_denied) - } - }, - uiState = uiState - ) - - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy( - dimensionResource(R.dimen.padding_medium) - ) - ) { - FilledTonalButton( - modifier = Modifier.weight(1F), - onClick = onNavigateUp - ) { - Text( - text = stringResource(R.string.action_cancel), - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - - Button( - modifier = Modifier.weight(1F), - onClick = { onIgnore(uiState.isInstalled) }, - enabled = !uiState.isDownloading - ) { - Text( - text = if (uiState.isInstalled) { - stringResource(R.string.action_install) - } else { - stringResource(R.string.action_ignore) - }, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - } - } - } -} - -@Preview -@Composable -private fun MicroGScreenPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - ScreenContent(topAppBarTitle = app.displayName) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/MoreScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/details/MoreScreen.kt deleted file mode 100644 index f8d167593..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/MoreScreen.kt +++ /dev/null @@ -1,197 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.adaptive.WindowAdaptiveInfo -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.text.fromHtml -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.aurora.extensions.adaptiveNavigationIcon -import com.aurora.extensions.isWindowCompact -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.composable.Header -import com.aurora.store.compose.composable.Info -import com.aurora.store.compose.composable.TopAppBar -import com.aurora.store.compose.composable.app.AppListItem -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.viewmodel.details.AppDetailsViewModel -import com.aurora.store.viewmodel.details.MoreViewModel -import java.util.Locale - -@Composable -fun MoreScreen( - packageName: String, - onNavigateUp: () -> Unit, - onNavigateToAppDetails: (packageName: String) -> Unit, - appDetailsViewModel: AppDetailsViewModel = hiltViewModel(key = packageName), - moreViewModel: MoreViewModel = hiltViewModel( - key = "$packageName/more", - creationCallback = { factory: MoreViewModel.Factory -> - factory.create(appDetailsViewModel.app.value!!.dependencies.dependentPackages) - } - ) -) { - val app by appDetailsViewModel.app.collectAsStateWithLifecycle() - val dependencies by moreViewModel.dependentApps.collectAsStateWithLifecycle() - - ScreenContent( - app = app!!, - dependencies = dependencies, - onNavigateUp = onNavigateUp, - onNavigateToAppDetails = onNavigateToAppDetails - ) -} - -@Composable -private fun ScreenContent( - app: App, - dependencies: List? = null, - onNavigateUp: () -> Unit = {}, - onNavigateToAppDetails: (packageName: String) -> Unit = {}, - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() -) { - val topAppBarTitle = when { - windowAdaptiveInfo.isWindowCompact -> app.displayName - else -> stringResource(R.string.details_more_about_app) - } - - Scaffold( - topBar = { - TopAppBar( - title = topAppBarTitle, - navigationIcon = windowAdaptiveInfo.adaptiveNavigationIcon, - onNavigateUp = onNavigateUp - ) - } - ) { paddingValues -> - Column( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - .verticalScroll(rememberScrollState()), - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - Header(title = stringResource(R.string.details_description)) - Text( - modifier = Modifier.padding(horizontal = dimensionResource(R.dimen.padding_medium)), - text = AnnotatedString.fromHtml( - htmlString = app.description - ), - style = MaterialTheme.typography.bodyMedium - ) - - if (dependencies != null) { - AppDependencies( - dependencies = dependencies, - onNavigateToAppDetails = onNavigateToAppDetails - ) - } - - AppInfoMore(app = app) - } - } -} - -/** - * Composable to show dependencies of an app - */ -@Composable -private fun AppDependencies( - dependencies: List, - onNavigateToAppDetails: (packageName: String) -> Unit -) { - Header(title = stringResource(R.string.details_dependencies)) - if (dependencies.isEmpty()) { - Info( - title = AnnotatedString(text = stringResource(R.string.details_no_dependencies)) - ) - } else { - LazyRow(modifier = Modifier.fillMaxWidth()) { - items(items = dependencies, key = { item -> item.id }) { app -> - AppListItem( - app = app, - onClick = { onNavigateToAppDetails(app.packageName) } - ) - } - } - } -} - -/** - * Composable to show more information about the app that maybe advanced - */ -@Composable -private fun AppInfoMore(app: App) { - Header(title = stringResource(R.string.details_more_info)) - Info( - title = AnnotatedString( - text = stringResource(R.string.details_more_package_name) - ), - description = AnnotatedString(text = app.packageName) - ) - - Info( - title = AnnotatedString( - text = stringResource(R.string.details_more_target_api) - ), - description = AnnotatedString(text = "API ${app.targetSdk}") - ) - - Info( - title = AnnotatedString( - text = stringResource(R.string.details_more_content_rating) - ), - description = AnnotatedString(text = app.contentRating.title) - ) - - app.appInfo.appInfoMap.forEach { (title, subtitle) -> - Info( - title = AnnotatedString( - text = title.replace("_", " ") - .lowercase(Locale.getDefault()) - .replaceFirstChar { - if (it.isLowerCase()) { - it.titlecase(Locale.getDefault()) - } else { - it.toString() - } - } - ), - description = AnnotatedString(text = subtitle) - ) - } -} - -@Preview -@Composable -private fun MoreScreenPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - ScreenContent(app = app) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/PermissionScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/details/PermissionScreen.kt deleted file mode 100644 index d2722aae9..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/PermissionScreen.kt +++ /dev/null @@ -1,126 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details - -import android.content.pm.PermissionInfo -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.material3.Scaffold -import androidx.compose.material3.adaptive.WindowAdaptiveInfo -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.aurora.extensions.adaptiveNavigationIcon -import com.aurora.extensions.isWindowCompact -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.composable.Info -import com.aurora.store.compose.composable.TopAppBar -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.viewmodel.details.AppDetailsViewModel -import com.aurora.store.viewmodel.details.PermissionViewModel -import java.util.Locale - -@Composable -fun PermissionScreen( - packageName: String, - onNavigateUp: () -> Unit, - appDetailsViewModel: AppDetailsViewModel = hiltViewModel(key = packageName), - permissionViewModel: PermissionViewModel = hiltViewModel( - key = "$packageName/permission", - creationCallback = { factory: PermissionViewModel.Factory -> - factory.create(appDetailsViewModel.app.value!!.permissions) - } - ), - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() -) { - val app by appDetailsViewModel.app.collectAsStateWithLifecycle() - val permissionsInfo by permissionViewModel.permissionsInfo.collectAsStateWithLifecycle() - - val topAppBarTitle = when { - windowAdaptiveInfo.isWindowCompact -> app!!.displayName - else -> stringResource(R.string.details_permission) - } - - ScreenContent( - topAppBarTitle = topAppBarTitle, - onNavigateUp = onNavigateUp, - permissionsInfo = permissionsInfo - ) -} - -@Composable -private fun ScreenContent( - topAppBarTitle: String? = null, - permissionsInfo: Map = emptyMap(), - onNavigateUp: () -> Unit = {}, - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() -) { - val packageManager = LocalContext.current.packageManager - - Scaffold( - topBar = { - TopAppBar( - title = topAppBarTitle, - navigationIcon = windowAdaptiveInfo.adaptiveNavigationIcon, - onNavigateUp = onNavigateUp - ) - } - ) { paddingValues -> - LazyColumn( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - .padding(horizontal = dimensionResource(R.dimen.padding_medium)), - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - items(items = permissionsInfo.keys.toList(), key = { it }) { permission -> - val permissionInfo = permissionsInfo.getValue(permission) - - Info( - title = AnnotatedString( - text = permissionInfo.loadLabel(packageManager) - .toString() - .replaceFirstChar { - if (it.isLowerCase()) { - it.titlecase(Locale.getDefault()) - } else { - it.toString() - } - } - ), - description = AnnotatedString( - text = permissionInfo.loadDescription(packageManager)?.toString() - ?: stringResource(R.string.no_description) - ) - ) - } - } - } -} - -@Preview -@Composable -private fun PermissionScreenPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - ScreenContent( - topAppBarTitle = app.displayName - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/ReviewScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/details/ReviewScreen.kt deleted file mode 100644 index a987c53fc..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/ReviewScreen.kt +++ /dev/null @@ -1,190 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.items -import androidx.compose.material3.FilterChip -import androidx.compose.material3.Icon -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.adaptive.WindowAdaptiveInfo -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.paging.LoadState -import androidx.paging.PagingData -import androidx.paging.compose.LazyPagingItems -import androidx.paging.compose.collectAsLazyPagingItems -import androidx.paging.compose.itemKey -import com.aurora.extensions.adaptiveNavigationIcon -import com.aurora.extensions.emptyPagingItems -import com.aurora.extensions.isWindowCompact -import com.aurora.gplayapi.data.models.Review -import com.aurora.store.R -import com.aurora.store.compose.composable.ContainedLoadingIndicator -import com.aurora.store.compose.composable.Error -import com.aurora.store.compose.composable.TopAppBar -import com.aurora.store.compose.composable.details.ReviewListItem -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.compose.preview.ReviewPreviewProvider -import com.aurora.store.viewmodel.details.AppDetailsViewModel -import com.aurora.store.viewmodel.details.ReviewViewModel -import kotlin.random.Random -import kotlinx.coroutines.flow.MutableStateFlow - -@Composable -fun ReviewScreen( - packageName: String, - onNavigateUp: () -> Unit, - appDetailsViewModel: AppDetailsViewModel = hiltViewModel(key = packageName), - reviewViewModel: ReviewViewModel = hiltViewModel( - key = "$packageName/review", - creationCallback = { factory: ReviewViewModel.Factory -> - factory.create(appDetailsViewModel.app.value!!.packageName) - } - ), - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() -) { - val app by appDetailsViewModel.app.collectAsStateWithLifecycle() - val reviews = reviewViewModel.reviews.collectAsLazyPagingItems() - - val topAppBarTitle = when { - windowAdaptiveInfo.isWindowCompact -> app!!.displayName - else -> stringResource(R.string.details_ratings) - } - - ScreenContent( - topAppBarTitle = topAppBarTitle, - reviews = reviews, - onNavigateUp = onNavigateUp, - onFilter = { filter -> reviewViewModel.fetchReviews(filter) } - ) -} - -@Composable -private fun ScreenContent( - topAppBarTitle: String? = null, - onNavigateUp: () -> Unit = {}, - reviews: LazyPagingItems = emptyPagingItems(), - onFilter: (filter: Review.Filter) -> Unit = {}, - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() -) { - Scaffold( - topBar = { - TopAppBar( - title = topAppBarTitle, - navigationIcon = windowAdaptiveInfo.adaptiveNavigationIcon, - onNavigateUp = onNavigateUp - ) - } - ) { paddingValues -> - Column( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - .padding(horizontal = dimensionResource(R.dimen.padding_medium)) - ) { - FilterHeader { filter -> onFilter(filter) } - - when (reviews.loadState.refresh) { - is LoadState.Loading -> ContainedLoadingIndicator() - - is LoadState.Error -> { - Error( - modifier = Modifier.padding(paddingValues), - painter = painterResource(R.drawable.ic_disclaimer), - message = stringResource(R.string.error) - ) - } - - else -> { - LazyColumn(modifier = Modifier.fillMaxSize()) { - items( - count = reviews.itemCount, - key = reviews.itemKey { it.commentId } - ) { index -> - reviews[index]?.let { review -> ReviewListItem(review = review) } - } - } - } - } - } - } -} - -/** - * Composable to hold sticky header for filtering through the reviews - */ -@Composable -private fun FilterHeader(onClick: (filter: Review.Filter) -> Unit) { - var activeFilter by rememberSaveable { mutableStateOf(Review.Filter.ALL) } - - val filters = mapOf( - Review.Filter.ALL to R.string.filter_review_all, - Review.Filter.NEWEST to R.string.filter_latest, - Review.Filter.CRITICAL to R.string.filter_review_critical, - Review.Filter.POSITIVE to R.string.filter_review_positive, - Review.Filter.FIVE to R.string.filter_review_five, - Review.Filter.FOUR to R.string.filter_review_four, - Review.Filter.THREE to R.string.filter_review_three, - Review.Filter.TWO to R.string.filter_review_two, - Review.Filter.ONE to R.string.filter_review_one - ) - - LazyRow( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_normal)) - ) { - items(items = filters.keys.toList(), key = { item -> item }) { filter -> - val selected = activeFilter == filter - FilterChip( - onClick = { - activeFilter = filter - onClick(filter) - }, - label = { Text(text = stringResource(filters.getValue(filter))) }, - selected = selected, - leadingIcon = { - if (selected) { - Icon( - painter = painterResource(R.drawable.ic_check), - contentDescription = stringResource(filters.getValue(filter)) - ) - } - } - ) - } - } -} - -@Preview -@Composable -private fun ReviewScreenPreview(@PreviewParameter(ReviewPreviewProvider::class) review: Review) { - PreviewTemplate { - val reviews = List(10) { review.copy(commentId = Random.nextInt().toString()) } - val reviewsFlow = MutableStateFlow(PagingData.from(reviews)).collectAsLazyPagingItems() - - ScreenContent(reviews = reviewsFlow) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/ScreenshotScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/details/ScreenshotScreen.kt deleted file mode 100644 index a58cdf494..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/ScreenshotScreen.kt +++ /dev/null @@ -1,103 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details - -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.pager.HorizontalPager -import androidx.compose.foundation.pager.rememberPagerState -import androidx.compose.material3.Scaffold -import androidx.compose.material3.adaptive.WindowAdaptiveInfo -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.aurora.extensions.adaptiveNavigationIcon -import com.aurora.extensions.isWindowCompact -import com.aurora.gplayapi.data.models.Artwork -import com.aurora.store.R -import com.aurora.store.compose.composable.TopAppBar -import com.aurora.store.compose.composable.details.ScreenshotListItem -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.viewmodel.details.AppDetailsViewModel - -@Composable -fun ScreenshotScreen( - packageName: String, - index: Int, - onNavigateUp: () -> Unit, - viewModel: AppDetailsViewModel = hiltViewModel(key = packageName), - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() -) { - val app by viewModel.app.collectAsStateWithLifecycle() - - val topAppBarTitle = when { - windowAdaptiveInfo.isWindowCompact -> app!!.displayName - else -> stringResource(R.string.details_more_about_app) - } - - ScreenContent( - topAppBarTitle = topAppBarTitle, - onNavigateUp = onNavigateUp, - screenshots = app!!.screenshots, - index = index - ) -} - -@Composable -private fun ScreenContent( - topAppBarTitle: String? = null, - onNavigateUp: () -> Unit = {}, - screenshots: List = emptyList(), - index: Int = 0, - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() -) { - val displayMetrics = LocalContext.current.resources.displayMetrics - val pagerState = rememberPagerState(initialPage = index) { screenshots.size } - - LaunchedEffect(key1 = index) { - if (pagerState.currentPage != index) pagerState.scrollToPage(index) - } - - Scaffold( - topBar = { - TopAppBar( - title = topAppBarTitle, - navigationIcon = windowAdaptiveInfo.adaptiveNavigationIcon, - onNavigateUp = onNavigateUp - ) - } - ) { paddingValues -> - HorizontalPager( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize(), - state = pagerState - ) { page -> - val artwork = screenshots[page] - ScreenshotListItem( - modifier = Modifier.fillMaxSize(), - url = "${artwork.url}=rw-w${displayMetrics.widthPixels}-v1-e15" - ) - } - } -} - -@Preview -@Composable -private fun ScreenshotScreenPreview() { - PreviewTemplate { - ScreenContent( - topAppBarTitle = stringResource(R.string.app_name) - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Actions.kt b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Actions.kt deleted file mode 100644 index dae2e1cdf..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Actions.kt +++ /dev/null @@ -1,97 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details.composable - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.widthIn -import androidx.compose.material3.Button -import androidx.compose.material3.FilledTonalButton -import androidx.compose.material3.Text -import androidx.compose.material3.adaptive.WindowAdaptiveInfo -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.extensions.isWindowCompact -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Composable to display primary and secondary actions available for the app, supposed to be used - * as a part of the Column with proper vertical arrangement spacing in the AppDetailsScreen. - * @param primaryActionDisplayName Name of the primary action - * @param secondaryActionDisplayName Name of the secondary action - * @param isPrimaryActionEnabled Whether the primary action is enabled - * @param isSecondaryActionEnabled Whether the secondary action is enabled - * @param onPrimaryAction Callback when the primary action is clicked - * @param onSecondaryAction Callback when the secondary action is clicked - * @param windowAdaptiveInfo Adaptive window information - */ -@Composable -fun Actions( - primaryActionDisplayName: String, - secondaryActionDisplayName: String, - isPrimaryActionEnabled: Boolean = true, - isSecondaryActionEnabled: Boolean = true, - onPrimaryAction: () -> Unit = {}, - onSecondaryAction: () -> Unit = {}, - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() -) { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.padding_medium)) - ) { - val buttonWidthModifier = when { - windowAdaptiveInfo.isWindowCompact -> Modifier.weight(1F) - else -> Modifier.widthIn(min = dimensionResource(R.dimen.width_button)) - } - - FilledTonalButton( - modifier = buttonWidthModifier, - onClick = onSecondaryAction, - enabled = isSecondaryActionEnabled - ) { - Text( - text = secondaryActionDisplayName, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - - Button( - modifier = buttonWidthModifier, - onClick = onPrimaryAction, - enabled = isPrimaryActionEnabled - ) { - Text( - text = primaryActionDisplayName, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun ActionsPreview() { - PreviewTemplate { - Column( - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - Actions( - primaryActionDisplayName = stringResource(R.string.action_install), - secondaryActionDisplayName = stringResource(R.string.title_manual_download) - ) - } - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Changelog.kt b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Changelog.kt deleted file mode 100644 index eb25db005..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Changelog.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details.composable - -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.text.fromHtml -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.composable.Header -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Composable to display app changelog, supposed to be used as a part - * of the Column with proper vertical arrangement spacing in the AppDetailsScreen. - * @param changelog Changelog to show - */ -@Composable -fun Changelog(changelog: String) { - Header(title = stringResource(R.string.details_changelog)) - Box( - modifier = Modifier - .fillMaxWidth() - .clip(RoundedCornerShape(dimensionResource(R.dimen.radius_small))) - .background(color = MaterialTheme.colorScheme.secondaryContainer) - .padding(dimensionResource(R.dimen.padding_medium)) - ) { - Text( - text = if (changelog.isBlank()) { - AnnotatedString(text = stringResource(R.string.details_changelog_unavailable)) - } else { - AnnotatedString.fromHtml(htmlString = changelog) - }, - style = MaterialTheme.typography.bodyMedium - ) - } -} - -@Preview(showBackground = true) -@Composable -private fun ChangelogPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - Column( - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - Changelog(changelog = app.changes) - } - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Compatibility.kt b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Compatibility.kt deleted file mode 100644 index b0d26b2a4..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Compatibility.kt +++ /dev/null @@ -1,89 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details.composable - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.runtime.Composable -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import com.aurora.store.compose.composable.Header -import com.aurora.store.compose.composable.Info -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.compose.theme.successColor -import com.aurora.store.compose.theme.warningColor -import com.aurora.store.data.model.Scores - -/** - * Composable to display app compatibility rating from Plexus, supposed to be used as a part - * of the Column with proper vertical arrangement spacing in the AppDetailsScreen. - * @param needsGms Whether this app needs Google Play Services to work properly - * @param plexusScores Scores from the Plexus - */ -@Composable -fun Compatibility(needsGms: Boolean, plexusScores: Scores? = null) { - Header( - title = stringResource(R.string.details_compatibility_title), - subtitle = stringResource(R.string.plexus_powered) - ) - - if (!needsGms) { - Info( - painter = painterResource(R.drawable.ic_menu_about), - titleColor = successColor, - title = AnnotatedString( - text = stringResource(R.string.details_compatibility_gms_not_required_title) - ), - description = AnnotatedString( - text = stringResource(R.string.details_compatibility_gms_not_required_subtitle) - ) - ) - - // Nothing more to show - return - } - - Info( - painter = painterResource(R.drawable.ic_menu_about), - titleColor = warningColor, - title = AnnotatedString( - text = stringResource(R.string.details_compatibility_gms_required_title) - ), - description = AnnotatedString( - text = stringResource(R.string.details_compatibility_gms_required_subtitle) - ) - ) - - val scoresStatus = mapOf( - R.string.details_compatibility_no_gms to plexusScores?.aosp?.status, - R.string.details_compatibility_microg to plexusScores?.microG?.status - ) - scoresStatus.forEach { (title, description) -> - Info( - painter = painterResource(R.drawable.ic_android), - title = AnnotatedString(text = stringResource(title)), - description = AnnotatedString( - text = stringResource(description ?: R.string.details_compatibility_status_unknown) - ) - ) - } -} - -@Preview(showBackground = true) -@Composable -private fun CompatibilityPreview() { - PreviewTemplate { - Column( - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - Compatibility(needsGms = true) - } - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/composable/DataSafety.kt b/app/src/main/java/com/aurora/store/compose/ui/details/composable/DataSafety.kt deleted file mode 100644 index 01db06aa3..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/composable/DataSafety.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details.composable - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import com.aurora.extensions.browse -import com.aurora.gplayapi.data.models.App -import com.aurora.gplayapi.data.models.datasafety.Entry -import com.aurora.gplayapi.data.models.datasafety.EntryType -import com.aurora.gplayapi.data.models.datasafety.Report -import com.aurora.store.R -import com.aurora.store.compose.composable.Header -import com.aurora.store.compose.composable.Info -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Composable to display app's data safety report, supposed to be used as a part - * of the Column with proper vertical arrangement spacing in the AppDetailsScreen. - * @param report App's data safety report - * @param privacyPolicyUrl App's privacy policy URL - */ -@Composable -fun DataSafety(report: Report, privacyPolicyUrl: String) { - val context = LocalContext.current - - Header( - title = stringResource(R.string.details_data_safety_title), - subtitle = stringResource(R.string.details_data_safety_subtitle), - onClick = { context.browse(privacyPolicyUrl) } - ) - - report.entries.groupBy { it.type }.forEach { (type, entries) -> - when (type) { - EntryType.DATA_COLLECTED -> { - Info( - painter = painterResource(R.drawable.ic_cloud_upload), - title = AnnotatedString( - text = stringResource(R.string.details_data_safety_collect) - ), - description = AnnotatedString( - text = entries.first().subEntries.joinToString(", ") { it.name } - .ifBlank { - stringResource(R.string.details_data_safety_collect_none) - } - ) - ) - } - - EntryType.DATA_SHARED -> { - Info( - painter = painterResource(R.drawable.ic_share), - title = AnnotatedString( - text = stringResource(R.string.details_data_safety_shared) - ), - description = AnnotatedString( - text = entries.first().subEntries.joinToString(", ") { it.name } - .ifBlank { - stringResource(R.string.details_data_safety_share_none) - } - ) - ) - } - - // We don't care about any other sections - else -> {} - } - } -} - -@Preview(showBackground = true) -@Composable -private fun DataSafetyPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - Column( - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - DataSafety( - privacyPolicyUrl = app.privacyPolicyUrl, - report = Report( - packageName = app.packageName, - entries = listOf( - Entry( - type = EntryType.DATA_COLLECTED, - name = String(), - description = String() - ), - Entry( - type = EntryType.DATA_SHARED, - name = String(), - description = String() - ) - ) - ) - ) - } - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Details.kt b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Details.kt deleted file mode 100644 index 7bf2e2ce2..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Details.kt +++ /dev/null @@ -1,169 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details.composable - -import android.text.format.Formatter -import androidx.compose.animation.AnimatedContent -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredSize -import androidx.compose.foundation.text.InlineTextContent -import androidx.compose.foundation.text.appendInlineContent -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalLayoutDirection -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.Placeholder -import androidx.compose.ui.text.PlaceholderVerticalAlign -import androidx.compose.ui.text.buildAnnotatedString -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.unit.LayoutDirection -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.composable.app.AnimatedAppIcon -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.data.model.AppState -import com.aurora.store.util.CommonUtil -import com.aurora.store.util.PackageUtil - -/** - * Composable to display basic app details, supposed to be used as a part - * of the Column with proper vertical arrangement spacing in the AppDetailsScreen. - * @param app App to show details about - * @param state State of the app - * @param onNavigateToDetailsDevProfile Callback when the developer name is tapped - */ -@Composable -fun Details( - app: App, - state: AppState = AppState.Unavailable, - onNavigateToDetailsDevProfile: (developerName: String) -> Unit = {} -) { - val context = LocalContext.current - val versionName = if (state is AppState.Installed) state.versionName else app.versionName - val versionCode = if (state is AppState.Installed) state.versionCode else app.versionCode - val speed = if (state is AppState.Downloading) state.speed else 0 - val timeRemaining = if (state is AppState.Downloading) state.timeRemaining else 0 - - @Composable - fun UpdatableVersion() { - val updateVersion = stringResource(R.string.version, versionName, versionCode) - val localVersion = stringResource( - R.string.version, - PackageUtil.getInstalledVersionName(context, app.packageName), - PackageUtil.getInstalledVersionCode(context, app.packageName) - ) - - Text( - style = MaterialTheme.typography.bodySmall, - text = buildAnnotatedString { - when (LocalLayoutDirection.current) { - LayoutDirection.Ltr -> append(localVersion) - LayoutDirection.Rtl -> append(updateVersion) - } - - append(" ") - appendInlineContent("iconId", "[arrow]") - append(" ") - - when (LocalLayoutDirection.current) { - LayoutDirection.Ltr -> append(updateVersion) - LayoutDirection.Rtl -> append(localVersion) - } - }, - inlineContent = mapOf( - "iconId" to InlineTextContent( - Placeholder( - width = MaterialTheme.typography.bodySmall.fontSize, - height = MaterialTheme.typography.bodySmall.fontSize, - placeholderVerticalAlign = PlaceholderVerticalAlign.TextCenter - ) - ) { - Icon( - painter = painterResource(R.drawable.ic_arrow_forward), - contentDescription = null - ) - } - ) - ) - } - - Row(modifier = Modifier.fillMaxWidth()) { - AnimatedAppIcon( - modifier = Modifier.requiredSize(dimensionResource(R.dimen.icon_size_large)), - iconUrl = app.iconArtwork.url, - inProgress = state.inProgress(), - progress = state.progress() - ) - Column(modifier = Modifier.padding(horizontal = dimensionResource(R.dimen.margin_small))) { - Text( - text = app.displayName, - style = MaterialTheme.typography.titleLarge, - maxLines = 2, - overflow = TextOverflow.Ellipsis - ) - Text( - modifier = Modifier - .clickable(onClick = { onNavigateToDetailsDevProfile(app.developerName) }), - text = app.developerName, - style = MaterialTheme.typography.bodyMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - color = MaterialTheme.colorScheme.primary - ) - AnimatedContent(targetState = state::class) { cState -> - if (cState == AppState.Updatable::class) { - UpdatableVersion() - return@AnimatedContent - } - - Text( - style = MaterialTheme.typography.bodySmall, - text = when (cState) { - AppState.Installing::class, - AppState.Downloading::class -> { - "${Formatter.formatShortFileSize(context, speed)}/s" + - ", " + CommonUtil.getETAString(context, timeRemaining) - } - - AppState.Queued::class -> stringResource(R.string.status_queued) - - AppState.Purchasing::class -> stringResource(R.string.preparing_to_install) - - else -> { - stringResource(R.string.version, versionName, versionCode) - } - } - ) - } - } - } -} - -@Preview(showBackground = true) -@Composable -private fun DetailsPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - Column( - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - Details(app = app) - } - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/composable/DeveloperDetails.kt b/app/src/main/java/com/aurora/store/compose/ui/details/composable/DeveloperDetails.kt deleted file mode 100644 index 77d77d51f..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/composable/DeveloperDetails.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details.composable - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.text.fromHtml -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import com.aurora.extensions.browse -import com.aurora.extensions.copyToClipBoard -import com.aurora.extensions.mailTo -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.composable.Header -import com.aurora.store.compose.composable.Info -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Composable to display details of the app developer, supposed to be used as a part - * of the Column with proper vertical arrangement spacing in the AppDetailsScreen. - * @param address Address of the app developer - * @param website Website of the app developer - * @param email Email address of the app developer - */ -@Composable -fun DeveloperDetails(address: String, website: String, email: String) { - val context = LocalContext.current - - Header(title = stringResource(R.string.details_dev_details)) - Column { - if (website.isNotBlank()) { - Info( - title = AnnotatedString(text = stringResource(R.string.details_dev_website)), - description = AnnotatedString(text = website), - painter = painterResource(R.drawable.ic_network), - onClick = { context.browse(website) } - ) - } - - if (email.isNotBlank()) { - Info( - title = AnnotatedString(text = stringResource(R.string.details_dev_email)), - description = AnnotatedString(text = email), - painter = painterResource(R.drawable.ic_mail), - onClick = { context.mailTo(email) } - ) - } - - if (address.isNotBlank()) { - Info( - title = AnnotatedString(text = stringResource(R.string.details_dev_address)), - description = AnnotatedString.fromHtml(htmlString = address), - painter = painterResource(R.drawable.ic_person_location), - onClick = { context.copyToClipBoard(address) } - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun DeveloperDetailsPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - Column( - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - DeveloperDetails( - address = app.developerAddress, - website = app.developerWebsite, - email = app.developerEmail - ) - } - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Privacy.kt b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Privacy.kt deleted file mode 100644 index b81684510..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Privacy.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details.composable - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.runtime.Composable -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import com.aurora.store.compose.composable.Header -import com.aurora.store.compose.composable.Info -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.compose.theme.successColor -import com.aurora.store.compose.theme.warningColor -import com.aurora.store.data.model.Report - -/** - * Composable to display app's privacy report from ExodusPrivacy, supposed to be used as a part - * of the Column with proper vertical arrangement spacing in the AppDetailsScreen. - * @param report Report from Exodus Privacy for the app - * @param onNavigateToDetailsExodus Callback when the user navigates - */ -@Composable -fun Privacy(report: Report?, onNavigateToDetailsExodus: (() -> Unit)? = null) { - Header( - title = stringResource(R.string.details_privacy), - subtitle = stringResource(R.string.exodus_powered), - onClick = onNavigateToDetailsExodus - ) - - val reportStatus = when { - report == null -> stringResource(R.string.failed_to_fetch_report) - - report.id == -1 -> stringResource(R.string.exodus_progress) - - else -> if (report.trackers.isEmpty()) { - stringResource(R.string.exodus_no_tracker) - } else { - stringResource(R.string.exodus_report_trackers, report.trackers.size, report.version) - } - } - - Info( - painter = painterResource(R.drawable.ic_visibility), - titleColor = when { - report != null && report.trackers.isEmpty() -> successColor - else -> warningColor - }, - title = AnnotatedString(text = reportStatus), - description = AnnotatedString(text = stringResource(R.string.exodus_tracker_desc)) - ) -} - -@Preview(showBackground = true) -@Composable -private fun PrivacyPreview() { - PreviewTemplate { - Column( - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - Privacy(report = Report(), onNavigateToDetailsExodus = {}) - } - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/composable/RatingAndReviews.kt b/app/src/main/java/com/aurora/store/compose/ui/details/composable/RatingAndReviews.kt deleted file mode 100644 index c48dd5f04..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/composable/RatingAndReviews.kt +++ /dev/null @@ -1,163 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details.composable - -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredHeight -import androidx.compose.foundation.pager.HorizontalPager -import androidx.compose.foundation.pager.rememberPagerState -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.material3.adaptive.WindowAdaptiveInfo -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.tooling.preview.datasource.LoremIpsum -import androidx.compose.ui.util.fastForEach -import com.aurora.extensions.isWindowCompact -import com.aurora.gplayapi.data.models.App -import com.aurora.gplayapi.data.models.Rating -import com.aurora.gplayapi.data.models.Review -import com.aurora.store.R -import com.aurora.store.compose.composable.Header -import com.aurora.store.compose.composable.details.RatingListItem -import com.aurora.store.compose.composable.details.ReviewListItem -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate -import java.util.Locale - -/** - * Composable to display reviews of the app, supposed to be used as a part - * of the Column with proper vertical arrangement spacing in the AppDetailsScreen. - * @param rating Rating of the app - * @param featuredReviews Featured app reviews - * @param onNavigateToDetailsReview Callback when the user navigates - * @param windowAdaptiveInfo Adaptive window information - */ -@Composable -fun RatingAndReviews( - rating: Rating, - featuredReviews: List = emptyList(), - onNavigateToDetailsReview: () -> Unit = {}, - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() -) { - val stars = listOf( - rating.oneStar, - rating.twoStar, - rating.threeStar, - rating.fourStar, - rating.fiveStar - ).map { it.toFloat() }.also { - // No ratings available, nothing to show - if (it.sum() == 0F) return - } - - val avgRating = when { - windowAdaptiveInfo.isWindowCompact -> { - String.format(Locale.getDefault(), "%.1f", rating.average) - } - - else -> { - String.format(Locale.getDefault(), "%.1f / 5.0", rating.average) - } - } - - Header( - title = stringResource(R.string.details_ratings), - onClick = onNavigateToDetailsReview - ) - - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_small)) - ) { - Column( - modifier = Modifier.padding(dimensionResource(R.dimen.padding_medium)), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text( - text = avgRating, - maxLines = 1, - style = MaterialTheme.typography.displayMedium, - overflow = TextOverflow.Ellipsis - ) - Text( - text = rating.abbreviatedLabel, - maxLines = 1, - style = MaterialTheme.typography.bodySmall, - overflow = TextOverflow.Ellipsis - ) - } - - Column( - modifier = Modifier.padding(dimensionResource(R.dimen.padding_medium)), - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_small)) - ) { - stars.reversed().fastForEach { star -> - RatingListItem( - label = (stars.indexOf(star) + 1).toString(), - rating = star / stars.sum() - ) - } - } - } - - if (featuredReviews.isNotEmpty()) { - val pagerState = rememberPagerState { featuredReviews.size } - HorizontalPager( - state = pagerState, - contentPadding = PaddingValues(dimensionResource(R.dimen.padding_large)), - pageSpacing = dimensionResource(R.dimen.margin_medium) - ) { page -> - Box( - modifier = Modifier - .fillMaxWidth() - .clip(RoundedCornerShape(dimensionResource(R.dimen.radius_small))) - .background(color = MaterialTheme.colorScheme.surfaceContainer) - .requiredHeight(dimensionResource(R.dimen.review_height)) - ) { - ReviewListItem(review = featuredReviews[page]) - } - } - } -} - -@Preview(showBackground = true) -@Composable -private fun RatingAndReviewsPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - val reviews = List(3) { - Review( - userName = "Rahul Kumar Patel", - timeStamp = 1745750879, - rating = 4, - comment = LoremIpsum(40).values.first() - ) - } - PreviewTemplate { - Column( - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - RatingAndReviews(rating = app.rating, featuredReviews = reviews) - } - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Screenshots.kt b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Screenshots.kt deleted file mode 100644 index b995cf7c2..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Screenshots.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details.composable - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import com.aurora.gplayapi.data.models.App -import com.aurora.gplayapi.data.models.Artwork -import com.aurora.store.R -import com.aurora.store.compose.composable.details.ScreenshotListItem -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Composable to display screenshots of the app, supposed to be used as a part - * of the Column with proper vertical arrangement spacing in the AppDetailsScreen. - * @param screenshots Screenshots to display - * @param onNavigateToScreenshot Callback when a screenshot is clicked - */ -@Composable -fun Screenshots(screenshots: List, onNavigateToScreenshot: (index: Int) -> Unit = {}) { - LazyRow(horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_small))) { - items(items = screenshots, key = { artwork -> artwork.url }) { artwork -> - ScreenshotListItem( - modifier = Modifier - .height(dimensionResource(R.dimen.screenshot_height)) - .clip(RoundedCornerShape(dimensionResource(R.dimen.radius_small))) - .clickable { onNavigateToScreenshot(screenshots.indexOf(artwork)) }, - url = "${artwork.url}=rw-w480-v1-e15" - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun ScreenshotsPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - Column( - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - Screenshots(screenshots = app.screenshots) - } - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Tags.kt b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Tags.kt deleted file mode 100644 index 113f49e2e..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Tags.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details.composable - -import android.text.format.Formatter -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.items -import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.composable.app.TagListItem -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.util.CommonUtil - -/** - * Composable to display tags related to the app, supposed to be used as a part - * of the Column with proper vertical arrangement spacing in the AppDetailsScreen. - * @param app App to show tags - */ -@Composable -fun Tags(app: App) { - val context = LocalContext.current - - val installsLabel = CommonUtil.addDiPrefix(app.installs) - val averageRating = if (app.labeledRating == "0.0" || app.labeledRating.isBlank()) { - null - } else { - app.labeledRating - } - val paidLabel = if (app.isFree) { - stringResource(R.string.details_free) - } else { - stringResource(R.string.details_paid) - } - val adsLabel = if (app.containsAds) { - stringResource(R.string.details_contains_ads) - } else { - stringResource(R.string.details_no_ads) - } - - val tags = mapOf( - averageRating to R.drawable.ic_star, - installsLabel to R.drawable.ic_download_manager, - Formatter.formatShortFileSize(context, app.size) to R.drawable.ic_apk_install, - app.updatedOn to R.drawable.ic_updates, - paidLabel to R.drawable.ic_paid, - adsLabel to R.drawable.ic_campaign - ).filterKeys { it != null } - - LazyRow( - horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.padding_medium)) - ) { - items(items = tags.keys.toList()) { label -> - TagListItem(label = label!!, painter = painterResource(tags.getValue(label))) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun TagsPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - Column( - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - Tags(app = app) - } - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Testing.kt b/app/src/main/java/com/aurora/store/compose/ui/details/composable/Testing.kt deleted file mode 100644 index abf6941c4..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/composable/Testing.kt +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details.composable - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.material3.FilledTonalButton -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.composable.Header -import com.aurora.store.compose.composable.Info -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Composable to display app's beta testing status, supposed to be used as a part of the - * Column with proper vertical arrangement spacing in the AppDetailsScreen. - * - * @param isSubscribed Whether the user is subscribed to the beta testing program - * @param onTestingSubscriptionChange Callback when the the subscription button is clicked - */ -@Composable -fun Testing(isSubscribed: Boolean, onTestingSubscriptionChange: (subscribe: Boolean) -> Unit = {}) { - Header(title = stringResource(R.string.details_beta)) - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_small)) - ) { - Info( - modifier = Modifier.weight(1F), - painter = painterResource(R.drawable.ic_experiment), - title = AnnotatedString( - text = if (isSubscribed) { - stringResource(R.string.details_beta_subscribed) - } else { - stringResource(R.string.details_beta_available) - } - ), - description = AnnotatedString(text = stringResource(R.string.details_beta_description)) - ) - FilledTonalButton(onClick = { onTestingSubscriptionChange(!isSubscribed) }) { - Text( - text = if (isSubscribed) { - stringResource(R.string.action_leave) - } else { - stringResource(R.string.action_join) - }, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun TestingPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - Column( - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - Testing(isSubscribed = app.testingProgram!!.isSubscribed) - } - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/menu/AppDetailsMenu.kt b/app/src/main/java/com/aurora/store/compose/ui/details/menu/AppDetailsMenu.kt deleted file mode 100644 index 3b6b92fa3..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/menu/AppDetailsMenu.kt +++ /dev/null @@ -1,103 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details.menu - -import androidx.compose.foundation.layout.Box -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import com.aurora.store.compose.composable.TopAppBar -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.data.model.AppState - -/** - * Menu for the app details screen - * @param modifier The modifier to be applied to the composable - * @param onMenuItemClicked Callback when a menu item has been clicked - * @see MenuItem - */ -@Composable -fun AppDetailsMenu( - modifier: Modifier = Modifier, - state: AppState = AppState.Unavailable, - isFavorite: Boolean = false, - isExpanded: Boolean = false, - onMenuItemClicked: (menuItem: MenuItem) -> Unit = {} -) { - var expanded by remember { mutableStateOf(isExpanded) } - fun onClick(menuItem: MenuItem) { - onMenuItemClicked(menuItem) - expanded = false - } - - IconButton(onClick = { onClick(MenuItem.FAVORITE) }) { - Icon( - painter = if (isFavorite) { - painterResource(R.drawable.ic_favorite_checked) - } else { - painterResource(R.drawable.ic_favorite_unchecked) - }, - contentDescription = stringResource(R.string.action_favourite) - ) - } - - IconButton(onClick = { onClick(MenuItem.SHARE) }) { - Icon( - painter = painterResource(R.drawable.ic_share), - contentDescription = stringResource(R.string.action_share) - ) - } - - Box(modifier = modifier) { - IconButton(onClick = { expanded = true }) { - Icon( - painter = painterResource(R.drawable.ic_more_vert), - contentDescription = stringResource(R.string.menu) - ) - } - DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) { - DropdownMenuItem( - text = { Text(text = stringResource(R.string.title_manual_download)) }, - onClick = { onClick(MenuItem.MANUAL_DOWNLOAD) }, - enabled = !state.inProgress() - ) - DropdownMenuItem( - text = { Text(text = stringResource(R.string.action_info)) }, - onClick = { onClick(MenuItem.APP_INFO) }, - enabled = state is AppState.Installed || state is AppState.Updatable - ) - DropdownMenuItem( - text = { Text(text = stringResource(R.string.action_home_screen)) }, - onClick = { onClick(MenuItem.ADD_TO_HOME) }, - enabled = state is AppState.Installed || state is AppState.Updatable - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun AppDetailsMenuPreview() { - PreviewTemplate { - TopAppBar( - actions = { - AppDetailsMenu(isFavorite = true, isExpanded = true) - } - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/menu/MenuItem.kt b/app/src/main/java/com/aurora/store/compose/ui/details/menu/MenuItem.kt deleted file mode 100644 index a9e65355b..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/menu/MenuItem.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details.menu - -/** - * Valid menu items for app details screen for handling clicks - */ -enum class MenuItem { - FAVORITE, - SHARE, - MANUAL_DOWNLOAD, - APP_INFO, - ADD_TO_HOME -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/details/navigation/ExtraScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/details/navigation/ExtraScreen.kt deleted file mode 100644 index 3f1e0f181..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/details/navigation/ExtraScreen.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.details.navigation - -import android.os.Parcelable -import androidx.navigation3.runtime.NavKey -import kotlinx.parcelize.Parcelize -import kotlinx.serialization.Serializable - -/** - * Extra destinations for app detail's screen - * - * All of these destinations require and show information related to an app and thus aren't part of - * the main navigation display class. - */ -@Parcelize -@Serializable -sealed class ExtraScreen : NavKey, Parcelable { - - @Serializable - data object More : ExtraScreen() - - @Serializable - data class Screenshot(val index: Int) : ExtraScreen() - - @Serializable - data object Exodus : ExtraScreen() - - @Serializable - data object Review : ExtraScreen() - - @Serializable - data object Permission : ExtraScreen() - - @Serializable - data object ManualDownload : ExtraScreen() - - @Serializable - data object MicroG : ExtraScreen() -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/dev/DevProfileScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/dev/DevProfileScreen.kt deleted file mode 100644 index 6adbc41e6..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/dev/DevProfileScreen.kt +++ /dev/null @@ -1,140 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.dev - -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.material3.Scaffold -import androidx.compose.material3.adaptive.WindowAdaptiveInfo -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.paging.LoadState -import androidx.paging.PagingData -import androidx.paging.compose.LazyPagingItems -import androidx.paging.compose.collectAsLazyPagingItems -import androidx.paging.compose.itemKey -import com.aurora.extensions.adaptiveNavigationIcon -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.composable.ContainedLoadingIndicator -import com.aurora.store.compose.composable.Error -import com.aurora.store.compose.composable.TopAppBar -import com.aurora.store.compose.composable.app.LargeAppListItem -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.viewmodel.details.DevProfileViewModel -import com.aurora.store.viewmodel.search.SearchViewModel -import kotlin.random.Random -import kotlinx.coroutines.flow.MutableStateFlow - -/** - * Screen to display apps from a developer using the developerId - * for e.g. https://play.google.com/store/apps/dev?id=5700313618786177705 - */ -@Composable -fun DevProfileScreen( - developerId: String, - onNavigateUp: () -> Unit, - onNavigateToAppDetails: (packageName: String) -> Unit, - viewModel: DevProfileViewModel = hiltViewModel() -) { - // TODO: Implement when migrating logic for current DevProfileFragment -} - -/** - * Screen to display apps from a developer by searching using the publisherId - * for e.g. https://play.google.com/store/apps/developer?id=The+Tor+Project - */ -@Composable -fun DevProfileScreen( - publisherId: String, - onNavigateUp: () -> Unit, - onNavigateToAppDetails: (packageName: String) -> Unit, - viewModel: SearchViewModel = hiltViewModel() -) { - val apps = viewModel.apps.collectAsLazyPagingItems() - - LaunchedEffect(key1 = Unit) { viewModel.search("pub:$publisherId") } - - ScreenContent( - apps = apps, - topAppBarTitle = publisherId, - onNavigateUp = onNavigateUp, - onNavigateToAppDetails = onNavigateToAppDetails - ) -} - -@Composable -private fun ScreenContent( - apps: LazyPagingItems, - topAppBarTitle: String, - onNavigateUp: () -> Unit = {}, - onNavigateToAppDetails: (packageName: String) -> Unit = {}, - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() -) { - Scaffold( - topBar = { - TopAppBar( - title = topAppBarTitle, - navigationIcon = windowAdaptiveInfo.adaptiveNavigationIcon, - onNavigateUp = onNavigateUp - ) - } - ) { paddingValues -> - when (apps.loadState.refresh) { - is LoadState.Loading -> ContainedLoadingIndicator() - - is LoadState.Error -> { - Error( - modifier = Modifier.padding(paddingValues), - painter = painterResource(R.drawable.ic_disclaimer), - message = stringResource(R.string.error) - ) - } - - else -> { - LazyColumn( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - .padding(vertical = dimensionResource(R.dimen.padding_medium)) - ) { - items(count = apps.itemCount, key = apps.itemKey { it.id }) { index -> - apps[index]?.let { app -> - LargeAppListItem( - app = app, - onClick = { onNavigateToAppDetails(app.packageName) } - ) - } - } - } - } - } - } -} - -@Preview -@Composable -private fun DevProfileScreenPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - val apps = List(10) { app.copy(id = Random.nextInt()) } - val pagedApps = MutableStateFlow(PagingData.from(apps)).collectAsLazyPagingItems() - - ScreenContent( - topAppBarTitle = app.developerName, - apps = pagedApps - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/dispenser/DispenserScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/dispenser/DispenserScreen.kt deleted file mode 100644 index 5df1b7124..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/dispenser/DispenserScreen.kt +++ /dev/null @@ -1,140 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.dispenser - -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.material3.FloatingActionButton -import androidx.compose.material3.Icon -import androidx.compose.material3.Scaffold -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.aurora.extensions.copyToClipBoard -import com.aurora.store.R -import com.aurora.store.compose.composable.DispenserListItem -import com.aurora.store.compose.composable.Error -import com.aurora.store.compose.composable.TopAppBar -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.viewmodel.dispenser.DispenserViewModel - -@Composable -fun DispenserScreen(onNavigateUp: () -> Unit, viewModel: DispenserViewModel = hiltViewModel()) { - val dispensers by viewModel.dispensers.collectAsStateWithLifecycle() - - var shouldShowInputDialog by rememberSaveable { mutableStateOf(false) } - if (shouldShowInputDialog) { - InputDispenserDialog( - onAdd = { url -> - viewModel.addDispenser(url) - shouldShowInputDialog = false - }, - onDismiss = { shouldShowInputDialog = false } - ) - } - - var shouldRemoveDispenser: String? by rememberSaveable { mutableStateOf(null) } - shouldRemoveDispenser?.let { url -> - RemoveDispenserDialog( - url = url, - onRemove = { - viewModel.removeDispenser(url) - shouldRemoveDispenser = null - }, - onDismiss = { shouldRemoveDispenser = null } - ) - } - - ScreenContent( - dispensers = dispensers, - onNavigateUp = onNavigateUp, - onAddDispenser = { shouldShowInputDialog = true }, - onRemoveDispenser = { url -> shouldRemoveDispenser = url } - ) -} - -@Composable -private fun ScreenContent( - onNavigateUp: () -> Unit = {}, - dispensers: Set = emptySet(), - onAddDispenser: () -> Unit = {}, - onRemoveDispenser: (url: String) -> Unit = {} -) { - val context = LocalContext.current - - Scaffold( - topBar = { - TopAppBar( - title = stringResource(R.string.pref_dispenser_title), - onNavigateUp = onNavigateUp - ) - }, - floatingActionButton = { - if (dispensers.isNotEmpty()) { - FloatingActionButton(onClick = onAddDispenser) { - Icon( - painter = painterResource(R.drawable.ic_add), - contentDescription = stringResource(R.string.add_dispenser_title) - ) - } - } - } - ) { paddingValues -> - if (dispensers.isEmpty()) { - Error( - modifier = Modifier.padding(paddingValues), - painter = painterResource(R.drawable.ic_server), - message = stringResource(R.string.no_dispensers_available), - actionMessage = stringResource(R.string.add_dispenser_title), - onAction = onAddDispenser - ) - } else { - LazyColumn( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - .padding(vertical = dimensionResource(R.dimen.padding_medium)) - ) { - items(items = dispensers.toList(), key = { url -> url }) { url -> - DispenserListItem( - url = url, - onClick = { context.copyToClipBoard(url) }, - onClear = { onRemoveDispenser(url) } - ) - } - } - } - } -} - -@Preview -@Composable -private fun DispenserScreenPreview() { - val dispensers = List(10) { "https://auroraoss.com/api/auth/$it" } - PreviewTemplate { - ScreenContent(dispensers = dispensers.toSet()) - } -} - -@Preview -@Composable -private fun DispenserScreenEmptyPreview() { - PreviewTemplate { - ScreenContent() - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/dispenser/InputDispenserDialog.kt b/app/src/main/java/com/aurora/store/compose/ui/dispenser/InputDispenserDialog.kt deleted file mode 100644 index abfe565b9..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/dispenser/InputDispenserDialog.kt +++ /dev/null @@ -1,93 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.dispenser - -import android.util.Patterns -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusRequester -import androidx.compose.ui.platform.LocalFocusManager -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.TextFieldValue -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.aurora.store.R -import kotlinx.coroutines.android.awaitFrame - -/** - * Dialog for adding a new token dispenser - * @param onAdd Callback on adding a new dispenser - * @param onDismiss Callback on dismiss - */ -@Composable -fun InputDispenserDialog(onAdd: (url: String) -> Unit = {}, onDismiss: () -> Unit = {}) { - val focusManager = LocalFocusManager.current - val focusRequester = remember { FocusRequester() } - var url by remember { mutableStateOf(TextFieldValue()) } - - LaunchedEffect(focusRequester) { - awaitFrame() - focusRequester.requestFocus() - } - - AlertDialog( - title = { Text(text = stringResource(R.string.add_dispenser_title)) }, - text = { - Column( - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - Text(text = stringResource(R.string.add_dispenser_summary)) - OutlinedTextField( - modifier = Modifier - .fillMaxWidth() - .focusRequester(focusRequester), - value = url, - placeholder = { Text(text = stringResource(R.string.add_dispenser_hint)) }, - onValueChange = { url = it }, - shape = RoundedCornerShape(10.dp), - singleLine = true, - keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }) - ) - } - }, - onDismissRequest = onDismiss, - confirmButton = { - TextButton( - onClick = { onAdd(url.text) }, - enabled = Patterns.WEB_URL.matcher(url.text).matches() - ) { - Text(text = stringResource(R.string.add)) - } - }, - dismissButton = { - TextButton(onClick = onDismiss) { - Text(text = stringResource(android.R.string.cancel)) - } - } - ) -} - -@Preview -@Composable -private fun InputDispenserDialogPreview() { - InputDispenserDialog() -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/dispenser/RemoveDispenserDialog.kt b/app/src/main/java/com/aurora/store/compose/ui/dispenser/RemoveDispenserDialog.kt deleted file mode 100644 index b0ecabce6..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/dispenser/RemoveDispenserDialog.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.dispenser - -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R - -/** - * Dialog for removing a token dispenser - * @param onRemove Callback on removing a dispenser - * @param onDismiss Callback on dismiss - */ -@Composable -fun RemoveDispenserDialog(url: String, onRemove: () -> Unit = {}, onDismiss: () -> Unit = {}) { - AlertDialog( - title = { Text(text = stringResource(R.string.remove_dispenser_title)) }, - text = { - Text(text = stringResource(R.string.remove_dispenser_summary, url)) - }, - onDismissRequest = onDismiss, - confirmButton = { - TextButton(onClick = onRemove) { - Text(text = stringResource(R.string.remove)) - } - }, - dismissButton = { - TextButton(onClick = onDismiss) { - Text(text = stringResource(android.R.string.cancel)) - } - } - ) -} - -@Preview -@Composable -private fun RemoveDispenserDialogPreview() { - RemoveDispenserDialog(url = "https://auroraoss.com/api/auth/") -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/downloads/DownloadsScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/downloads/DownloadsScreen.kt deleted file mode 100644 index f9a3dfe1b..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/downloads/DownloadsScreen.kt +++ /dev/null @@ -1,193 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.downloads - -import androidx.activity.compose.rememberLauncherForActivityResult -import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.material3.Scaffold -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.paging.LoadState -import androidx.paging.PagingData -import androidx.paging.compose.LazyPagingItems -import androidx.paging.compose.collectAsLazyPagingItems -import androidx.paging.compose.itemKey -import com.aurora.extensions.emptyPagingItems -import com.aurora.extensions.toast -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.composable.ContainedLoadingIndicator -import com.aurora.store.compose.composable.DownloadListItem -import com.aurora.store.compose.composable.Error -import com.aurora.store.compose.composable.TopAppBar -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.compose.ui.downloads.menu.DownloadsMenu -import com.aurora.store.compose.ui.downloads.menu.MenuItem -import com.aurora.store.data.model.DownloadStatus -import com.aurora.store.data.room.download.Download -import com.aurora.store.viewmodel.downloads.DownloadsViewModel -import kotlin.random.Random -import kotlinx.coroutines.flow.MutableStateFlow - -@Composable -fun DownloadsScreen( - onNavigateUp: () -> Unit, - viewModel: DownloadsViewModel = hiltViewModel(), - onNavigateToAppDetails: (packageName: String) -> Unit -) { - val context = LocalContext.current - val downloads = viewModel.downloads.collectAsLazyPagingItems() - - val exportMimeType = "application/zip" - var requestedExport by rememberSaveable { mutableStateOf(null) } - val documentLauncher = rememberLauncherForActivityResult( - contract = ActivityResultContracts.CreateDocument(exportMimeType), - onResult = { - if (it != null) { - requestedExport?.let { download -> viewModel.export(download, it) } - } else { - context.toast(R.string.failed_apk_export) - } - requestedExport = null - } - ) - - ScreenContent( - onNavigateUp = onNavigateUp, - downloads = downloads, - onNavigateToAppDetails = onNavigateToAppDetails, - onCancelAll = { viewModel.cancelAll() }, - onForceClearAll = { viewModel.clearAll() }, - onClearFinished = { viewModel.clearFinished() }, - onCancel = { packageName -> viewModel.cancel(packageName) }, - onInstall = { download -> viewModel.install(download) }, - onClear = { download -> - viewModel.clear(download.packageName, download.versionCode) - }, - onExport = { download -> - requestedExport = download - documentLauncher.launch("${download.packageName}.zip") - } - ) -} - -@Composable -private fun ScreenContent( - downloads: LazyPagingItems = emptyPagingItems(), - onNavigateUp: () -> Unit = {}, - onNavigateToAppDetails: (packageName: String) -> Unit = {}, - onCancel: (packageName: String) -> Unit = {}, - onClear: (download: Download) -> Unit = {}, - onExport: (download: Download) -> Unit = {}, - onInstall: (download: Download) -> Unit = {}, - onCancelAll: () -> Unit = {}, - onForceClearAll: () -> Unit = {}, - onClearFinished: () -> Unit = {} -) { - /* - * For some reason paging3 frequently out-of-nowhere invalidates the list which causes - * the loading animation to play again even if the keys are same causing a glitching effect. - * - * Save the initial loading state to make sure we don't replay the loading animation again. - */ - var initialLoad by rememberSaveable { mutableStateOf(true) } - - @Composable - fun SetupMenu() { - DownloadsMenu { menuItem -> - when (menuItem) { - MenuItem.CANCEL_ALL -> onCancelAll() - MenuItem.FORCE_CLEAR_ALL -> onForceClearAll() - MenuItem.CLEAR_FINISHED -> onClearFinished() - } - } - } - - Scaffold( - topBar = { - TopAppBar( - title = stringResource(R.string.title_download_manager), - onNavigateUp = onNavigateUp, - actions = { if (downloads.itemCount != 0) SetupMenu() } - ) - } - ) { paddingValues -> - Column( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - .padding(vertical = dimensionResource(R.dimen.padding_medium)) - ) { - when { - downloads.loadState.refresh is LoadState.Loading && initialLoad -> { - ContainedLoadingIndicator() - } - - else -> { - initialLoad = false - - if (downloads.itemCount == 0) { - Error( - modifier = Modifier.padding(paddingValues), - painter = painterResource(R.drawable.ic_download_manager), - message = stringResource(R.string.download_none) - ) - } else { - LazyColumn { - items( - count = downloads.itemCount, - key = downloads.itemKey { it.packageName } - ) { index -> - downloads[index]?.let { download -> - DownloadListItem( - modifier = Modifier.animateItem(), - download = download, - onClick = { onNavigateToAppDetails(download.packageName) }, - onClear = { onClear(download) }, - onCancel = { onCancel(download.packageName) }, - onExport = { onExport(download) }, - onInstall = { onInstall(download) } - ) - } - } - } - } - } - } - } - } -} - -@Preview -@Composable -private fun DownloadsScreenPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - val downloads = List(10) { - Download.fromApp(app).copy( - packageName = Random.nextInt().toString(), - status = DownloadStatus.entries.random() - ) - } - val pagedDownloads = MutableStateFlow(PagingData.from(downloads)).collectAsLazyPagingItems() - ScreenContent(downloads = pagedDownloads) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/downloads/menu/DownloadsMenu.kt b/app/src/main/java/com/aurora/store/compose/ui/downloads/menu/DownloadsMenu.kt deleted file mode 100644 index ad1aaeaa1..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/downloads/menu/DownloadsMenu.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.downloads.menu - -import androidx.compose.foundation.layout.Box -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Menu for the blacklist screen - * @param modifier The modifier to be applied to the composable - * @param onMenuItemClicked Callback when a menu item has been clicked - * @see MenuItem - */ -@Composable -fun DownloadsMenu( - modifier: Modifier = Modifier, - isExpanded: Boolean = false, - onMenuItemClicked: (menuItem: MenuItem) -> Unit = {} -) { - var expanded by remember { mutableStateOf(isExpanded) } - fun onClick(menuItem: MenuItem) { - onMenuItemClicked(menuItem) - expanded = false - } - - Box(modifier = modifier) { - IconButton(onClick = { expanded = true }) { - Icon( - painter = painterResource(R.drawable.ic_more_vert), - contentDescription = stringResource(R.string.menu) - ) - } - DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) { - DropdownMenuItem( - text = { Text(text = stringResource(R.string.download_cancel_all)) }, - onClick = { onClick(MenuItem.CANCEL_ALL) } - ) - DropdownMenuItem( - text = { Text(text = stringResource(R.string.download_clear_finished)) }, - onClick = { onClick(MenuItem.CLEAR_FINISHED) } - ) - DropdownMenuItem( - text = { Text(text = stringResource(R.string.download_force_clear_all)) }, - onClick = { onClick(MenuItem.FORCE_CLEAR_ALL) } - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun DownloadsMenuPreview() { - PreviewTemplate { - DownloadsMenu(isExpanded = true) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/downloads/menu/MenuItem.kt b/app/src/main/java/com/aurora/store/compose/ui/downloads/menu/MenuItem.kt deleted file mode 100644 index 05517e934..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/downloads/menu/MenuItem.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.downloads.menu - -/** - * Valid menu items for the purpose of handling clicks - */ -enum class MenuItem { - CANCEL_ALL, - FORCE_CLEAR_ALL, - CLEAR_FINISHED -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/favourite/FavouriteScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/favourite/FavouriteScreen.kt deleted file mode 100644 index 77430b970..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/favourite/FavouriteScreen.kt +++ /dev/null @@ -1,192 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.favourite - -import androidx.activity.compose.rememberLauncherForActivityResult -import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.material3.Scaffold -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.paging.LoadState -import androidx.paging.PagingData -import androidx.paging.compose.LazyPagingItems -import androidx.paging.compose.collectAsLazyPagingItems -import androidx.paging.compose.itemKey -import com.aurora.Constants.JSON_MIME_TYPE -import com.aurora.extensions.emptyPagingItems -import com.aurora.extensions.toast -import com.aurora.store.R -import com.aurora.store.compose.composable.ContainedLoadingIndicator -import com.aurora.store.compose.composable.Error -import com.aurora.store.compose.composable.FavouriteListItem -import com.aurora.store.compose.composable.TopAppBar -import com.aurora.store.compose.preview.FavouritePreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.compose.ui.favourite.menu.FavouriteMenu -import com.aurora.store.compose.ui.favourite.menu.MenuItem -import com.aurora.store.data.room.favourite.Favourite -import com.aurora.store.viewmodel.all.FavouriteViewModel -import java.util.Calendar -import kotlin.random.Random -import kotlinx.coroutines.flow.MutableStateFlow - -@Composable -fun FavouriteScreen( - onNavigateUp: () -> Unit, - onNavigateToAppDetails: (packageName: String) -> Unit, - viewModel: FavouriteViewModel = hiltViewModel() -) { - val context = LocalContext.current - val favourites = viewModel.favourites.collectAsLazyPagingItems() - - val documentOpenLauncher = rememberLauncherForActivityResult( - contract = ActivityResultContracts.OpenDocument(), - onResult = { - if (it != null) { - viewModel.importFavourites(it) - context.toast(R.string.toast_fav_import_success) - } else { - context.toast(R.string.toast_fav_import_failed) - } - } - ) - - val documentCreateLauncher = rememberLauncherForActivityResult( - contract = ActivityResultContracts.CreateDocument(JSON_MIME_TYPE), - onResult = { - if (it != null) { - viewModel.exportFavourites(it) - context.toast(R.string.toast_fav_export_success) - } else { - context.toast(R.string.toast_fav_export_failed) - } - } - ) - - ScreenContent( - favourites = favourites, - onNavigateUp = onNavigateUp, - onNavigateToAppDetails = onNavigateToAppDetails, - onRemoveFavourite = { packageName -> viewModel.removeFavourite(packageName) }, - onImportFavourites = { - documentOpenLauncher.launch(arrayOf(JSON_MIME_TYPE)) - }, - onExportFavourites = { - documentCreateLauncher.launch( - "aurora_store_favourites_${Calendar.getInstance().time.time}.json" - ) - } - ) -} - -@Composable -private fun ScreenContent( - favourites: LazyPagingItems = emptyPagingItems(), - onNavigateUp: () -> Unit = {}, - onNavigateToAppDetails: (packageName: String) -> Unit = {}, - onRemoveFavourite: (packageName: String) -> Unit = {}, - onImportFavourites: () -> Unit = {}, - onExportFavourites: () -> Unit = {} -) { - /* - * For some reason paging3 frequently out-of-nowhere invalidates the list which causes - * the loading animation to play again even if the keys are same causing a glitching effect. - * - * Save the initial loading state to make sure we don't replay the loading animation again. - */ - var initialLoad by rememberSaveable { mutableStateOf(true) } - - @Composable - fun SetupMenu() { - FavouriteMenu { menuItem -> - when (menuItem) { - MenuItem.IMPORT -> onImportFavourites() - MenuItem.EXPORT -> onExportFavourites() - } - } - } - - Scaffold( - topBar = { - TopAppBar( - title = stringResource(R.string.title_favourites_manager), - onNavigateUp = onNavigateUp, - actions = { if (favourites.itemCount != 0) SetupMenu() } - ) - } - ) { paddingValues -> - Column( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - .padding(vertical = dimensionResource(R.dimen.padding_medium)) - ) { - when { - favourites.loadState.refresh is LoadState.Loading && initialLoad -> { - ContainedLoadingIndicator() - } - - else -> { - initialLoad = false - - if (favourites.itemCount == 0) { - Error( - modifier = Modifier.padding(paddingValues), - painter = painterResource(R.drawable.ic_favorite_unchecked), - message = stringResource(R.string.details_no_favourites) - ) - } else { - LazyColumn { - items( - count = favourites.itemCount, - key = favourites.itemKey { it.packageName } - ) { index -> - favourites[index]?.let { favourite -> - FavouriteListItem( - modifier = Modifier.animateItem(), - favourite = favourite, - onClick = { onNavigateToAppDetails(favourite.packageName) }, - onClear = { onRemoveFavourite(favourite.packageName) } - ) - } - } - } - } - } - } - } - } -} - -@Preview -@Composable -private fun FavouriteScreenPreview( - @PreviewParameter(FavouritePreviewProvider::class) favourite: Favourite -) { - PreviewTemplate { - val favourites = List(10) { - favourite.copy(packageName = "${favourite.packageName}.${Random.nextInt()}") - } - val flow = MutableStateFlow(PagingData.from(favourites)).collectAsLazyPagingItems() - - ScreenContent(favourites = flow) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/favourite/menu/FavouriteMenu.kt b/app/src/main/java/com/aurora/store/compose/ui/favourite/menu/FavouriteMenu.kt deleted file mode 100644 index 02d6d5cf1..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/favourite/menu/FavouriteMenu.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.favourite.menu - -import androidx.compose.foundation.layout.Box -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Menu for the favourite screen - * @param modifier The modifier to be applied to the composable - * @param onMenuItemClicked Callback when a menu item has been clicked - * @see MenuItem - */ -@Composable -fun FavouriteMenu( - modifier: Modifier = Modifier, - isExpanded: Boolean = false, - onMenuItemClicked: (menuItem: MenuItem) -> Unit = {} -) { - var expanded by remember { mutableStateOf(isExpanded) } - fun onClick(menuItem: MenuItem) { - onMenuItemClicked(menuItem) - expanded = false - } - - Box(modifier = modifier) { - IconButton(onClick = { expanded = true }) { - Icon( - painter = painterResource(R.drawable.ic_more_vert), - contentDescription = stringResource(R.string.menu) - ) - } - DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) { - DropdownMenuItem( - text = { Text(text = stringResource(R.string.action_import)) }, - onClick = { onClick(MenuItem.IMPORT) } - ) - DropdownMenuItem( - text = { Text(text = stringResource(R.string.action_export)) }, - onClick = { onClick(MenuItem.EXPORT) } - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun FavouriteMenuPreview() { - PreviewTemplate { - FavouriteMenu(isExpanded = true) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/favourite/menu/MenuItem.kt b/app/src/main/java/com/aurora/store/compose/ui/favourite/menu/MenuItem.kt deleted file mode 100644 index 1f6aebef2..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/favourite/menu/MenuItem.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.favourite.menu - -/** - * Valid menu items for the purpose of handling clicks - */ -enum class MenuItem { - IMPORT, - EXPORT -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/installed/InstalledScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/installed/InstalledScreen.kt deleted file mode 100644 index 1ee6ce66f..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/installed/InstalledScreen.kt +++ /dev/null @@ -1,127 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.installed - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.material3.Scaffold -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.paging.LoadState -import androidx.paging.PagingData -import androidx.paging.compose.LazyPagingItems -import androidx.paging.compose.collectAsLazyPagingItems -import androidx.paging.compose.itemKey -import com.aurora.extensions.emptyPagingItems -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.composable.ContainedLoadingIndicator -import com.aurora.store.compose.composable.Error -import com.aurora.store.compose.composable.TopAppBar -import com.aurora.store.compose.composable.app.LargeAppListItem -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.viewmodel.all.InstalledViewModel -import kotlin.random.Random -import kotlinx.coroutines.flow.MutableStateFlow - -@Composable -fun InstalledScreen( - onNavigateUp: () -> Unit, - onNavigateToAppDetails: (packageName: String) -> Unit, - viewModel: InstalledViewModel = hiltViewModel() -) { - val apps = viewModel.apps.collectAsLazyPagingItems() - - ScreenContent( - apps = apps, - onNavigateUp = onNavigateUp, - onNavigateToAppDetails = onNavigateToAppDetails - ) -} - -@Composable -private fun ScreenContent( - onNavigateUp: () -> Unit = {}, - apps: LazyPagingItems = emptyPagingItems(), - onNavigateToAppDetails: (packageName: String) -> Unit = {} -) { - /* - * For some reason paging3 frequently out-of-nowhere invalidates the list which causes - * the loading animation to play again even if the keys are same causing a glitching effect. - * - * Save the initial loading state to make sure we don't replay the loading animation again. - */ - var initialLoad by rememberSaveable { mutableStateOf(true) } - - Scaffold( - topBar = { - TopAppBar( - title = stringResource(R.string.title_apps_games), - onNavigateUp = onNavigateUp - ) - } - ) { paddingValues -> - Column( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - ) { - when { - apps.loadState.refresh is LoadState.Loading && initialLoad -> { - ContainedLoadingIndicator() - } - - else -> { - initialLoad = false - - if (apps.itemCount == 0) { - Error( - modifier = Modifier.padding(paddingValues), - painter = painterResource(R.drawable.ic_apps_outage), - message = stringResource(R.string.no_apps_available) - ) - } else { - LazyColumn { - items( - count = apps.itemCount, - key = apps.itemKey { it.packageName } - ) { index -> - apps[index]?.let { app -> - LargeAppListItem( - app = app, - onClick = { onNavigateToAppDetails(app.packageName) } - ) - } - } - } - } - } - } - } - } -} - -@Preview -@Composable -private fun InstalledScreenPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - val apps = List(15) { app.copy(packageName = Random.nextInt().toString()) } - val pagedApps = MutableStateFlow(PagingData.from(apps)).collectAsLazyPagingItems() - ScreenContent(apps = pagedApps) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/onboarding/MicroGPage.kt b/app/src/main/java/com/aurora/store/compose/ui/onboarding/MicroGPage.kt deleted file mode 100644 index 502582860..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/onboarding/MicroGPage.kt +++ /dev/null @@ -1,101 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.onboarding - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import com.aurora.extensions.toast -import com.aurora.store.R -import com.aurora.store.compose.composable.MicroG -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.data.model.PermissionType -import com.aurora.store.data.providers.PermissionProvider -import com.aurora.store.viewmodel.onboarding.MicroGUIState -import com.aurora.store.viewmodel.onboarding.MicroGViewModel - -@Composable -fun MicroGPage( - onMicrogTOSChecked: (Boolean) -> Unit = {}, - viewModel: MicroGViewModel = hiltViewModel() -) { - ScreenContent( - uiState = viewModel.uiState, - onInstall = { viewModel.downloadMicroG() }, - onMicrogTOSChecked = onMicrogTOSChecked - ) -} - -@Composable -private fun ScreenContent( - uiState: MicroGUIState, - onInstall: () -> Unit = {}, - onMicrogTOSChecked: (Boolean) -> Unit = {} -) { - val context = LocalContext.current - - Column( - modifier = Modifier - .fillMaxSize() - .padding(horizontal = dimensionResource(R.dimen.padding_medium)) - .verticalScroll(rememberScrollState()), - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_medium)) - ) { - Column( - modifier = Modifier.padding(dimensionResource(R.dimen.padding_medium)) - ) { - Text( - text = stringResource(R.string.onboarding_title_gsf), - style = MaterialTheme.typography.headlineLargeEmphasized, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = stringResource(R.string.onboarding_title_gsf_desc), - style = MaterialTheme.typography.titleMedium, - maxLines = 2, - overflow = TextOverflow.Ellipsis - ) - } - - MicroG( - onInstall = { - when { - PermissionProvider.isGranted(context, PermissionType.INSTALL_UNKNOWN_APPS) -> { - onInstall() - } - - else -> context.toast(R.string.permissions_denied) - } - }, - uiState = uiState, - onTOSChecked = onMicrogTOSChecked - ) - } -} - -@Preview(showBackground = true) -@Composable -private fun MicroGPagePreview() { - PreviewTemplate { - ScreenContent( - uiState = MicroGUIState() - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/onboarding/OnboardingScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/onboarding/OnboardingScreen.kt deleted file mode 100644 index ac9162f83..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/onboarding/OnboardingScreen.kt +++ /dev/null @@ -1,211 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.onboarding - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.widthIn -import androidx.compose.foundation.pager.HorizontalPager -import androidx.compose.foundation.pager.rememberPagerState -import androidx.compose.material3.Button -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.adaptive.WindowAdaptiveInfo -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.runtime.Composable -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import com.aurora.extensions.isWindowCompact -import com.aurora.store.R -import com.aurora.store.compose.composable.Logo -import com.aurora.store.compose.composable.PageIndicator -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.compose.ui.onboarding.navigation.OnboardingPage -import com.aurora.store.viewmodel.onboarding.OnboardingUiState -import com.aurora.store.viewmodel.onboarding.OnboardingViewModel -import kotlinx.coroutines.launch - -@Composable -fun OnboardingScreen(viewModel: OnboardingViewModel = hiltViewModel()) { - val pages = listOfNotNull( - OnboardingPage.WELCOME, - OnboardingPage.PERMISSIONS, - if (viewModel.isMicroGPromptRequired) OnboardingPage.MICRO_G else null - ) - - ScreenContent( - pages = pages, - onFinishOnboarding = { - viewModel.finishOnboarding() - }, - uiState = viewModel.uiState, - onMicrogTOSChecked = viewModel::onMicrogTOSChecked - ) -} - -@Composable -private fun ScreenContent( - pages: List = emptyList(), - onFinishOnboarding: () -> Unit = {}, - uiState: OnboardingUiState, - onMicrogTOSChecked: (Boolean) -> Unit, - windowAdaptiveInfo: WindowAdaptiveInfo = currentWindowAdaptiveInfo() -) { - val pagerState = rememberPagerState { pages.size } - val coroutineScope = rememberCoroutineScope() - - fun isFinalPage(): Boolean = pagerState.currentPage == (pagerState.pageCount - 1) - - @Composable - fun SetupActions(uiState: OnboardingUiState) { - val horizontalButtonPadding = when { - windowAdaptiveInfo.isWindowCompact -> dimensionResource(R.dimen.padding_medium) - else -> dimensionResource(R.dimen.padding_xlarge) - } - - Row( - modifier = Modifier - .fillMaxWidth() - .padding( - vertical = dimensionResource(R.dimen.padding_medium), - horizontal = horizontalButtonPadding - ), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy( - dimensionResource(R.dimen.padding_medium), - Alignment.End - ) - ) { - val buttonWidthModifier = when { - windowAdaptiveInfo.isWindowCompact -> Modifier.weight(1F) - else -> Modifier.widthIn(min = dimensionResource(R.dimen.width_button)) - } - - TextButton( - modifier = buttonWidthModifier, - onClick = { - when (pagerState.currentPage) { - 0 -> onFinishOnboarding() - - else -> { - coroutineScope.launch { - pagerState.animateScrollToPage(pagerState.currentPage - 1) - } - } - } - } - ) { - Text( - text = when (pagerState.currentPage) { - 0 -> stringResource(R.string.action_skip) - else -> stringResource(R.string.action_back) - }, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - - Button( - modifier = buttonWidthModifier, - enabled = !isFinalPage() || - (!uiState.isMicroBundleChecked || uiState.isMicroGBundleInstalled), - onClick = { - when { - isFinalPage() -> onFinishOnboarding() - - else -> { - coroutineScope.launch { - pagerState.animateScrollToPage(pagerState.currentPage + 1) - } - } - } - } - ) { - Text( - text = when { - isFinalPage() -> stringResource(R.string.action_finish) - else -> stringResource(R.string.action_next) - }, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - } - } - - Scaffold( - topBar = { - TopAppBar( - modifier = Modifier.height(64.dp), - title = { - PageIndicator(totalPages = pages.size, currentPage = pagerState.currentPage) - } - ) - } - ) { paddingValues -> - Column( - modifier = Modifier - .fillMaxSize() - .padding(paddingValues), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally - ) { - Row( - modifier = Modifier.weight(1F), - horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically - ) { - if (!windowAdaptiveInfo.isWindowCompact) { - Logo(modifier = Modifier.weight(1F)) - } - - HorizontalPager( - modifier = Modifier.weight(1F), - state = pagerState, - verticalAlignment = Alignment.Top - ) { page -> - when (pages[page]) { - OnboardingPage.WELCOME -> WelcomePage() - - OnboardingPage.PERMISSIONS -> PermissionsPage() - - OnboardingPage.MICRO_G -> MicroGPage( - onMicrogTOSChecked = onMicrogTOSChecked - ) - } - } - } - - SetupActions(uiState) - } - } -} - -@Preview -@Composable -private fun OnboardingScreenPreview() { - PreviewTemplate { - ScreenContent( - pages = listOf(OnboardingPage.WELCOME, OnboardingPage.PERMISSIONS), - uiState = OnboardingUiState(), - onMicrogTOSChecked = {} - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/onboarding/PermissionsPage.kt b/app/src/main/java/com/aurora/store/compose/ui/onboarding/PermissionsPage.kt deleted file mode 100644 index d9e1d1e9b..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/onboarding/PermissionsPage.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.onboarding - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.datasource.LoremIpsum -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.aurora.store.R -import com.aurora.store.compose.composable.PermissionList -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.data.model.Permission -import com.aurora.store.data.model.PermissionType -import com.aurora.store.viewmodel.commons.PermissionRationaleViewModel -import kotlin.random.Random - -@Composable -fun PermissionsPage(viewModel: PermissionRationaleViewModel = hiltViewModel()) { - val permissions by viewModel.permissions.collectAsStateWithLifecycle() - - PageContent( - permissions = permissions, - onPermissionCallback = { viewModel.refreshPermissionsList() } - ) -} - -@Composable -private fun PageContent( - permissions: List = emptyList(), - onPermissionCallback: (type: PermissionType) -> Unit = {} -) { - PermissionList( - modifier = Modifier.padding(horizontal = dimensionResource(R.dimen.padding_medium)), - permissions = permissions, - onPermissionCallback = onPermissionCallback, - header = { - Surface(modifier = Modifier.fillMaxWidth()) { - Column( - modifier = Modifier.padding(dimensionResource(R.dimen.padding_medium)) - ) { - Text( - text = stringResource(R.string.onboarding_title_permissions), - style = MaterialTheme.typography.headlineLargeEmphasized, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = stringResource(R.string.onboarding_permission_select), - style = MaterialTheme.typography.titleMedium, - maxLines = 2, - overflow = TextOverflow.Ellipsis - ) - } - } - } - ) -} - -@Preview(showBackground = true) -@Composable -private fun PermissionsPagePreview() { - val permissions = PermissionType.entries.map { type -> - Permission( - type = type, - title = LoremIpsum(3).values.first(), - subtitle = LoremIpsum(7).values.first(), - optional = Random.nextBoolean(), - isGranted = Random.nextBoolean() - ) - } - PreviewTemplate { - PageContent( - permissions = permissions - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/onboarding/WelcomePage.kt b/app/src/main/java/com/aurora/store/compose/ui/onboarding/WelcomePage.kt deleted file mode 100644 index e400d062d..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/onboarding/WelcomePage.kt +++ /dev/null @@ -1,144 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.onboarding - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.extensions.browse -import com.aurora.store.R -import com.aurora.store.compose.composable.LinkListItem -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.compose.ui.about.AboutDialog -import com.aurora.store.data.model.Link - -@Composable -fun WelcomePage() { - var shouldShowAboutDialog by rememberSaveable { mutableStateOf(false) } - - if (shouldShowAboutDialog) { - AboutDialog(onDismiss = { shouldShowAboutDialog = false }) - } - - PageContent(onAboutAurora = { shouldShowAboutDialog = true }) -} - -@Composable -private fun PageContent(onAboutAurora: () -> Unit = {}) { - val context = LocalContext.current - - val links = listOf( - Link( - id = 0, - title = stringResource(R.string.title_about), - subtitle = stringResource(R.string.about_aurora_store_subtitle), - icon = R.drawable.ic_menu_about, - url = "https://auroraoss.com/" - ), - Link( - id = 1, - title = stringResource(R.string.faqs_title), - subtitle = stringResource(R.string.faqs_subtitle), - icon = R.drawable.ic_faq, - url = "https://gitlab.com/AuroraOSS/AuroraStore/-/wikis/Frequently%20Asked%20Questions" - ), - Link( - id = 2, - title = stringResource(R.string.source_code_title), - subtitle = stringResource(R.string.source_code_subtitle), - icon = R.drawable.ic_code, - url = "https://gitlab.com/AuroraOSS/AuroraStore/" - ), - Link( - id = 3, - title = stringResource(R.string.menu_license), - subtitle = stringResource(R.string.license_subtitle), - icon = R.drawable.ic_license, - url = "https://gitlab.com/AuroraOSS/AuroraStore/-/blob/master/LICENSE" - ), - Link( - id = 4, - title = stringResource(R.string.privacy_policy_title), - subtitle = stringResource(R.string.privacy_policy_subtitle), - icon = R.drawable.ic_privacy, - url = "https://gitlab.com/AuroraOSS/AuroraStore/-/blob/master/POLICY.md" - ), - Link( - id = 5, - title = stringResource(R.string.menu_disclaimer), - subtitle = stringResource(R.string.disclaimer_subtitle), - icon = R.drawable.ic_disclaimer, - url = "https://gitlab.com/AuroraOSS/AuroraStore/-/blob/master/DISCLAIMER.md" - ) - ) - - LazyColumn( - modifier = Modifier.fillMaxSize(), - contentPadding = PaddingValues(horizontal = dimensionResource(R.dimen.padding_medium)), - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_xxsmall)) - ) { - stickyHeader { - Surface(modifier = Modifier.fillMaxWidth()) { - Column( - modifier = Modifier.padding(dimensionResource(R.dimen.padding_medium)) - ) { - Text( - text = stringResource(R.string.onboarding_title_welcome), - style = MaterialTheme.typography.headlineLargeEmphasized, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = stringResource(R.string.onboarding_welcome_select), - style = MaterialTheme.typography.titleMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - } - } - - items(items = links, key = { item -> item.id }) { link -> - LinkListItem( - link = link, - onClick = { - when (link.id) { - 0 -> onAboutAurora() - else -> context.browse(link.url) - } - }, - iconTint = MaterialTheme.colorScheme.primary - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun WelcomePagePreview() { - PreviewTemplate { - PageContent() - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/onboarding/navigation/OnboardingPage.kt b/app/src/main/java/com/aurora/store/compose/ui/onboarding/navigation/OnboardingPage.kt deleted file mode 100644 index 35ae683c9..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/onboarding/navigation/OnboardingPage.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 Aurora OSS - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.onboarding.navigation - -/** - * Pages that can be shown during onboarding - */ -enum class OnboardingPage { - WELCOME, - PERMISSIONS, - MICRO_G -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/preferences/installation/InstallerScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/preferences/installation/InstallerScreen.kt deleted file mode 100644 index 4205ba101..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/preferences/installation/InstallerScreen.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.preferences.installation - -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.aurora.store.R -import com.aurora.store.compose.composable.InstallerListItem -import com.aurora.store.compose.composable.TopAppBar -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.data.installer.AppInstaller -import com.aurora.store.data.installer.SessionInstaller -import com.aurora.store.data.model.Installer -import com.aurora.store.data.model.InstallerInfo -import com.aurora.store.viewmodel.preferences.InstallerViewModel - -@Composable -fun InstallerScreen(onNavigateUp: () -> Unit, viewModel: InstallerViewModel = hiltViewModel()) { - val currentInstallerId by viewModel.currentInstaller.collectAsStateWithLifecycle() - val snackBarHostState = remember { SnackbarHostState() } - - LaunchedEffect(key1 = Unit) { - viewModel.error.collect { error -> - snackBarHostState.showSnackbar(message = error) - } - } - - ScreenContent( - onNavigateUp = onNavigateUp, - snackBarHostState = snackBarHostState, - currentInstaller = Installer.entries[currentInstallerId], - availableInstallers = AppInstaller.getAvailableInstallersInfo(LocalContext.current), - onInstallerSelected = { installer -> viewModel.save(installer) } - ) -} - -@Composable -private fun ScreenContent( - onNavigateUp: () -> Unit = {}, - snackBarHostState: SnackbarHostState = SnackbarHostState(), - currentInstaller: Installer = Installer.SESSION, - availableInstallers: List = emptyList(), - onInstallerSelected: (installer: Installer) -> Unit = {} -) { - val snackBarHostState = remember { snackBarHostState } - - Scaffold( - snackbarHost = { - SnackbarHost(hostState = snackBarHostState) - }, - topBar = { - TopAppBar( - title = stringResource(R.string.pref_install_mode_title), - onNavigateUp = onNavigateUp - ) - } - ) { paddingValues -> - LazyColumn( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - .padding(vertical = dimensionResource(R.dimen.padding_medium)) - ) { - items(items = availableInstallers, key = { i -> i.id }) { installerInfo -> - InstallerListItem( - installerInfo = installerInfo, - isSelected = installerInfo.installer == currentInstaller, - onClick = { onInstallerSelected(installerInfo.installer) } - ) - } - } - } -} - -@Preview -@Composable -private fun InstallerScreenPreview() { - PreviewTemplate { - ScreenContent( - availableInstallers = listOf(SessionInstaller.installerInfo) - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/search/SearchScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/search/SearchScreen.kt deleted file mode 100644 index 2d06463f4..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/search/SearchScreen.kt +++ /dev/null @@ -1,450 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.search - -import androidx.annotation.StringRes -import androidx.compose.foundation.focusable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.interaction.PressInteraction -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.text.input.clearText -import androidx.compose.foundation.text.input.rememberTextFieldState -import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd -import androidx.compose.material3.AppBarWithSearch -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ExpandedDockedSearchBar -import androidx.compose.material3.FilterChip -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.Scaffold -import androidx.compose.material3.SearchBarDefaults -import androidx.compose.material3.Text -import androidx.compose.material3.adaptive.layout.AnimatedPane -import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldRole -import androidx.compose.material3.adaptive.navigation.NavigableListDetailPaneScaffold -import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator -import androidx.compose.material3.rememberSearchBarState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.runtime.snapshotFlow -import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusRequester -import androidx.compose.ui.platform.LocalFocusManager -import androidx.compose.ui.platform.LocalSoftwareKeyboardController -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringArrayResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.tooling.preview.PreviewScreenSizes -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.paging.LoadState -import androidx.paging.PagingData -import androidx.paging.compose.LazyPagingItems -import androidx.paging.compose.collectAsLazyPagingItems -import androidx.paging.compose.itemKey -import com.aurora.extensions.emptyPagingItems -import com.aurora.gplayapi.SearchSuggestEntry -import com.aurora.gplayapi.data.models.App -import com.aurora.store.R -import com.aurora.store.compose.composable.ContainedLoadingIndicator -import com.aurora.store.compose.composable.Error -import com.aurora.store.compose.composable.SearchSuggestionListItem -import com.aurora.store.compose.composable.app.LargeAppListItem -import com.aurora.store.compose.preview.AppPreviewProvider -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.compose.ui.details.AppDetailsScreen -import com.aurora.store.data.model.SearchFilter -import com.aurora.store.viewmodel.search.SearchViewModel -import kotlin.random.Random -import kotlinx.coroutines.android.awaitFrame -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.launch - -@Composable -fun SearchScreen(onNavigateUp: () -> Unit, viewModel: SearchViewModel = hiltViewModel()) { - val suggestions by viewModel.suggestions.collectAsStateWithLifecycle() - val results = viewModel.apps.collectAsLazyPagingItems() - - val onSearchCallback = remember<(String) -> Unit> { { query -> viewModel.search(query) } } - val onFetchSuggestionsCallback = - remember<(String) -> Unit> { { query -> viewModel.fetchSuggestions(query) } } - - ScreenContent( - suggestions = suggestions, - results = results, - onNavigateUp = onNavigateUp, - onSearch = onSearchCallback, - onFetchSuggestions = onFetchSuggestionsCallback, - onFilter = { filter -> viewModel.filterResults(filter) }, - isAnonymous = viewModel.authProvider.isAnonymous - ) -} - -@Composable -private fun ScreenContent( - suggestions: List = emptyList(), - results: LazyPagingItems = emptyPagingItems(), - onNavigateUp: () -> Unit = {}, - onFetchSuggestions: (String) -> Unit = {}, - onSearch: (String) -> Unit = {}, - onFilter: (filter: SearchFilter) -> Unit = {}, - isAnonymous: Boolean = true -) { - val textFieldState = rememberTextFieldState() - val searchBarState = rememberSearchBarState() - var isSearching by rememberSaveable { mutableStateOf(false) } - - val focusRequester = remember { FocusRequester() } - val scaffoldNavigator = rememberListDetailPaneScaffoldNavigator() - val coroutineScope = rememberCoroutineScope() - - val focusManager = LocalFocusManager.current - val keyboardController = LocalSoftwareKeyboardController.current - - LaunchedEffect(key1 = focusRequester) { - awaitFrame() - focusRequester.requestFocus() - } - - LaunchedEffect(key1 = textFieldState) { - snapshotFlow { textFieldState.text.toString() } - .collectLatest { query -> onFetchSuggestions(query) } - } - - fun showDetailPane(packageName: String) { - coroutineScope.launch { - scaffoldNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail, packageName) - } - } - - fun onRequestSearch(query: String) { - textFieldState.setTextAndPlaceCursorAtEnd(query.trim()) - coroutineScope.launch { - focusManager.clearFocus() - keyboardController?.hide() - searchBarState.animateToCollapsed() - } - onSearch(textFieldState.text.toString()) - isSearching = true - } - - @Composable - fun SearchBar() { - val interactionSource = remember { MutableInteractionSource() } - - LaunchedEffect(interactionSource) { - interactionSource.interactions.collectLatest { interaction -> - if (interaction is PressInteraction.Press) { - awaitFrame() - focusRequester.requestFocus() - } - } - } - - val inputField = @Composable { - SearchBarDefaults.InputField( - modifier = Modifier.focusRequester(focusRequester), - searchBarState = searchBarState, - textFieldState = textFieldState, - interactionSource = interactionSource, - onSearch = { query -> onRequestSearch(query) }, - placeholder = { - Text( - text = stringResource(R.string.search_hint), - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - }, - leadingIcon = { - IconButton(onClick = onNavigateUp) { - Icon( - painter = painterResource(R.drawable.ic_arrow_back), - contentDescription = stringResource(R.string.action_back) - ) - } - }, - trailingIcon = { - if (textFieldState.text.isNotBlank()) { - IconButton( - onClick = { - textFieldState.clearText() - focusRequester.requestFocus() - } - ) { - Icon( - painter = painterResource(R.drawable.ic_cancel), - contentDescription = stringResource(R.string.action_clear) - ) - } - } - } - ) - } - - AppBarWithSearch(state = searchBarState, inputField = inputField) - ExpandedDockedSearchBar(state = searchBarState, inputField = inputField) { - suggestions.forEach { suggestion -> - SearchSuggestionListItem( - searchSuggestEntry = suggestion, - onClick = { query -> onRequestSearch(query) }, - onAction = { query -> textFieldState.setTextAndPlaceCursorAtEnd(query.trim()) } - ) - } - } - } - - @Composable - fun ListPane() { - // TODO: https://issuetracker.google.com/issues/445720462 - Scaffold( - modifier = Modifier.focusable(), - topBar = { SearchBar() } - ) { paddingValues -> - Column( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - .padding(vertical = dimensionResource(R.dimen.padding_medium)) - ) { - FilterHeader( - isEnabled = isSearching && results.loadState.refresh is LoadState.NotLoading, - isAnonymous = isAnonymous, - onFilter = onFilter - ) - - when (results.loadState.refresh) { - is LoadState.Loading -> ContainedLoadingIndicator() - - is LoadState.Error -> { - Error( - modifier = Modifier.padding(paddingValues), - painter = painterResource(R.drawable.ic_disclaimer), - message = stringResource(R.string.error) - ) - } - - else -> { - if (isSearching && results.itemCount == 0) { - Error( - modifier = Modifier.padding(paddingValues), - painter = painterResource(R.drawable.ic_disclaimer), - message = stringResource(R.string.no_apps_available) - ) - } else { - LazyColumn { - items( - count = results.itemCount, - key = results.itemKey { it.id } - ) { index -> - results[index]?.let { app -> - LargeAppListItem( - app = app, - onClick = { showDetailPane(app.packageName) } - ) - } - } - } - } - } - } - } - } - } - - @Composable - fun DetailPane() { - with(scaffoldNavigator.currentDestination?.contentKey) { - when { - this != null -> { - AppDetailsScreen( - packageName = this, - onNavigateToAppDetails = { packageName -> showDetailPane(packageName) }, - onNavigateUp = { - coroutineScope.launch { scaffoldNavigator.navigateBack() } - }, - forceSinglePane = true - ) - } - - else -> { - if (isSearching && results.itemCount > 0) { - Error( - painter = painterResource(R.drawable.ic_round_search), - message = stringResource(R.string.select_app_for_details) - ) - } - } - } - } - } - - NavigableListDetailPaneScaffold( - navigator = scaffoldNavigator, - listPane = { AnimatedPane { ListPane() } }, - detailPane = { AnimatedPane { DetailPane() } } - ) -} - -@Composable -private fun FilterHeader( - isAnonymous: Boolean = true, - isEnabled: Boolean = true, - onFilter: (filter: SearchFilter) -> Unit -) { - var activeFilter by rememberSaveable { mutableStateOf(SearchFilter()) } - - val filters = listOfNotNull( - R.string.action_filter_rating, - R.string.app_info_downloads, - R.string.details_free, - R.string.action_filter_no_ads, - if (!isAnonymous) R.string.action_filter_no_gms else null - ) - - @Composable - fun NonExpandableFilterChip(@StringRes filter: Int, isSelected: Boolean) { - FilterChip( - enabled = isEnabled, - onClick = { - activeFilter = when (filter) { - R.string.details_free -> activeFilter.copy(isFree = !activeFilter.isFree) - R.string.action_filter_no_ads -> activeFilter.copy(noAds = !activeFilter.noAds) - else -> activeFilter.copy(noGMS = !activeFilter.noGMS) - } - onFilter(activeFilter) - }, - label = { Text(text = stringResource(filter)) }, - selected = isSelected, - leadingIcon = { - if (isSelected) { - Icon( - painter = painterResource(R.drawable.ic_check), - contentDescription = stringResource(filter) - ) - } - } - ) - } - - @Composable - fun ExpandableFilterChip(@StringRes filter: Int, isSelected: Boolean) { - var isExpanded by rememberSaveable { mutableStateOf(false) } - - Box { - FilterChip( - enabled = isEnabled, - onClick = { isExpanded = !isExpanded }, - label = { Text(text = stringResource(filter)) }, - selected = isSelected, - leadingIcon = { - if (isSelected) { - Icon( - painter = painterResource(R.drawable.ic_check), - contentDescription = stringResource(filter) - ) - } - }, - trailingIcon = { - Icon( - painter = painterResource(R.drawable.ic_arrow_drop_down), - contentDescription = stringResource(filter) - ) - } - ) - - DropdownMenu(expanded = isExpanded, onDismissRequest = { isExpanded = false }) { - val downloadLabels = stringArrayResource(R.array.filterDownloadsLabels) - val downloadValues = stringArrayResource(R.array.filterDownloadsValues) - val ratingLabels = stringArrayResource(R.array.filterRatingLabels) - val ratingValues = stringArrayResource(R.array.filterRatingValues) - - val options = when (filter) { - R.string.action_filter_rating -> ratingLabels.zip(ratingValues).toMap() - R.string.app_info_downloads -> downloadLabels.zip(downloadValues).toMap() - else -> emptyMap() - } - - options.forEach { (key, value) -> - DropdownMenuItem( - text = { Text(text = key) }, - onClick = { - activeFilter = when (filter) { - R.string.action_filter_rating -> { - activeFilter.copy(minRating = value.toFloat()) - } - - else -> activeFilter.copy(minInstalls = value.toLong()) - } - onFilter(activeFilter) - isExpanded = false - } - ) - } - } - } - } - - LazyRow( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = dimensionResource(R.dimen.padding_medium)), - horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_normal)) - ) { - items(items = filters, key = { item -> item }) { filter -> - val isSelected = when (filter) { - R.string.action_filter_rating -> activeFilter.minRating > 0.0 - R.string.app_info_downloads -> activeFilter.minInstalls > 0 - R.string.details_free -> activeFilter.isFree - R.string.action_filter_no_ads -> activeFilter.noAds - R.string.action_filter_no_gms -> activeFilter.noGMS - else -> false - } - - when (filter) { - R.string.details_free, - R.string.action_filter_no_ads, - R.string.action_filter_no_gms -> { - NonExpandableFilterChip(filter = filter, isSelected = isSelected) - } - - R.string.action_filter_rating, - R.string.app_info_downloads -> { - ExpandableFilterChip(filter = filter, isSelected = isSelected) - } - } - } - } -} - -@PreviewScreenSizes -@Composable -private fun SearchScreenPreview(@PreviewParameter(AppPreviewProvider::class) app: App) { - PreviewTemplate { - val apps = List(10) { app.copy(id = Random.nextInt()) } - val results = MutableStateFlow(PagingData.from(apps)).collectAsLazyPagingItems() - ScreenContent(results = results) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/spoof/DevicePage.kt b/app/src/main/java/com/aurora/store/compose/ui/spoof/DevicePage.kt deleted file mode 100644 index 2de199f3b..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/spoof/DevicePage.kt +++ /dev/null @@ -1,116 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.spoof - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.material3.Surface -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.aurora.store.R -import com.aurora.store.compose.composable.DeviceListItem -import com.aurora.store.compose.composable.TextDividerComposable -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.viewmodel.spoof.SpoofViewModel -import java.util.Properties -import kotlin.random.Random - -@Composable -fun DevicePage(onRequestNavigateToSplash: () -> Unit, viewModel: SpoofViewModel = hiltViewModel()) { - val availableDevices by viewModel.availableDevices.collectAsStateWithLifecycle() - val currentDevice by viewModel.currentDevice.collectAsStateWithLifecycle() - - PageContent( - devices = availableDevices, - defaultDevice = viewModel.defaultProperties, - isDeviceSelected = { device -> device == currentDevice }, - onDeviceSelected = { properties -> - viewModel.onDeviceSelected(properties) - onRequestNavigateToSplash() - } - ) -} - -@Composable -private fun PageContent( - defaultDevice: Properties = Properties(), - devices: List = emptyList(), - isDeviceSelected: (properties: Properties) -> Boolean = { false }, - onDeviceSelected: (properties: Properties) -> Unit = {} -) { - LazyColumn( - modifier = Modifier.fillMaxSize(), - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_xxsmall)) - ) { - stickyHeader { - Surface(modifier = Modifier.fillMaxWidth()) { - TextDividerComposable( - title = stringResource(R.string.default_spoof) - ) - } - } - - item { - DeviceListItem( - userReadableName = defaultDevice.getProperty("UserReadableName"), - manufacturer = defaultDevice.getProperty("Build.MANUFACTURER"), - androidVersionSdk = defaultDevice.getProperty("Build.VERSION.SDK_INT"), - platforms = defaultDevice.getProperty("Platforms"), - isChecked = isDeviceSelected(defaultDevice), - onClick = { onDeviceSelected(defaultDevice) } - ) - } - - stickyHeader { - Surface(modifier = Modifier.fillMaxWidth()) { - TextDividerComposable( - title = stringResource(R.string.available_spoof) - ) - } - } - - items(items = devices, key = { device -> device.getProperty("Build.PRODUCT") }) { device -> - DeviceListItem( - userReadableName = device.getProperty("UserReadableName"), - manufacturer = device.getProperty("Build.MANUFACTURER"), - androidVersionSdk = device.getProperty("Build.VERSION.SDK_INT"), - platforms = device.getProperty("Platforms"), - isChecked = isDeviceSelected(device), - onClick = { onDeviceSelected(device) } - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun DevicePagePreview() { - fun getDevice(): Properties = Properties().apply { - setProperty("UserReadableName", "Google Pixel 9a") - setProperty("Build.VERSION.SDK_INT", "35") - setProperty("Build.MANUFACTURER", "Google") - setProperty("Platforms", "arm64-v8a") - setProperty("Build.PRODUCT", Random.nextInt().toString()) - } - - PreviewTemplate { - val defaultDevice = getDevice() - PageContent( - defaultDevice = defaultDevice, - devices = List(10) { getDevice() }, - isDeviceSelected = { device -> defaultDevice == device } - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/spoof/LocalePage.kt b/app/src/main/java/com/aurora/store/compose/ui/spoof/LocalePage.kt deleted file mode 100644 index 99c75fae6..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/spoof/LocalePage.kt +++ /dev/null @@ -1,101 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.spoof - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.material3.Surface -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.aurora.store.R -import com.aurora.store.compose.composable.LocaleListItem -import com.aurora.store.compose.composable.TextDividerComposable -import com.aurora.store.compose.preview.PreviewTemplate -import com.aurora.store.viewmodel.spoof.SpoofViewModel -import java.util.Locale - -@Composable -fun LocalePage(onRequestNavigateToSplash: () -> Unit, viewModel: SpoofViewModel = hiltViewModel()) { - val availableLocales by viewModel.availableLocales.collectAsStateWithLifecycle() - val currentLocale by viewModel.currentLocale.collectAsStateWithLifecycle() - - PageContent( - defaultLocale = viewModel.defaultLocale, - locales = availableLocales, - isLocaleSelected = { locale -> currentLocale == locale }, - onLocaleSelected = { locale -> - viewModel.onLocaleSelected(locale) - onRequestNavigateToSplash() - } - ) -} - -@Composable -private fun PageContent( - defaultLocale: Locale = Locale.getDefault(), - locales: List = emptyList(), - isLocaleSelected: (locale: Locale) -> Boolean = { false }, - onLocaleSelected: (locale: Locale) -> Unit = {} -) { - LazyColumn( - modifier = Modifier.fillMaxSize(), - verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.margin_xxsmall)) - ) { - stickyHeader { - Surface(modifier = Modifier.fillMaxWidth()) { - TextDividerComposable( - title = stringResource(R.string.default_spoof) - ) - } - } - - item { - LocaleListItem( - displayName = defaultLocale.displayName, - displayLanguage = defaultLocale.getDisplayLanguage(defaultLocale), - isChecked = isLocaleSelected(defaultLocale), - onClick = { onLocaleSelected(defaultLocale) } - ) - } - - stickyHeader { - Surface(modifier = Modifier.fillMaxWidth()) { - TextDividerComposable( - title = stringResource(R.string.available_spoof) - ) - } - } - - items(items = locales, key = { locale -> locale.hashCode() }) { locale -> - LocaleListItem( - displayName = locale.displayName, - displayLanguage = locale.getDisplayLanguage(locale), - isChecked = isLocaleSelected(locale), - onClick = { onLocaleSelected(locale) } - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun LocalePagePreview() { - PreviewTemplate { - PageContent( - locales = Locale.getAvailableLocales().toList().filter { it.displayName.isNotBlank() }, - isLocaleSelected = { locale -> locale == Locale.getDefault() } - ) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/spoof/SpoofScreen.kt b/app/src/main/java/com/aurora/store/compose/ui/spoof/SpoofScreen.kt deleted file mode 100644 index 4c2f1e392..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/spoof/SpoofScreen.kt +++ /dev/null @@ -1,181 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.spoof - -import android.net.Uri -import android.os.Build -import androidx.activity.compose.rememberLauncherForActivityResult -import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.pager.HorizontalPager -import androidx.compose.foundation.pager.rememberPagerState -import androidx.compose.material3.Scaffold -import androidx.compose.material3.SecondaryTabRow -import androidx.compose.material3.SnackbarDuration -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState -import androidx.compose.material3.SnackbarResult -import androidx.compose.material3.Tab -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.util.fastForEachIndexed -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import com.aurora.Constants -import com.aurora.extensions.toast -import com.aurora.store.R -import com.aurora.store.compose.composable.TopAppBar -import com.aurora.store.compose.ui.spoof.menu.MenuItem -import com.aurora.store.compose.ui.spoof.menu.SpoofMenu -import com.aurora.store.compose.ui.spoof.navigation.SpoofPage -import com.aurora.store.data.providers.AccountProvider -import com.aurora.store.viewmodel.spoof.SpoofViewModel -import kotlinx.coroutines.launch - -@Composable -fun SpoofScreen( - onNavigateUp: () -> Unit, - onNavigateToSplash: () -> Unit, - viewModel: SpoofViewModel = hiltViewModel() -) { - ScreenContent( - onNavigateUp = onNavigateUp, - onNavigateToSplash = onNavigateToSplash, - onDeviceSpoofImport = { uri -> viewModel.importDeviceSpoof(uri) }, - onDeviceSpoofExport = { uri -> viewModel.exportDeviceSpoof(uri) } - ) -} - -@Composable -private fun ScreenContent( - pages: List = listOf(SpoofPage.DEVICE, SpoofPage.LOCALE), - onNavigateUp: () -> Unit = {}, - onNavigateToSplash: () -> Unit = {}, - onDeviceSpoofImport: (uri: Uri) -> Unit = {}, - onDeviceSpoofExport: (uri: Uri) -> Unit = {} -) { - val context = LocalContext.current - val pagerState = rememberPagerState { pages.size } - val coroutineScope = rememberCoroutineScope() - val snackBarHostState = remember { SnackbarHostState() } - - val docImportLauncher = rememberLauncherForActivityResult( - contract = ActivityResultContracts.OpenDocument(), - onResult = { - if (it != null) { - onDeviceSpoofImport(it) - } else { - context.toast(R.string.toast_import_failed) - } - } - ) - val docExportLauncher = rememberLauncherForActivityResult( - contract = ActivityResultContracts.CreateDocument(Constants.PROPERTIES_EXPORT_MIME_TYPE), - onResult = { - if (it != null) { - onDeviceSpoofExport(it) - } else { - context.toast(R.string.toast_export_failed) - } - } - ) - - fun onRequestNavigateToSplash() { - coroutineScope.launch { - val result = snackBarHostState.showSnackbar( - message = context.getString(R.string.force_restart_snack), - actionLabel = context.getString(R.string.action_restart), - duration = SnackbarDuration.Indefinite - ) - when (result) { - SnackbarResult.ActionPerformed -> { - AccountProvider.logout(context) - onNavigateToSplash() - } - - else -> Unit - } - } - } - - @Composable - fun SetupMenu() { - SpoofMenu { menuItem -> - when (menuItem) { - MenuItem.IMPORT -> { - docImportLauncher.launch(arrayOf(Constants.PROPERTIES_IMPORT_MIME_TYPE)) - } - - MenuItem.EXPORT -> { - docExportLauncher.launch( - "aurora_store_${Build.BRAND}_${Build.DEVICE}.properties" - ) - } - } - } - } - - Scaffold( - snackbarHost = { - SnackbarHost(hostState = snackBarHostState) - }, - topBar = { - TopAppBar( - title = stringResource(R.string.title_spoof_manager), - onNavigateUp = onNavigateUp, - actions = { SetupMenu() } - ) - } - ) { paddingValues -> - Column( - modifier = Modifier - .fillMaxSize() - .padding(paddingValues) - ) { - SecondaryTabRow( - modifier = Modifier.fillMaxWidth(), - selectedTabIndex = pagerState.currentPage - ) { - pages.fastForEachIndexed { index, _ -> - Tab( - selected = pagerState.currentPage == index, - onClick = { - coroutineScope.launch { - pagerState.animateScrollToPage(index) - } - }, - text = { - Text(text = stringResource(id = pages[index].localized)) - } - ) - } - } - HorizontalPager( - modifier = Modifier.fillMaxSize(), - state = pagerState, - verticalAlignment = Alignment.Top - ) { page -> - when (pages[page]) { - SpoofPage.DEVICE -> DevicePage( - onRequestNavigateToSplash = ::onRequestNavigateToSplash - ) - - SpoofPage.LOCALE -> LocalePage( - onRequestNavigateToSplash = ::onRequestNavigateToSplash - ) - } - } - } - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/spoof/menu/MenuItem.kt b/app/src/main/java/com/aurora/store/compose/ui/spoof/menu/MenuItem.kt deleted file mode 100644 index 313817774..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/spoof/menu/MenuItem.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.spoof.menu - -enum class MenuItem { - IMPORT, - EXPORT -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/spoof/menu/SpoofMenu.kt b/app/src/main/java/com/aurora/store/compose/ui/spoof/menu/SpoofMenu.kt deleted file mode 100644 index 0a2753b67..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/spoof/menu/SpoofMenu.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.spoof.menu - -import androidx.compose.foundation.layout.Box -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import com.aurora.store.R -import com.aurora.store.compose.preview.PreviewTemplate - -/** - * Menu for the blacklist screen - * @param modifier The modifier to be applied to the composable - * @param onMenuItemClicked Callback when a menu item has been clicked - * @see MenuItem - */ -@Composable -fun SpoofMenu( - modifier: Modifier = Modifier, - isExpanded: Boolean = false, - onMenuItemClicked: (menuItem: MenuItem) -> Unit = {} -) { - var expanded by remember { mutableStateOf(isExpanded) } - fun onClick(menuItem: MenuItem) { - onMenuItemClicked(menuItem) - expanded = false - } - - Box(modifier = modifier) { - IconButton(onClick = { expanded = true }) { - Icon( - painter = painterResource(R.drawable.ic_more_vert), - contentDescription = stringResource(R.string.menu) - ) - } - DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) { - DropdownMenuItem( - text = { Text(text = stringResource(R.string.action_import)) }, - onClick = { onClick(MenuItem.IMPORT) } - ) - DropdownMenuItem( - text = { Text(text = stringResource(R.string.action_export)) }, - onClick = { onClick(MenuItem.EXPORT) } - ) - } - } -} - -@Preview(showBackground = true) -@Composable -private fun SpoofMenuPreview() { - PreviewTemplate { - SpoofMenu(isExpanded = true) - } -} diff --git a/app/src/main/java/com/aurora/store/compose/ui/spoof/navigation/SpoofPage.kt b/app/src/main/java/com/aurora/store/compose/ui/spoof/navigation/SpoofPage.kt deleted file mode 100644 index d7f2f5ce0..000000000 --- a/app/src/main/java/com/aurora/store/compose/ui/spoof/navigation/SpoofPage.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.compose.ui.spoof.navigation - -import androidx.annotation.StringRes -import com.aurora.store.R - -/** - * Pages that are shown in SpoofScreen - */ -enum class SpoofPage(@StringRes val localized: Int) { - DEVICE(R.string.title_device), - LOCALE(R.string.title_language) -} diff --git a/app/src/main/java/com/aurora/store/data/activity/InstallActivity.kt b/app/src/main/java/com/aurora/store/data/activity/InstallActivity.kt index 56e8f0135..68248c718 100644 --- a/app/src/main/java/com/aurora/store/data/activity/InstallActivity.kt +++ b/app/src/main/java/com/aurora/store/data/activity/InstallActivity.kt @@ -7,7 +7,6 @@ import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity import androidx.core.content.IntentCompat import com.aurora.Constants -import com.aurora.extensions.TAG import com.aurora.store.data.installer.SessionInstaller import com.aurora.store.data.room.download.Download import dagger.hilt.android.AndroidEntryPoint @@ -16,6 +15,8 @@ import javax.inject.Inject @AndroidEntryPoint class InstallActivity : AppCompatActivity() { + private val TAG = InstallActivity::class.java.simpleName + @Inject lateinit var sessionInstaller: SessionInstaller diff --git a/app/src/main/java/com/aurora/store/data/activity/MicroGInstallerActivity.kt b/app/src/main/java/com/aurora/store/data/activity/MicroGInstallerActivity.kt deleted file mode 100644 index b4d7f1cdc..000000000 --- a/app/src/main/java/com/aurora/store/data/activity/MicroGInstallerActivity.kt +++ /dev/null @@ -1,73 +0,0 @@ -package com.aurora.store.data.activity - -import android.app.Activity -import android.content.Context -import android.content.Intent -import android.net.Uri -import android.os.Bundle -import android.util.Log -import androidx.core.content.FileProvider -import androidx.core.content.IntentCompat -import com.aurora.Constants.PACKAGE_NAME_PLAY_STORE -import com.aurora.extensions.TAG -import com.aurora.store.BuildConfig -import com.aurora.store.data.installer.MicroGInstaller.Companion.buildMicroGInstallIntent -import java.io.File - -class MicroGInstallerActivity : Activity() { - - companion object { - private const val REQUEST_CODE = 1001 - const val EXTRA_FILES = "extra_files" - const val EXTRA_PACKAGE_NAME = "extra_package_name" - - fun launch(context: Context, packageName: String, files: List) { - val uris = files.map { file -> - val uri = FileProvider.getUriForFile( - context, - "${BuildConfig.APPLICATION_ID}.fileProvider", - file - ) - - context.grantUriPermission( - PACKAGE_NAME_PLAY_STORE, - uri, - Intent.FLAG_GRANT_READ_URI_PERMISSION - ) - - uri - } - - val intent = Intent(context, MicroGInstallerActivity::class.java).apply { - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - putExtra(EXTRA_PACKAGE_NAME, packageName) - putExtra(EXTRA_FILES, ArrayList(uris)) - } - - context.startActivity(intent) - } - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - val files: ArrayList? = - IntentCompat.getParcelableArrayListExtra(intent, EXTRA_FILES, Uri::class.java) - - if (files.isNullOrEmpty()) { - Log.e(TAG, "No files provided, cannot proceed with MicroG installation") - return finish() - } - - startActivityForResult( - buildMicroGInstallIntent(files), - REQUEST_CODE - ) - } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - // TODO: Handle result if needed - finish() - } -} diff --git a/app/src/main/java/com/aurora/store/data/event/BusEvent.kt b/app/src/main/java/com/aurora/store/data/event/BusEvent.kt index 444e18c37..9dcb2282e 100644 --- a/app/src/main/java/com/aurora/store/data/event/BusEvent.kt +++ b/app/src/main/java/com/aurora/store/data/event/BusEvent.kt @@ -26,24 +26,22 @@ sealed class BusEvent : Event() { lateinit var error: String data class Blacklisted(val packageName: String) : BusEvent() + data class ManualDownload(val packageName: String, val versionCode: Int) : BusEvent() } sealed class AuthEvent : Event() { data class GoogleLogin(val success: Boolean, val email: String, val token: String) : AuthEvent() } -open class InstallerEvent(open val packageName: String) : Event() { - data class Installed(override val packageName: String) : InstallerEvent(packageName) - data class Uninstalled(override val packageName: String) : InstallerEvent(packageName) +sealed class InstallerEvent : Event() { + lateinit var extra: String + lateinit var error: String - data class Installing( - override val packageName: String, - val progress: Float = 0.0F - ) : InstallerEvent(packageName) + var progress: Int = -1 - data class Failed( - override val packageName: String, - val error: String? = null, - val extra: String? = null - ) : InstallerEvent(packageName) + data class Installed(val packageName: String) : InstallerEvent() + data class Uninstalled(val packageName: String) : InstallerEvent() + data class Installing(val packageName: String) : InstallerEvent() + data class Cancelled(val packageName: String) : InstallerEvent() + data class Failed(val packageName: String) : InstallerEvent() } diff --git a/app/src/main/java/com/aurora/store/data/event/EventFlow.kt b/app/src/main/java/com/aurora/store/data/event/EventFlow.kt index 495e8245a..3c3105d12 100644 --- a/app/src/main/java/com/aurora/store/data/event/EventFlow.kt +++ b/app/src/main/java/com/aurora/store/data/event/EventFlow.kt @@ -1,14 +1,15 @@ package com.aurora.store.data.event import android.util.Log -import com.aurora.extensions.TAG -import javax.inject.Singleton import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.asSharedFlow +import javax.inject.Singleton @Singleton class EventFlow { + private val TAG = EventFlow::class.java.simpleName + private val _busEvent = MutableSharedFlow(extraBufferCapacity = 1) val busEvent = _busEvent.asSharedFlow() diff --git a/app/src/main/java/com/aurora/store/data/helper/DownloadHelper.kt b/app/src/main/java/com/aurora/store/data/helper/DownloadHelper.kt index b0a9b7fb2..9bde44706 100644 --- a/app/src/main/java/com/aurora/store/data/helper/DownloadHelper.kt +++ b/app/src/main/java/com/aurora/store/data/helper/DownloadHelper.kt @@ -7,24 +7,22 @@ import androidx.work.ExistingWorkPolicy import androidx.work.OneTimeWorkRequestBuilder import androidx.work.OutOfQuotaPolicy import androidx.work.WorkManager -import com.aurora.extensions.TAG import com.aurora.gplayapi.data.models.App import com.aurora.store.AuroraApp import com.aurora.store.data.model.DownloadStatus import com.aurora.store.data.room.download.Download import com.aurora.store.data.room.download.DownloadDao -import com.aurora.store.data.room.suite.ExternalApk import com.aurora.store.data.room.update.Update import com.aurora.store.data.work.DownloadWorker import com.aurora.store.util.PathUtil import dagger.hilt.android.qualifiers.ApplicationContext -import javax.inject.Inject import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.firstOrNull -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import javax.inject.Inject /** * Helper class to work with the [DownloadWorker]. @@ -43,10 +41,10 @@ class DownloadHelper @Inject constructor( private const val VERSION_CODE = "VERSION_CODE" } - val downloadsList get() = downloadDao.downloads() + val downloadsList = downloadDao.downloads() .stateIn(AuroraApp.scope, SharingStarted.WhileSubscribed(), emptyList()) - val pagedDownloads get() = downloadDao.pagedDownloads() + private val TAG = DownloadHelper::class.java.simpleName /** * Removes failed download from the queue and starts observing for newly enqueued apps. @@ -60,19 +58,23 @@ class DownloadHelper @Inject constructor( } private fun observeDownloads() { - downloadDao.downloads().onEach { list -> - try { - if (list.none { it.status == DownloadStatus.DOWNLOADING }) { - list.find { it.status == DownloadStatus.QUEUED } - ?.let { queuedDownload -> - Log.i(TAG, "Enqueued download worker for ${queuedDownload.packageName}") - trigger(queuedDownload) + AuroraApp.scope.launch { + downloadDao.downloads().collectLatest { list -> + // Check and trigger next download in queue, if any + if (!list.any { it.downloadStatus == DownloadStatus.DOWNLOADING }) { + val enqueuedDownloads = list.filter { it.downloadStatus == DownloadStatus.QUEUED } + enqueuedDownloads.firstOrNull()?.let { + try { + Log.i(DOWNLOAD_WORKER, "Downloading ${it.packageName}") + trigger(it) + } catch (exception: Exception) { + Log.i(DOWNLOAD_WORKER, "Failed to download app", exception) + downloadDao.updateStatus(it.packageName, DownloadStatus.FAILED) } + } } - } catch (exception: Exception) { - Log.e(TAG, "Failed to enqueue download worker", exception) } - }.launchIn(AuroraApp.scope) + } } /** @@ -91,14 +93,6 @@ class DownloadHelper @Inject constructor( downloadDao.insert(Download.fromUpdate(update)) } - /** - * Enqueues ExternalApk for download & install - * @param externalApk [ExternalApk] to download - */ - suspend fun enqueueStandalone(externalApk: ExternalApk) { - downloadDao.insert(Download.fromExternalApk(externalApk)) - } - /** * Cancels the download for the given package * @param packageName Name of the package to cancel download @@ -106,7 +100,9 @@ class DownloadHelper @Inject constructor( suspend fun cancelDownload(packageName: String) { Log.i(TAG, "Cancelling download for $packageName") WorkManager.getInstance(context).cancelAllWorkByTag("$PACKAGE_NAME:$packageName") - downloadDao.updateStatus(packageName, DownloadStatus.CANCELLED) + downloadsList.filter { it.isNotEmpty() }.firstOrNull() + ?.find { it.packageName == packageName } + ?.let { downloadDao.updateStatus(packageName, DownloadStatus.CANCELLED) } } /** @@ -114,7 +110,7 @@ class DownloadHelper @Inject constructor( * @param packageName Name of the package of the app * @param versionCode Version of the package */ - suspend fun clearDownload(packageName: String, versionCode: Long) { + suspend fun clearDownload(packageName: String, versionCode: Int) { Log.i(TAG, "Clearing downloads for $packageName ($versionCode)") downloadDao.delete(packageName) PathUtil.getAppDownloadDir(context, packageName, versionCode) @@ -135,7 +131,7 @@ class DownloadHelper @Inject constructor( * Clears finished downloads and their downloaded files */ suspend fun clearFinishedDownloads() { - downloadDao.downloads().firstOrNull()?.filter { it.isFinished }?.forEach { + downloadsList.value.filter { it.isFinished }.forEach { clearDownload(it.packageName, it.versionCode) } } @@ -146,10 +142,8 @@ class DownloadHelper @Inject constructor( */ suspend fun cancelAll(updatesOnly: Boolean = false) { // Cancel all enqueued downloads first to avoid triggering re-download - downloadDao.downloads().firstOrNull() - ?.filter { it.status == DownloadStatus.QUEUED } - ?.filter { if (updatesOnly) it.isInstalled else true } - ?.forEach { + downloadsList.value.filter { it.downloadStatus == DownloadStatus.QUEUED } + .filter { if (updatesOnly) it.isInstalled else true }.forEach { downloadDao.updateStatus(it.packageName, DownloadStatus.CANCELLED) } @@ -184,9 +178,8 @@ class DownloadHelper @Inject constructor( // Ensure all app downloads are unique to preserve individual records WorkManager.getInstance(context) .enqueueUniqueWork( - "$DOWNLOAD_WORKER/${download.packageName}/${download.versionCode}", - ExistingWorkPolicy.KEEP, - work + "$DOWNLOAD_WORKER/${download.packageName}", + ExistingWorkPolicy.KEEP, work ) } } diff --git a/app/src/main/java/com/aurora/store/data/helper/UpdateHelper.kt b/app/src/main/java/com/aurora/store/data/helper/UpdateHelper.kt index 37a6c7fa0..c63a6e288 100644 --- a/app/src/main/java/com/aurora/store/data/helper/UpdateHelper.kt +++ b/app/src/main/java/com/aurora/store/data/helper/UpdateHelper.kt @@ -12,7 +12,7 @@ import androidx.work.OutOfQuotaPolicy import androidx.work.PeriodicWorkRequest import androidx.work.PeriodicWorkRequestBuilder import androidx.work.WorkManager -import com.aurora.extensions.TAG +import com.aurora.extensions.isMAndAbove import com.aurora.store.AuroraApp import com.aurora.store.data.event.BusEvent import com.aurora.store.data.event.InstallerEvent @@ -20,15 +20,8 @@ import com.aurora.store.data.model.UpdateMode import com.aurora.store.data.room.update.UpdateDao import com.aurora.store.data.work.UpdateWorker import com.aurora.store.util.Preferences -import com.aurora.store.util.Preferences.PREFERENCES_UPDATES_RESTRICTIONS_BATTERY -import com.aurora.store.util.Preferences.PREFERENCES_UPDATES_RESTRICTIONS_IDLE -import com.aurora.store.util.Preferences.PREFERENCES_UPDATES_RESTRICTIONS_METERED import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_CHECK_INTERVAL import dagger.hilt.android.qualifiers.ApplicationContext -import java.util.UUID -import java.util.concurrent.TimeUnit.HOURS -import java.util.concurrent.TimeUnit.MINUTES -import javax.inject.Inject import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.launchIn @@ -36,6 +29,9 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import java.util.concurrent.TimeUnit.HOURS +import java.util.concurrent.TimeUnit.MINUTES +import javax.inject.Inject /** * Helper class to work with the [UpdateWorker]. @@ -50,39 +46,10 @@ class UpdateHelper @Inject constructor( private const val UPDATE_WORKER = "UPDATE_WORKER" private const val EXPEDITED_UPDATE_WORKER = "EXPEDITED_UPDATE_WORKER" - - fun getAutoUpdateWork(context: Context): PeriodicWorkRequest { - val updateCheckInterval = Preferences.getInteger( - context, - PREFERENCE_UPDATES_CHECK_INTERVAL, - 3 - ).toLong() - - val constraints = Constraints.Builder() - - if (Preferences.getBoolean(context, PREFERENCES_UPDATES_RESTRICTIONS_METERED, true)) { - constraints.setRequiredNetworkType(NetworkType.UNMETERED) - } - - if (Preferences.getBoolean(context, PREFERENCES_UPDATES_RESTRICTIONS_BATTERY, true)) { - constraints.setRequiresBatteryNotLow(true) - } - - if (Preferences.getBoolean(context, PREFERENCES_UPDATES_RESTRICTIONS_IDLE, true)) { - constraints.setRequiresDeviceIdle(true) - } - - return PeriodicWorkRequestBuilder( - repeatInterval = updateCheckInterval, - repeatIntervalTimeUnit = HOURS, - flexTimeInterval = 30, - flexTimeIntervalUnit = MINUTES - ).setConstraints(constraints.build()) - .setId(UUID.nameUUIDFromBytes(UPDATE_WORKER.toByteArray())) - .build() - } } + private val TAG = UpdateHelper::class.java.simpleName + private val isExtendedUpdateEnabled get() = Preferences.getBoolean(context, Preferences.PREFERENCE_UPDATES_EXTENDED) @@ -146,13 +113,6 @@ class UpdateHelper @Inject constructor( updateDao.delete(packageName) } - /** - * Delete all updates from the database - */ - suspend fun deleteAllUpdates() { - updateDao.deleteAll() - } - /** * Cancels the automated updates check * @see [UpdateWorker] @@ -167,12 +127,12 @@ class UpdateHelper @Inject constructor( * @see [UpdateWorker] */ fun scheduleAutomatedCheck() { - Log.i(TAG, "Scheduling periodic app updates!") + Log.i(TAG,"Scheduling periodic app updates!") WorkManager.getInstance(context) .enqueueUniquePeriodicWork( UPDATE_WORKER, ExistingPeriodicWorkPolicy.KEEP, - getAutoUpdateWork(context) + getAutoUpdateWork() ) } @@ -181,9 +141,29 @@ class UpdateHelper @Inject constructor( * @see [UpdateWorker] */ fun updateAutomatedCheck() { - Log.i(TAG, "Updating periodic app updates!") - runCatching { WorkManager.getInstance(context).updateWork(getAutoUpdateWork(context)) } - .onFailure { Log.e(TAG, "Failed to update periodic app updates!", it) } + Log.i(TAG,"Updating periodic app updates!") + WorkManager.getInstance(context).updateWork(getAutoUpdateWork()) + } + + private fun getAutoUpdateWork(): PeriodicWorkRequest { + val updateCheckInterval = Preferences.getInteger( + context, + PREFERENCE_UPDATES_CHECK_INTERVAL, + 3 + ).toLong() + + val constraints = Constraints.Builder() + .setRequiredNetworkType(NetworkType.UNMETERED) + .setRequiresBatteryNotLow(true) + + if (isMAndAbove) constraints.setRequiresDeviceIdle(true) + + return PeriodicWorkRequestBuilder( + repeatInterval = updateCheckInterval, + repeatIntervalTimeUnit = HOURS, + flexTimeInterval = 30, + flexTimeIntervalUnit = MINUTES + ).setConstraints(constraints.build()).build() } private suspend fun deleteInvalidUpdates() { diff --git a/app/src/main/java/com/aurora/store/data/installer/AMInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/AMInstaller.kt index bd2e5a04e..d993dfaac 100644 --- a/app/src/main/java/com/aurora/store/data/installer/AMInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/AMInstaller.kt @@ -3,7 +3,6 @@ package com.aurora.store.data.installer import android.content.Context import android.content.Intent import android.util.Log -import com.aurora.extensions.TAG import com.aurora.store.R import com.aurora.store.data.installer.base.InstallerBase import com.aurora.store.data.model.Installer @@ -39,6 +38,8 @@ class AMInstaller @Inject constructor( ) } + private val TAG = AMInstaller::class.java.simpleName + override fun install(download: Download) { if (isAlreadyQueued(download.packageName)) { Log.i(TAG, "${download.packageName} already queued") diff --git a/app/src/main/java/com/aurora/store/data/installer/AppInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/AppInstaller.kt index d0739df30..8d7b0a97e 100644 --- a/app/src/main/java/com/aurora/store/data/installer/AppInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/AppInstaller.kt @@ -31,20 +31,18 @@ import com.aurora.extensions.isOAndAbove import com.aurora.extensions.isPAndAbove import com.aurora.extensions.isSAndAbove import com.aurora.store.BuildConfig -import com.aurora.store.data.installer.ShizukuInstaller.Companion.SHIZUKU_PACKAGE_NAME import com.aurora.store.data.installer.base.IInstaller import com.aurora.store.data.model.Installer import com.aurora.store.data.model.InstallerInfo import com.aurora.store.util.PackageUtil -import com.aurora.store.util.PackageUtil.hasMicroGCompanion import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences.PREFERENCE_INSTALLER_ID import com.topjohnwu.superuser.Shell import dagger.hilt.android.qualifiers.ApplicationContext -import javax.inject.Inject -import javax.inject.Singleton import rikka.shizuku.Shizuku import rikka.sui.Sui +import javax.inject.Inject +import javax.inject.Singleton @Singleton class AppInstaller @Inject constructor( @@ -54,33 +52,30 @@ class AppInstaller @Inject constructor( private val rootInstaller: RootInstaller, private val serviceInstaller: ServiceInstaller, private val amInstaller: AMInstaller, - private val shizukuInstaller: ShizukuInstaller, - private val microGInstaller: MicroGInstaller + private val shizukuInstaller: ShizukuInstaller ) { companion object { - const val ACTION_INSTALL_STATUS = - "com.aurora.store.data.installer.AppInstaller.INSTALL_STATUS" - - const val EXTRA_PACKAGE_NAME = - "com.aurora.store.data.installer.AppInstaller.EXTRA_PACKAGE_NAME" - const val EXTRA_VERSION_CODE = - "com.aurora.store.data.installer.AppInstaller.EXTRA_VERSION_CODE" - const val EXTRA_DISPLAY_NAME = - "com.aurora.store.data.installer.AppInstaller.EXTRA_DISPLAY_NAME" - - fun getCurrentInstaller(context: Context): Installer = - Installer.entries[Preferences.getInteger(context, PREFERENCE_INSTALLER_ID)] - - fun getAvailableInstallersInfo(context: Context): List = listOfNotNull( - SessionInstaller.installerInfo, - NativeInstaller.installerInfo, - if (hasRootAccess()) RootInstaller.installerInfo else null, - if (hasAuroraService(context)) ServiceInstaller.installerInfo else null, - if (hasAppManager(context)) AMInstaller.installerInfo else null, - if (hasShizukuOrSui(context)) ShizukuInstaller.installerInfo else null, - if (hasMicroGCompanion(context)) MicroGInstaller.installerInfo else null - ) + const val ACTION_INSTALL_STATUS = "com.aurora.store.data.installer.AppInstaller.INSTALL_STATUS" + + const val EXTRA_PACKAGE_NAME = "com.aurora.store.data.installer.AppInstaller.EXTRA_PACKAGE_NAME" + const val EXTRA_VERSION_CODE = "com.aurora.store.data.installer.AppInstaller.EXTRA_VERSION_CODE" + const val EXTRA_DISPLAY_NAME = "com.aurora.store.data.installer.AppInstaller.EXTRA_DISPLAY_NAME" + + fun getCurrentInstaller(context: Context): Installer { + return Installer.entries[Preferences.getInteger(context, PREFERENCE_INSTALLER_ID)] + } + + fun getAvailableInstallersInfo(context: Context): List { + return listOfNotNull( + SessionInstaller.installerInfo, + NativeInstaller.installerInfo, + if (hasRootAccess()) RootInstaller.installerInfo else null, + if (hasAuroraService(context)) ServiceInstaller.installerInfo else null, + if (hasAppManager(context)) AMInstaller.installerInfo else null, + if (hasShizukuOrSui(context)) ShizukuInstaller.installerInfo else null + ) + } /** * Checks if the given package can be silently installed @@ -94,71 +89,58 @@ class AppInstaller @Inject constructor( if (!PackageUtil.isInstalled(context, packageName) || !isSAndAbove) return false // We cannot do silent updates if we are not the update owner - if (context.packageManager.getUpdateOwnerPackageNameCompat(packageName) != - BuildConfig.APPLICATION_ID - ) { - return false - } + if (context.packageManager.getUpdateOwnerPackageNameCompat(packageName) != BuildConfig.APPLICATION_ID) return false // Ensure app being installed satisfies Android's requirement for targetSdk level when (Build.VERSION.SDK_INT) { - Build.VERSION_CODES.BAKLAVA -> { - targetSdk >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE - } - - Build.VERSION_CODES.VANILLA_ICE_CREAM -> { - targetSdk >= Build.VERSION_CODES.TIRAMISU - } - + Build.VERSION_CODES.VANILLA_ICE_CREAM -> targetSdk >= Build.VERSION_CODES.TIRAMISU Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> targetSdk >= Build.VERSION_CODES.S - Build.VERSION_CODES.TIRAMISU -> targetSdk >= Build.VERSION_CODES.R - Build.VERSION_CODES.S -> targetSdk >= Build.VERSION_CODES.Q - else -> false // Only Android version above 12 can silently update apps } } - - // Native installer requires user interaction - Installer.NATIVE -> false - + Installer.NATIVE -> false // Native installer requires user interaction Installer.ROOT -> hasRootAccess() - Installer.SERVICE -> hasAuroraService(context) - - // We cannot check if AppManager has ability to auto-update - Installer.AM -> false - + Installer.AM -> false // We cannot check if AppManager has ability to auto-update Installer.SHIZUKU -> isOAndAbove && hasShizukuOrSui(context) && hasShizukuPerm() - - Installer.MICROG -> false } } - fun hasRootAccess(): Boolean = Shell.getShell().isRoot - - fun hasAuroraService(context: Context): Boolean = try { - val packageInfo = PackageUtil.getPackageInfo( - context, - ServiceInstaller.PRIVILEGED_EXTENSION_PACKAGE_NAME - ) - val version = PackageInfoCompat.getLongVersionCode(packageInfo) + fun hasRootAccess(): Boolean { + return Shell.getShell().isRoot + } - packageInfo.applicationInfo!!.enabled && version >= 9 - } catch (_: Exception) { - false + fun hasAuroraService(context: Context): Boolean { + return try { + val packageInfo = PackageUtil.getPackageInfo( + context, + ServiceInstaller.PRIVILEGED_EXTENSION_PACKAGE_NAME + ) + val version = PackageInfoCompat.getLongVersionCode(packageInfo) + + packageInfo.applicationInfo!!.enabled && version >= 9 + } catch (exception: Exception) { + false + } } - fun hasAppManager(context: Context): Boolean = - PackageUtil.isInstalled(context, AMInstaller.AM_PACKAGE_NAME) or - PackageUtil.isInstalled(context, AMInstaller.AM_DEBUG_PACKAGE_NAME) + fun hasAppManager(context: Context): Boolean { + return PackageUtil.isInstalled(context, AMInstaller.AM_PACKAGE_NAME) or + PackageUtil.isInstalled(context, AMInstaller.AM_DEBUG_PACKAGE_NAME) + } - fun hasShizukuOrSui(context: Context): Boolean = isOAndAbove && - (PackageUtil.isInstalled(context, SHIZUKU_PACKAGE_NAME) || Sui.isSui()) + fun hasShizukuOrSui(context: Context): Boolean { + return isOAndAbove && (PackageUtil.isInstalled( + context, + ShizukuInstaller.SHIZUKU_PACKAGE_NAME + ) || Sui.isSui()) + } - fun hasShizukuPerm(): Boolean = - Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED + fun hasShizukuPerm(): Boolean { + return Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED + } fun uninstall(context: Context, packageName: String) { val intent = Intent().apply { @@ -179,33 +161,20 @@ class AppInstaller @Inject constructor( private val defaultInstaller: IInstaller get() = sessionInstaller - fun getMicroGInstaller(): IInstaller = microGInstaller - - fun getPreferredInstaller(): IInstaller = when (getCurrentInstaller(context)) { - Installer.SESSION -> sessionInstaller - - Installer.NATIVE -> nativeInstaller - - Installer.ROOT -> if (hasRootAccess()) rootInstaller else defaultInstaller - - Installer.SERVICE -> if (hasAuroraService(context)) { - serviceInstaller - } else { - defaultInstaller - } - - Installer.AM -> if (hasAppManager(context)) amInstaller else defaultInstaller - - Installer.SHIZUKU -> if (hasShizukuOrSui(context) && hasShizukuPerm()) { - shizukuInstaller - } else { - defaultInstaller - } - - Installer.MICROG -> if (hasMicroGCompanion(context)) { - microGInstaller - } else { - defaultInstaller + fun getPreferredInstaller(): IInstaller { + return when (getCurrentInstaller(context)) { + Installer.SESSION -> sessionInstaller + Installer.NATIVE -> nativeInstaller + Installer.ROOT -> if (hasRootAccess()) rootInstaller else defaultInstaller + Installer.SERVICE -> if (hasAuroraService(context)) serviceInstaller else defaultInstaller + Installer.AM -> if (hasAppManager(context)) amInstaller else defaultInstaller + Installer.SHIZUKU -> { + if (hasShizukuOrSui(context) && hasShizukuPerm()) { + shizukuInstaller + } else { + defaultInstaller + } + } } } } diff --git a/app/src/main/java/com/aurora/store/data/installer/MicroGInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/MicroGInstaller.kt deleted file mode 100644 index e72fcf4cb..000000000 --- a/app/src/main/java/com/aurora/store/data/installer/MicroGInstaller.kt +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Aurora Store - * Copyright (C) 2021, Rahul Kumar Patel - * - * Aurora Store is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Aurora Store is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Aurora Store. If not, see . - * - */ - -package com.aurora.store.data.installer - -import android.content.Context -import android.content.Intent -import android.net.Uri -import android.util.Log -import com.aurora.Constants.PACKAGE_NAME_PLAY_STORE -import com.aurora.extensions.TAG -import com.aurora.store.R -import com.aurora.store.data.activity.MicroGInstallerActivity -import com.aurora.store.data.installer.base.InstallerBase -import com.aurora.store.data.model.Installer -import com.aurora.store.data.model.InstallerInfo -import com.aurora.store.data.room.download.Download -import com.aurora.store.util.PackageUtil.hasMicroGCompanion -import dagger.hilt.android.qualifiers.ApplicationContext -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class MicroGInstaller @Inject constructor( - @ApplicationContext private val context: Context -) : InstallerBase(context) { - - companion object { - val installerInfo: InstallerInfo - get() = InstallerInfo( - id = 6, - installer = Installer.MICROG, - packageNames = listOf(PACKAGE_NAME_PLAY_STORE), - installerPackageNames = listOf(PACKAGE_NAME_PLAY_STORE), - title = R.string.pref_install_mode_microg, - subtitle = R.string.microg_installer_subtitle, - description = R.string.microg_installer_desc - ) - - fun buildMicroGInstallIntent(uris: ArrayList): Intent = - Intent("org.microg.vending.action.INSTALL_PACKAGE").apply { - setPackage(PACKAGE_NAME_PLAY_STORE) - setType("application/vnd.android.package-archive") - putExtra(Intent.EXTRA_STREAM, uris) - } - } - - override fun install(download: Download) { - super.install(download) - - when { - isAlreadyQueued(download.packageName) -> { - Log.i(TAG, "${download.packageName} already queued") - } - - hasMicroGCompanion(context) -> { - Log.i(TAG, "Received microG install request for ${download.packageName}") - - val files = getFiles(download.packageName, download.versionCode) - MicroGInstallerActivity.launch(context, download.packageName, files) - - Log.i(TAG, "Sent install request to microG installer for ${download.packageName}") - } - - else -> { - postError( - download.packageName, - context.getString(R.string.installer_status_failure), - context.getString(R.string.installer_microg_misconfigured) - ) - } - } - } -} diff --git a/app/src/main/java/com/aurora/store/data/installer/NativeInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/NativeInstaller.kt index 97948d04f..3ae866934 100644 --- a/app/src/main/java/com/aurora/store/data/installer/NativeInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/NativeInstaller.kt @@ -24,7 +24,6 @@ import android.content.Intent import android.net.Uri import android.os.Build import android.util.Log -import com.aurora.extensions.TAG import com.aurora.extensions.runOnUiThread import com.aurora.store.R import com.aurora.store.data.installer.base.InstallerBase @@ -57,6 +56,8 @@ class NativeInstaller @Inject constructor( ) } + private val TAG = NativeInstaller::class.java.simpleName + override fun install(download: Download) { if (isAlreadyQueued(download.packageName)) { Log.i(TAG, "${download.packageName} already queued") diff --git a/app/src/main/java/com/aurora/store/data/installer/RootInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/RootInstaller.kt index 1d4d9484a..84a7924f4 100644 --- a/app/src/main/java/com/aurora/store/data/installer/RootInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/RootInstaller.kt @@ -21,7 +21,6 @@ package com.aurora.store.data.installer import android.content.Context import android.util.Log -import com.aurora.extensions.TAG import com.aurora.store.AuroraApp import com.aurora.store.R import com.aurora.store.data.event.InstallerEvent @@ -57,6 +56,8 @@ class RootInstaller @Inject constructor( ) } + private val TAG = RootInstaller::class.java.simpleName + override fun install(download: Download) { if (isAlreadyQueued(download.packageName)) { Log.i(TAG, "${download.packageName} already queued") @@ -75,20 +76,16 @@ class RootInstaller @Inject constructor( context.getString(R.string.installer_status_failure), context.getString(R.string.installer_root_unavailable) ) - Log.e( - TAG, - " >>>>>>>>>>>>>>>>>>>>>>>>>> NO ROOT ACCESS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<" - ) + Log.e(TAG, " >>>>>>>>>>>>>>>>>>>>>>>>>> NO ROOT ACCESS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<") } } } - private fun xInstall(packageName: String, versionCode: Long, sharedLibPkgName: String = "") { + private fun xInstall(packageName: String, versionCode: Int, sharedLibPkgName: String = "") { var totalSize = 0 - for (file in getFiles(packageName, versionCode, sharedLibPkgName)) { + for (file in getFiles(packageName, versionCode, sharedLibPkgName)) totalSize += file.length().toInt() - } val result: Shell.Result = Shell.cmd("pm install-create -i $PLAY_PACKAGE_NAME --user 0 -r -S $totalSize") @@ -104,9 +101,7 @@ class RootInstaller @Inject constructor( val sessionId = sessionIdMatcher.group(1)?.toInt() if (Shell.getShell().isRoot && sessionId != null) { for (file in getFiles(packageName, versionCode, sharedLibPkgName)) { - Shell.cmd( - "cat \"${file.absoluteFile}\" | pm install-write -S ${file.length()} $sessionId \"${file.name}\"" - ) + Shell.cmd("cat \"${file.absoluteFile}\" | pm install-write -S ${file.length()} $sessionId \"${file.name}\"") .exec() } @@ -117,12 +112,11 @@ class RootInstaller @Inject constructor( if (packageName == download?.packageName) onInstallationSuccess() } else { removeFromInstallQueue(packageName) - AuroraApp.events.send( - InstallerEvent.Failed( - packageName = packageName, - error = parseError(shellResult) - ) - ) + val event = InstallerEvent.Failed(packageName).apply { + this.extra = context.getString(R.string.installer_status_failure) + this.error = parseError(shellResult) + } + AuroraApp.events.send(event) } } else { removeFromInstallQueue(packageName) @@ -142,5 +136,7 @@ class RootInstaller @Inject constructor( } } - private fun parseError(result: Shell.Result): String = result.err.joinToString(separator = "\n") + private fun parseError(result: Shell.Result): String { + return result.err.joinToString(separator = "\n") + } } diff --git a/app/src/main/java/com/aurora/store/data/installer/ServiceInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/ServiceInstaller.kt index d933be6a9..e354db4f0 100644 --- a/app/src/main/java/com/aurora/store/data/installer/ServiceInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/ServiceInstaller.kt @@ -30,7 +30,6 @@ import android.os.IBinder import android.os.Looper import android.os.RemoteException import android.util.Log -import com.aurora.extensions.TAG import com.aurora.services.IPrivilegedCallback import com.aurora.services.IPrivilegedService import com.aurora.store.AuroraApp @@ -76,6 +75,8 @@ class ServiceInstaller @Inject constructor( ) } + private val TAG = ServiceInstaller::class.java.simpleName + override fun install(download: Download) { super.install(download) @@ -229,7 +230,11 @@ class ServiceInstaller @Inject constructor( try { when (returnCode) { PackageInstaller.STATUS_SUCCESS -> { - AuroraApp.events.send(InstallerEvent.Uninstalled(packageName = packageName)) + AuroraApp.events.send( + InstallerEvent.Uninstalled(packageName).apply { + this.extra = context.getString(R.string.action_uninstall_success) + } + ) } else -> postError(packageName, getErrorString(context, returnCode), extra) @@ -248,7 +253,11 @@ class ServiceInstaller @Inject constructor( try { when (returnCode) { PackageInstaller.STATUS_SUCCESS -> { - AuroraApp.events.send(InstallerEvent.Installed(packageName = packageName)) + AuroraApp.events.send( + InstallerEvent.Installed(packageName).apply { + this.extra = context.getString(R.string.installer_status_success) + } + ) // Installation is not yet finished if this is a shared library if (packageName == download?.packageName) onInstallationSuccess() } diff --git a/app/src/main/java/com/aurora/store/data/installer/SessionInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/SessionInstaller.kt index f3726d7f4..5caff1339 100644 --- a/app/src/main/java/com/aurora/store/data/installer/SessionInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/SessionInstaller.kt @@ -25,14 +25,12 @@ import android.content.Context import android.content.Intent import android.content.pm.PackageInfo import android.content.pm.PackageInstaller -import android.content.pm.PackageInstaller.EXTRA_SESSION_ID import android.content.pm.PackageInstaller.PACKAGE_SOURCE_STORE import android.content.pm.PackageInstaller.SessionParams import android.content.pm.PackageManager import android.os.Process import android.util.Log import androidx.core.app.PendingIntentCompat -import com.aurora.extensions.TAG import com.aurora.extensions.isNAndAbove import com.aurora.extensions.isOAndAbove import com.aurora.extensions.isSAndAbove @@ -64,6 +62,8 @@ class SessionInstaller @Inject constructor( @ApplicationContext private val context: Context ) : InstallerBase(context) { + private val TAG = SessionInstaller::class.java.simpleName + val currentSessionId: Int? get() = enqueuedSessions.firstOrNull()?.last()?.sessionId @@ -85,40 +85,31 @@ class SessionInstaller @Inject constructor( if (packageName != null && progress > 0.0) { AuroraApp.events.send( - InstallerEvent.Installing( - packageName = packageName, - progress = progress - ) + InstallerEvent.Installing(packageName).apply { + this.progress = (progress * 100).toInt() + } ) } } override fun onFinished(sessionId: Int, success: Boolean) { - val sessionSet = - enqueuedSessions.find { it.any { session -> session.sessionId == sessionId } } - ?: return - - // Find session safely, if not found return - val sessionToRemove = sessionSet.firstOrNull { it.sessionId == sessionId } ?: return - - // Remove the session safely - sessionSet.remove(sessionToRemove) - - if (success && sessionSet.isNotEmpty()) { - commitInstall(sessionSet.first()) // Proceed with next session (shared lib), if any - return - } + enqueuedSessions.find { set -> set.any { it.sessionId == sessionId } } + ?.let { sessionSet -> + sessionSet.remove(sessionSet.first { it.sessionId == sessionId }) + + // If this was a shared lib, proceed installing other libs or actual package + if (sessionSet.isNotEmpty() && success) { + commitInstall(sessionSet.first()); return + } else { + enqueuedSessions.remove(sessionSet) + } + } - // Manually remove empty sets using iterator (for API 21 support) - val iterator = enqueuedSessions.iterator() - while (iterator.hasNext()) { - if (iterator.next().isEmpty()) { - iterator.remove() + if (enqueuedSessions.isNotEmpty()) { + enqueuedSessions.firstOrNull()?.let { sessionSet -> + commitInstall(sessionSet.first()) } } - - // Proceed with the next available session - enqueuedSessions.firstOrNull()?.firstOrNull()?.let(::commitInstall) } } @@ -184,7 +175,7 @@ class SessionInstaller @Inject constructor( private fun stageInstall( packageName: String, - versionCode: Long, + versionCode: Int, sharedLibPkgName: String = "" ): Int? { val resolvedPackageName = sharedLibPkgName.ifBlank { packageName } @@ -216,8 +207,8 @@ class SessionInstaller @Inject constructor( } } - private fun buildSessionParams(packageName: String): SessionParams = - SessionParams(SessionParams.MODE_FULL_INSTALL).apply { + private fun buildSessionParams(packageName: String): SessionParams { + return SessionParams(SessionParams.MODE_FULL_INSTALL).apply { setAppPackageName(packageName) setInstallLocation(PackageInfo.INSTALL_LOCATION_AUTO) if (isNAndAbove) { @@ -238,42 +229,19 @@ class SessionInstaller @Inject constructor( setApplicationEnabledSettingPersistent() } } - - private fun commitInstall(sessionInfo: SessionInfo) { - try { - Log.i(TAG, "Starting install session for ${sessionInfo.packageName}") - - val existingSessionInfo = packageInstaller.getSessionInfo(sessionInfo.sessionId) - if (existingSessionInfo == null) { - Log.e(TAG, "Session ${sessionInfo.sessionId} is no longer valid.") - return removeFromInstallQueue(sessionInfo.packageName) - } - - commitSession(sessionInfo) - } catch (e: Exception) { - Log.e(TAG, "Error committing session: ${e.message}") - removeFromInstallQueue(sessionInfo.packageName) - postError(sessionInfo.packageName, e.localizedMessage, e.stackTraceToString()) - } } - private fun commitSession(sessionInfo: SessionInfo) { - try { - val session = packageInstaller.openSession(sessionInfo.sessionId) - session.commit(getCallBackIntent(sessionInfo)!!.intentSender) - session.close() - } catch (e: Exception) { - Log.e(TAG, "Error committing session: ${e.message}") - } finally { - removeFromInstallQueue(sessionInfo.packageName) - } + private fun commitInstall(sessionInfo: SessionInfo) { + Log.i(TAG, "Starting install session for ${sessionInfo.packageName}") + val session = packageInstaller.openSession(sessionInfo.sessionId) + session.commit(getCallBackIntent(sessionInfo)!!.intentSender) + session.close() } private fun getCallBackIntent(sessionInfo: SessionInfo): PendingIntent? { val callBackIntent = Intent(context, InstallerStatusReceiver::class.java).apply { action = ACTION_INSTALL_STATUS setPackage(context.packageName) - putExtra(EXTRA_SESSION_ID, sessionInfo.sessionId) putExtra(EXTRA_PACKAGE_NAME, sessionInfo.packageName) putExtra(EXTRA_VERSION_CODE, sessionInfo.versionCode) putExtra(EXTRA_DISPLAY_NAME, sessionInfo.displayName) @@ -288,22 +256,4 @@ class SessionInstaller @Inject constructor( true ) } - - enum class ServiceResultCode(val code: Int, val reason: String) { - SUCCESS(0, "Request successful"), - SERVICE_VERSION_UPDATE_REQUIRED(2, "Interface depends on a higher version"), - SERVICE_INVALID(4, "Service is invalid"), - METHOD_UNSUPPORTED(5, "Interface is not supported"), - RESOLUTION_REQUIRED(6, "Needs to be resolved by opening PendingIntent"), - NETWORK_ERROR(7, "Network exception, unable to complete interface request"), - INTERNAL_ERROR(8, "Internal code error, incorrect parameter transmission in scenario"), - TIMEOUT(10, "Interface access timeout return"), - DEAD_CLIENT(12, "Current client is unavailable"), - RESPONSE_ERROR(13, "Server returns abnormal response"), - PROTOCOL_ERROR(15, "Not signed Huawei App Market agreement"); - - companion object { - fun fromCode(code: Int): ServiceResultCode? = entries.find { it.code == code } - } - } } diff --git a/app/src/main/java/com/aurora/store/data/installer/ShizukuInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/ShizukuInstaller.kt index db090dc50..c664021f7 100644 --- a/app/src/main/java/com/aurora/store/data/installer/ShizukuInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/ShizukuInstaller.kt @@ -35,7 +35,6 @@ import android.os.IInterface import android.util.Log import androidx.annotation.RequiresApi import androidx.core.app.PendingIntentCompat -import com.aurora.extensions.TAG import com.aurora.extensions.isOAndAbove import com.aurora.extensions.isSAndAbove import com.aurora.store.R @@ -51,10 +50,10 @@ import com.aurora.store.data.room.download.Download import com.aurora.store.util.PackageUtil.isSharedLibraryInstalled import dagger.hilt.android.qualifiers.ApplicationContext import dev.rikka.tools.refine.Refine -import javax.inject.Inject -import javax.inject.Singleton import rikka.shizuku.ShizukuBinderWrapper import rikka.shizuku.SystemServiceHelper +import javax.inject.Inject +import javax.inject.Singleton @Singleton @RequiresApi(Build.VERSION_CODES.O) @@ -78,6 +77,8 @@ class ShizukuInstaller @Inject constructor( ) } + private val TAG = ShizukuInstaller::class.java.simpleName + // Taken from LSPatch (https://github.com/LSPosed/LSPatch) private fun IBinder.wrap() = ShizukuBinderWrapper(this) private fun IInterface.asShizukuBinder() = this.asBinder().wrap() @@ -99,9 +100,7 @@ class ShizukuInstaller @Inject constructor( Refine.unsafeCast( PackageInstallerHidden(iPackageInstaller, PLAY_PACKAGE_NAME, 0) ) - } else { - null - } + } else null } override fun install(download: Download) { @@ -130,14 +129,11 @@ class ShizukuInstaller @Inject constructor( private fun install( packageName: String, - versionCode: Long, + versionCode: Int, sharedLibPkgName: String = "", displayName: String = "" ) { - Log.i( - TAG, - "Received session install request for ${sharedLibPkgName.ifBlank { packageName }}" - ) + Log.i(TAG, "Received session install request for ${sharedLibPkgName.ifBlank { packageName }}") val (sessionId, session) = kotlin.runCatching { val params = SessionParams(SessionParams.MODE_FULL_INSTALL) @@ -172,11 +168,7 @@ class ShizukuInstaller @Inject constructor( Log.i(TAG, "Writing splits to session for ${sharedLibPkgName.ifBlank { packageName }}") getFiles(packageName, versionCode, sharedLibPkgName).forEach { it.inputStream().use { input -> - session.openWrite( - "${sharedLibPkgName.ifBlank { packageName }}_${System.currentTimeMillis()}", - 0, - -1 - ).use { output -> + session.openWrite("${sharedLibPkgName.ifBlank { packageName }}_${System.currentTimeMillis()}", 0, -1).use { output -> input.copyTo(output) session.fsync(output) } diff --git a/app/src/main/java/com/aurora/store/data/installer/base/InstallerBase.kt b/app/src/main/java/com/aurora/store/data/installer/base/InstallerBase.kt index 035523af3..5627ce2cd 100644 --- a/app/src/main/java/com/aurora/store/data/installer/base/InstallerBase.kt +++ b/app/src/main/java/com/aurora/store/data/installer/base/InstallerBase.kt @@ -26,11 +26,11 @@ import android.net.Uri import android.util.Log import androidx.core.content.FileProvider import androidx.core.content.getSystemService -import com.aurora.extensions.TAG import com.aurora.store.AuroraApp import com.aurora.store.BuildConfig import com.aurora.store.R import com.aurora.store.data.event.InstallerEvent +import com.aurora.store.data.installer.AppInstaller import com.aurora.store.data.room.download.Download import com.aurora.store.util.NotificationUtil import com.aurora.store.util.PathUtil @@ -43,43 +43,25 @@ abstract class InstallerBase(private val context: Context) : IInstaller { companion object { fun notifyInstallation(context: Context, displayName: String, packageName: String) { val notificationManager = context.getSystemService() - val notification = NotificationUtil.getInstallNotification( - context, - displayName, - packageName - ) + val notification = NotificationUtil.getInstallNotification(context, displayName, packageName) notificationManager!!.notify(packageName.hashCode(), notification) } - fun getErrorString(context: Context, status: Int): String = when (status) { - PackageInstaller.STATUS_FAILURE_ABORTED -> context.getString( - R.string.installer_status_user_action - ) - - PackageInstaller.STATUS_FAILURE_BLOCKED -> context.getString( - R.string.installer_status_failure_blocked - ) - - PackageInstaller.STATUS_FAILURE_CONFLICT -> context.getString( - R.string.installer_status_failure_conflict - ) - - PackageInstaller.STATUS_FAILURE_INCOMPATIBLE -> context.getString( - R.string.installer_status_failure_incompatible - ) - - PackageInstaller.STATUS_FAILURE_INVALID -> context.getString( - R.string.installer_status_failure_invalid - ) - - PackageInstaller.STATUS_FAILURE_STORAGE -> context.getString( - R.string.installer_status_failure_storage - ) - - else -> context.getString(R.string.installer_status_failure) + fun getErrorString(context: Context, status: Int): String { + return when (status) { + PackageInstaller.STATUS_FAILURE_ABORTED -> context.getString(R.string.installer_status_user_action) + PackageInstaller.STATUS_FAILURE_BLOCKED -> context.getString(R.string.installer_status_failure_blocked) + PackageInstaller.STATUS_FAILURE_CONFLICT -> context.getString(R.string.installer_status_failure_conflict) + PackageInstaller.STATUS_FAILURE_INCOMPATIBLE -> context.getString(R.string.installer_status_failure_incompatible) + PackageInstaller.STATUS_FAILURE_INVALID -> context.getString(R.string.installer_status_failure_invalid) + PackageInstaller.STATUS_FAILURE_STORAGE -> context.getString(R.string.installer_status_failure_storage) + else -> context.getString(R.string.installer_status_failure) + } } } + private val TAG = InstallerBase::class.java.simpleName + var download: Download? = null private set @@ -91,8 +73,9 @@ abstract class InstallerBase(private val context: Context) : IInstaller { AuroraApp.enqueuedInstalls.clear() } - override fun isAlreadyQueued(packageName: String): Boolean = - AuroraApp.enqueuedInstalls.contains(packageName) + override fun isAlreadyQueued(packageName: String): Boolean { + return AuroraApp.enqueuedInstalls.contains(packageName) + } override fun removeFromInstallQueue(packageName: String) { AuroraApp.enqueuedInstalls.remove(packageName) @@ -109,19 +92,19 @@ abstract class InstallerBase(private val context: Context) : IInstaller { } open fun postError(packageName: String, error: String?, extra: String?) { - Log.e(TAG, "Installer Error :$error") - AuroraApp.events.send( - InstallerEvent.Failed( - packageName = packageName, - error = error, - extra = extra - ) - ) + Log.e(TAG, "Service Error :$error") + + val event = InstallerEvent.Failed(packageName).apply { + this.error = error ?: "" + this.extra = extra ?: "" + } + + AuroraApp.events.send(event) } fun getFiles( packageName: String, - versionCode: Long, + versionCode: Int, sharedLibPackageName: String = "" ): List { val downloadDir = if (sharedLibPackageName.isNotBlank()) { @@ -132,9 +115,11 @@ abstract class InstallerBase(private val context: Context) : IInstaller { return downloadDir.listFiles()!!.filter { it.path.endsWith(".apk") } } - fun getUri(file: File): Uri = FileProvider.getUriForFile( - context, - "${BuildConfig.APPLICATION_ID}.fileProvider", - file - ) + fun getUri(file: File): Uri { + return FileProvider.getUriForFile( + context, + "${BuildConfig.APPLICATION_ID}.fileProvider", + file + ) + } } diff --git a/app/src/main/java/com/aurora/store/data/model/Auth.kt b/app/src/main/java/com/aurora/store/data/model/Auth.kt index 12de75e09..ea8fae583 100644 --- a/app/src/main/java/com/aurora/store/data/model/Auth.kt +++ b/app/src/main/java/com/aurora/store/data/model/Auth.kt @@ -19,13 +19,7 @@ package com.aurora.store.data.model -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable data class Auth( val email: String, - - @SerialName("authToken") val auth: String ) diff --git a/app/src/main/java/com/aurora/store/data/model/Black.kt b/app/src/main/java/com/aurora/store/data/model/Black.kt index 750e9ab1a..d5960eeb5 100644 --- a/app/src/main/java/com/aurora/store/data/model/Black.kt +++ b/app/src/main/java/com/aurora/store/data/model/Black.kt @@ -27,10 +27,14 @@ data class Black(val packageName: String) { var versionName: String = String() var versionCode: Long = 0 - override fun hashCode(): Int = packageName.hashCode() + override fun hashCode(): Int { + return packageName.hashCode() + } - override fun equals(other: Any?): Boolean = when (other) { - is Black -> other.packageName == packageName - else -> false + override fun equals(other: Any?): Boolean { + return when (other) { + is Black -> other.packageName == packageName + else -> false + } } } diff --git a/app/src/huawei/java/com/aurora/store/view/ui/splash/SplashFragment.kt b/app/src/main/java/com/aurora/store/data/model/Dash.kt similarity index 64% rename from app/src/huawei/java/com/aurora/store/view/ui/splash/SplashFragment.kt rename to app/src/main/java/com/aurora/store/data/model/Dash.kt index 2b5f789be..6893f339e 100644 --- a/app/src/huawei/java/com/aurora/store/view/ui/splash/SplashFragment.kt +++ b/app/src/main/java/com/aurora/store/data/model/Dash.kt @@ -17,22 +17,25 @@ * */ -package com.aurora.store.view.ui.splash +package com.aurora.store.data.model -import com.aurora.extensions.hide -import dagger.hilt.android.AndroidEntryPoint +import androidx.annotation.DrawableRes -@AndroidEntryPoint -class SplashFragment : BaseFlavouredSplashFragment() { - override fun attachActions() { - super.attachActions() - - binding.btnAnonymous.hide() +data class Dash( + var id: Int, + var title: String, + var subtitle: String, + @DrawableRes var icon: Int, + var url: String +) { + override fun equals(other: Any?): Boolean { + return when (other) { + is Dash -> other.id == id + else -> false + } } - override fun resetActions() { - super.resetActions() - - binding.btnAnonymous.hide() + override fun hashCode(): Int { + return id.hashCode() } } diff --git a/app/src/main/java/com/aurora/store/data/model/DownloadStatus.kt b/app/src/main/java/com/aurora/store/data/model/DownloadStatus.kt index da3dada10..4e1a8596a 100644 --- a/app/src/main/java/com/aurora/store/data/model/DownloadStatus.kt +++ b/app/src/main/java/com/aurora/store/data/model/DownloadStatus.kt @@ -10,11 +10,10 @@ enum class DownloadStatus(@StringRes val localized: Int) { COMPLETED(R.string.status_completed), QUEUED(R.string.status_queued), UNAVAILABLE(R.string.status_unavailable), - VERIFYING(R.string.status_verifying), - PURCHASING(R.string.preparing_to_install); + VERIFYING(R.string.status_verifying); companion object { val finished = listOf(FAILED, CANCELLED, COMPLETED) - val running = listOf(QUEUED, PURCHASING, DOWNLOADING) + val running = listOf(QUEUED, DOWNLOADING) } } diff --git a/app/src/main/java/com/aurora/store/data/model/Exodus.kt b/app/src/main/java/com/aurora/store/data/model/Exodus.kt index 41e660902..e2f72ccdc 100644 --- a/app/src/main/java/com/aurora/store/data/model/Exodus.kt +++ b/app/src/main/java/com/aurora/store/data/model/Exodus.kt @@ -21,19 +21,15 @@ package com.aurora.store.data.model import android.os.Parcelable import kotlinx.parcelize.Parcelize -import kotlinx.serialization.Serializable - -@Serializable data class ExodusReport( val creator: String = String(), val name: String = String(), val reports: List = listOf() ) -@Serializable @Parcelize data class Report( - val id: Int = -1, + val id: Int = 0, val downloads: String = String(), val version: String = String(), val creationDate: String = String(), @@ -42,7 +38,6 @@ data class Report( val trackers: List = listOf() ) : Parcelable -@Serializable data class ExodusTracker( val id: Int = 0, val name: String = String(), @@ -55,10 +50,14 @@ data class ExodusTracker( val categories: List = emptyList() ) { - override fun hashCode(): Int = id + override fun hashCode(): Int { + return id + } - override fun equals(other: Any?): Boolean = when (other) { - is ExodusTracker -> other.id == id - else -> false + override fun equals(other: Any?): Boolean { + return when (other) { + is ExodusTracker -> other.id == id + else -> false + } } } diff --git a/app/src/vanilla/java/com/aurora/store/view/ui/splash/SplashFragment.kt b/app/src/main/java/com/aurora/store/data/model/Filter.kt similarity index 73% rename from app/src/vanilla/java/com/aurora/store/view/ui/splash/SplashFragment.kt rename to app/src/main/java/com/aurora/store/data/model/Filter.kt index d965d10e4..80050214e 100644 --- a/app/src/vanilla/java/com/aurora/store/view/ui/splash/SplashFragment.kt +++ b/app/src/main/java/com/aurora/store/data/model/Filter.kt @@ -17,9 +17,13 @@ * */ -package com.aurora.store.view.ui.splash +package com.aurora.store.data.model -import dagger.hilt.android.AndroidEntryPoint - -@AndroidEntryPoint -class SplashFragment : BaseFlavouredSplashFragment() +data class Filter( + val appsWithAds: Boolean = true, + val appsWithIAP: Boolean = true, + val paidApps: Boolean = true, + val gsfDependentApps: Boolean = true, + val rating: Float = 0.0f, + val downloads: Int = 0 +) diff --git a/app/src/main/java/com/aurora/store/data/model/Installer.kt b/app/src/main/java/com/aurora/store/data/model/Installer.kt index 59366452f..7efa730b1 100644 --- a/app/src/main/java/com/aurora/store/data/model/Installer.kt +++ b/app/src/main/java/com/aurora/store/data/model/Installer.kt @@ -9,6 +9,5 @@ enum class Installer { ROOT, SERVICE, AM, - SHIZUKU, - MICROG + SHIZUKU } diff --git a/app/src/main/java/com/aurora/store/data/model/InstallerInfo.kt b/app/src/main/java/com/aurora/store/data/model/InstallerInfo.kt index ebb0a5a10..0521b7ce2 100644 --- a/app/src/main/java/com/aurora/store/data/model/InstallerInfo.kt +++ b/app/src/main/java/com/aurora/store/data/model/InstallerInfo.kt @@ -33,10 +33,14 @@ data class InstallerInfo( @StringRes val subtitle: Int, @StringRes val description: Int ) { - override fun equals(other: Any?): Boolean = when (other) { - is InstallerInfo -> other.id == id - else -> false + override fun equals(other: Any?): Boolean { + return when (other) { + is InstallerInfo -> other.id == id + else -> false + } } - override fun hashCode(): Int = id.hashCode() + override fun hashCode(): Int { + return id.hashCode() + } } diff --git a/app/src/main/java/com/aurora/store/data/model/Link.kt b/app/src/main/java/com/aurora/store/data/model/Link.kt index 184a611ca..b7ad6ed69 100644 --- a/app/src/main/java/com/aurora/store/data/model/Link.kt +++ b/app/src/main/java/com/aurora/store/data/model/Link.kt @@ -24,12 +24,16 @@ data class Link( var title: String, var subtitle: String, var url: String, - var icon: Int + var icon: Int, ) { - override fun equals(other: Any?): Boolean = when (other) { - is Link -> other.id == id - else -> false + override fun equals(other: Any?): Boolean { + return when (other) { + is Link -> other.id == id + else -> false + } } - override fun hashCode(): Int = id.hashCode() + override fun hashCode(): Int { + return id.hashCode() + } } diff --git a/app/src/main/java/com/aurora/store/data/model/MinimalApp.kt b/app/src/main/java/com/aurora/store/data/model/MinimalApp.kt index 41519abef..a3e0a648c 100644 --- a/app/src/main/java/com/aurora/store/data/model/MinimalApp.kt +++ b/app/src/main/java/com/aurora/store/data/model/MinimalApp.kt @@ -1,9 +1,14 @@ package com.aurora.store.data.model +import android.content.Context +import android.content.pm.PackageInfo import android.graphics.Bitmap +import android.graphics.drawable.Drawable import android.os.Parcelable +import androidx.core.content.pm.PackageInfoCompat import com.aurora.gplayapi.data.models.App import com.aurora.store.data.room.update.Update +import com.aurora.store.util.PackageUtil import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.Parcelize @@ -11,7 +16,7 @@ import kotlinx.parcelize.Parcelize data class MinimalApp( val packageName: String, val versionName: String, - val versionCode: Long, + val versionCode: Int, val displayName: String, @IgnoredOnParcel val icon: Bitmap? = null @@ -19,18 +24,40 @@ data class MinimalApp( companion object { - fun fromApp(app: App): MinimalApp = MinimalApp( - app.packageName, - app.versionName, - app.versionCode, - app.displayName - ) + fun fromApp(app: App): MinimalApp { + return MinimalApp( + app.packageName, + app.versionName, + app.versionCode, + app.displayName + ) + } - fun fromUpdate(update: Update): MinimalApp = MinimalApp( - update.packageName, - update.versionName, - update.versionCode, - update.displayName - ) + fun toApp(minimalApp: MinimalApp): App { + return App(minimalApp.packageName).apply { + versionName = minimalApp.versionName ?: "" + versionCode = minimalApp.versionCode + displayName = minimalApp.displayName + } + } + + fun fromUpdate(update: Update): MinimalApp { + return MinimalApp( + update.packageName, + update.versionName, + update.versionCode, + update.displayName + ) + } + + fun fromPackageInfo(context: Context, packageInfo: PackageInfo): MinimalApp { + return MinimalApp( + packageInfo.packageName, + packageInfo.versionName ?: "", + PackageInfoCompat.getLongVersionCode(packageInfo).toInt(), + packageInfo.applicationInfo!!.loadLabel(context.packageManager).toString(), + PackageUtil.getIconForPackage(context, packageInfo.packageName) + ) + } } } diff --git a/app/src/main/java/com/aurora/store/data/model/PaginatedAppList.kt b/app/src/main/java/com/aurora/store/data/model/PaginatedAppList.kt index 0f12252a4..186da0fdc 100644 --- a/app/src/main/java/com/aurora/store/data/model/PaginatedAppList.kt +++ b/app/src/main/java/com/aurora/store/data/model/PaginatedAppList.kt @@ -5,4 +5,4 @@ import com.aurora.gplayapi.data.models.App data class PaginatedAppList( val appList: MutableList = mutableListOf(), var hasMore: Boolean -) +) \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/data/model/Permission.kt b/app/src/main/java/com/aurora/store/data/model/Permission.kt index 1266fd6a1..c24294cc0 100644 --- a/app/src/main/java/com/aurora/store/data/model/Permission.kt +++ b/app/src/main/java/com/aurora/store/data/model/Permission.kt @@ -24,5 +24,15 @@ data class Permission( val title: String, val subtitle: String, val optional: Boolean = false, - val isGranted: Boolean = false -) +) { + override fun equals(other: Any?): Boolean { + return when (other) { + is Permission -> other.type == type + else -> false + } + } + + override fun hashCode(): Int { + return type.hashCode() + } +} diff --git a/app/src/main/java/com/aurora/store/data/model/PermissionGroupInfo.kt b/app/src/main/java/com/aurora/store/data/model/PermissionGroupInfo.kt new file mode 100644 index 000000000..cee70d50a --- /dev/null +++ b/app/src/main/java/com/aurora/store/data/model/PermissionGroupInfo.kt @@ -0,0 +1,10 @@ +package com.aurora.store.data.model + +import androidx.annotation.DrawableRes +import com.aurora.store.R + +data class PermissionGroupInfo( + val name: String = "unknown", + @DrawableRes var icon: Int = R.drawable.ic_permission_unknown, + val label: String = "UNDEFINED" +) diff --git a/app/src/main/java/com/aurora/store/data/model/Plexus.kt b/app/src/main/java/com/aurora/store/data/model/Plexus.kt index cd5f1a263..1e5fcf492 100644 --- a/app/src/main/java/com/aurora/store/data/model/Plexus.kt +++ b/app/src/main/java/com/aurora/store/data/model/Plexus.kt @@ -2,45 +2,38 @@ package com.aurora.store.data.model import androidx.annotation.StringRes import com.aurora.store.R -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable +import com.google.gson.annotations.SerializedName -@Serializable data class PlexusReport( - @SerialName("data") + @SerializedName("data") val report: Data? ) -@Serializable data class Data( val name: String, val scores: Scores, - @SerialName("updated_at") + @SerializedName("updated_at") val updatedAt: String ) -@Serializable data class Scores( - @SerialName("micro_g") - val microG: Rating = Rating(), - @SerialName("native") - val aosp: Rating = Rating() + @SerializedName("micro_g") + val microG: Rating, + @SerializedName("native") + val aosp: Rating ) -@Serializable data class Rating( - val denominator: Float = -1F, - val numerator: Float = -1F, - val rating_type: String = String(), - val total_count: Long = -1 + val denominator: Float, + val numerator: Float, + val rating_type: String, + val total_count: Long ) { - private val fraction - get() = if (numerator == -1F && denominator == -1F) -1F else numerator / denominator + private val fraction get() = numerator / denominator @get:StringRes val status: Int get() = when { - fraction == -1F -> R.string.plexus_progress fraction == 0F -> R.string.details_compatibility_status_unknown fraction >= 0.90 -> R.string.details_compatibility_status_compatible fraction >= 0.50 -> R.string.details_compatibility_status_limited diff --git a/app/src/main/java/com/aurora/store/data/model/ProxyInfo.kt b/app/src/main/java/com/aurora/store/data/model/ProxyInfo.kt index 1943b9f95..68f6343d6 100644 --- a/app/src/main/java/com/aurora/store/data/model/ProxyInfo.kt +++ b/app/src/main/java/com/aurora/store/data/model/ProxyInfo.kt @@ -2,9 +2,7 @@ package com.aurora.store.data.model import android.os.Parcelable import kotlinx.parcelize.Parcelize -import kotlinx.serialization.Serializable -@Serializable @Parcelize data class ProxyInfo( var protocol: String, diff --git a/app/src/main/java/com/aurora/store/data/model/SearchFilter.kt b/app/src/main/java/com/aurora/store/data/model/SearchFilter.kt deleted file mode 100644 index ac1b144e7..000000000 --- a/app/src/main/java/com/aurora/store/data/model/SearchFilter.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.data.model - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize -import kotlinx.serialization.Serializable - -/** - * Filter for list with search results - */ -@Parcelize -@Serializable -data class SearchFilter( - val noAds: Boolean = false, - val isFree: Boolean = false, - val noGMS: Boolean = false, - val minRating: Float = 0F, - val minInstalls: Long = 0 -) : Parcelable diff --git a/app/src/main/java/com/aurora/store/data/model/SelfUpdate.kt b/app/src/main/java/com/aurora/store/data/model/SelfUpdate.kt index 37e4a4e2a..dc0d746bd 100644 --- a/app/src/main/java/com/aurora/store/data/model/SelfUpdate.kt +++ b/app/src/main/java/com/aurora/store/data/model/SelfUpdate.kt @@ -23,20 +23,18 @@ import android.content.Context import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.Artwork import com.aurora.gplayapi.data.models.EncodedCertificateSet -import com.aurora.gplayapi.data.models.PlayFile +import com.aurora.gplayapi.data.models.File import com.aurora.store.BuildConfig import com.aurora.store.R import com.aurora.store.util.CertUtil -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable +import com.google.gson.annotations.SerializedName -@Serializable data class SelfUpdate( - @SerialName("version_name") var versionName: String = String(), - @SerialName("version_code") var versionCode: Long = 0, - @SerialName("aurora_build") var auroraBuild: String = String(), - @SerialName("fdroid_build") var fdroidBuild: String = String(), - @SerialName("updated_on") var updatedOn: String = String(), + @SerializedName("version_name") var versionName: String = String(), + @SerializedName("version_code") var versionCode: Int = 0, + @SerializedName("aurora_build") var auroraBuild: String = String(), + @SerializedName("fdroid_build") var fdroidBuild: String = String(), + @SerializedName("updated_on") var updatedOn: String = String(), val changelog: String = String(), val size: Long = 0L, val timestamp: Long = 0L @@ -65,7 +63,7 @@ data class SelfUpdate( developerName = "Rahul Kumar Patel", iconArtwork = Artwork(url = "$BASE_URL/$icon"), fileList = mutableListOf( - PlayFile( + File( name = "${context.packageName}.apk", url = downloadURL, size = selfUpdate.size @@ -74,8 +72,7 @@ data class SelfUpdate( isFree = true, isInstalled = true, certificateSetList = CertUtil.getEncodedCertificateHashes( - context, - context.packageName + context, context.packageName ).map { EncodedCertificateSet(certificateSet = it, sha256 = String()) }.toMutableList() diff --git a/app/src/main/java/com/aurora/store/data/model/SessionInfo.kt b/app/src/main/java/com/aurora/store/data/model/SessionInfo.kt index e253db335..a09a15e88 100644 --- a/app/src/main/java/com/aurora/store/data/model/SessionInfo.kt +++ b/app/src/main/java/com/aurora/store/data/model/SessionInfo.kt @@ -3,6 +3,6 @@ package com.aurora.store.data.model data class SessionInfo( val sessionId: Int, val packageName: String, - val versionCode: Long, + val versionCode: Int, val displayName: String = String() ) diff --git a/app/src/main/java/com/aurora/store/data/model/State.kt b/app/src/main/java/com/aurora/store/data/model/State.kt index 6451a5394..bca70557a 100644 --- a/app/src/main/java/com/aurora/store/data/model/State.kt +++ b/app/src/main/java/com/aurora/store/data/model/State.kt @@ -19,8 +19,11 @@ package com.aurora.store.data.model + sealed class ViewState { - inline fun ViewState.getDataAs(): T = (this as? Success<*>)?.data as T + inline fun ViewState.getDataAs(): T { + return (this as? Success<*>)?.data as T + } data object Loading : ViewState() data object Empty : ViewState() @@ -30,7 +33,7 @@ sealed class ViewState { } sealed class AuthState { - data object Init : AuthState() + data object Init: AuthState() data object Available : AuthState() data object Unavailable : AuthState() data object SignedIn : AuthState() @@ -38,42 +41,5 @@ sealed class AuthState { data object Valid : AuthState() data object Fetching : AuthState() data object Verifying : AuthState() - data class PendingAccountManager(val email: String, val token: String) : AuthState() data class Failed(val status: String) : AuthState() } - -/** - * Possible states of an app to show appropriate actions on UI - */ -sealed class AppState { - data class Downloading( - val progress: Float, - val speed: Long, - val timeRemaining: Long - ) : AppState() - - data object Queued : AppState() - data object Purchasing : AppState() - data class Installing(val progress: Float) : AppState() - data class Error(val message: String?) : AppState() - data class Installed(val versionName: String, val versionCode: Long) : AppState() - data object Archived : AppState() - data object Updatable : AppState() - data object Unavailable : AppState() - data object Loading : AppState() - - /** - * Whether there is some sort of ongoing process related to the app - */ - fun inProgress(): Boolean = - this is Downloading || this is Installing || this is Purchasing || this is Queued - - /** - * Progress of the process related to the app; 0 otherwise - */ - fun progress(): Float = when (this) { - is Downloading -> progress - is Installing -> progress - else -> 0F - } -} diff --git a/app/src/main/java/com/aurora/store/data/model/UpdateMode.kt b/app/src/main/java/com/aurora/store/data/model/UpdateMode.kt index 5e2bdc2e3..cb6c94741 100644 --- a/app/src/main/java/com/aurora/store/data/model/UpdateMode.kt +++ b/app/src/main/java/com/aurora/store/data/model/UpdateMode.kt @@ -4,5 +4,5 @@ enum class UpdateMode { DISABLED, CHECK_AND_NOTIFY, CHECK_AND_INSTALL, - CHECK_ONLY + CHECK_ONLY, } diff --git a/app/src/main/java/com/aurora/store/data/network/HttpClient.kt b/app/src/main/java/com/aurora/store/data/network/HttpClient.kt index b4c8d038a..18f5f4663 100644 --- a/app/src/main/java/com/aurora/store/data/network/HttpClient.kt +++ b/app/src/main/java/com/aurora/store/data/network/HttpClient.kt @@ -20,15 +20,9 @@ package com.aurora.store.data.network import android.util.Log -import com.aurora.extensions.TAG import com.aurora.gplayapi.data.models.PlayResponse import com.aurora.gplayapi.network.IHttpClient -import com.aurora.store.BuildConfig.APPLICATION_ID -import com.aurora.store.BuildConfig.VERSION_CODE -import com.aurora.store.BuildConfig.VERSION_NAME -import java.io.IOException -import javax.inject.Inject -import javax.inject.Singleton +import com.aurora.store.BuildConfig import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -41,14 +35,17 @@ import okhttp3.Request import okhttp3.RequestBody import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response +import java.io.IOException +import javax.inject.Inject +import javax.inject.Singleton @Singleton -class HttpClient @Inject constructor(private val okHttpClient: OkHttpClient) : IHttpClient { +class HttpClient @Inject constructor(private val okHttpClient: OkHttpClient): IHttpClient { - companion object { - private const val POST = "POST" - private const val GET = "GET" - } + private val TAG = HttpClient::class.java.simpleName + + private val POST = "POST" + private val GET = "GET" private val _responseCode = MutableStateFlow(100) override val responseCode: StateFlow @@ -56,21 +53,20 @@ class HttpClient @Inject constructor(private val okHttpClient: OkHttpClient) : I @Throws(IOException::class) fun post(url: String, headers: Map, requestBody: RequestBody): PlayResponse { - val request = Request( - url = url.toHttpUrl(), - headers = headers.toHeaders(), - method = POST, - body = requestBody - ) + val request = Request.Builder() + .url(url) + .headers(headers.toHeaders()) + .method(POST, requestBody) + .build() return processRequest(request) } @Throws(IOException::class) fun call(url: String, headers: Map = emptyMap()): Response { - val request = Request( - url = url.toHttpUrl(), - headers = headers.toHeaders() - ) + val request = Request.Builder() + .url(url) + .headers(headers.toHeaders()) + .build() return okHttpClient.newCall(request).execute() } @@ -80,34 +76,36 @@ class HttpClient @Inject constructor(private val okHttpClient: OkHttpClient) : I headers: Map, params: Map ): PlayResponse { - val request = Request( - url = buildUrl(url, params), - headers = headers.toHeaders(), - method = POST, - body = "".toRequestBody(null) - ) + val request = Request.Builder() + .url(buildUrl(url, params)) + .headers(headers.toHeaders()) + .method(POST, "".toRequestBody(null)) + .build() return processRequest(request) } override fun postAuth(url: String, body: ByteArray): PlayResponse { - val headers = mapOf("User-Agent" to "${APPLICATION_ID}-${VERSION_NAME}-${VERSION_CODE}") val requestBody = body.toRequestBody("application/json".toMediaType(), 0, body.size) - val request = Request( - url = url.toHttpUrl(), - headers = headers.toHeaders(), - method = POST, - body = requestBody - ) + val request = Request.Builder() + .url(url) + .header( + "User-Agent", + "${BuildConfig.APPLICATION_ID}-${BuildConfig.VERSION_NAME}-${BuildConfig.VERSION_CODE}" + ) + .method(POST, requestBody) + .build() return processRequest(request) } @Throws(IOException::class) - override fun post(url: String, headers: Map, body: ByteArray): PlayResponse = - post(url, headers, body.toRequestBody()) + override fun post(url: String, headers: Map, body: ByteArray): PlayResponse { + return post(url, headers, body.toRequestBody()) + } @Throws(IOException::class) - override fun get(url: String, headers: Map): PlayResponse = - get(url, headers, mapOf()) + override fun get(url: String, headers: Map): PlayResponse { + return get(url, headers, mapOf()) + } @Throws(IOException::class) override fun get( @@ -115,31 +113,37 @@ class HttpClient @Inject constructor(private val okHttpClient: OkHttpClient) : I headers: Map, params: Map ): PlayResponse { - val request = Request( - url = buildUrl(url, params), - headers = headers.toHeaders(), - method = GET - ) + val request = Request.Builder() + .url(buildUrl(url, params)) + .headers(headers.toHeaders()) + .method(GET, null) + .build() return processRequest(request) } override fun getAuth(url: String): PlayResponse { - val headers = mapOf("User-Agent" to "${APPLICATION_ID}-${VERSION_NAME}-${VERSION_CODE}") - val request = Request( - url = url.toHttpUrl(), - headers = headers.toHeaders(), - method = GET - ) + val request = Request.Builder() + .url(url) + .header( + "User-Agent", + "${BuildConfig.APPLICATION_ID}-${BuildConfig.VERSION_NAME}-${BuildConfig.VERSION_CODE}" + ) + .method(GET, null) + .build() return processRequest(request) } @Throws(IOException::class) - override fun get(url: String, headers: Map, paramString: String): PlayResponse { - val request = Request( - url = "$url$paramString".toHttpUrl(), - headers = headers.toHeaders(), - method = GET - ) + override fun get( + url: String, + headers: Map, + paramString: String + ): PlayResponse { + val request = Request.Builder() + .url(url + paramString) + .headers(headers.toHeaders()) + .method(GET, null) + .build() return processRequest(request) } @@ -159,14 +163,15 @@ class HttpClient @Inject constructor(private val okHttpClient: OkHttpClient) : I return urlBuilder.build() } - private fun buildPlayResponse(response: Response): PlayResponse = PlayResponse( - isSuccessful = response.isSuccessful, - code = response.code, - responseBytes = response.body.bytes(), - errorString = if (!response.isSuccessful) response.message else String() - ).also { - val isCached = if (response.cacheResponse != null) "CACHED" else "NETWORK" - _responseCode.value = response.code - Log.i(TAG, "OKHTTP [$isCached] [${response.code}] ${response.request.url}") + private fun buildPlayResponse(response: Response): PlayResponse { + return PlayResponse( + isSuccessful = response.isSuccessful, + code = response.code, + responseBytes = response.body?.bytes() ?: byteArrayOf(), + errorString = if (!response.isSuccessful) response.message else String() + ).also { + _responseCode.value = response.code + Log.i(TAG, "OKHTTP [${response.code}] ${response.request.url}") + } } } diff --git a/app/src/main/java/com/aurora/store/data/network/IHttpClientModule.kt b/app/src/main/java/com/aurora/store/data/network/IHttpClientModule.kt index c00c75328..adfafbdf6 100644 --- a/app/src/main/java/com/aurora/store/data/network/IHttpClientModule.kt +++ b/app/src/main/java/com/aurora/store/data/network/IHttpClientModule.kt @@ -13,5 +13,7 @@ object IHttpClientModule { @Provides @Singleton - fun providesIHttpClientInstance(httpClient: HttpClient): IHttpClient = httpClient + fun providesIHttpClientInstance(httpClient: HttpClient): IHttpClient { + return httpClient + } } diff --git a/app/src/main/java/com/aurora/store/data/network/OkHttpClientModule.kt b/app/src/main/java/com/aurora/store/data/network/OkHttpClientModule.kt index bab521fa6..21de9b5c6 100644 --- a/app/src/main/java/com/aurora/store/data/network/OkHttpClientModule.kt +++ b/app/src/main/java/com/aurora/store/data/network/OkHttpClientModule.kt @@ -27,15 +27,18 @@ import com.aurora.store.R import com.aurora.store.data.model.Algorithm import com.aurora.store.data.model.ProxyInfo import com.aurora.store.util.Preferences +import com.aurora.store.util.Preferences.PREFERENCE_PROXY_ENABLED import com.aurora.store.util.Preferences.PREFERENCE_PROXY_INFO +import com.google.gson.Gson import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import java.io.ByteArrayInputStream -import java.io.File import java.io.InputStream +import okhttp3.CertificatePinner +import okhttp3.OkHttpClient import java.net.Authenticator import java.net.InetSocketAddress import java.net.PasswordAuthentication @@ -45,10 +48,6 @@ import java.security.cert.CertificateFactory import java.security.cert.X509Certificate import java.util.concurrent.TimeUnit import javax.inject.Singleton -import kotlinx.serialization.json.Json -import okhttp3.Cache -import okhttp3.CertificatePinner -import okhttp3.OkHttpClient @Module @InstallIn(SingletonComponent::class) @@ -61,13 +60,8 @@ object OkHttpClientModule { @Provides @Singleton - fun providesOkHttpClientInstance( - certificatePinner: CertificatePinner, - proxy: Proxy?, - cache: Cache - ): OkHttpClient { + fun providesOkHttpClientInstance(certPinner: CertificatePinner, proxy: Proxy?): OkHttpClient { val okHttpClientBuilder = OkHttpClient().newBuilder() - .cache(cache) .proxy(proxy) .connectTimeout(25, TimeUnit.SECONDS) .readTimeout(25, TimeUnit.SECONDS) @@ -77,7 +71,7 @@ object OkHttpClientModule { .followSslRedirects(true) if (!BuildConfig.DEBUG) { - okHttpClientBuilder.certificatePinner(certificatePinner) + okHttpClientBuilder.certificatePinner(certPinner) } return okHttpClientBuilder.build() @@ -90,29 +84,27 @@ object OkHttpClientModule { val googleRootCerts = getGoogleRootCertHashes(context).map { "sha256/$it" } .toTypedArray() - return CertificatePinner.Builder() + return CertificatePinner.Builder() .add("*.googleapis.com", *googleRootCerts) .add("*.google.com", *googleRootCerts) - .add("auroraoss.com", "sha256/mEflZT5enoR1FuXLgYYGqnVEoZvmf9c2bVBpiOjYQ0c=") - .add("*.exodus-privacy.eu.org", "sha256/C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=") - .add("gitlab.com", "sha256/x4QzPSC810K5/cMjb05Qm4k3Bw5zBn4lTdO/nEW/Td4=") - .add("plexus.techlore.tech", "sha256/C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=") + .add("auroraoss.com", "sha256/mEflZT5enoR1FuXLgYYGqnVEoZvmf9c2bVBpiOjYQ0c=") // GTS Root R4 + .add("*.exodus-privacy.eu.org", "sha256/C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=") // ISRG Root X1 + .add("gitlab.com", "sha256/x4QzPSC810K5/cMjb05Qm4k3Bw5zBn4lTdO/nEW/Td4=") // USERTrust RSA Certification Authority + .add("plexus.techlore.tech", "sha256/C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=") // ISRG Root X1 .build() } @Provides @Singleton - fun providesProxyInstance(@ApplicationContext context: Context, json: Json): Proxy? { + fun providesProxyInstance(@ApplicationContext context: Context, gson: Gson): Proxy? { + val proxyEnabled = Preferences.getBoolean(context, PREFERENCE_PROXY_ENABLED) val proxyInfoString = Preferences.getString(context, PREFERENCE_PROXY_INFO) - if (proxyInfoString.isNotBlank() && proxyInfoString != "{}") { - val proxyInfo = json.decodeFromString(proxyInfoString) + + if (proxyEnabled && proxyInfoString.isNotBlank() && proxyInfoString != "{}") { + val proxyInfo = gson.fromJson(proxyInfoString, ProxyInfo::class.java) val proxy = Proxy( - if (proxyInfo.protocol.removeSuffix("5") == "SOCKS") { - Proxy.Type.SOCKS - } else { - Proxy.Type.HTTP - }, + if (proxyInfo.protocol.removeSuffix("5") == "SOCKS") Proxy.Type.SOCKS else Proxy.Type.HTTP, InetSocketAddress.createUnresolved(proxyInfo.host, proxyInfo.port) ) @@ -121,8 +113,9 @@ object OkHttpClientModule { if (!proxyUser.isNullOrBlank() && !proxyPassword.isNullOrBlank()) { Authenticator.setDefault(object : Authenticator() { - override fun getPasswordAuthentication(): PasswordAuthentication = - PasswordAuthentication(proxyUser, proxyPassword.toCharArray()) + override fun getPasswordAuthentication(): PasswordAuthentication { + return PasswordAuthentication(proxyUser, proxyPassword.toCharArray()) + } }) } return proxy @@ -132,24 +125,18 @@ object OkHttpClientModule { } } - @Provides - @Singleton - fun providesCacheDir(@ApplicationContext context: Context): Cache = Cache( - directory = File(context.cacheDir, "http_cache"), - maxSize = 100L * 1024 * 1024 - ) - - private fun getGoogleRootCertHashes(context: Context): List = try { - val certs = - getX509Certificates(context.resources.openRawResource(R.raw.google_roots_ca)) - certs.map { - val messageDigest = MessageDigest.getInstance(Algorithm.SHA256.value) - messageDigest.update(it.publicKey.encoded) - Base64.encodeToString(messageDigest.digest(), Base64.NO_WRAP) + private fun getGoogleRootCertHashes(context: Context): List { + return try { + val certs = getX509Certificates(context.resources.openRawResource(R.raw.google_roots_ca)) + certs.map { + val messageDigest = MessageDigest.getInstance(Algorithm.SHA256.value) + messageDigest.update(it.publicKey.encoded) + Base64.encodeToString(messageDigest.digest(), Base64.NO_WRAP) + } + } catch (exception: Exception) { + Log.e(TAG, "Failed to get SHA256 certificate hash", exception) + emptyList() } - } catch (exception: Exception) { - Log.e(TAG, "Failed to get SHA256 certificate hash", exception) - emptyList() } private fun getX509Certificates(inputStream: InputStream): List { diff --git a/app/src/main/java/com/aurora/store/data/paging/GenericPagingSource.kt b/app/src/main/java/com/aurora/store/data/paging/GenericPagingSource.kt deleted file mode 100644 index 9b170d274..000000000 --- a/app/src/main/java/com/aurora/store/data/paging/GenericPagingSource.kt +++ /dev/null @@ -1,86 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.data.paging - -import androidx.paging.Pager -import androidx.paging.PagingConfig -import androidx.paging.PagingSource -import androidx.paging.PagingState -import com.aurora.store.data.paging.GenericPagingSource.Companion.manualPager -import com.aurora.store.data.paging.GenericPagingSource.Companion.pager -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext - -/** - * A generic paging source that is supposed to be able to load any type of data - * - * Consider calling [pager] method to create an instance of [Pager] instead of interacting - * with the class directly. - * @param block Data to load into the pager - */ -class GenericPagingSource( - private val block: suspend (Int) -> List -) : PagingSource() { - - companion object { - private const val DEFAULT_PAGE_SIZE = 20 - - /** - * Method to create pager objects using [PagingSource] - * @param pageSize Size of the page - * @param enablePlaceholders Whether placeholders should be shown - * @param data Data to load into the pager - * @see manualPager - */ - fun pager( - pageSize: Int = DEFAULT_PAGE_SIZE, - enablePlaceholders: Boolean = true, - data: () -> PagingSource - ): Pager = Pager( - config = PagingConfig(enablePlaceholders = enablePlaceholders, pageSize = pageSize), - pagingSourceFactory = { data() } - ) - - /** - * Method to create and manage pager objects manually - * @param pageSize Size of the page - * @param enablePlaceholders Whether placeholders should be shown - * @param data Data to load into the pager - */ - fun manualPager( - pageSize: Int = DEFAULT_PAGE_SIZE, - enablePlaceholders: Boolean = true, - data: suspend (Int) -> List - ): Pager = Pager( - config = PagingConfig(enablePlaceholders = enablePlaceholders, pageSize = pageSize), - pagingSourceFactory = { GenericPagingSource(data) } - ) - } - - override suspend fun load(params: LoadParams): LoadResult { - val page = params.key ?: 1 - return try { - withContext(Dispatchers.IO) { - val data = block(page) - val totalPages = if (data.isNotEmpty()) page + 1 else page - LoadResult.Page( - data = data, - prevKey = if (page == 1) null else page - 1, - nextKey = if (page == totalPages) null else totalPages, - itemsAfter = if (page == totalPages) 0 else DEFAULT_PAGE_SIZE - ) - } - } catch (exception: Exception) { - LoadResult.Error(exception) - } - } - - override fun getRefreshKey(state: PagingState): Int? = - state.anchorPosition?.let { anchorPosition -> - state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1) - ?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1) - } -} diff --git a/app/src/main/java/com/aurora/store/data/providers/AccountProvider.kt b/app/src/main/java/com/aurora/store/data/providers/AccountProvider.kt index 156c4ee9f..5fc660e8f 100644 --- a/app/src/main/java/com/aurora/store/data/providers/AccountProvider.kt +++ b/app/src/main/java/com/aurora/store/data/providers/AccountProvider.kt @@ -36,8 +36,9 @@ object AccountProvider { } } - fun isLoggedIn(context: Context): Boolean = - Preferences.getBoolean(context, Constants.ACCOUNT_SIGNED_IN, false) + fun isLoggedIn(context: Context): Boolean { + return Preferences.getBoolean(context, Constants.ACCOUNT_SIGNED_IN, false) + } fun getLoginEmail(context: Context): String? { val email = Preferences.getString(context, Constants.ACCOUNT_EMAIL_PLAIN) diff --git a/app/src/main/java/com/aurora/store/data/providers/AuthProvider.kt b/app/src/main/java/com/aurora/store/data/providers/AuthProvider.kt index e82a5a882..890b5ad25 100644 --- a/app/src/main/java/com/aurora/store/data/providers/AuthProvider.kt +++ b/app/src/main/java/com/aurora/store/data/providers/AuthProvider.kt @@ -21,9 +21,9 @@ package com.aurora.store.data.providers import android.content.Context import android.util.Log -import com.aurora.extensions.TAG import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.PlayResponse +import com.aurora.gplayapi.helpers.AppDetailsHelper import com.aurora.gplayapi.helpers.AuthHelper import com.aurora.gplayapi.network.IHttpClient import com.aurora.store.R @@ -32,21 +32,23 @@ import com.aurora.store.data.model.Auth import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences.PREFERENCE_AUTH_DATA import com.aurora.store.util.Preferences.PREFERENCE_DISPENSER_URLS +import com.google.gson.Gson import dagger.hilt.android.qualifiers.ApplicationContext -import javax.inject.Inject -import javax.inject.Singleton import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import kotlinx.serialization.json.Json +import javax.inject.Inject +import javax.inject.Singleton @Singleton class AuthProvider @Inject constructor( @ApplicationContext private val context: Context, - private val json: Json, + private val gson: Gson, private val spoofProvider: SpoofProvider, private val httpClient: IHttpClient ) { + private val TAG = AuthProvider::class.java.simpleName + val dispenserURL: String? get() { val dispensers = Preferences.getStringSet(context, PREFERENCE_DISPENSER_URLS) @@ -58,9 +60,9 @@ class AuthProvider @Inject constructor( Log.i(TAG, "Loading saved AuthData") val rawAuth: String = Preferences.getString(context, PREFERENCE_AUTH_DATA) return if (rawAuth.isNotBlank()) { - json.decodeFromString(rawAuth) + gson.fromJson(rawAuth, AuthData::class.java) } else { - AuthData("BOGUS") + null } } @@ -70,7 +72,21 @@ class AuthProvider @Inject constructor( /** * Checks whether saved AuthData is valid or not */ - fun isSavedAuthDataValid(): Boolean = AuthHelper.isValid(authData!!) + suspend fun isSavedAuthDataValid(): Boolean { + // TODO: Switch to the method from gplayapi + return withContext(Dispatchers.IO) { + try { + val testPackageName = "com.android.chrome" + val app = AppDetailsHelper(authData!!) + .using(httpClient) + .getAppByPackageName(testPackageName) + app.packageName == testPackageName && app.displayName.isNotBlank() + && app.versionCode != 0 + } catch (exception: Exception) { + false + } + } + } /** * Builds [AuthData] for login using personal Google account @@ -92,7 +108,7 @@ class AuthProvider @Inject constructor( token = token, tokenType = tokenType, properties = spoofProvider.deviceProperties, - locale = spoofProvider.locale + locale = spoofProvider.locale, ) ) } catch (exception: Exception) { @@ -109,14 +125,11 @@ class AuthProvider @Inject constructor( suspend fun buildAnonymousAuthData(): Result { return withContext(Dispatchers.IO) { try { - val playResponse = httpClient.postAuth( - dispenserURL!!, - json.encodeToString(spoofProvider.deviceProperties).toByteArray() - ).also { + val playResponse = httpClient.getAuth(dispenserURL!!).also { if (!it.isSuccessful) throwError(it, context) } - val auth = json.decodeFromString(String(playResponse.responseBytes)) + val auth = gson.fromJson(String(playResponse.responseBytes), Auth::class.java) return@withContext Result.success( AuthHelper.build( email = auth.email, @@ -138,7 +151,7 @@ class AuthProvider @Inject constructor( * Saves given [AuthData] */ fun saveAuthData(authData: AuthData) { - Preferences.putString(context, PREFERENCE_AUTH_DATA, json.encodeToString(authData)) + Preferences.putString(context, PREFERENCE_AUTH_DATA, gson.toJson(authData)) } /** @@ -152,15 +165,10 @@ class AuthProvider @Inject constructor( private fun throwError(playResponse: PlayResponse, context: Context) { when (playResponse.code) { 400 -> throw Exception(context.getString(R.string.bad_request)) - 403 -> throw Exception(context.getString(R.string.access_denied_using_vpn)) - 404 -> throw Exception(context.getString(R.string.server_unreachable)) - 429 -> throw Exception(context.getString(R.string.login_rate_limited)) - 503 -> throw Exception(context.getString(R.string.server_maintenance)) - else -> { if (playResponse.errorString.isNotBlank()) { throw Exception(playResponse.errorString) diff --git a/app/src/main/java/com/aurora/store/data/providers/BlacklistProvider.kt b/app/src/main/java/com/aurora/store/data/providers/BlacklistProvider.kt index 2ddf9d374..7a063eb61 100644 --- a/app/src/main/java/com/aurora/store/data/providers/BlacklistProvider.kt +++ b/app/src/main/java/com/aurora/store/data/providers/BlacklistProvider.kt @@ -21,30 +21,26 @@ package com.aurora.store.data.providers import android.content.Context import android.content.SharedPreferences +import androidx.preference.PreferenceManager import com.aurora.extensions.isNAndAbove import com.aurora.store.util.Preferences +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken import dagger.hilt.android.qualifiers.ApplicationContext import java.io.File import javax.inject.Inject import javax.inject.Singleton -import kotlinx.serialization.json.Json @Singleton class BlacklistProvider @Inject constructor( - private val json: Json, - @ApplicationContext val context: Context + private val gson: Gson, + @ApplicationContext val context: Context, ) { - companion object { - private const val PREFERENCE_BLACKLIST = "PREFERENCE_BLACKLIST" - } + private val PREFERENCE_BLACKLIST = "PREFERENCE_BLACKLIST" var blacklist: MutableSet - set(value) = Preferences.putString( - context, - PREFERENCE_BLACKLIST, - json.encodeToString(value) - ) + set(value) = Preferences.putString(context, PREFERENCE_BLACKLIST, gson.toJson(value)) get() { return try { val rawBlacklist = if (isNAndAbove) { @@ -59,7 +55,7 @@ class BlacklistProvider @Inject constructor( Context.MODE_PRIVATE ) as SharedPreferences - Preferences.getPrefs(context) + PreferenceManager.getDefaultSharedPreferences(context) .getString( PREFERENCE_BLACKLIST, refSharedPreferences.getString(PREFERENCE_BLACKLIST, "") @@ -67,17 +63,19 @@ class BlacklistProvider @Inject constructor( } else { Preferences.getString(context, PREFERENCE_BLACKLIST) } - if (rawBlacklist!!.isEmpty()) { + if (rawBlacklist!!.isEmpty()) mutableSetOf() - } else { - json.decodeFromString>(rawBlacklist) - } - } catch (_: Exception) { + else + gson.fromJson(rawBlacklist, object : TypeToken?>() {}.type) + } catch (e: Exception) { mutableSetOf() } } - fun isBlacklisted(packageName: String): Boolean = blacklist.contains(packageName) + fun isBlacklisted(packageName: String): Boolean { + return blacklist.contains(packageName) + } + fun blacklist(packageName: String) { blacklist = blacklist.apply { diff --git a/app/src/main/java/com/aurora/store/data/providers/EglExtensionProvider.kt b/app/src/main/java/com/aurora/store/data/providers/EglExtensionProvider.kt index 5a92db1b4..ccada95b2 100644 --- a/app/src/main/java/com/aurora/store/data/providers/EglExtensionProvider.kt +++ b/app/src/main/java/com/aurora/store/data/providers/EglExtensionProvider.kt @@ -41,10 +41,8 @@ object EglExtensionProvider { val configs = arrayOfNulls(configCount[0]) if (egl.eglGetConfigs(display, configs, configCount[0], configCount)) { val pbufferAttribs = intArrayOf( - EGL10.EGL_WIDTH, - EGL10.EGL_PBUFFER_BIT, - EGL10.EGL_HEIGHT, - EGL10.EGL_PBUFFER_BIT, + EGL10.EGL_WIDTH, EGL10.EGL_PBUFFER_BIT, + EGL10.EGL_HEIGHT, EGL10.EGL_PBUFFER_BIT, EGL10.EGL_NONE ) val contextAttributes = intArrayOf(12440, EGL10.EGL_PIXMAP_BIT, EGL10.EGL_NONE) diff --git a/app/src/main/java/com/aurora/store/data/providers/FilterProvider.kt b/app/src/main/java/com/aurora/store/data/providers/FilterProvider.kt new file mode 100644 index 000000000..7c1e9119b --- /dev/null +++ b/app/src/main/java/com/aurora/store/data/providers/FilterProvider.kt @@ -0,0 +1,54 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.data.providers + +import android.content.Context +import com.aurora.store.data.model.Filter +import com.aurora.store.util.Preferences +import com.aurora.store.util.remove +import com.google.gson.Gson +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class FilterProvider @Inject constructor( + private val gson: Gson, + @ApplicationContext private val context: Context +) { + + companion object { + const val PREFERENCE_FILTER = "PREFERENCE_FILTER" + } + + init { + // Clean any last saved filter + context.remove(PREFERENCE_FILTER) + } + + fun getSavedFilter(): Filter { + val rawFilter = Preferences.getString(context, PREFERENCE_FILTER) + return gson.fromJson(rawFilter.ifEmpty { "{}" }, Filter::class.java) + } + + fun saveFilter(filter: Filter) { + Preferences.putString(context, PREFERENCE_FILTER, gson.toJson(filter)) + } +} diff --git a/app/src/main/java/com/aurora/store/data/providers/NativeDeviceInfoProvider.kt b/app/src/main/java/com/aurora/store/data/providers/NativeDeviceInfoProvider.kt index 70220fd1b..f1c606315 100644 --- a/app/src/main/java/com/aurora/store/data/providers/NativeDeviceInfoProvider.kt +++ b/app/src/main/java/com/aurora/store/data/providers/NativeDeviceInfoProvider.kt @@ -30,16 +30,15 @@ object NativeDeviceInfoProvider { fun getNativeDeviceProperties(context: Context, isExport: Boolean = false): Properties { val properties = Properties().apply { - // Build Props + //Build Props setProperty("UserReadableName", "${Build.MANUFACTURER} ${Build.MODEL}") setProperty("Build.HARDWARE", Build.HARDWARE) setProperty( "Build.RADIO", - if (Build.getRadioVersion() != null) { + if (Build.getRadioVersion() != null) Build.getRadioVersion() - } else { + else "unknown" - } ) setProperty("Build.FINGERPRINT", Build.FINGERPRINT) setProperty("Build.BRAND", Build.BRAND) @@ -63,24 +62,21 @@ object NativeDeviceInfoProvider { "${config.navigation == Configuration.NAVIGATIONHIDDEN_YES}" ) - // Display Metrics + //Display Metrics val metrics = context.resources.displayMetrics setProperty("Screen.Density", "${metrics.densityDpi}") setProperty("Screen.Width", "${metrics.widthPixels}") setProperty("Screen.Height", "${metrics.heightPixels}") - // Supported Platforms + //Supported Platforms setProperty("Platforms", Build.SUPPORTED_ABIS.joinToString(separator = ",")) - // Supported Features + //Supported Features setProperty("Features", getFeatures(context).joinToString(separator = ",")) - // Shared Locales + //Shared Locales setProperty("Locales", getLocales(context).joinToString(separator = ",")) - // Shared Libraries - setProperty( - "SharedLibraries", - getSharedLibraries(context).joinToString(separator = ",") - ) - // GL Extensions + //Shared Libraries + setProperty("SharedLibraries", getSharedLibraries(context).joinToString(separator = ",")) + //GL Extensions val activityManager = context.getSystemService() setProperty( "GL.Version", @@ -91,7 +87,7 @@ object NativeDeviceInfoProvider { EglExtensionProvider.eglExtensions.joinToString(separator = ",") ) - // Google Related Props + //Google Related Props setProperty("Client", "android-google") val gsfVersionProvider = NativeGsfVersionProvider(context, isExport) @@ -99,11 +95,11 @@ object NativeDeviceInfoProvider { setProperty("Vending.version", gsfVersionProvider.vendingVersionCode.toString()) setProperty("Vending.versionString", gsfVersionProvider.vendingVersionString) - // MISC + //MISC setProperty("Roaming", "mobile-notroaming") setProperty("TimeZone", "UTC-10") - // Telephony (USA 3650 AT&T) + //Telephony (USA 3650 AT&T) setProperty("CellOperator", "310") setProperty("SimOperator", "38") } @@ -112,23 +108,29 @@ object NativeDeviceInfoProvider { return properties } - private fun getFeatures(context: Context): List = context - .packageManager - .systemAvailableFeatures - .mapNotNull { it.name } + private fun getFeatures(context: Context): List { + return context + .packageManager + .systemAvailableFeatures + .mapNotNull { it.name } + } - private fun getLocales(context: Context): List = context - .assets - .locales - .mapNotNull { it.replace("-", "_") } + private fun getLocales(context: Context): List { + return context + .assets + .locales + .mapNotNull { it.replace("-", "_") } + } - private fun getSharedLibraries(context: Context): List = context - .packageManager - .systemSharedLibraryNames - ?.toList() ?: emptyList() + private fun getSharedLibraries(context: Context): List { + return context + .packageManager + .systemSharedLibraryNames + ?.toList() ?: emptyList() + } private fun stripHuaweiProperties(properties: Properties): Properties { - // Add Pixel 7a properties + //Add Pixel 7a properties properties["Build.HARDWARE"] = "lynx" properties["Build.BOOTLOADER"] = "lynx-1.0-9716681" properties["Build.BRAND"] = "google" diff --git a/app/src/main/java/com/aurora/store/data/providers/NativeGsfVersionProvider.kt b/app/src/main/java/com/aurora/store/data/providers/NativeGsfVersionProvider.kt index b405f7a06..b0ca23a6f 100644 --- a/app/src/main/java/com/aurora/store/data/providers/NativeGsfVersionProvider.kt +++ b/app/src/main/java/com/aurora/store/data/providers/NativeGsfVersionProvider.kt @@ -25,11 +25,8 @@ import androidx.core.content.pm.PackageInfoCompat import com.aurora.store.util.PackageUtil.getPackageInfo class NativeGsfVersionProvider(context: Context, isExport: Boolean = false) { - - companion object { - private const val GOOGLE_SERVICES_PACKAGE_ID = "com.google.android.gms" - private const val GOOGLE_VENDING_PACKAGE_ID = "com.android.vending" - } + private val GOOGLE_SERVICES_PACKAGE_ID = "com.google.android.gms" + private val GOOGLE_VENDING_PACKAGE_ID = "com.android.vending" // Preferred defaults, not any specific reason they just work fine. var gsfVersionCode = 203019037L diff --git a/app/src/main/java/com/aurora/store/data/providers/NetworkProvider.kt b/app/src/main/java/com/aurora/store/data/providers/NetworkProvider.kt index c3b29961e..417d42a5f 100644 --- a/app/src/main/java/com/aurora/store/data/providers/NetworkProvider.kt +++ b/app/src/main/java/com/aurora/store/data/providers/NetworkProvider.kt @@ -22,9 +22,9 @@ package com.aurora.store.data.providers import android.content.Context import android.net.ConnectivityManager import android.net.Network -import android.net.NetworkRequest +import android.os.Build +import androidx.annotation.RequiresApi import androidx.core.content.getSystemService -import com.aurora.extensions.isNAndAbove import com.aurora.store.data.model.NetworkStatus import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject @@ -33,6 +33,7 @@ import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.launch /** * A simple provider with a flow to observe internet connectivity changes @@ -42,27 +43,24 @@ class NetworkProvider @Inject constructor(@ApplicationContext private val contex private val connectivityManager = context.getSystemService()!! + @get:RequiresApi(Build.VERSION_CODES.N) val status: Flow - get() = callbackFlow { - val networkCallback = object : ConnectivityManager.NetworkCallback() { - override fun onAvailable(network: Network) { - trySend(NetworkStatus.AVAILABLE).isSuccess - } + get() { + return callbackFlow { + val networkCallback = object : ConnectivityManager.NetworkCallback() { + override fun onAvailable(network: Network) { + super.onAvailable(network) + launch { send(NetworkStatus.AVAILABLE) } + } - override fun onLost(network: Network) { - trySend(NetworkStatus.UNAVAILABLE).isSuccess + override fun onLost(network: Network) { + super.onLost(network) + launch { send(NetworkStatus.UNAVAILABLE) } + } } - } - if (isNAndAbove) { connectivityManager.registerDefaultNetworkCallback(networkCallback) - } else { - connectivityManager.registerNetworkCallback( - NetworkRequest.Builder().build(), - networkCallback - ) - } - - awaitClose { connectivityManager.unregisterNetworkCallback(networkCallback) } - }.distinctUntilChanged() + awaitClose { connectivityManager.unregisterNetworkCallback(networkCallback) } + }.distinctUntilChanged() + } } diff --git a/app/src/main/java/com/aurora/store/data/providers/PermissionProvider.kt b/app/src/main/java/com/aurora/store/data/providers/PermissionProvider.kt index 9226be283..aa0ad0e2d 100644 --- a/app/src/main/java/com/aurora/store/data/providers/PermissionProvider.kt +++ b/app/src/main/java/com/aurora/store/data/providers/PermissionProvider.kt @@ -5,156 +5,30 @@ import android.annotation.SuppressLint import android.content.ActivityNotFoundException import android.content.Context import android.content.Intent +import android.net.Uri import android.provider.Settings import android.provider.Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS import android.util.Log import androidx.activity.result.ActivityResult import androidx.activity.result.ActivityResultCallback import androidx.activity.result.contract.ActivityResultContracts -import androidx.core.app.ActivityCompat -import androidx.core.net.toUri import androidx.fragment.app.Fragment -import com.aurora.extensions.TAG import com.aurora.extensions.checkManifestPermission import com.aurora.extensions.isDomainVerified import com.aurora.extensions.isExternalStorageAccessible import com.aurora.extensions.isIgnoringBatteryOptimizations -import com.aurora.extensions.isOAndAbove -import com.aurora.extensions.isRAndAbove -import com.aurora.extensions.isSAndAbove +import com.aurora.extensions.isMAndAbove import com.aurora.extensions.isTAndAbove -import com.aurora.extensions.requiresObbDir import com.aurora.extensions.toast -import com.aurora.gplayapi.data.models.App import com.aurora.store.BuildConfig import com.aurora.store.R -import com.aurora.store.data.model.Permission import com.aurora.store.data.model.PermissionType import com.aurora.store.util.PackageUtil class PermissionProvider(private val fragment: Fragment) : ActivityResultCallback { - companion object { - - /** - * Checks if Aurora Store has permissions to install the given app - */ - fun isPermittedToInstall(context: Context, app: App): Boolean { - if (!isGranted(context, PermissionType.INSTALL_UNKNOWN_APPS)) return false - return when { - app.fileList.requiresObbDir() -> { - return isGranted(context, PermissionType.STORAGE_MANAGER) - } - - else -> true - } - } - - /** - * Checks whether a known permission has been granted - */ - fun isGranted(context: Context, permissionType: PermissionType): Boolean = - when (permissionType) { - PermissionType.EXTERNAL_STORAGE, - PermissionType.STORAGE_MANAGER -> { - context.isExternalStorageAccessible() - } - - PermissionType.INSTALL_UNKNOWN_APPS -> { - PackageUtil.canRequestPackageInstalls(context) - } - - PermissionType.POST_NOTIFICATIONS -> { - if (isTAndAbove) { - context.checkManifestPermission(Manifest.permission.POST_NOTIFICATIONS) - } else { - true - } - } - - PermissionType.DOZE_WHITELIST -> context.isIgnoringBatteryOptimizations() - - PermissionType.APP_LINKS -> context.isDomainVerified("play.google.com") && - context.isDomainVerified("market.android.com") - } - - /** - * Returns all known permissions that can be requested by Aurora Store - */ - fun getAllKnownPermissions(context: Context): List { - val permissions = mutableListOf( - Permission( - type = PermissionType.INSTALL_UNKNOWN_APPS, - title = context.getString(R.string.onboarding_permission_installer), - subtitle = if (isOAndAbove) { - context.getString(R.string.onboarding_permission_installer_desc) - } else { - context.getString(R.string.onboarding_permission_installer_legacy_desc) - }, - optional = false, - isGranted = isGranted(context, PermissionType.INSTALL_UNKNOWN_APPS) - ), - Permission( - type = PermissionType.DOZE_WHITELIST, - title = context.getString(R.string.onboarding_permission_doze), - subtitle = context.getString(R.string.onboarding_permission_doze_desc), - optional = true, - isGranted = isGranted(context, PermissionType.DOZE_WHITELIST) - ) - ) - - if (isRAndAbove) { - permissions.add( - Permission( - type = PermissionType.STORAGE_MANAGER, - title = context.getString(R.string.onboarding_permission_esm), - subtitle = context.getString(R.string.onboarding_permission_esa_desc), - optional = false, - isGranted = isGranted(context, PermissionType.STORAGE_MANAGER) - ) - ) - } else { - permissions.add( - Permission( - type = PermissionType.EXTERNAL_STORAGE, - title = context.getString(R.string.onboarding_permission_esa), - subtitle = context.getString(R.string.onboarding_permission_esa_desc), - optional = false, - isGranted = isGranted(context, PermissionType.EXTERNAL_STORAGE) - ) - ) - } - - if (isTAndAbove) { - permissions.add( - Permission( - type = PermissionType.POST_NOTIFICATIONS, - title = context.getString(R.string.onboarding_permission_notifications), - subtitle = context.getString( - R.string.onboarding_permission_notifications_desc - ), - optional = true, - isGranted = isGranted(context, PermissionType.POST_NOTIFICATIONS) - ) - ) - } - - if (isSAndAbove) { - permissions.add( - Permission( - type = PermissionType.APP_LINKS, - title = context.getString(R.string.app_links_title), - subtitle = context.getString(R.string.app_links_desc), - optional = true, - isGranted = isGranted(context, PermissionType.APP_LINKS) - ) - ) - } - - return permissions - } - } + private val TAG = PermissionProvider::class.java.simpleName private val context: Context get() = fragment.requireContext() @@ -173,7 +47,7 @@ class PermissionProvider(private val fragment: Fragment) : } override fun onActivityResult(result: ActivityResult) { - permissionRequested?.let { permissionCallback(isGranted(context, it)) } + permissionRequested?.let { permissionCallback(isGranted(it)) } } fun request(permissionType: PermissionType, callback: (Boolean) -> Unit = {}) { @@ -192,32 +66,20 @@ class PermissionProvider(private val fragment: Fragment) : } } - PermissionType.STORAGE_MANAGER -> { - if (!isGranted(context, PermissionType.INSTALL_UNKNOWN_APPS)) { - context.toast(R.string.toast_permission_installer_required) + else -> { + val intent = knownPermissions()[permissionType] ?: return + + if (permissionType == PermissionType.STORAGE_MANAGER) { + if (!isGranted(PermissionType.INSTALL_UNKNOWN_APPS)) { + context.toast(R.string.toast_permission_installer_required) + } else { + context.toast(R.string.toast_permission_esm_restart) + intentLauncher.launch(intent) + } } else { - /* - * I don't know why, but for storage manager permission on Android 11 & 12, - * we need to request both permissions otherwise the permission is not granted, - * even though OS says it is granted. - */ - ActivityCompat.requestPermissions( - fragment.requireActivity(), - arrayOf( - Manifest.permission.WRITE_EXTERNAL_STORAGE - ), - 1 - ) - - val intent = knownPermissions()[permissionType] ?: return intentLauncher.launch(intent) } } - - else -> { - val intent = knownPermissions()[permissionType] ?: return - intentLauncher.launch(intent) - } } } catch (activityNotFoundException: ActivityNotFoundException) { Log.e(TAG, "Activity not found for $permissionType", activityNotFoundException) @@ -226,22 +88,50 @@ class PermissionProvider(private val fragment: Fragment) : } } + fun isGranted(permissionType: PermissionType): Boolean { + return when (permissionType) { + PermissionType.EXTERNAL_STORAGE, + PermissionType.STORAGE_MANAGER -> { + context.isExternalStorageAccessible() + } + + PermissionType.INSTALL_UNKNOWN_APPS -> PackageUtil.canRequestPackageInstalls(context) + + PermissionType.POST_NOTIFICATIONS -> { + if (isTAndAbove) { + context.checkManifestPermission(Manifest.permission.POST_NOTIFICATIONS) + } else { + true + } + } + + PermissionType.DOZE_WHITELIST -> { + if (isMAndAbove) context.isIgnoringBatteryOptimizations() else true + } + + PermissionType.APP_LINKS -> context.isDomainVerified("play.google.com") && + context.isDomainVerified("market.android.com") + } + } + fun unregister() { intentLauncher.unregister() permissionLauncher.unregister() } @SuppressLint("InlinedApi") - private fun knownPermissions(): Map = mapOf( - PermissionType.STORAGE_MANAGER to PackageUtil.getStorageManagerIntent(context), - PermissionType.INSTALL_UNKNOWN_APPS to PackageUtil.getInstallUnknownAppsIntent(), - PermissionType.DOZE_WHITELIST to Intent( - Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, - "package:${BuildConfig.APPLICATION_ID}".toUri() - ), - PermissionType.APP_LINKS to Intent( - ACTION_APP_OPEN_BY_DEFAULT_SETTINGS, - "package:${BuildConfig.APPLICATION_ID}".toUri() + private fun knownPermissions(): Map { + return mapOf( + PermissionType.STORAGE_MANAGER to PackageUtil.getStorageManagerIntent(context), + PermissionType.INSTALL_UNKNOWN_APPS to PackageUtil.getInstallUnknownAppsIntent(), + PermissionType.DOZE_WHITELIST to Intent( + Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, + Uri.parse("package:${BuildConfig.APPLICATION_ID}") + ), + PermissionType.APP_LINKS to Intent( + ACTION_APP_OPEN_BY_DEFAULT_SETTINGS, + Uri.parse("package:${BuildConfig.APPLICATION_ID}") + ) ) - ) + } } diff --git a/app/src/main/java/com/aurora/store/data/providers/SpoofDeviceProvider.kt b/app/src/main/java/com/aurora/store/data/providers/SpoofDeviceProvider.kt index 17fc4c3cd..4536f2d7c 100644 --- a/app/src/main/java/com/aurora/store/data/providers/SpoofDeviceProvider.kt +++ b/app/src/main/java/com/aurora/store/data/providers/SpoofDeviceProvider.kt @@ -21,7 +21,6 @@ package com.aurora.store.data.providers import android.content.Context import android.util.Log -import com.aurora.extensions.TAG import com.aurora.store.BuildConfig import com.aurora.store.util.PathUtil import java.io.BufferedInputStream @@ -41,17 +40,17 @@ import javax.inject.Singleton @Singleton open class SpoofDeviceProvider(private val context: Context) { - companion object { - private const val SUFFIX = ".properties" - } + private val TAG = SpoofDeviceProvider::class.java.simpleName + + private val SUFFIX = ".properties" - val availableDeviceProperties: List + val availableDeviceProperties: MutableList get() { val propertiesList: MutableList = ArrayList() propertiesList.addAll(spoofDevicesFromApk) propertiesList.addAll(spoofDevicesFromUser) propertiesList.sortBy { it.getProperty("UserReadableName") } - return propertiesList.distinctBy { it.getProperty("Build.PRODUCT") } + return propertiesList } private val spoofDevicesFromApk: List @@ -137,9 +136,12 @@ open class SpoofDeviceProvider(private val context: Context) { return File(sourceDir) } } catch (ignored: Exception) { + } return null } - private fun filenameValid(filename: String): Boolean = filename.endsWith(SUFFIX) + private fun filenameValid(filename: String): Boolean { + return filename.endsWith(SUFFIX) + } } diff --git a/app/src/main/java/com/aurora/store/data/providers/SpoofProvider.kt b/app/src/main/java/com/aurora/store/data/providers/SpoofProvider.kt index 510b303eb..dcbad046b 100644 --- a/app/src/main/java/com/aurora/store/data/providers/SpoofProvider.kt +++ b/app/src/main/java/com/aurora/store/data/providers/SpoofProvider.kt @@ -23,20 +23,20 @@ import android.content.Context import com.aurora.store.R import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences.PREFERENCE_VENDING_VERSION +import com.google.gson.Gson import dagger.hilt.android.qualifiers.ApplicationContext import java.util.Locale import java.util.Properties import javax.inject.Inject import javax.inject.Singleton -import kotlinx.serialization.json.Json /** * Provider class to work with device and locale spoofs */ @Singleton class SpoofProvider @Inject constructor( - private val json: Json, - @ApplicationContext val context: Context + private val gson: Gson, + @ApplicationContext val context: Context, ) : SpoofDeviceProvider(context) { companion object { @@ -79,14 +79,15 @@ class SpoofProvider @Inject constructor( get() = Preferences.getBoolean(context, DEVICE_SPOOF_ENABLED) private val spoofLocale: Locale - get() = Locale.Builder() - .setLanguage(Preferences.getString(context, LOCALE_SPOOF_LANG)) - .setRegion(Preferences.getString(context, LOCALE_SPOOF_COUNTRY)) - .build() + get() = Locale( + Preferences.getString(context, LOCALE_SPOOF_LANG), + Preferences.getString(context, LOCALE_SPOOF_COUNTRY) + ) private val spoofDeviceProperties: Properties - get() = json.decodeFromString( - Preferences.getString(context, DEVICE_SPOOF_PROPERTIES) + get() = gson.fromJson( + Preferences.getString(context, DEVICE_SPOOF_PROPERTIES), + Properties::class.java ) fun setSpoofLocale(locale: Locale) { @@ -97,7 +98,7 @@ class SpoofProvider @Inject constructor( fun setSpoofDeviceProperties(properties: Properties) { Preferences.putBoolean(context, DEVICE_SPOOF_ENABLED, true) - Preferences.putString(context, DEVICE_SPOOF_PROPERTIES, json.encodeToString(properties)) + Preferences.putString(context, DEVICE_SPOOF_PROPERTIES, gson.toJson(properties)) } fun removeSpoofLocale() { @@ -119,10 +120,7 @@ class SpoofProvider @Inject constructor( val versionStrings = resources.getStringArray(R.array.pref_vending_version) currentProperties.setProperty("Vending.version", versionCodes[vendingVersionIndex]) - currentProperties.setProperty( - "Vending.versionString", - versionStrings[vendingVersionIndex] - ) + currentProperties.setProperty("Vending.versionString", versionStrings[vendingVersionIndex]) } } } diff --git a/app/src/main/java/com/aurora/store/data/receiver/DownloadCancelReceiver.kt b/app/src/main/java/com/aurora/store/data/receiver/DownloadCancelReceiver.kt deleted file mode 100644 index 8534f669e..000000000 --- a/app/src/main/java/com/aurora/store/data/receiver/DownloadCancelReceiver.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 Aurora OSS - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.data.receiver - -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.util.Log -import com.aurora.extensions.TAG -import com.aurora.store.AuroraApp -import com.aurora.store.data.helper.DownloadHelper -import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch - -@AndroidEntryPoint -class DownloadCancelReceiver : BroadcastReceiver() { - - @Inject - lateinit var downloadHelper: DownloadHelper - - override fun onReceive(context: Context, intent: Intent?) { - val packageName: String = intent?.getStringExtra("PACKAGE_NAME") ?: "" - - if (packageName.isNotBlank()) { - Log.d(TAG, "Received cancel download request for $packageName") - AuroraApp.scope.launch(Dispatchers.IO) { - downloadHelper.cancelDownload(packageName) - } - } - } -} diff --git a/app/src/main/java/com/aurora/store/data/receiver/BaseInstallerStatusReceiver.kt b/app/src/main/java/com/aurora/store/data/receiver/InstallerStatusReceiver.kt similarity index 63% rename from app/src/main/java/com/aurora/store/data/receiver/BaseInstallerStatusReceiver.kt rename to app/src/main/java/com/aurora/store/data/receiver/InstallerStatusReceiver.kt index 2e42dbf6d..b5f713f7a 100644 --- a/app/src/main/java/com/aurora/store/data/receiver/BaseInstallerStatusReceiver.kt +++ b/app/src/main/java/com/aurora/store/data/receiver/InstallerStatusReceiver.kt @@ -23,42 +23,40 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.pm.PackageInstaller -import android.content.pm.PackageInstaller.EXTRA_SESSION_ID import android.util.Log import androidx.core.content.IntentCompat import androidx.core.content.getSystemService -import com.aurora.extensions.TAG import com.aurora.extensions.runOnUiThread import com.aurora.store.AuroraApp +import com.aurora.store.R import com.aurora.store.data.event.InstallerEvent import com.aurora.store.data.installer.AppInstaller.Companion.ACTION_INSTALL_STATUS import com.aurora.store.data.installer.AppInstaller.Companion.EXTRA_DISPLAY_NAME import com.aurora.store.data.installer.AppInstaller.Companion.EXTRA_PACKAGE_NAME import com.aurora.store.data.installer.AppInstaller.Companion.EXTRA_VERSION_CODE import com.aurora.store.data.installer.base.InstallerBase +import com.aurora.store.util.CommonUtil.inForeground import com.aurora.store.util.NotificationUtil import com.aurora.store.util.PackageUtil import com.aurora.store.util.PathUtil import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences.PREFERENCE_AUTO_DELETE +import dagger.hilt.android.AndroidEntryPoint -abstract class BaseInstallerStatusReceiver : BroadcastReceiver() { +@AndroidEntryPoint +class InstallerStatusReceiver : BroadcastReceiver() { + + private val TAG = InstallerStatusReceiver::class.java.simpleName override fun onReceive(context: Context?, intent: Intent?) { if (context != null && intent?.action == ACTION_INSTALL_STATUS) { - val packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME) ?: return - val displayName = intent.getStringExtra(EXTRA_DISPLAY_NAME) ?: packageName + val packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME)!! + val displayName = intent.getStringExtra(EXTRA_DISPLAY_NAME)!! + val versionCode = intent.getIntExtra(EXTRA_VERSION_CODE, -1) - val versionCode = intent.getLongExtra(EXTRA_VERSION_CODE, -1) - val sessionId = intent.getIntExtra(EXTRA_SESSION_ID, -1) val status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -1) val extra = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) - Log.i( - TAG, - "$packageName ($versionCode) sessionId=$sessionId, status=$status, extra=$extra" - ) - // If package was successfully installed, exit after notifying user and doing cleanup if (status == PackageInstaller.STATUS_SUCCESS) { // No post-install steps for shared libraries @@ -66,22 +64,19 @@ abstract class BaseInstallerStatusReceiver : BroadcastReceiver() { AuroraApp.enqueuedInstalls.remove(packageName) InstallerBase.notifyInstallation(context, displayName, packageName) - if (Preferences.getBoolean(context, PREFERENCE_AUTO_DELETE)) { PathUtil.getAppDownloadDir(context, packageName, versionCode) .deleteRecursively() } - - return postStatus(status, packageName, extra, context) + return } - if (status == PackageInstaller.STATUS_PENDING_USER_ACTION) { - doAppropriatePrompt(context, intent, sessionId) + if (inForeground() && status == PackageInstaller.STATUS_PENDING_USER_ACTION) { + promptUser(intent, context) } else { AuroraApp.enqueuedInstalls.remove(packageName) - notifyUser(context, packageName, displayName, status) - postStatus(status, packageName, extra, context) + notifyUser(context, packageName, displayName, status) } } } @@ -99,50 +94,44 @@ abstract class BaseInstallerStatusReceiver : BroadcastReceiver() { displayName, InstallerBase.getErrorString(context, status) ) - notificationManager?.notify(packageName.hashCode(), notification) + notificationManager!!.notify(packageName.hashCode(), notification) } - internal fun promptUser(context: Context, intent: Intent) { - runOnUiThread { - val launchIntent = IntentCompat.getParcelableExtra( - intent, - Intent.EXTRA_INTENT, - Intent::class.java - ) - - if (launchIntent != null) { - launchIntent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true) - launchIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, context.packageName) - launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + private fun promptUser(intent: Intent, context: Context) { + IntentCompat.getParcelableExtra(intent, Intent.EXTRA_INTENT, Intent::class.java)?.let { + it.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true) + it.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, "com.android.vending") + it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - try { - context.startActivity(launchIntent) - } catch (exception: Exception) { - Log.e(TAG, "Failed to launch intent!", exception) - } - } else { - Log.w(TAG, "No launch intent found in the installation request.") + try { + runOnUiThread { context.startActivity(it) } + } catch (exception: Exception) { + Log.e(TAG, "Failed to trigger installation!", exception) } } } - open fun doAppropriatePrompt(context: Context, intent: Intent, sessionId: Int) { - promptUser(context, intent) - } - - open fun postStatus(status: Int, packageName: String, extra: String?, context: Context) { + private fun postStatus(status: Int, packageName: String?, extra: String?, context: Context) { val event = when (status) { - PackageInstaller.STATUS_SUCCESS -> InstallerEvent.Installed( - packageName = packageName - ) + PackageInstaller.STATUS_SUCCESS -> { + InstallerEvent.Installed(packageName!!).apply { + this.extra = context.getString(R.string.installer_status_success) + } + } - else -> InstallerEvent.Failed( - packageName = packageName, - error = InstallerBase.getErrorString(context, status), - extra = extra - ) - } + PackageInstaller.STATUS_FAILURE_ABORTED -> { + InstallerEvent.Cancelled(packageName!!).apply { + this.extra = InstallerBase.getErrorString(context, status) + } + } + else -> { + InstallerEvent.Failed(packageName!!).apply { + this.error = InstallerBase.getErrorString(context, status) + this.extra = extra ?: "" + } + } + } AuroraApp.events.send(event) } } diff --git a/app/src/main/java/com/aurora/store/data/receiver/MigrationReceiver.kt b/app/src/main/java/com/aurora/store/data/receiver/MigrationReceiver.kt index 20b4d21c1..1d75abf9d 100644 --- a/app/src/main/java/com/aurora/store/data/receiver/MigrationReceiver.kt +++ b/app/src/main/java/com/aurora/store/data/receiver/MigrationReceiver.kt @@ -6,18 +6,14 @@ import android.content.Context import android.content.Intent import android.util.Log import androidx.core.content.getSystemService -import androidx.work.WorkManager import com.aurora.Constants import com.aurora.extensions.isOAndAbove -import com.aurora.store.data.helper.UpdateHelper.Companion.getAutoUpdateWork -import com.aurora.store.data.model.UpdateMode import com.aurora.store.data.work.CacheWorker import com.aurora.store.util.CertUtil import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences.PREFERENCE_DISPENSER_URLS import com.aurora.store.util.Preferences.PREFERENCE_INTRO import com.aurora.store.util.Preferences.PREFERENCE_MIGRATION_VERSION -import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_AUTO import com.aurora.store.util.Preferences.PREFERENCE_VENDING_VERSION import com.aurora.store.util.save import dagger.hilt.android.AndroidEntryPoint @@ -75,8 +71,7 @@ class MigrationReceiver : BroadcastReceiver() { // 63 -> 64 if (currentVersion == 2) { if (isOAndAbove) { - with(context.getSystemService()!!) { - // !1189 + with(context.getSystemService()!!) { // !1189 deleteNotificationChannel("NOTIFICATION_CHANNEL_GENERAL") deleteNotificationChannel("NOTIFICATION_CHANNEL_ALERT") } @@ -84,24 +79,6 @@ class MigrationReceiver : BroadcastReceiver() { currentVersion++ } - // 68 -> 69 - if (currentVersion == 3) { - val updateMode = UpdateMode.entries[ - Preferences.getInteger( - context, - PREFERENCE_UPDATES_AUTO, - UpdateMode.DISABLED.ordinal - ) - ] - - if (updateMode != UpdateMode.DISABLED) { - runCatching { - WorkManager.getInstance(context).updateWork(getAutoUpdateWork(context)) - }.onFailure { Log.e(TAG, "Failed to migrate app updates!", it) } - } - currentVersion++ - } - // Add new migrations / defaults above this point. if (currentVersion != PREF_VERSION) { Log.e(TAG, "Upgrading to version $PREF_VERSION left it at $currentVersion instead") diff --git a/app/src/main/java/com/aurora/store/data/receiver/NetworkBroadcastReceiver.kt b/app/src/main/java/com/aurora/store/data/receiver/NetworkBroadcastReceiver.kt deleted file mode 100644 index 041c0ef2b..000000000 --- a/app/src/main/java/com/aurora/store/data/receiver/NetworkBroadcastReceiver.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 Aurora OSS - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package com.aurora.store.data.receiver - -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.net.ConnectivityManager -import androidx.core.content.getSystemService - -/** - * Broadcast receiver for network status for API 21 & 22 - * @param callback Callback when the network status changes - */ -@Suppress("DEPRECATION") -class NetworkBroadcastReceiver(private val callback: (Boolean) -> Unit) : BroadcastReceiver() { - - override fun onReceive(context: Context?, intent: Intent?) { - val connectivityManager = context?.getSystemService() - val networkInfo = connectivityManager?.activeNetworkInfo - val isConnected = networkInfo?.isConnectedOrConnecting == true - - callback(isConnected) - } -} diff --git a/app/src/main/java/com/aurora/store/data/receiver/PackageManagerReceiver.kt b/app/src/main/java/com/aurora/store/data/receiver/PackageManagerReceiver.kt index dbc1f27cb..0d134dbe7 100644 --- a/app/src/main/java/com/aurora/store/data/receiver/PackageManagerReceiver.kt +++ b/app/src/main/java/com/aurora/store/data/receiver/PackageManagerReceiver.kt @@ -48,7 +48,7 @@ open class PackageManagerReceiver : BroadcastReceiver() { } } - // Clear installation queue + //Clear installation queue appInstaller.getPreferredInstaller().removeFromInstallQueue(packageName) } } diff --git a/app/src/main/java/com/aurora/store/data/receiver/UnarchivePackageReceiver.kt b/app/src/main/java/com/aurora/store/data/receiver/UnarchivePackageReceiver.kt index 4c271564c..378a062e4 100644 --- a/app/src/main/java/com/aurora/store/data/receiver/UnarchivePackageReceiver.kt +++ b/app/src/main/java/com/aurora/store/data/receiver/UnarchivePackageReceiver.kt @@ -7,7 +7,6 @@ import android.content.Intent import android.content.pm.PackageInstaller.EXTRA_UNARCHIVE_PACKAGE_NAME import android.util.Log import androidx.core.content.getSystemService -import com.aurora.extensions.TAG import com.aurora.extensions.isVAndAbove import com.aurora.gplayapi.helpers.AppDetailsHelper import com.aurora.store.AuroraApp @@ -15,15 +14,17 @@ import com.aurora.store.data.helper.DownloadHelper import com.aurora.store.data.providers.AccountProvider import com.aurora.store.util.NotificationUtil import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import javax.inject.Inject /** * Triggers re-install/unarchive of a previously archived app on Android 15+ devices. */ @AndroidEntryPoint -class UnarchivePackageReceiver : BroadcastReceiver() { +class UnarchivePackageReceiver: BroadcastReceiver() { + + private val TAG = UnarchivePackageReceiver::class.java.simpleName @Inject lateinit var appDetailsHelper: AppDetailsHelper diff --git a/app/src/main/java/com/aurora/store/data/room/AuroraDatabase.kt b/app/src/main/java/com/aurora/store/data/room/AuroraDatabase.kt index 298ad090e..2a7a94e3a 100644 --- a/app/src/main/java/com/aurora/store/data/room/AuroraDatabase.kt +++ b/app/src/main/java/com/aurora/store/data/room/AuroraDatabase.kt @@ -13,8 +13,8 @@ import com.aurora.store.data.room.update.UpdateDao @Database( entities = [Download::class, Favourite::class, Update::class], - version = 6, - exportSchema = true + version = 5, + exportSchema = false ) @TypeConverters(DownloadConverter::class) abstract class AuroraDatabase : RoomDatabase() { diff --git a/app/src/main/java/com/aurora/store/data/room/MigrationHelper.kt b/app/src/main/java/com/aurora/store/data/room/MigrationHelper.kt index fa2b05c90..0f2ed0b8c 100644 --- a/app/src/main/java/com/aurora/store/data/room/MigrationHelper.kt +++ b/app/src/main/java/com/aurora/store/data/room/MigrationHelper.kt @@ -10,14 +10,6 @@ import androidx.sqlite.db.SupportSQLiteDatabase */ object MigrationHelper { - val MIGRATION_1_2 = object : Migration(1, 2) { - override fun migrate(db: SupportSQLiteDatabase) = migrateFrom1To2(db) - } - - val MIGRATION_2_3 = object : Migration(2, 3) { - override fun migrate(db: SupportSQLiteDatabase) = migrateFrom2To3(db) - } - val MIGRATION_3_4 = object : Migration(3, 4) { override fun migrate(db: SupportSQLiteDatabase) = migrateFrom3To4(db) } @@ -26,40 +18,8 @@ object MigrationHelper { override fun migrate(db: SupportSQLiteDatabase) = migrateFrom4To5(db) } - val MIGRATION_5_6 = object : Migration(5, 6) { - override fun migrate(db: SupportSQLiteDatabase) = migrateFrom5To6(db) - } - private const val TAG = "MigrationHelper" - private fun migrateFrom1To2(database: SupportSQLiteDatabase) { - database.beginTransaction() - try { - database.execSQL( - "CREATE TABLE `favourite` (`packageName` TEXT NOT NULL, `displayName` TEXT NOT NULL, `iconURL` TEXT NOT NULL, `added` INTEGER NOT NULL, `mode` TEXT NOT NULL, PRIMARY KEY(`packageName`))" - ) - database.setTransactionSuccessful() - } catch (exception: Exception) { - Log.e(TAG, "Failed while migrating from database version 1 to 2", exception) - } finally { - database.endTransaction() - } - } - - private fun migrateFrom2To3(database: SupportSQLiteDatabase) { - database.beginTransaction() - try { - database.execSQL( - "CREATE TABLE `update` (`packageName` TEXT NOT NULL, `versionCode` INTEGER NOT NULL, `versionName` TEXT NOT NULL, `displayName` TEXT NOT NULL, `iconURL` TEXT NOT NULL, `changelog` TEXT NOT NULL, `id` INTEGER NOT NULL, `developerName` TEXT NOT NULL, `size` INTEGER NOT NULL, `updatedOn` TEXT NOT NULL, `hasValidCert` INTEGER NOT NULL, `offerType` INTEGER NOT NULL, `fileList` TEXT NOT NULL, `sharedLibs` TEXT NOT NULL, PRIMARY KEY(`packageName`))" - ) - database.setTransactionSuccessful() - } catch (exception: Exception) { - Log.e(TAG, "Failed while migrating from database version 2 to 3", exception) - } finally { - database.endTransaction() - } - } - /** * Add targetSdk column to download and update table for checking if silent install is possible. */ @@ -67,9 +27,7 @@ object MigrationHelper { database.beginTransaction() try { listOf("download", "update").forEach { - database.execSQL( - "ALTER TABLE `$it` ADD COLUMN targetSdk INTEGER NOT NULL DEFAULT 1" - ) + database.execSQL("ALTER TABLE `$it` ADD COLUMN targetSdk INTEGER NOT NULL DEFAULT 1") } database.setTransactionSuccessful() } catch (exception: Exception) { @@ -85,9 +43,7 @@ object MigrationHelper { private fun migrateFrom4To5(database: SupportSQLiteDatabase) { database.beginTransaction() try { - database.execSQL( - "ALTER TABLE `download` ADD COLUMN downloadedAt INTEGER NOT NULL DEFAULT 0" - ) + database.execSQL("ALTER TABLE `download` ADD COLUMN downloadedAt INTEGER NOT NULL DEFAULT 0") database.setTransactionSuccessful() } catch (exception: Exception) { Log.e(TAG, "Failed while migrating from database version 4 to 5", exception) @@ -95,21 +51,4 @@ object MigrationHelper { database.endTransaction() } } - - /** - * Add requiresGMS column to download table for checking if app requires GMS to install. - */ - private fun migrateFrom5To6(database: SupportSQLiteDatabase) { - database.beginTransaction() - try { - database.execSQL( - "ALTER TABLE `download` ADD COLUMN requiresGMS INTEGER NOT NULL DEFAULT 0" - ) - database.setTransactionSuccessful() - } catch (exception: Exception) { - Log.e(TAG, "Failed while migrating from database version 5 to 6", exception) - } finally { - database.endTransaction() - } - } } diff --git a/app/src/main/java/com/aurora/store/data/room/RoomModule.kt b/app/src/main/java/com/aurora/store/data/room/RoomModule.kt index 05ecb723e..2e557ea84 100644 --- a/app/src/main/java/com/aurora/store/data/room/RoomModule.kt +++ b/app/src/main/java/com/aurora/store/data/room/RoomModule.kt @@ -2,11 +2,8 @@ package com.aurora.store.data.room import android.content.Context import androidx.room.Room -import com.aurora.store.data.room.MigrationHelper.MIGRATION_1_2 -import com.aurora.store.data.room.MigrationHelper.MIGRATION_2_3 import com.aurora.store.data.room.MigrationHelper.MIGRATION_3_4 import com.aurora.store.data.room.MigrationHelper.MIGRATION_4_5 -import com.aurora.store.data.room.MigrationHelper.MIGRATION_5_6 import com.aurora.store.data.room.download.DownloadConverter import com.aurora.store.data.room.download.DownloadDao import com.aurora.store.data.room.favourite.FavouriteDao @@ -29,25 +26,25 @@ object RoomModule { fun providesRoomInstance( @ApplicationContext context: Context, downloadConverter: DownloadConverter - ): AuroraDatabase = Room.databaseBuilder(context, AuroraDatabase::class.java, DATABASE) - .addMigrations( - MIGRATION_1_2, - MIGRATION_2_3, - MIGRATION_3_4, - MIGRATION_4_5, - MIGRATION_5_6 - ) - .addTypeConverter(downloadConverter) - .build() + ): AuroraDatabase { + return Room.databaseBuilder(context, AuroraDatabase::class.java, DATABASE) + .addMigrations(MIGRATION_3_4, MIGRATION_4_5) + .addTypeConverter(downloadConverter) + .build() + } @Provides - fun providesDownloadDao(auroraDatabase: AuroraDatabase): DownloadDao = - auroraDatabase.downloadDao() + fun providesDownloadDao(auroraDatabase: AuroraDatabase): DownloadDao { + return auroraDatabase.downloadDao() + } @Provides - fun providesFavouriteDao(auroraDatabase: AuroraDatabase): FavouriteDao = - auroraDatabase.favouriteDao() + fun providesFavouriteDao(auroraDatabase: AuroraDatabase): FavouriteDao { + return auroraDatabase.favouriteDao() + } @Provides - fun providesUpdateDao(auroraDatabase: AuroraDatabase): UpdateDao = auroraDatabase.updateDao() + fun providesUpdateDao(auroraDatabase: AuroraDatabase): UpdateDao { + return auroraDatabase.updateDao() + } } diff --git a/app/src/main/java/com/aurora/store/data/room/download/Download.kt b/app/src/main/java/com/aurora/store/data/room/download/Download.kt index 5a2ef3f40..4bf120518 100644 --- a/app/src/main/java/com/aurora/store/data/room/download/Download.kt +++ b/app/src/main/java/com/aurora/store/data/room/download/Download.kt @@ -1,114 +1,85 @@ package com.aurora.store.data.room.download -import android.content.Context import android.os.Parcelable -import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey -import com.aurora.extensions.requiresGMS import com.aurora.gplayapi.data.models.App -import com.aurora.gplayapi.data.models.PlayFile +import com.aurora.gplayapi.data.models.File import com.aurora.store.data.model.DownloadStatus -import com.aurora.store.data.room.suite.ExternalApk import com.aurora.store.data.room.update.Update -import com.aurora.store.util.PathUtil -import java.util.Date import kotlinx.parcelize.Parcelize +import java.util.Date @Parcelize @Entity(tableName = "download") data class Download( @PrimaryKey val packageName: String, - val versionCode: Long, + val versionCode: Int, val offerType: Int, val isInstalled: Boolean, val displayName: String, val iconURL: String, val size: Long, val id: Int, - @ColumnInfo("downloadStatus") - var status: DownloadStatus, + var downloadStatus: DownloadStatus, var progress: Int, var speed: Long, var timeRemaining: Long, var totalFiles: Int, var downloadedFiles: Int, - var fileList: List, + var fileList: List, val sharedLibs: List, val targetSdk: Int = 1, - val downloadedAt: Long = 0, - val requiresGMS: Boolean = false + val downloadedAt: Long = 0 ) : Parcelable { - val isFinished get() = status in DownloadStatus.finished - val isRunning get() = status in DownloadStatus.running - private val isSuccessful get() = status == DownloadStatus.COMPLETED + val isFinished get() = downloadStatus in DownloadStatus.finished + val isRunning get() = downloadStatus in DownloadStatus.running companion object { - fun fromApp(app: App): Download = Download( - app.packageName, - app.versionCode, - app.offerType, - app.isInstalled, - app.displayName, - app.iconArtwork.url, - app.size, - app.id, - DownloadStatus.QUEUED, - 0, - 0L, - 0L, - 0, - 0, - app.fileList.filterNot { it.url.isBlank() }, - app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) }, - app.targetSdk, - Date().time, - app.requiresGMS() - ) - - fun fromUpdate(update: Update): Download = Download( - update.packageName, - update.versionCode, - update.offerType, - true, - update.displayName, - update.iconURL, - update.size, - update.id, - DownloadStatus.QUEUED, - 0, - 0L, - 0L, - 0, - 0, - update.fileList, - update.sharedLibs, - update.targetSdk, - Date().time - ) - - fun fromExternalApk(externalApk: ExternalApk): Download = Download( - packageName = externalApk.packageName, - versionCode = externalApk.versionCode, - offerType = 0, - isInstalled = false, - displayName = externalApk.displayName, - iconURL = externalApk.iconURL, - size = 0, - id = 0, - status = DownloadStatus.QUEUED, - progress = 0, - speed = 0L, - timeRemaining = 0L, - totalFiles = 1, - downloadedFiles = 0, - fileList = externalApk.fileList, - sharedLibs = emptyList() - ) - } + fun fromApp(app: App): Download { + return Download( + app.packageName, + app.versionCode, + app.offerType, + app.isInstalled, + app.displayName, + app.iconArtwork.url, + app.size, + app.id, + DownloadStatus.QUEUED, + 0, + 0L, + 0L, + 0, + 0, + app.fileList.filterNot { it.url.isBlank() }, + app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) }, + app.targetSdk, + Date().time + ) + } - fun canInstall(context: Context): Boolean { - val dir = PathUtil.getAppDownloadDir(context, packageName, versionCode) - return isSuccessful && dir.listFiles() != null + fun fromUpdate(update: Update): Download { + return Download( + update.packageName, + update.versionCode, + update.offerType, + true, + update.displayName, + update.iconURL, + update.size, + update.id, + DownloadStatus.QUEUED, + 0, + 0L, + 0L, + 0, + 0, + update.fileList, + update.sharedLibs, + update.targetSdk, + Date().time + ) + } } } diff --git a/app/src/main/java/com/aurora/store/data/room/download/DownloadConverter.kt b/app/src/main/java/com/aurora/store/data/room/download/DownloadConverter.kt index 144dc0bab..65cc4d053 100644 --- a/app/src/main/java/com/aurora/store/data/room/download/DownloadConverter.kt +++ b/app/src/main/java/com/aurora/store/data/room/download/DownloadConverter.kt @@ -2,26 +2,35 @@ package com.aurora.store.data.room.download import androidx.room.ProvidedTypeConverter import androidx.room.TypeConverter -import com.aurora.gplayapi.data.models.PlayFile +import com.aurora.gplayapi.data.models.File +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken import javax.inject.Inject import javax.inject.Singleton -import kotlinx.serialization.json.Json @Singleton @ProvidedTypeConverter -class DownloadConverter @Inject constructor(private val json: Json) { +class DownloadConverter @Inject constructor(private val gson: Gson) { @TypeConverter - fun toSharedLibList(string: String): List = - json.decodeFromString>(string) + fun toSharedLibList(string: String): List { + val listType = object : TypeToken>() {}.type + return gson.fromJson(string, listType) + } @TypeConverter - fun fromSharedLibList(list: List): String = json.encodeToString(list) + fun fromSharedLibList(list: List): String { + return gson.toJson(list) + } @TypeConverter - fun toGPlayFileList(string: String): List = - json.decodeFromString>(string) + fun toGPlayFileList(string: String): List { + val listType = object : TypeToken>() {}.type + return gson.fromJson(string, listType) + } @TypeConverter - fun fromGPlayFileList(list: List): String = json.encodeToString(list) + fun fromGPlayFileList(list: List): String { + return gson.toJson(list) + } } diff --git a/app/src/main/java/com/aurora/store/data/room/download/DownloadDao.kt b/app/src/main/java/com/aurora/store/data/room/download/DownloadDao.kt index c65ac3553..de2b795d0 100644 --- a/app/src/main/java/com/aurora/store/data/room/download/DownloadDao.kt +++ b/app/src/main/java/com/aurora/store/data/room/download/DownloadDao.kt @@ -1,11 +1,10 @@ package com.aurora.store.data.room.download -import androidx.paging.PagingSource import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query -import com.aurora.gplayapi.data.models.PlayFile +import com.aurora.gplayapi.data.models.File import com.aurora.store.data.model.DownloadStatus import kotlinx.coroutines.flow.Flow @@ -19,7 +18,7 @@ interface DownloadDao { suspend fun updateStatus(packageName: String, downloadStatus: DownloadStatus) @Query("UPDATE download SET fileList=:fileList WHERE packageName=:packageName") - suspend fun updateFiles(packageName: String, fileList: List) + suspend fun updateFiles(packageName: String, fileList: List) @Query("UPDATE download SET sharedLibs=:sharedLibs WHERE packageName=:packageName") suspend fun updateSharedLibs(packageName: String, sharedLibs: List) @@ -31,14 +30,16 @@ interface DownloadDao { WHERE packageName=:packageName """ ) - suspend fun updateProgress(packageName: String, progress: Int, speed: Long, timeRemaining: Long) + suspend fun updateProgress( + packageName: String, + progress: Int, + speed: Long, + timeRemaining: Long + ) @Query("SELECT * FROM download") fun downloads(): Flow> - @Query("SELECT * FROM download ORDER BY downloadedAt DESC") - fun pagedDownloads(): PagingSource - @Query("SELECT * FROM download WHERE packageName = :packageName") suspend fun getDownload(packageName: String): Download diff --git a/app/src/main/java/com/aurora/store/data/room/download/SharedLib.kt b/app/src/main/java/com/aurora/store/data/room/download/SharedLib.kt index 37174e2fe..89afc83b1 100644 --- a/app/src/main/java/com/aurora/store/data/room/download/SharedLib.kt +++ b/app/src/main/java/com/aurora/store/data/room/download/SharedLib.kt @@ -2,22 +2,22 @@ package com.aurora.store.data.room.download import android.os.Parcelable import com.aurora.gplayapi.data.models.App -import com.aurora.gplayapi.data.models.PlayFile +import com.aurora.gplayapi.data.models.File import kotlinx.parcelize.Parcelize -import kotlinx.serialization.Serializable -@Serializable @Parcelize data class SharedLib( val packageName: String, - val versionCode: Long, - var fileList: List + val versionCode: Int, + var fileList: List ) : Parcelable { companion object { - fun fromApp(app: App): SharedLib = SharedLib( - app.packageName, - app.versionCode, - app.fileList.filterNot { it.url.isBlank() } - ) + fun fromApp(app: App): SharedLib { + return SharedLib( + app.packageName, + app.versionCode, + app.fileList.filterNot { it.url.isBlank() } + ) + } } } diff --git a/app/src/main/java/com/aurora/store/data/room/favourite/Favourite.kt b/app/src/main/java/com/aurora/store/data/room/favourite/Favourite.kt index c854ee930..b71017988 100644 --- a/app/src/main/java/com/aurora/store/data/room/favourite/Favourite.kt +++ b/app/src/main/java/com/aurora/store/data/room/favourite/Favourite.kt @@ -6,9 +6,7 @@ import androidx.room.PrimaryKey import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.Artwork import kotlinx.parcelize.Parcelize -import kotlinx.serialization.Serializable -@Serializable @Parcelize @Entity(tableName = "favourite") data class Favourite( @@ -21,19 +19,23 @@ data class Favourite( ) : Parcelable { companion object { - fun fromApp(app: App, mode: Mode): Favourite = Favourite( - packageName = app.packageName, - displayName = app.displayName, - iconURL = app.iconArtwork.url, - added = System.currentTimeMillis(), - mode = mode - ) + fun fromApp(app: App, mode: Mode): Favourite { + return Favourite( + packageName = app.packageName, + displayName = app.displayName, + iconURL = app.iconArtwork.url, + added = System.currentTimeMillis(), + mode = mode + ) + } - fun Favourite.toApp(): App = App( - packageName = packageName, - displayName = displayName, - iconArtwork = Artwork(url = iconURL) - ) + fun Favourite.toApp(): App { + return App( + packageName = packageName, + displayName = displayName, + iconArtwork = Artwork(url = iconURL) + ) + } } enum class Mode { diff --git a/app/src/main/java/com/aurora/store/data/room/favourite/FavouriteDao.kt b/app/src/main/java/com/aurora/store/data/room/favourite/FavouriteDao.kt index 7d62b1c08..5a043eef8 100644 --- a/app/src/main/java/com/aurora/store/data/room/favourite/FavouriteDao.kt +++ b/app/src/main/java/com/aurora/store/data/room/favourite/FavouriteDao.kt @@ -1,6 +1,5 @@ package com.aurora.store.data.room.favourite -import androidx.paging.PagingSource import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy @@ -19,9 +18,6 @@ interface FavouriteDao { @Query("SELECT * FROM favourite") fun favourites(): Flow> - @Query("SELECT * FROM favourite") - fun pagedFavourites(): PagingSource - @Query("SELECT EXISTS(SELECT 1 FROM favourite WHERE packageName = :packageName)") suspend fun isFavourite(packageName: String): Boolean diff --git a/app/src/main/java/com/aurora/store/data/room/favourite/ImportExport.kt b/app/src/main/java/com/aurora/store/data/room/favourite/ImportExport.kt index 8c41cfaba..51059e2c6 100644 --- a/app/src/main/java/com/aurora/store/data/room/favourite/ImportExport.kt +++ b/app/src/main/java/com/aurora/store/data/room/favourite/ImportExport.kt @@ -1,10 +1,8 @@ package com.aurora.store.data.room.favourite import com.aurora.store.BuildConfig -import kotlinx.serialization.Serializable -@Serializable data class ImportExport( val favourites: List, - val auroraStoreVersion: Int = BuildConfig.VERSION_CODE + val auroraStoreVersion: Int = BuildConfig.VERSION_CODE, ) diff --git a/app/src/main/java/com/aurora/store/data/room/suite/ExternalApk.kt b/app/src/main/java/com/aurora/store/data/room/suite/ExternalApk.kt deleted file mode 100644 index b72cfb177..000000000 --- a/app/src/main/java/com/aurora/store/data/room/suite/ExternalApk.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.aurora.store.data.room.suite - -import android.content.Context -import android.os.Parcelable -import androidx.room.Entity -import androidx.room.PrimaryKey -import com.aurora.gplayapi.data.models.PlayFile -import com.aurora.store.util.PackageUtil -import kotlinx.parcelize.Parcelize - -@Parcelize -@Entity(tableName = "externalApk") -data class ExternalApk( - @PrimaryKey - val packageName: String, - val versionCode: Long, - val versionName: String, - val displayName: String, - val iconURL: String, - val developerName: String, - var fileList: List -) : Parcelable { - - fun isInstalled(context: Context): Boolean = PackageUtil.isInstalled(context, packageName) -} diff --git a/app/src/main/java/com/aurora/store/data/room/update/Update.kt b/app/src/main/java/com/aurora/store/data/room/update/Update.kt index bec3e8e76..d18b89565 100644 --- a/app/src/main/java/com/aurora/store/data/room/update/Update.kt +++ b/app/src/main/java/com/aurora/store/data/room/update/Update.kt @@ -5,7 +5,7 @@ import android.os.Parcelable import androidx.room.Entity import androidx.room.PrimaryKey import com.aurora.gplayapi.data.models.App -import com.aurora.gplayapi.data.models.PlayFile +import com.aurora.gplayapi.data.models.File import com.aurora.store.data.room.download.SharedLib import com.aurora.store.util.CertUtil import com.aurora.store.util.PackageUtil @@ -16,7 +16,7 @@ import kotlinx.parcelize.Parcelize data class Update( @PrimaryKey val packageName: String, - val versionCode: Long, + val versionCode: Int, val versionName: String, val displayName: String, val iconURL: String, @@ -27,40 +27,46 @@ data class Update( val updatedOn: String, val hasValidCert: Boolean, val offerType: Int, - var fileList: List, + var fileList: List, val sharedLibs: List, val targetSdk: Int = 1 ) : Parcelable { companion object { - fun fromApp(context: Context, app: App): Update = Update( - app.packageName, - app.versionCode, - app.versionName, - app.displayName, - app.iconArtwork.url, - app.changes, - app.id, - app.developerName, - app.size, - app.updatedOn, - app.certificateSetList.any { - it.certificateSet in CertUtil.getEncodedCertificateHashes( - context, - app.packageName - ) - }, - app.offerType, - app.fileList.filterNot { it.url.isBlank() }, - app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) }, - app.targetSdk - ) + fun fromApp(context: Context, app: App): Update { + return Update( + app.packageName, + app.versionCode, + app.versionName, + app.displayName, + app.iconArtwork.url, + app.changes, + app.id, + app.developerName, + app.size, + app.updatedOn, + app.certificateSetList.any { + it.certificateSet in CertUtil.getEncodedCertificateHashes( + context, app.packageName + ) + }, + app.offerType, + app.fileList.filterNot { it.url.isBlank() }, + app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) }, + app.targetSdk + ) + } } - fun isSelfUpdate(context: Context): Boolean = packageName == context.packageName + fun isSelfUpdate(context: Context): Boolean { + return packageName == context.packageName + } - fun isInstalled(context: Context): Boolean = PackageUtil.isInstalled(context, packageName) + fun isInstalled(context: Context): Boolean { + return PackageUtil.isInstalled(context, packageName) + } - fun isUpToDate(context: Context): Boolean = - PackageUtil.isInstalled(context, packageName, versionCode) + fun isUpToDate(context: Context): Boolean { + return PackageUtil.isInstalled(context, packageName, versionCode) + } } diff --git a/app/src/main/java/com/aurora/store/data/work/AuthWorker.kt b/app/src/main/java/com/aurora/store/data/work/AuthWorker.kt index 19e30e6ac..3ce970815 100644 --- a/app/src/main/java/com/aurora/store/data/work/AuthWorker.kt +++ b/app/src/main/java/com/aurora/store/data/work/AuthWorker.kt @@ -2,18 +2,15 @@ package com.aurora.store.data.work import android.accounts.Account import android.accounts.AccountManager -import android.accounts.AccountManagerCallback import android.content.Context -import android.os.Bundle import android.os.Handler import android.os.Looper import android.util.Base64 import android.util.Log +import androidx.core.os.bundleOf import androidx.hilt.work.HiltWorker import androidx.work.CoroutineWorker import androidx.work.WorkerParameters -import com.aurora.Constants.PACKAGE_NAME_PLAY_STORE -import com.aurora.extensions.TAG import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.helpers.AuthHelper import com.aurora.store.data.model.AccountType @@ -22,11 +19,13 @@ import com.aurora.store.data.providers.AuthProvider import com.aurora.store.util.CertUtil.GOOGLE_ACCOUNT_TYPE import com.aurora.store.util.CertUtil.GOOGLE_PLAY_AUTH_TOKEN_TYPE import com.aurora.store.util.CertUtil.GOOGLE_PLAY_CERT +import com.aurora.store.util.CertUtil.GOOGLE_PLAY_PACKAGE_NAME import dagger.assisted.Assisted import dagger.assisted.AssistedInject -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException -import kotlin.coroutines.suspendCoroutine +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.take +import kotlinx.coroutines.runBlocking /** * Worker to refresh [AuthData] in background @@ -35,12 +34,16 @@ import kotlin.coroutines.suspendCoroutine @HiltWorker open class AuthWorker @AssistedInject constructor( private val authProvider: AuthProvider, - @Assisted private val context: Context, + @Assisted private val appContext: Context, @Assisted workerParams: WorkerParameters -) : CoroutineWorker(context, workerParams) { +) : CoroutineWorker(appContext, workerParams) { + + private val TAG = AuthWorker::class.java.simpleName + + private val authToken: MutableSharedFlow = MutableSharedFlow(extraBufferCapacity = 1) override suspend fun doWork(): Result { - if (!AccountProvider.isLoggedIn(context)) { + if (!AccountProvider.isLoggedIn(appContext)) { Log.i(TAG, "User has logged out!") return Result.failure() } @@ -52,35 +55,44 @@ open class AuthWorker @AssistedInject constructor( // Generate and validate new auth try { - val accountType = AccountProvider.getAccountType(context) + val accountType = AccountProvider.getAccountType(appContext) val authData = when (accountType) { AccountType.GOOGLE -> { - val email = AccountProvider.getLoginEmail(context) - val tokenPair = AccountProvider.getLoginToken(context) - - if (email == null || tokenPair == null) { - throw Exception() - } + val email = AccountProvider.getLoginEmail(appContext)!! + val token = AccountProvider.getLoginToken(appContext)!!.first + val tokenType = AccountProvider.getLoginToken(appContext)!!.second - when (tokenPair.second) { - AuthHelper.Token.AAS -> { - Log.i(TAG, "Refreshing AuthData for personal account") + if (tokenType == AuthHelper.Token.AAS) { + Log.i(TAG, "Refreshing AuthData for personal account") + authProvider.buildGoogleAuthData(email, token, tokenType).getOrThrow() + } else { + /* + * We are working with AuthToken here. The only scenario when we will have + * AuthToken and Google login is when the user used microG to login into + * Aurora Store. In this case, we use system's AccountManager to request credentials. + */ + Log.i(TAG, "Refreshing AuthData for personal account using AccountManager") + AccountManager.get(appContext) + .getAuthToken( + Account(email, GOOGLE_ACCOUNT_TYPE), + GOOGLE_PLAY_AUTH_TOKEN_TYPE, + bundleOf( + "overridePackage" to GOOGLE_PLAY_PACKAGE_NAME, + "overrideCertificate" to Base64.decode(GOOGLE_PLAY_CERT, Base64.DEFAULT) + ), + true, + { + authToken.tryEmit(it.result.getString(AccountManager.KEY_AUTHTOKEN)) + }, + Handler(Looper.getMainLooper()) + ) + runBlocking { authProvider.buildGoogleAuthData( email, - tokenPair.first, - AuthHelper.Token.AAS + authToken.take(1).first()!!, + tokenType ).getOrThrow() } - - AuthHelper.Token.AUTH -> { - Log.i( - TAG, - "Refreshing AuthData for personal account using AccountManager" - ) - val newToken = fetchAuthToken(email, tokenPair.first) - authProvider.buildGoogleAuthData(email, newToken, AuthHelper.Token.AAS) - .getOrThrow() - } } } @@ -99,67 +111,11 @@ open class AuthWorker @AssistedInject constructor( } } - private suspend fun fetchAuthToken(email: String, oldToken: String? = null): String = - suspendCoroutine { continuation -> - fetchAuthToken(email, oldToken) { future -> - try { - val bundle = future.result - val token = bundle.getString(AccountManager.KEY_AUTHTOKEN) - - if (token != null) { - continuation.resume(token) - } else { - continuation.resumeWithException( - IllegalStateException("Auth token is null") - ) - } - } catch (e: Exception) { - continuation.resumeWithException(e) - } - } - } - - private fun fetchAuthToken( - email: String, - oldToken: String? = null, - callback: AccountManagerCallback - ) { - try { - if (oldToken != null) { - // Invalidate the old token before requesting a new one - AccountManager.get(context) - .invalidateAuthToken( - GOOGLE_ACCOUNT_TYPE, - oldToken - ) - } - - AccountManager.get(context) - .getAuthToken( - Account(email, GOOGLE_ACCOUNT_TYPE), - GOOGLE_PLAY_AUTH_TOKEN_TYPE, - Bundle().apply { - putString("overridePackage", PACKAGE_NAME_PLAY_STORE) - putByteArray( - "overrideCertificate", - Base64.decode(GOOGLE_PLAY_CERT, Base64.DEFAULT) - ) - }, - true, - callback, - Handler(Looper.getMainLooper()) - ) - } catch (e: Exception) { - Log.e(TAG, "Failed to fetch auth token", e) - callback.run(null) - } - } - - private fun verifyAndSaveAuth(authData: AuthData, accountType: AccountType): AuthData? = - if (authData.authToken.isNotEmpty() && authData.deviceConfigToken.isNotEmpty()) { + private fun verifyAndSaveAuth(authData: AuthData, accountType: AccountType): AuthData? { + return if (authData.authToken.isNotEmpty() && authData.deviceConfigToken.isNotEmpty()) { authProvider.saveAuthData(authData) AccountProvider.login( - context, + appContext, authData.email, authData.aasToken.ifBlank { authData.authToken }, if (authData.aasToken.isBlank()) AuthHelper.Token.AUTH else AuthHelper.Token.AAS, @@ -167,8 +123,9 @@ open class AuthWorker @AssistedInject constructor( ) authData } else { - authProvider.removeAuthData(context) - AccountProvider.logout(context) + authProvider.removeAuthData(appContext) + AccountProvider.logout(appContext) null } + } } diff --git a/app/src/main/java/com/aurora/store/data/work/CacheWorker.kt b/app/src/main/java/com/aurora/store/data/work/CacheWorker.kt index 076f0db54..77309345c 100644 --- a/app/src/main/java/com/aurora/store/data/work/CacheWorker.kt +++ b/app/src/main/java/com/aurora/store/data/work/CacheWorker.kt @@ -23,9 +23,9 @@ import kotlin.time.toDuration */ @HiltWorker class CacheWorker @AssistedInject constructor( - @Assisted private val context: Context, + @Assisted private val appContext: Context, @Assisted workerParams: WorkerParameters -) : CoroutineWorker(context, workerParams) { +) : CoroutineWorker(appContext, workerParams) { companion object { private const val TAG = "CleanCacheWorker" @@ -58,23 +58,19 @@ class CacheWorker @AssistedInject constructor( override suspend fun doWork(): Result { Log.i(TAG, "Cleaning cache") - PathUtil.getOldDownloadDirectories(context).filter { it.exists() }.forEach { dir -> - // Downloads + PathUtil.getOldDownloadDirectories(appContext).filter { it.exists() }.forEach { dir -> // Downloads Log.i(TAG, "Deleting old unused download directory: $dir") dir.deleteRecursively() } - PathUtil.getDownloadDirectory(context).listFiles()?.forEach { download -> - // com.example.app + PathUtil.getDownloadDirectory(appContext).listFiles()?.forEach { download -> // com.example.app // Delete if the download directory is empty if (download.listFiles().isNullOrEmpty()) { Log.i(TAG, "Removing empty download directory for ${download.name}") - download.deleteRecursively() - return@forEach + download.deleteRecursively(); return@forEach } - download.listFiles()!!.forEach { versionCode -> - // 20240325 + download.listFiles()!!.forEach { versionCode -> // 20240325 if (versionCode.listFiles().isNullOrEmpty()) { // Purge empty non-accessible directory Log.i(TAG, "Removing empty directory for ${download.name}, ${versionCode.name}") diff --git a/app/src/main/java/com/aurora/store/data/work/DownloadWorker.kt b/app/src/main/java/com/aurora/store/data/work/DownloadWorker.kt index e61a97ec9..937904344 100644 --- a/app/src/main/java/com/aurora/store/data/work/DownloadWorker.kt +++ b/app/src/main/java/com/aurora/store/data/work/DownloadWorker.kt @@ -1,9 +1,3 @@ -/* - * SPDX-FileCopyrightText: 2025 Aurora OSS - * SPDX-FileCopyrightText: 2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - package com.aurora.store.data.work import android.app.NotificationManager @@ -13,19 +7,16 @@ import android.graphics.Bitmap import android.graphics.BitmapFactory import android.util.Log import androidx.core.content.getSystemService -import androidx.core.graphics.scale import androidx.hilt.work.HiltWorker import androidx.work.ForegroundInfo import androidx.work.WorkInfo.Companion.STOP_REASON_CANCELLED_BY_APP import androidx.work.WorkInfo.Companion.STOP_REASON_USER import androidx.work.WorkerParameters -import com.aurora.extensions.TAG import com.aurora.extensions.copyTo import com.aurora.extensions.isPAndAbove import com.aurora.extensions.isQAndAbove import com.aurora.extensions.isSAndAbove import com.aurora.extensions.requiresObbDir -import com.aurora.gplayapi.data.models.PlayFile import com.aurora.gplayapi.helpers.PurchaseHelper import com.aurora.gplayapi.network.IHttpClient import com.aurora.store.AuroraApp @@ -42,22 +33,19 @@ import com.aurora.store.data.room.download.Download import com.aurora.store.data.room.download.DownloadDao import com.aurora.store.util.CertUtil import com.aurora.store.util.NotificationUtil -import com.aurora.store.util.PackageUtil import com.aurora.store.util.PathUtil import dagger.assisted.Assisted import dagger.assisted.AssistedInject +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.NonCancellable +import kotlinx.coroutines.delay +import kotlinx.coroutines.withContext import java.io.File import java.io.FileOutputStream -import java.net.SocketException -import java.net.SocketTimeoutException -import java.net.UnknownHostException import java.security.DigestInputStream import java.security.MessageDigest -import kotlin.coroutines.cancellation.CancellationException import kotlin.properties.Delegates -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.NonCancellable -import kotlinx.coroutines.withContext +import com.aurora.gplayapi.data.models.File as GPlayFile /** * An expedited long-running worker to download and trigger installation for given apps. @@ -66,184 +54,162 @@ import kotlinx.coroutines.withContext */ @HiltWorker class DownloadWorker @AssistedInject constructor( - authProvider: AuthProvider, private val downloadDao: DownloadDao, private val appInstaller: AppInstaller, + private val authProvider: AuthProvider, private val httpClient: IHttpClient, private val purchaseHelper: PurchaseHelper, - @Assisted private val context: Context, + @Assisted private val appContext: Context, @Assisted workerParams: WorkerParameters -) : AuthWorker(authProvider, context, workerParams) { - - companion object { - private const val NOTIFICATION_ID: Int = 200 - } +) : AuthWorker(authProvider, appContext, workerParams) { private lateinit var download: Download + private lateinit var icon: Bitmap - private val notificationManager = context.getSystemService()!! + private val notificationManager = appContext.getSystemService()!! - private var icon: Bitmap? = null + private val NOTIFICATION_ID = 200 + + private var downloading = false private var totalBytes by Delegates.notNull() private var totalProgress = 0 private var downloadedBytes = 0L - inner class NoNetworkException : Exception(context.getString(R.string.title_no_network)) - inner class NothingToDownloadException : Exception(context.getString(R.string.purchase_no_file)) - inner class DownloadFailedException : Exception(context.getString(R.string.download_failed)) - inner class DownloadCancelledException : - Exception(context.getString(R.string.download_canceled)) - - inner class VerificationFailedException : - Exception(context.getString(R.string.verification_failed)) + private val TAG = DownloadWorker::class.java.simpleName override suspend fun doWork(): Result { super.doWork() + // Bail out immediately if authData is not valid + if (!authProvider.isSavedAuthDataValid()) { + Log.e(TAG, "AuthData is not valid, exiting!") + onFailure() + return Result.failure() + } + // Fetch required data for download try { - download = downloadDao.getDownload(inputData.getString(DownloadHelper.PACKAGE_NAME)!!) + val packageName = inputData.getString(DownloadHelper.PACKAGE_NAME) + download = downloadDao.getDownload(packageName!!) - val response = (httpClient as HttpClient).call(download.iconURL).body - val bitmap = BitmapFactory.decodeStream( - withContext(Dispatchers.IO) { response.byteStream() } - ) - icon = bitmap.scale(96, 96) + val bitmap = BitmapFactory.decodeStream(withContext(Dispatchers.IO) { + (httpClient as HttpClient).call(download.iconURL).body!!.byteStream() + }) + icon = Bitmap.createScaledBitmap(bitmap, 96, 96, true) } catch (exception: Exception) { - return onFailure(exception) + Log.e(TAG, "Failed to parse download data", exception) + onFailure() + return Result.failure() } // Set work/service to foreground on < Android 12.0 setForeground(getForegroundInfo()) - // Try to purchase the app if file list is empty - notifyStatus(DownloadStatus.PURCHASING) + // Bail out if file list is empty download.fileList = download.fileList.ifEmpty { purchase(download.packageName, download.versionCode, download.offerType) } - - // Bail out if file list is empty after purchase - if (download.fileList.isEmpty()) return onFailure(NothingToDownloadException()) + if (download.fileList.isEmpty()) { + Log.i(TAG, "Nothing to download!") + onFailure(appContext.getString(R.string.purchase_failed)) + return Result.failure() + } // Create dirs & generate download request for files and shared libs (if any) - PathUtil.getAppDownloadDir(context, download.packageName, download.versionCode).mkdirs() - - // Create OBB dir if required + PathUtil.getAppDownloadDir(appContext, download.packageName, download.versionCode).mkdirs() if (download.fileList.requiresObbDir()) { PathUtil.getObbDownloadDir(download.packageName).mkdirs() } - val files = mutableListOf() - - // Check if shared libs are present, if yes, handle them first + // Purchase the app (free apps needs to be purchased too) + val requestList = mutableListOf() if (download.sharedLibs.isNotEmpty()) { download.sharedLibs.forEach { - // Create shared lib download dir PathUtil.getLibDownloadDir( - context, + appContext, download.packageName, download.versionCode, it.packageName ).mkdirs() - - // Purchase shared lib if file list is empty - it.fileList = it.fileList.ifEmpty { - purchase(it.packageName, it.versionCode, 0) - } - files.addAll(it.fileList) + it.fileList = it.fileList.ifEmpty { purchase(it.packageName, it.versionCode, 0) } + requestList.addAll(it.fileList) } } - files.addAll(download.fileList) + requestList.addAll(download.fileList) // Update data for notification - download.totalFiles = files.size - totalBytes = files.sumOf { it.size } + download.totalFiles = requestList.size + totalBytes = requestList.sumOf { it.size } // Update database with all latest purchases downloadDao.updateFiles(download.packageName, download.fileList) downloadDao.updateSharedLibs(download.packageName, download.sharedLibs) - // Download files - try { - for (file in files) { - if (isStopped) { - throw DownloadCancelledException() + // Download and verify all files exists + requestList.forEach { request -> + downloading = true + runCatching { downloadFile(request); download.downloadedFiles++ } + .onSuccess { downloading = false } + .onFailure { + Log.e(TAG, "Failed to download ${download.packageName}", it) + downloading = false + onFailure() + return Result.failure() + } + while (downloading) { + delay(1000) + val d = downloadDao.getDownload(download.packageName) + if (isStopped || d.downloadStatus == DownloadStatus.CANCELLED) { + onFailure() + break } - - downloadFile(download.packageName, file) - download.downloadedFiles++ - } - } catch (exception: Exception) { - if (exception is DownloadCancelledException) { - Log.i(TAG, "Download cancelled for ${download.packageName}") - // Try to delete all downloaded files - runCatching { files.forEach { deleteFile(it) } } } - - return onFailure(exception) } - // Report failure if download was stopped or failed - if (isStopped) return onFailure(DownloadFailedException()) - - // Verify downloaded files try { + // Verify all downloaded files + Log.i(TAG, "Verifying downloaded files") notifyStatus(DownloadStatus.VERIFYING) - files.forEach { file -> require(verifyFile(file)) } + requestList.forEach { require(verifyFile(it)) } } catch (exception: Exception) { - Log.e(TAG, "Failed to verify ${download.packageName}", exception) - onFailure(VerificationFailedException()) + Log.e(TAG, "Failed to verify downloaded files!", exception) + onFailure() + return Result.failure() } - Log.i(TAG, "Finished downloading & verifying ${download.packageName}") - notifyStatus(DownloadStatus.COMPLETED) - - return onSuccess() + // Mark download as completed + onSuccess() + return Result.success() } - private suspend fun onSuccess(): Result { - return withContext(NonCancellable) { - return@withContext try { + private suspend fun onSuccess() { + withContext(NonCancellable) { + Log.i(TAG, "Finished downloading ${download.packageName}") + notifyStatus(DownloadStatus.COMPLETED) + + try { appInstaller.getPreferredInstaller().install(download) - Result.success() } catch (exception: Exception) { Log.e(TAG, "Failed to install ${download.packageName}", exception) - onFailure(exception) } } } - private suspend fun onFailure(exception: Exception): Result { - return withContext(NonCancellable) { - Log.i(TAG, "Job failed: ${download.packageName}", exception) - + private suspend fun onFailure(errorMessage: String? = null, exception: Exception? = null) { + withContext(NonCancellable) { + Log.i(TAG, "Failed downloading ${download.packageName}") val cancelReasons = listOf(STOP_REASON_USER, STOP_REASON_CANCELLED_BY_APP) if (isSAndAbove && stopReason in cancelReasons) { notifyStatus(DownloadStatus.CANCELLED) } else { - when (exception) { - is DownloadCancelledException -> { - notifyStatus(DownloadStatus.CANCELLED) - } - - else -> { - notifyStatus(status = DownloadStatus.FAILED, exception = exception) - AuroraApp.events.send( - InstallerEvent.Failed( - packageName = download.packageName, - error = exception.stackTraceToString(), - extra = exception.message - ?: context.getString(R.string.download_failed) - ) - ) - } - } + notifyStatus(DownloadStatus.FAILED) + AuroraApp.events.send(InstallerEvent.Failed(download.packageName).apply { + extra = errorMessage ?: appContext.getString(R.string.download_failed) + error = exception?.stackTraceToString() ?: String() + }) } - // Remove all notifications notificationManager.cancel(NOTIFICATION_ID) - - return@withContext Result.success() } } @@ -254,15 +220,15 @@ class DownloadWorker @AssistedInject constructor( * @param offerType Offer type of the app (free/paid) * @return A list of purchased files */ - private fun purchase(packageName: String, versionCode: Long, offerType: Int): List { + private fun purchase(packageName: String, versionCode: Int, offerType: Int): List { try { // Android 9.0+ supports key rotation, so purchase with latest certificate's hash - return if (isPAndAbove && PackageUtil.isInstalled(context, download.packageName)) { + return if (isPAndAbove && download.isInstalled) { purchaseHelper.purchase( packageName, versionCode, offerType, - CertUtil.getEncodedCertificateHashes(context, download.packageName).last() + CertUtil.getEncodedCertificateHashes(appContext, download.packageName).last() ) } else { purchaseHelper.purchase(packageName, versionCode, offerType) @@ -276,26 +242,24 @@ class DownloadWorker @AssistedInject constructor( /** * Downloads the file from the given request. * Failed downloads aren't removed and persists as long as [CacheWorker] doesn't cleans them. - * @param gFile A [PlayFile] to download - * @return A [Boolean] indicating whether the file was downloaded or not. + * @param gFile A [GPlayFile] to download + * @return A [Result] indicating whether the file was downloaded or not. */ - private suspend fun downloadFile(packageName: String, gFile: PlayFile): Boolean { + private suspend fun downloadFile(gFile: GPlayFile): Result { return withContext(Dispatchers.IO) { - Log.i(TAG, "Downloading $packageName @ ${gFile.name}") - val file = PathUtil.getLocalFile(context, gFile, download) + val file = PathUtil.getLocalFile(appContext, gFile, download) // If file exists and has integrity intact, no need to download again if (file.exists() && verifyFile(gFile)) { Log.i(TAG, "$file is already downloaded!") downloadedBytes += file.length() - return@withContext true + return@withContext Result.success() } try { + // Download as a temporary file to avoid installing corrupted files val tmpFileSuffix = ".tmp" val tmpFile = File(file.absolutePath + tmpFileSuffix) - - // Download as a temporary file to avoid installing corrupted files val isNewFile = tmpFile.createNewFile() val okHttpClient = httpClient as HttpClient @@ -307,9 +271,9 @@ class DownloadWorker @AssistedInject constructor( headers["Range"] = "bytes=${tmpFile.length()}-" } - okHttpClient.call(gFile.url, headers).body.byteStream().use { input -> + okHttpClient.call(gFile.url, headers).body?.byteStream()?.use { input -> FileOutputStream(tmpFile, !isNewFile).use { - input.copyTo(it, gFile.size).collect { info -> onProgress(info) } + input.copyTo(it, gFile.size).collect { p -> onProgress(p) } } } @@ -317,21 +281,11 @@ class DownloadWorker @AssistedInject constructor( throw Exception("Failed to remove .tmp extension from $tmpFile") } - return@withContext true + return@withContext Result.success() } catch (exception: Exception) { - when (exception) { - is SocketException, - is SocketTimeoutException, - is UnknownHostException -> { - throw NoNetworkException() - } - - is CancellationException -> { - throw DownloadCancelledException() - } - - else -> throw exception - } + Log.e(TAG, "Failed to download $file!", exception) + notifyStatus(DownloadStatus.FAILED) + return@withContext Result.failure() } } } @@ -344,28 +298,18 @@ class DownloadWorker @AssistedInject constructor( if (!isStopped && !download.isFinished) { downloadedBytes += downloadInfo.bytesCopied - val progress = ((downloadedBytes * 100L) / totalBytes).toInt() + val progress = (downloadedBytes * 100 / totalBytes).toInt() val bytesRemaining = totalBytes - downloadedBytes - val speed = if (downloadInfo.speed == 0L) 1L else downloadInfo.speed - - // Consider a 10% change in speed - val speedChanged = if (download.speed > 0) { - val speedDifference = kotlin.math.abs(download.speed - speed) - (speedDifference * 100.0 / download.speed) >= 10 - } else { - // If previous speed was zero, any change matters - speed != download.speed - } + val speed = if (downloadInfo.speed == 0L) 1 else downloadInfo.speed // Individual file progress can be negligible in contrast to total progress - // Only notify the UI if progress/speed change considerably to avoid being rate-limited by Android - if ((progress - totalProgress) >= 5 || speedChanged) { + // Only notify the UI if progress is greater or speed has changed to avoid being rate-limited by Android + if (progress > totalProgress || speed != download.speed) { download.apply { this.progress = progress - this.speed = speed - this.timeRemaining = (bytesRemaining / speed) * 1000 + this.speed = downloadInfo.speed + this.timeRemaining = bytesRemaining / speed * 1000 } - downloadDao.updateProgress( download.packageName, download.progress, @@ -373,7 +317,7 @@ class DownloadWorker @AssistedInject constructor( download.timeRemaining ) - notifyStatus(DownloadStatus.DOWNLOADING, true) + notifyStatus(DownloadStatus.DOWNLOADING, NOTIFICATION_ID) totalProgress = progress } } @@ -381,9 +325,9 @@ class DownloadWorker @AssistedInject constructor( override suspend fun getForegroundInfo(): ForegroundInfo { val notification = if (this::download.isInitialized) { - NotificationUtil.getDownloadNotification(context, download, icon) + NotificationUtil.getDownloadNotification(appContext, download, id, icon) } else { - NotificationUtil.getDownloadNotification(context) + NotificationUtil.getDownloadNotification(appContext) } return if (isQAndAbove) { @@ -396,20 +340,16 @@ class DownloadWorker @AssistedInject constructor( /** * Notifies the user of the current status of the download. * @param status Current [DownloadStatus] + * @param dID ID of the notification, defaults to hashCode of the download's packageName */ - private suspend fun notifyStatus( - status: DownloadStatus, - isProgress: Boolean = false, - exception: Exception? = null - ) { + private suspend fun notifyStatus(status: DownloadStatus, dID: Int = -1) { // Update status in database - download.status = status + download.downloadStatus = status downloadDao.updateStatus(download.packageName, status) when (status) { DownloadStatus.VERIFYING, DownloadStatus.CANCELLED -> return - DownloadStatus.COMPLETED -> { // Mark progress as 100 manually to avoid race conditions download.progress = 100 @@ -419,65 +359,32 @@ class DownloadWorker @AssistedInject constructor( else -> {} } - val notification = NotificationUtil.getDownloadNotification( - context, - download, - icon, - exception?.message - ) - notificationManager.notify( - if (isProgress) NOTIFICATION_ID else download.packageName.hashCode(), - notification - ) + val notification = NotificationUtil.getDownloadNotification(appContext, download, id, icon) + val notificationID = if (dID != -1) dID else download.packageName.hashCode() + notificationManager.notify(notificationID, notification) } /** - * Verifies integrity of a downloaded [PlayFile]. - * @param gFile [PlayFile] to verify + * Verifies integrity of a downloaded [GPlayFile]. + * @param gFile [GPlayFile] to verify */ @OptIn(ExperimentalStdlibApi::class) - private suspend fun verifyFile(gFile: PlayFile): Boolean { - val file = PathUtil.getLocalFile(context, gFile, download) - Log.i(TAG, "Verifying $file") - + private suspend fun verifyFile(gFile: GPlayFile): Boolean { + val file = PathUtil.getLocalFile(appContext, gFile, download) val algorithm = if (gFile.sha256.isBlank()) Algorithm.SHA1 else Algorithm.SHA256 val expectedSha = if (algorithm == Algorithm.SHA1) gFile.sha1 else gFile.sha256 - if (expectedSha.isBlank()) return false - return withContext(Dispatchers.IO) { - try { - val messageDigest = MessageDigest.getInstance(algorithm.value) - file.inputStream().use { fis -> - DigestInputStream(fis, messageDigest).use { dis -> - val buffer = ByteArray(DEFAULT_BUFFER_SIZE) - while (dis.read(buffer) != - -1 - ) { - /* Just read, digest updates automatically */ - } - } + val messageDigest = MessageDigest.getInstance(algorithm.value) + DigestInputStream(file.inputStream(), messageDigest).use { input -> + val buffer = ByteArray(DEFAULT_BUFFER_SIZE) + var read = input.read(buffer, 0, DEFAULT_BUFFER_SIZE) + while (read > -1) { + read = input.read(buffer, 0, DEFAULT_BUFFER_SIZE) } - - messageDigest.digest().toHexString() == expectedSha - } catch (e: Exception) { - Log.e(TAG, "Failed to verify $file", e) - false } - } - } - - private fun deleteFile(file: PlayFile) { - val apkFile = PathUtil.getLocalFile(context, file, download) - if (apkFile.exists()) { - apkFile.delete() - Log.i(TAG, "Deleted Apk: $apkFile") - } - - val tmpFile = File(apkFile.absolutePath + ".tmp") - if (tmpFile.exists()) { - tmpFile.delete() - Log.i(TAG, "Deleted Temp: $tmpFile") + val sha = messageDigest.digest().toHexString() + return@withContext sha == expectedSha } } } diff --git a/app/src/main/java/com/aurora/store/data/work/ExportWorker.kt b/app/src/main/java/com/aurora/store/data/work/ExportWorker.kt index 1e743db42..3e85fef65 100644 --- a/app/src/main/java/com/aurora/store/data/work/ExportWorker.kt +++ b/app/src/main/java/com/aurora/store/data/work/ExportWorker.kt @@ -6,7 +6,6 @@ import android.content.pm.PackageManager import android.net.Uri import android.util.Log import androidx.core.content.getSystemService -import androidx.core.net.toUri import androidx.hilt.work.HiltWorker import androidx.work.CoroutineWorker import androidx.work.Data @@ -31,9 +30,9 @@ import java.util.zip.ZipOutputStream */ @HiltWorker class ExportWorker @AssistedInject constructor( - @Assisted private val context: Context, + @Assisted private val appContext: Context, @Assisted workerParams: WorkerParameters -) : CoroutineWorker(context, workerParams) { +) : CoroutineWorker(appContext, workerParams) { companion object { private const val TAG = "ExportWorker" @@ -44,9 +43,6 @@ class ExportWorker @AssistedInject constructor( private const val VERSION_CODE = "VERSION_CODE" private const val DISPLAY_NAME = "DISPLAY_NAME" - private const val NOTIFICATION_ID = 500 - private const val NOTIFICATION_ID_FGS = 501 - /** * Exports the installed package to the given URI * @param app App to export @@ -80,7 +76,7 @@ class ExportWorker @AssistedInject constructor( .putString(URI, uri.toString()) .putString(DISPLAY_NAME, download.displayName) .putString(PACKAGE_NAME, download.packageName) - .putLong(VERSION_CODE, download.versionCode) + .putInt(VERSION_CODE, download.versionCode) .build() val oneTimeWorkRequest = OneTimeWorkRequestBuilder() @@ -94,17 +90,19 @@ class ExportWorker @AssistedInject constructor( } private lateinit var notificationManager: NotificationManager + private val NOTIFICATION_ID = 500 + private val NOTIFICATION_ID_FGS = 501 override suspend fun doWork(): Result { val isDownload = inputData.getBoolean(IS_DOWNLOAD, false) - val uri = inputData.getString(URI)!!.toUri() + val uri = Uri.parse(inputData.getString(URI)) val packageName = inputData.getString(PACKAGE_NAME) val displayName = inputData.getString(DISPLAY_NAME) - val versionCode = inputData.getLong(VERSION_CODE, -1) + val versionCode = inputData.getInt(VERSION_CODE, -1) - notificationManager = context.getSystemService()!! + notificationManager = appContext.getSystemService()!! - if (packageName.isNullOrEmpty() || isDownload && versionCode == -1L) { + if (packageName.isNullOrEmpty() || isDownload && versionCode == -1) { Log.e(TAG, "Input data is corrupt, bailing out!") notifyStatus(displayName ?: String(), uri, false) return Result.failure() @@ -126,16 +124,18 @@ class ExportWorker @AssistedInject constructor( return Result.success() } - override suspend fun getForegroundInfo(): ForegroundInfo = ForegroundInfo( - NOTIFICATION_ID_FGS, - NotificationUtil.getExportNotification(context) - ) + override suspend fun getForegroundInfo(): ForegroundInfo { + return ForegroundInfo( + NOTIFICATION_ID_FGS, + NotificationUtil.getExportNotification(appContext) + ) + } private fun notifyStatus(packageName: String, uri: Uri, success: Boolean = true) { notificationManager.notify( NOTIFICATION_ID, NotificationUtil.getExportStatusNotification( - context, + appContext, packageName, uri, success @@ -144,7 +144,7 @@ class ExportWorker @AssistedInject constructor( } private fun copyInstalledApp(packageName: String, uri: Uri) { - val packageInfo = getPackageInfo(context, packageName, PackageManager.GET_META_DATA) + val packageInfo = getPackageInfo(appContext, packageName, PackageManager.GET_META_DATA) val fileList: MutableList = mutableListOf() fileList.add(File(packageInfo.applicationInfo!!.sourceDir)) @@ -155,10 +155,12 @@ class ExportWorker @AssistedInject constructor( bundleAllAPKs(fileList.filterNotNull(), uri) } - private fun copyDownloadedApp(packageName: String, versionCode: Long, uri: Uri) = bundleAllAPKs( - PathUtil.getAppDownloadDir(context, packageName, versionCode).listFiles()!!.toList(), - uri - ) + private fun copyDownloadedApp(packageName: String, versionCode: Int, uri: Uri) { + return bundleAllAPKs( + PathUtil.getAppDownloadDir(appContext, packageName, versionCode).listFiles()!!.toList(), + uri + ) + } /** * Bundles all the given APKs to a zip file @@ -166,7 +168,7 @@ class ExportWorker @AssistedInject constructor( * @param uri [Uri] of the file to write the APKs */ private fun bundleAllAPKs(fileList: List, uri: Uri) { - ZipOutputStream(context.contentResolver.openOutputStream(uri)).use { zipOutput -> + ZipOutputStream(appContext.contentResolver.openOutputStream(uri)).use { zipOutput -> fileList.forEach { file -> file.inputStream().use { input -> val zipEntry = ZipEntry(file.name) diff --git a/app/src/main/java/com/aurora/store/data/work/UpdateWorker.kt b/app/src/main/java/com/aurora/store/data/work/UpdateWorker.kt index ff92e1166..47761e94d 100644 --- a/app/src/main/java/com/aurora/store/data/work/UpdateWorker.kt +++ b/app/src/main/java/com/aurora/store/data/work/UpdateWorker.kt @@ -8,7 +8,6 @@ import androidx.hilt.work.HiltWorker import androidx.work.ForegroundInfo import androidx.work.WorkerParameters import com.aurora.Constants -import com.aurora.extensions.TAG import com.aurora.extensions.isIgnoringBatteryOptimizations import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.helpers.AppDetailsHelper @@ -30,12 +29,12 @@ import com.aurora.store.util.NotificationUtil import com.aurora.store.util.PackageUtil import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_AUTO +import com.google.gson.Gson import dagger.assisted.Assisted import dagger.assisted.AssistedInject -import java.util.Locale import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import kotlinx.serialization.json.Json +import java.util.Locale /** * A worker to check for updates for installed apps based on saved authentication data, @@ -47,48 +46,48 @@ import kotlinx.serialization.json.Json */ @HiltWorker class UpdateWorker @AssistedInject constructor( - private val json: Json, + private val gson: Gson, private val blacklistProvider: BlacklistProvider, private val httpClient: IHttpClient, private val updateDao: UpdateDao, private val downloadHelper: DownloadHelper, private val authProvider: AuthProvider, private val appDetailsHelper: AppDetailsHelper, - @Assisted private val context: Context, + @Assisted private val appContext: Context, @Assisted workerParams: WorkerParameters -) : AuthWorker(authProvider, context, workerParams) { +) : AuthWorker(authProvider, appContext, workerParams) { + + private val TAG = UpdateWorker::class.java.simpleName private val notificationID = 100 - private val canSelfUpdate = !CertUtil.isFDroidApp(context, BuildConfig.APPLICATION_ID) && - !CertUtil.isAppGalleryApp(context, BuildConfig.APPLICATION_ID) && - BuildType.CURRENT != BuildType.DEBUG + private val canSelfUpdate = !CertUtil.isFDroidApp(appContext, BuildConfig.APPLICATION_ID) && + !CertUtil.isAppGalleryApp(appContext, BuildConfig.APPLICATION_ID) && + BuildType.CURRENT != BuildType.DEBUG private val isAuroraOnlyFilterEnabled: Boolean - get() = Preferences.getBoolean(context, Preferences.PREFERENCE_FILTER_AURORA_ONLY, false) + get() = Preferences.getBoolean(appContext, Preferences.PREFERENCE_FILTER_AURORA_ONLY, false) private val isFDroidFilterEnabled: Boolean - get() = Preferences.getBoolean(context, Preferences.PREFERENCE_FILTER_FDROID) + get() = Preferences.getBoolean(appContext, Preferences.PREFERENCE_FILTER_FDROID) private val isExtendedUpdateEnabled: Boolean - get() = Preferences.getBoolean(context, Preferences.PREFERENCE_UPDATES_EXTENDED) + get() = Preferences.getBoolean(appContext, Preferences.PREFERENCE_UPDATES_EXTENDED) override suspend fun doWork(): Result { super.doWork() Log.i(TAG, "Checking for app updates") - val updateMode = UpdateMode.entries[ - inputData.getInt( - UpdateHelper.UPDATE_MODE, - Preferences.getInteger( - context, - PREFERENCE_UPDATES_AUTO, - UpdateMode.CHECK_AND_INSTALL.ordinal - ) + val updateMode = UpdateMode.entries[inputData.getInt( + UpdateHelper.UPDATE_MODE, + Preferences.getInteger( + appContext, + PREFERENCE_UPDATES_AUTO, + UpdateMode.CHECK_AND_INSTALL.ordinal ) - ] + )] - if (updateMode == UpdateMode.DISABLED || !AccountProvider.isLoggedIn(context)) { + if (updateMode == UpdateMode.DISABLED || !AccountProvider.isLoggedIn(appContext)) { Log.i(TAG, "Updates are disabled, bailing out!") return Result.failure() } @@ -109,9 +108,7 @@ class UpdateWorker @AssistedInject constructor( } // Notify and exit if we are only checking for updates or if battery optimizations are enabled - if (updateMode == UpdateMode.CHECK_AND_NOTIFY || - !context.isIgnoringBatteryOptimizations() - ) { + if (updateMode == UpdateMode.CHECK_AND_NOTIFY || !appContext.isIgnoringBatteryOptimizations()) { Log.i(TAG, "Found ${updates.size} updates, notifying!") notifyUpdates(updates) return Result.success() @@ -120,19 +117,14 @@ class UpdateWorker @AssistedInject constructor( // Clean the update list to prepare for installing val filteredUpdates = updates .filter { it.hasValidCert } - .filterNot { it.isSelfUpdate(context) } + .filterNot { it.isSelfUpdate(appContext) } .partition { - AppInstaller.canInstallSilently(context, it.packageName, it.targetSdk) + AppInstaller.canInstallSilently(appContext, it.packageName, it.targetSdk) } // Notify about apps that cannot be auto-updated - if (filteredUpdates.second.isNotEmpty()) { - Log.i( - TAG, - "Found ${updates.size} updates out of which ${filteredUpdates.second.size} cannot be auto-updated" - ) - notifyUpdates(filteredUpdates.second) - } + Log.i(TAG, "Found ${updates.size} updates out of which ${filteredUpdates.second.size} cannot be auto-updated") + notifyUpdates(filteredUpdates.second) // Trigger download for apps if they can be auto-updated filteredUpdates.first.forEach { downloadHelper.enqueueUpdate(it) } @@ -144,41 +136,37 @@ class UpdateWorker @AssistedInject constructor( } } - override suspend fun getForegroundInfo(): ForegroundInfo = ForegroundInfo( - notificationID, - NotificationUtil.getUpdateNotification(context) - ) + override suspend fun getForegroundInfo(): ForegroundInfo { + return ForegroundInfo( + notificationID, + NotificationUtil.getUpdateNotification(appContext) + ) + } /** * Checks and returns updates for all possible apps */ private suspend fun checkUpdates(): List { return withContext(Dispatchers.IO) { - val packages = PackageUtil.getAllValidPackages(context) + val packages = PackageUtil.getAllValidPackages(appContext) .filterNot { blacklistProvider.isBlacklisted(it.packageName) } .filter { if (!isExtendedUpdateEnabled) it.applicationInfo!!.enabled else true } // Filter out packages based on user's preferences val filteredPackages = if (isAuroraOnlyFilterEnabled) { - packages.filter { CertUtil.isAuroraStoreApp(context, it.packageName) } + packages.filter { CertUtil.isAuroraStoreApp(appContext, it.packageName) } } else { - packages.filterNot { - if (isFDroidFilterEnabled) { - CertUtil.isFDroidApp(context, it.packageName) - } else { - false - } - } - }.map { it.packageName } + packages.filterNot { if (isFDroidFilterEnabled) CertUtil.isFDroidApp(appContext, it.packageName) else false } + } - val updates = appDetailsHelper.getAppByPackageName(filteredPackages) + val updates = appDetailsHelper.getAppByPackageName(filteredPackages.map { it.packageName }) .filter { it.displayName.isNotEmpty() } - .filter { PackageUtil.isUpdatable(context, it.packageName, it.versionCode) } + .filter { PackageUtil.isUpdatable(appContext, it.packageName, it.versionCode.toLong()) } .toMutableList() if (canSelfUpdate) getSelfUpdate()?.let { updates.add(it) } - return@withContext updates.map { Update.fromApp(context, it) } + return@withContext updates.map { Update.fromApp(appContext, it) } .sortedBy { it.displayName.lowercase(Locale.getDefault()) } } } @@ -190,9 +178,7 @@ class UpdateWorker @AssistedInject constructor( return withContext(Dispatchers.IO) { val updateUrl = when (BuildType.CURRENT) { BuildType.RELEASE -> Constants.UPDATE_URL_STABLE - BuildType.NIGHTLY -> Constants.UPDATE_URL_NIGHTLY - else -> { Log.i(TAG, "Self-updates are not available for this build!") return@withContext null @@ -201,22 +187,24 @@ class UpdateWorker @AssistedInject constructor( try { val response = httpClient.get(updateUrl, mapOf()) - val selfUpdate = json.decodeFromString(String(response.responseBytes)) + val selfUpdate = gson.fromJson( + String(response.responseBytes), + SelfUpdate::class.java + ) val isUpdate = when (BuildType.CURRENT) { BuildType.NIGHTLY, BuildType.RELEASE -> selfUpdate.versionCode > BuildConfig.VERSION_CODE - else -> false } if (isUpdate) { - if (CertUtil.isFDroidApp(context, BuildConfig.APPLICATION_ID)) { + if (CertUtil.isFDroidApp(appContext, BuildConfig.APPLICATION_ID)) { if (selfUpdate.fdroidBuild.isNotEmpty()) { - return@withContext SelfUpdate.toApp(selfUpdate, context) + return@withContext SelfUpdate.toApp(selfUpdate, appContext) } } else if (selfUpdate.auroraBuild.isNotEmpty()) { - return@withContext SelfUpdate.toApp(selfUpdate, context) + return@withContext SelfUpdate.toApp(selfUpdate, appContext) } else { Log.e(TAG, "Update file is missing!") return@withContext null @@ -233,10 +221,10 @@ class UpdateWorker @AssistedInject constructor( } private fun notifyUpdates(updates: List) { - with(context.getSystemService()!!) { + with(appContext.getSystemService()!!) { notify( notificationID, - NotificationUtil.getUpdateNotification(context, updates) + NotificationUtil.getUpdateNotification(appContext, updates) ) } } diff --git a/app/src/main/java/com/aurora/store/module/CommonModule.kt b/app/src/main/java/com/aurora/store/module/CommonModule.kt index a3816420d..c8e60209d 100644 --- a/app/src/main/java/com/aurora/store/module/CommonModule.kt +++ b/app/src/main/java/com/aurora/store/module/CommonModule.kt @@ -1,15 +1,12 @@ package com.aurora.store.module -import com.aurora.gplayapi.data.serializers.LocaleSerializer -import com.aurora.gplayapi.data.serializers.PropertiesSerializer +import com.google.gson.Gson +import com.google.gson.GsonBuilder import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import javax.inject.Singleton -import kotlinx.serialization.json.Json -import kotlinx.serialization.modules.SerializersModule -import kotlinx.serialization.modules.contextual @Module @InstallIn(SingletonComponent::class) @@ -17,18 +14,9 @@ object CommonModule { @Singleton @Provides - fun providesJsonInstance(): Json { - val module = SerializersModule { - contextual(LocaleSerializer) - contextual(PropertiesSerializer) - } - - return Json { - prettyPrint = true - ignoreUnknownKeys = true - coerceInputValues = true - serializersModule = module - explicitNulls = false - } + fun providesGsonInstance(): Gson { + return GsonBuilder() + .setPrettyPrinting() + .create() } } diff --git a/app/src/main/java/com/aurora/store/module/ExodusModule.kt b/app/src/main/java/com/aurora/store/module/ExodusModule.kt index 3d3976f32..eccb55e45 100644 --- a/app/src/main/java/com/aurora/store/module/ExodusModule.kt +++ b/app/src/main/java/com/aurora/store/module/ExodusModule.kt @@ -25,10 +25,10 @@ import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent -import java.nio.charset.StandardCharsets -import javax.inject.Singleton import org.json.JSONArray import org.json.JSONObject +import java.nio.charset.StandardCharsets +import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) diff --git a/app/src/main/java/com/aurora/store/module/HelperModule.kt b/app/src/main/java/com/aurora/store/module/HelperModule.kt index a2b735258..f4d7195fd 100644 --- a/app/src/main/java/com/aurora/store/module/HelperModule.kt +++ b/app/src/main/java/com/aurora/store/module/HelperModule.kt @@ -34,108 +34,134 @@ object HelperModule { fun providesAppDetailsHelperInstance( authProvider: AuthProvider, httpClient: IHttpClient - ): AppDetailsHelper = AppDetailsHelper(authProvider.authData!!) - .using(httpClient) + ): AppDetailsHelper { + return AppDetailsHelper(authProvider.authData!!) + .using(httpClient) + } @Singleton @Provides fun providesStreamHelperInstance( authProvider: AuthProvider, httpClient: IHttpClient - ): StreamHelper = StreamHelper(authProvider.authData!!) - .using(httpClient) + ): StreamHelper { + return StreamHelper(authProvider.authData!!) + .using(httpClient) + } @Singleton @Provides fun providesExpandedBrowseHelperInstance( authProvider: AuthProvider, httpClient: IHttpClient - ): ExpandedBrowseHelper = ExpandedBrowseHelper(authProvider.authData!!) - .using(httpClient) + ): ExpandedBrowseHelper { + return ExpandedBrowseHelper(authProvider.authData!!) + .using(httpClient) + } @Singleton @Provides fun providesCategoryHelperInstance( authProvider: AuthProvider, httpClient: IHttpClient - ): CategoryHelper = CategoryHelper(authProvider.authData!!) - .using(httpClient) + ): CategoryHelper { + return CategoryHelper(authProvider.authData!!) + .using(httpClient) + } @Singleton @Provides fun providesReviewsHelperInstance( authProvider: AuthProvider, httpClient: IHttpClient - ): ReviewsHelper = ReviewsHelper(authProvider.authData!!) - .using(httpClient) + ): ReviewsHelper { + return ReviewsHelper(authProvider.authData!!) + .using(httpClient) + } @Singleton @Provides fun providesSearchHelperInstance( authProvider: AuthProvider, httpClient: IHttpClient - ): SearchHelper = SearchHelper(authProvider.authData!!) - .using(httpClient) + ): SearchHelper { + return SearchHelper(authProvider.authData!!) + .using(httpClient) + } @Singleton @Provides fun providesPurchaseHelperInstance( authProvider: AuthProvider, httpClient: IHttpClient - ): PurchaseHelper = PurchaseHelper(authProvider.authData!!) - .using(httpClient) + ): PurchaseHelper { + return PurchaseHelper(authProvider.authData!!) + .using(httpClient) + } @Singleton @Provides fun providesWebStreamHelperInstance( spoofProvider: SpoofProvider, httpClient: IHttpClient - ): WebStreamHelper = WebStreamHelper() - .using(httpClient) - .with(spoofProvider.locale) + ): WebStreamHelper { + return WebStreamHelper() + .using(httpClient) + .with(spoofProvider.locale) + } @Singleton @Provides fun providesWebDataSafetyHelperInstance( spoofProvider: SpoofProvider, httpClient: IHttpClient - ): WebDataSafetyHelper = WebDataSafetyHelper() - .using(httpClient) - .with(spoofProvider.locale) + ): WebDataSafetyHelper { + return WebDataSafetyHelper() + .using(httpClient) + .with(spoofProvider.locale) + } @Singleton @Provides fun providesWebSearchHelperInstance( spoofProvider: SpoofProvider, httpClient: IHttpClient - ): WebSearchHelper = WebSearchHelper() - .using(httpClient) - .with(spoofProvider.locale) + ): WebSearchHelper { + return WebSearchHelper() + .using(httpClient) + .with(spoofProvider.locale) + } @Singleton @Provides fun providesWebCategoryStreamHelperInstance( spoofProvider: SpoofProvider, httpClient: IHttpClient - ): WebCategoryStreamHelper = WebCategoryStreamHelper() - .using(httpClient) - .with(spoofProvider.locale) + ): WebCategoryStreamHelper { + return WebCategoryStreamHelper() + .using(httpClient) + .with(spoofProvider.locale) + } @Singleton @Provides fun providesWebTopChartsHelperInstance( spoofProvider: SpoofProvider, httpClient: IHttpClient - ): WebTopChartsHelper = WebTopChartsHelper() - .using(httpClient) - .with(spoofProvider.locale) + ): WebTopChartsHelper { + return WebTopChartsHelper() + .using(httpClient) + .with(spoofProvider.locale) + } @Singleton @Provides fun providesWebAppDetailsHelperInstance( spoofProvider: SpoofProvider, httpClient: IHttpClient - ): WebAppDetailsHelper = WebAppDetailsHelper() - .using(httpClient) - .with(spoofProvider.locale) + ): WebAppDetailsHelper { + return WebAppDetailsHelper() + .using(httpClient) + .with(spoofProvider.locale) + } } diff --git a/app/src/main/java/com/aurora/store/util/AC2DMTask.kt b/app/src/main/java/com/aurora/store/util/AC2DMTask.kt index d5415a728..05843a969 100644 --- a/app/src/main/java/com/aurora/store/util/AC2DMTask.kt +++ b/app/src/main/java/com/aurora/store/util/AC2DMTask.kt @@ -20,17 +20,16 @@ package com.aurora.store.util import com.aurora.store.data.network.HttpClient +import okhttp3.RequestBody.Companion.toRequestBody import java.util.Locale import javax.inject.Inject -import okhttp3.RequestBody.Companion.toRequestBody class AC2DMTask @Inject constructor(private val httpClient: HttpClient) { @Throws(Exception::class) fun getAC2DMResponse(email: String?, oAuthToken: String?): Map { - if (email == null || oAuthToken == null) { + if (email == null || oAuthToken == null) return mapOf() - } val params: MutableMap = hashMapOf() params["lang"] = Locale.getDefault().toString().replace("_", "-") @@ -45,7 +44,6 @@ class AC2DMTask @Inject constructor(private val httpClient: HttpClient) { params["add_account"] = 1 params["Token"] = oAuthToken params["callerSig"] = "38918a453d07199354f8b19af05ec6562ced5788" - params["droidguard_results"] = "null" val body = params.map { "${it.key}=${it.value}" }.joinToString(separator = "&") diff --git a/app/src/main/java/com/aurora/store/util/CertUtil.kt b/app/src/main/java/com/aurora/store/util/CertUtil.kt index 1db0d0669..f7709d0c2 100644 --- a/app/src/main/java/com/aurora/store/util/CertUtil.kt +++ b/app/src/main/java/com/aurora/store/util/CertUtil.kt @@ -24,9 +24,6 @@ import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.util.Base64 import android.util.Log -import com.aurora.Constants.PACKAGE_NAME_APP_GALLERY -import com.aurora.Constants.PACKAGE_NAME_GMS -import com.aurora.extensions.TAG import com.aurora.extensions.generateX509Certificate import com.aurora.extensions.getUpdateOwnerPackageNameCompat import com.aurora.extensions.isPAndAbove @@ -35,28 +32,25 @@ import com.aurora.store.data.model.Algorithm import com.aurora.store.util.PackageUtil.getPackageInfo import java.security.MessageDigest import java.security.cert.X509Certificate +import javax.security.auth.x500.X500Principal object CertUtil { + private val TAG = "CertUtil" + const val GOOGLE_ACCOUNT_TYPE = "com.google" const val GOOGLE_PLAY_AUTH_TOKEN_TYPE = "oauth2:https://www.googleapis.com/auth/googleplay" + const val GOOGLE_PLAY_PACKAGE_NAME = "com.android.vending" const val GOOGLE_PLAY_CERT = "MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK" - private val fdroidPackages = listOf( - "org.fdroid.basic", - "org.fdroid.fdroid", - "org.fdroid.fdroid.privileged", - "com.looker.droidify", - "com.machiav3lli.fdroid" - ) - - fun isFDroidApp(context: Context, packageName: String): Boolean = - isInstalledByFDroid(context, packageName) || isSignedByFDroid(context, packageName) + fun isFDroidApp(context: Context, packageName: String): Boolean { + return isInstalledByFDroid(context, packageName) || isSignedByFDroid(context, packageName) + } - fun isAppGalleryApp(context: Context, packageName: String): Boolean = - context.packageManager.getUpdateOwnerPackageNameCompat(packageName) == - PACKAGE_NAME_APP_GALLERY + fun isAppGalleryApp(context: Context, packageName: String): Boolean { + return context.packageManager.getUpdateOwnerPackageNameCompat(packageName) == "com.huawei.appmarket" + } fun isAuroraStoreApp(context: Context, packageName: String): Boolean { val installerPackageNames = AppInstaller.getAvailableInstallersInfo(context) @@ -66,65 +60,68 @@ object CertUtil { return installerPackageNames.contains(packageInstaller) } - fun getEncodedCertificateHashes(context: Context, packageName: String): List = try { - val certificates = getX509Certificates(context, packageName) - certificates.map { - val messageDigest = MessageDigest.getInstance(Algorithm.SHA.value) - messageDigest.update(it.encoded) - Base64.encodeToString( - messageDigest.digest(), - Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP - ) + fun getEncodedCertificateHashes(context: Context, packageName: String): List { + return try { + val certificates = getX509Certificates(context, packageName) + certificates.map { + val messageDigest = MessageDigest.getInstance(Algorithm.SHA.value) + messageDigest.update(it.encoded) + Base64.encodeToString( + messageDigest.digest(), + Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP + ) + } + } catch (exception: Exception) { + Log.e(TAG, "Failed to get SHA256 certificate hash", exception) + emptyList() } - } catch (exception: Exception) { - Log.e(TAG, "Failed to get SHA256 certificate hash", exception) - emptyList() } - private fun isSignedByFDroid(context: Context, packageName: String): Boolean = try { - getX509Certificates(context, packageName).any { cert -> - cert.subjectDN.name.split(",").associate { - val (left, right) = it.split("=") - left to right - }["O"] == "fdroid.org" + private fun isSignedByFDroid(context: Context, packageName: String): Boolean { + return try { + getX509Certificates(context, packageName).any { cert -> + cert.subjectDN.name.split(",").associate { + val (left, right) = it.split("=") + left to right + }["O"] == "fdroid.org" + } + } catch (exception: Exception) { + Log.e(TAG, "Failed to check signing cert for $packageName") + false } - } catch (exception: Exception) { - Log.e(TAG, "Failed to check signing cert for $packageName", exception) - false } - fun isMicroGGms(context: Context): Boolean { + fun isMicroGGMS(context: Context, packageName: String): Boolean { return try { - val packageInfo = - getPackageInfo(context, PACKAGE_NAME_GMS, PackageManager.GET_PERMISSIONS) + val packageInfo = getPackageInfo(context, packageName, PackageManager.GET_PERMISSIONS) val hasFakePackageSignature = packageInfo.requestedPermissions?.any { permission -> permission == "android.permission.FAKE_PACKAGE_SIGNATURE" } == true return hasFakePackageSignature } catch (exception: Exception) { - Log.e(TAG, "Failed to check origin for $PACKAGE_NAME_GMS", exception) + Log.e(TAG, "Failed to check origin for $packageName") false } } - private fun isInstalledByFDroid(context: Context, packageName: String): Boolean = - fdroidPackages.contains( + private fun isInstalledByFDroid(context: Context, packageName: String): Boolean { + val fdroidPackages = listOf( + "org.fdroid.basic", "org.fdroid.fdroid", "org.fdroid.fdroid.privileged" + ) + return fdroidPackages.contains( context.packageManager.getUpdateOwnerPackageNameCompat(packageName) ) + } - private fun getX509Certificates(context: Context, packageName: String): List = - try { + private fun getX509Certificates(context: Context, packageName: String): List { + return try { val packageInfo = getPackageInfoWithSignature(context, packageName) if (isPAndAbove) { if (packageInfo.signingInfo!!.hasMultipleSigners()) { - packageInfo.signingInfo!!.apkContentsSigners.map { - it.generateX509Certificate() - } + packageInfo.signingInfo!!.apkContentsSigners.map { it.generateX509Certificate() } } else { - packageInfo.signingInfo!!.signingCertificateHistory.map { - it.generateX509Certificate() - } + packageInfo.signingInfo!!.signingCertificateHistory.map { it.generateX509Certificate() } } } else { @Suppress("DEPRECATION") @@ -134,12 +131,29 @@ object CertUtil { Log.e(TAG, "Failed to get X509 certificates", exception) emptyList() } + } - private fun getPackageInfoWithSignature(context: Context, packageName: String): PackageInfo = - if (isPAndAbove) { + private fun getPackageInfoWithSignature(context: Context, packageName: String): PackageInfo { + return if (isPAndAbove) { getPackageInfo(context, packageName, PackageManager.GET_SIGNING_CERTIFICATES) } else { @Suppress("DEPRECATION") getPackageInfo(context, packageName, PackageManager.GET_SIGNATURES) } + } + + private fun extractSHA1Fingerprint(certificate: X509Certificate): String { + val messageDigest = MessageDigest.getInstance(Algorithm.SHA1.value) + messageDigest.update(certificate.encoded) + return messageDigest.digest() + .joinToString("") { byte -> String.format("%02x", byte) } + .lowercase() + } + + private fun parseX500Principal(principal: X500Principal): Map { + return principal.name.split(",").associate { + val (left, right) = it.split("=") + left.trim() to right.trim() + } + } } diff --git a/app/src/main/java/com/aurora/store/util/CommonUtil.kt b/app/src/main/java/com/aurora/store/util/CommonUtil.kt index a65684460..275a38b4e 100644 --- a/app/src/main/java/com/aurora/store/util/CommonUtil.kt +++ b/app/src/main/java/com/aurora/store/util/CommonUtil.kt @@ -21,8 +21,11 @@ package com.aurora.store.util import android.content.Context import android.util.Log +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.ProcessLifecycleOwner import com.aurora.store.R import com.aurora.store.data.model.ProxyInfo +import java.text.DecimalFormat import java.util.Locale import kotlin.math.ln import kotlin.math.pow @@ -48,9 +51,8 @@ object CommonUtil { ) fun addSiPrefix(value: Long): String { - if (value <= 1L) { + if (value <= 1L) return "NA" - } var tempValue = value var order = 0 while (tempValue >= 1000.0) { @@ -60,8 +62,9 @@ object CommonUtil { return tempValue.toString() + siPrefixes[order] } - fun addDiPrefix(value: Long): String? { - if (value <= 1L) return null + fun addDiPrefix(value: Long): String { + if (value <= 1L) + return "NA" var tempValue = value var order = 0 while (tempValue >= 1000.0) { @@ -101,13 +104,46 @@ object CommonUtil { val exp = (ln(bytes.toDouble()) / ln(unit.toDouble())).toInt() val pre = (if (si) "kMGTPE" else "KMGTPE")[exp - 1].toString() + if (si) "" else "i" return String.format( - Locale.getDefault(), - "%.1f %sB/s", + Locale.getDefault(), "%.1f %sB/s", bytes / unit.toDouble().pow(exp.toDouble()), pre ) } + fun humanReadableByteValue(bytes: Long, si: Boolean): String { + val unit = if (si) 1000 else 1024 + if (bytes < unit) return "$bytes B" + val exp = (ln(bytes.toDouble()) / ln(unit.toDouble())).toInt() + val pre = (if (si) "kMGTPE" else "KMGTPE")[exp - 1].toString() + if (si) "" else "i" + return String.format( + Locale.getDefault(), "%.1f %sB", + bytes / unit.toDouble().pow(exp.toDouble()), + pre + ) + } + + fun getDownloadSpeedString(context: Context, downloadedBytesPerSecond: Long): String { + if (downloadedBytesPerSecond < 0) { + return context.getString(R.string.download_speed_estimating) + } + val kb = downloadedBytesPerSecond.toDouble() / 1000.toDouble() + val mb = kb / 1000.toDouble() + val decimalFormat = DecimalFormat(".##") + return when { + mb >= 1 -> { + context.getString(R.string.download_speed_mb, decimalFormat.format(mb)) + } + + kb >= 1 -> { + context.getString(R.string.download_speed_kb, decimalFormat.format(kb)) + } + + else -> { + context.getString(R.string.download_speed_bytes, downloadedBytesPerSecond) + } + } + } + fun cleanupInstallationSessions(context: Context) { val packageInstaller = context.packageManager.packageInstaller for (sessionInfo in packageInstaller.mySessions) { @@ -122,8 +158,8 @@ object CommonUtil { } fun parseProxyUrl(proxyUrl: String): ProxyInfo? { - val pattern = """^(https?|socks5?)://(?:([^\s:@]+):([^\s:@]+)@)?([^\s:@]+):(\d+)$""" - val match = pattern.toRegex().find(proxyUrl) + val pattern = """^(https?|socks5?)://(?:([^\s:@]+):([^\s:@]+)@)?([^\s:@]+):(\d+)$""".toRegex() + val match = pattern.find(proxyUrl) return when { match != null -> { @@ -145,4 +181,8 @@ object CommonUtil { else -> null } } + + fun inForeground(): Boolean { + return ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED) + } } diff --git a/app/src/main/java/com/aurora/store/util/IFlavouredUtil.kt b/app/src/main/java/com/aurora/store/util/IFlavouredUtil.kt deleted file mode 100644 index b960623da..000000000 --- a/app/src/main/java/com/aurora/store/util/IFlavouredUtil.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.aurora.store.util - -import android.content.Context - -interface IFlavouredUtil { - val defaultDispensers: Set - fun promptMicroGInstall(context: Context): Boolean -} diff --git a/app/src/main/java/com/aurora/store/util/NotificationUtil.kt b/app/src/main/java/com/aurora/store/util/NotificationUtil.kt index da2e95e64..e37ac9655 100644 --- a/app/src/main/java/com/aurora/store/util/NotificationUtil.kt +++ b/app/src/main/java/com/aurora/store/util/NotificationUtil.kt @@ -10,24 +10,22 @@ import android.graphics.Bitmap import android.graphics.Color import android.net.Uri import android.os.Build -import android.os.Bundle import androidx.core.app.NotificationCompat import androidx.core.app.PendingIntentCompat import androidx.core.content.getSystemService +import androidx.core.os.bundleOf import androidx.navigation.NavDeepLinkBuilder +import androidx.work.WorkManager import com.aurora.Constants import com.aurora.store.MainActivity import com.aurora.store.R import com.aurora.store.data.activity.InstallActivity -import com.aurora.store.data.helper.DownloadHelper import com.aurora.store.data.installer.AppInstaller import com.aurora.store.data.model.DownloadStatus -import com.aurora.store.data.receiver.DownloadCancelReceiver import com.aurora.store.data.room.download.Download -import com.aurora.store.data.room.download.Download as AuroraDownload import com.aurora.store.data.room.update.Update import java.util.UUID -import kotlin.math.absoluteValue +import com.aurora.store.data.room.download.Download as AuroraDownload object NotificationUtil { @@ -78,39 +76,27 @@ object NotificationUtil { } } - fun getDownloadNotification(context: Context): Notification = - NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_DOWNLOADS) + fun getDownloadNotification(context: Context): Notification { + return NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_DOWNLOADS) .setSmallIcon(android.R.drawable.stat_sys_download) .setContentTitle(context.getString(R.string.app_updater_service_notif_title)) .setContentText(context.getString(R.string.app_updater_service_notif_text)) .setOngoing(true) .build() + } fun getDownloadNotification( context: Context, download: AuroraDownload, - largeIcon: Bitmap? = null, - message: String? = null + workID: UUID, + largeIcon: Bitmap? = null ): Notification { val builder = NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_DOWNLOADS) - builder.setSmallIcon(R.drawable.ic_notification_outlined) builder.setContentTitle(download.displayName) - builder.setContentIntent(getContentIntentForDetails(context, download.packageName)) + builder.setContentIntent(getContentIntentForDownloads(context)) builder.setLargeIcon(largeIcon) - val cancelIntent = Intent(context, DownloadCancelReceiver::class.java).apply { - putExtra(DownloadHelper.PACKAGE_NAME, download.packageName) - } - - val pendingCancelIntent = PendingIntentCompat.getBroadcast( - context, - download.packageName.hashCode().absoluteValue, - cancelIntent, - PendingIntent.FLAG_UPDATE_CURRENT, - false - ) - - when (download.status) { + when (download.downloadStatus) { DownloadStatus.CANCELLED -> { builder.setSmallIcon(R.drawable.ic_download_cancel) builder.setContentText(context.getString(R.string.download_canceled)) @@ -120,7 +106,7 @@ object NotificationUtil { DownloadStatus.FAILED -> { builder.setSmallIcon(R.drawable.ic_download_fail) - builder.setContentText(message ?: context.getString(R.string.download_failed)) + builder.setContentText(context.getString(R.string.download_failed)) builder.color = Color.RED builder.setCategory(Notification.CATEGORY_ERROR) } @@ -133,12 +119,7 @@ object NotificationUtil { builder.setContentIntent(getContentIntentForDetails(context, download.packageName)) // Show install action if app cannot be silently installed - if (!AppInstaller.canInstallSilently( - context, - download.packageName, - download.targetSdk - ) - ) { + if (!AppInstaller.canInstallSilently(context, download.packageName, download.targetSdk)) { builder.addAction( NotificationCompat.Action.Builder( R.drawable.ic_install, @@ -152,12 +133,12 @@ object NotificationUtil { DownloadStatus.DOWNLOADING, DownloadStatus.QUEUED -> { builder.setSmallIcon(android.R.drawable.stat_sys_download) builder.setContentText( - if (download.progress <= 0) { + if (download.progress == 0) { context.getString(R.string.download_queued) } else { context.getString( R.string.download_progress, - download.downloadedFiles + 1, + download.downloadedFiles, download.totalFiles, CommonUtil.humanReadableByteSpeed(download.speed, true) ) @@ -165,13 +146,13 @@ object NotificationUtil { ) builder.setOngoing(true) builder.setCategory(Notification.CATEGORY_PROGRESS) - builder.setProgress(100, download.progress, download.progress <= 0) + builder.setProgress(100, download.progress, download.progress == 0) builder.foregroundServiceBehavior = NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE builder.addAction( NotificationCompat.Action.Builder( R.drawable.ic_download_cancel, context.getString(R.string.action_cancel), - pendingCancelIntent + WorkManager.getInstance(context).createCancelPendingIntent(workID) ).build() ) } @@ -185,59 +166,59 @@ object NotificationUtil { context: Context, displayName: String, packageName: String - ): Notification = NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_INSTALL) - .setSmallIcon(R.drawable.ic_install) - .setLargeIcon(PackageUtil.getIconForPackage(context, packageName)) - .setContentTitle(displayName) - .setContentText(context.getString(R.string.installer_status_success)) - .setContentIntent(getContentIntentForDetails(context, packageName)) - .build() + ): Notification { + return NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_INSTALL) + .setSmallIcon(R.drawable.ic_install) + .setLargeIcon(PackageUtil.getIconForPackage(context, packageName)) + .setContentTitle(displayName) + .setContentText(context.getString(R.string.installer_status_success)) + .setContentIntent(getContentIntentForDetails(context, packageName)) + .build() + } fun getInstallerStatusNotification( context: Context, packageName: String, displayName: String, content: String? - ): Notification = NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_INSTALL) - .setSmallIcon(R.drawable.ic_install) - .setContentTitle(displayName) - .setContentText(content) - .setContentIntent(getContentIntentForDetails(context, packageName)) - .build() + ): Notification { + return NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_INSTALL) + .setSmallIcon(R.drawable.ic_install) + .setContentTitle(displayName) + .setContentText(content) + .setContentIntent(getContentIntentForDetails(context, packageName)) + .build() + } - fun getUpdateNotification(context: Context): Notification = - NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_UPDATES) + fun getUpdateNotification(context: Context): Notification { + return NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_UPDATES) .setSmallIcon(R.drawable.ic_updates) .setContentTitle(context.getString(R.string.checking_updates)) .setOngoing(true) .build() + } fun getUpdateNotification(context: Context, updatesList: List): Notification { - val arguments = Bundle().apply { - putInt("destinationId", R.id.updatesFragment) - } - val contentIntent = NavDeepLinkBuilder(context) .setGraph(R.navigation.mobile_navigation) .setDestination(R.id.splashFragment) .setComponentName(MainActivity::class.java) - .setArguments(arguments) + .setArguments(bundleOf("destinationId" to R.id.updatesFragment)) .createPendingIntent() return NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_UPDATES) .setSmallIcon(R.drawable.ic_updates) .setContentTitle( - if (updatesList.size == 1) { + if (updatesList.size == 1) context.getString( R.string.notification_updates_available_1, updatesList.size ) - } else { + else context.getString( R.string.notification_updates_available, updatesList.size ) - } ) .setContentText( when (updatesList.size) { @@ -279,20 +260,22 @@ object NotificationUtil { .setContentIntent(contentIntent) .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setCategory(NotificationCompat.CATEGORY_RECOMMENDATION) + .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setAutoCancel(true) .build() } - fun getExportNotification(context: Context): Notification = - NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_EXPORT) + fun getExportNotification(context: Context): Notification { + return NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_EXPORT) .setSmallIcon(R.drawable.ic_file_copy) .setContentTitle(context.getString(R.string.export_app_title)) .setContentText(context.getString(R.string.export_app_summary)) .setOngoing(true) .build() + } - fun getUnarchiveAuthNotification(context: Context, packageName: String): Notification = - NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_ACCOUNT) + fun getUnarchiveAuthNotification(context: Context, packageName: String): Notification { + return NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_ACCOUNT) .setSmallIcon(R.drawable.ic_account) .setContentTitle(context.getString(R.string.authentication_required_title)) .setContentText(context.getString(R.string.authentication_required_unarchive)) @@ -301,6 +284,7 @@ object NotificationUtil { .setCategory(NotificationCompat.CATEGORY_ERROR) .setPriority(NotificationCompat.PRIORITY_HIGH) .build() + } fun getExportStatusNotification( context: Context, @@ -360,26 +344,28 @@ object NotificationUtil { } private fun getContentIntentForSplash(context: Context, packageName: String): PendingIntent { - val arguments = Bundle().apply { - putString("packageName", packageName) - } return NavDeepLinkBuilder(context) .setGraph(R.navigation.mobile_navigation) .setDestination(R.id.splashFragment) .setComponentName(MainActivity::class.java) - .setArguments(arguments) + .setArguments(bundleOf("packageName" to packageName)) .createPendingIntent() } private fun getContentIntentForDetails(context: Context, packageName: String): PendingIntent { - val arguments = Bundle().apply { - putString("packageName", packageName) - } return NavDeepLinkBuilder(context) .setGraph(R.navigation.mobile_navigation) - .setDestination(R.id.splashFragment) + .setDestination(R.id.appDetailsFragment) + .setComponentName(MainActivity::class.java) + .setArguments(bundleOf("packageName" to packageName)) + .createPendingIntent() + } + + private fun getContentIntentForDownloads(context: Context): PendingIntent { + return NavDeepLinkBuilder(context) + .setGraph(R.navigation.mobile_navigation) + .setDestination(R.id.downloadFragment) .setComponentName(MainActivity::class.java) - .setArguments(arguments) .createPendingIntent() } diff --git a/app/src/main/java/com/aurora/store/util/PackageUtil.kt b/app/src/main/java/com/aurora/store/util/PackageUtil.kt index 1f800c942..a485d19af 100644 --- a/app/src/main/java/com/aurora/store/util/PackageUtil.kt +++ b/app/src/main/java/com/aurora/store/util/PackageUtil.kt @@ -28,6 +28,7 @@ import android.content.pm.PackageManager.PackageInfoFlags import android.content.pm.SharedLibraryInfo import android.graphics.Bitmap import android.graphics.drawable.Drawable +import android.net.Uri import android.os.Build import android.provider.Settings import android.util.Log @@ -35,10 +36,6 @@ import androidx.annotation.RequiresApi import androidx.appcompat.content.res.AppCompatResources import androidx.core.content.pm.PackageInfoCompat import androidx.core.graphics.drawable.toBitmap -import androidx.core.net.toUri -import com.aurora.Constants.PACKAGE_NAME_APP_GALLERY -import com.aurora.Constants.PACKAGE_NAME_GMS -import com.aurora.Constants.PACKAGE_NAME_PLAY_STORE import com.aurora.extensions.isHuawei import com.aurora.extensions.isOAndAbove import com.aurora.extensions.isPAndAbove @@ -53,53 +50,23 @@ object PackageUtil { private const val TAG = "PackageUtil" - private const val VERSION_CODE_MICRO_G: Long = 240913402 - private const val VERSION_CODE_MICRO_G_HUAWEI: Long = 240913007 - private const val VERSION_CODE_MICROG_COMPANION_MIN: Long = 84022620 - private const val MICROG_INSTALL_ACTIVITY = "org.microg.vending.installer.AppInstallActivity" + const val PACKAGE_NAME_GMS = "com.google.android.gms" + private const val VERSION_CODE_MICRO_G = 240913402 + private const val VERSION_CODE_MICRO_G_HUAWEI = 240913007 - fun getAllValidPackages(context: Context): List = - context.packageManager.getInstalledPackages(PackageManager.GET_META_DATA) + fun getAllValidPackages(context: Context): List { + val sharedLibs = context.packageManager.systemSharedLibraryNames ?: emptyArray() + return context.packageManager.getInstalledPackages(PackageManager.GET_META_DATA) .filter { it.isValidApp(context.packageManager) } + .filterNot { it.packageName in sharedLibs } .sortedBy { it.applicationInfo!!.loadLabel(context.packageManager).toString() .lowercase(Locale.getDefault()) } - - fun hasSupportedAppGallery(context: Context): Boolean { - return try { - val result = context.packageManager.checkPermission( - android.Manifest.permission.INSTALL_PACKAGES, - PACKAGE_NAME_APP_GALLERY - ) - - if (result != PackageManager.PERMISSION_GRANTED) { - Log.w(TAG, "AppGallery does not have INSTALL_PACKAGES permission") - return false - } - - val packageInfo = context.packageManager.getPackageInfo( - PACKAGE_NAME_APP_GALLERY, - PackageManager.GET_META_DATA - ) - - @Suppress("DEPRECATION") - val versionCode = if (Build.VERSION.SDK_INT >= 28) { - packageInfo.longVersionCode - } else { - packageInfo.versionCode.toLong() - } - - Log.i(TAG, "AppGallery - ${packageInfo.versionName} ($versionCode)") - - versionCode >= 15010000L - } catch (_: Exception) { - false - } } - fun hasSupportedMicroGVariant(context: Context): Boolean { - val isMicroG = CertUtil.isMicroGGms(context) + fun hasSupportedMicroG(context: Context): Boolean { + val isMicroG = CertUtil.isMicroGGMS(context, PACKAGE_NAME_GMS) // Do not proceed if MicroG variant is not installed if (!isMicroG) return false @@ -111,127 +78,116 @@ object PackageUtil { } } - fun hasActivity(context: Context, packageName: String, activityName: String): Boolean { - val intent = Intent() - intent.setClassName(packageName, activityName) - - val resolveInfo = context.packageManager.resolveActivity(intent, 0) - return resolveInfo != null + fun isInstalled(context: Context, packageName: String): Boolean { + return try { + getPackageInfo(context, packageName, PackageManager.GET_META_DATA) + true + } catch (e: PackageManager.NameNotFoundException) { + false + } } - fun hasMicroGCompanion(context: Context): Boolean = isInstalled( - context, - PACKAGE_NAME_PLAY_STORE, - VERSION_CODE_MICROG_COMPANION_MIN - ) && - hasActivity( - context, - PACKAGE_NAME_PLAY_STORE, - MICROG_INSTALL_ACTIVITY - ) - - fun isInstalled(context: Context, packageName: String, versionCode: Long? = null): Boolean = - try { - val packageInfo = getPackageInfo(context, packageName, PackageManager.GET_META_DATA) - if (versionCode != null) { - PackageInfoCompat.getLongVersionCode(packageInfo) >= versionCode - } else { - true - } - } catch (_: PackageManager.NameNotFoundException) { + fun isInstalled(context: Context, packageName: String, versionCode: Int): Boolean { + return try { + val packageInfo = getPackageInfo(context, packageName) + return PackageInfoCompat.getLongVersionCode(packageInfo) >= versionCode.toLong() + } catch (e: PackageManager.NameNotFoundException) { false } + } - fun isArchived(context: Context, packageName: String): Boolean = try { - isVAndAbove && context.packageManager.getArchivedPackage(packageName) != null - } catch (_: Exception) { - false + fun isArchived(context: Context, packageName: String): Boolean { + return try { + isVAndAbove && context.packageManager.getArchivedPackage(packageName) != null + } catch (e: PackageManager.NameNotFoundException) { + false + } } - fun isSharedLibrary(context: Context, packageName: String): Boolean = if (isOAndAbove) { - getAllSharedLibraries(context).any { it.name == packageName } - } else { - false + fun isSharedLibrary(context: Context, packageName: String): Boolean { + return if (isOAndAbove) { + getAllSharedLibraries(context).any { it.name == packageName } + } else { + false + } } - fun isSharedLibraryInstalled( - context: Context, - packageName: String, - versionCode: Long - ): Boolean = if (isOAndAbove) { - val sharedLibraries = getAllSharedLibraries(context) - if (isPAndAbove) { - sharedLibraries.any { - it.name == packageName && it.longVersion == versionCode + fun isSharedLibraryInstalled(context: Context, packageName: String, versionCode: Int): Boolean { + return if (isOAndAbove) { + val sharedLibraries = getAllSharedLibraries(context) + if (isPAndAbove) { + sharedLibraries.any { + it.name == packageName && it.longVersion == versionCode.toLong() + } + } else { + sharedLibraries.any { + @Suppress("DEPRECATION") + it.name == packageName && it.version == versionCode + } } } else { - sharedLibraries.any { - @Suppress("DEPRECATION") - it.name == packageName && it.version == versionCode.toInt() - } + false } - } else { - false } fun isUpdatable(context: Context, packageName: String, versionCode: Long): Boolean { return try { val packageInfo = getPackageInfo(context, packageName) return versionCode > PackageInfoCompat.getLongVersionCode(packageInfo) - } catch (_: PackageManager.NameNotFoundException) { + } catch (e: PackageManager.NameNotFoundException) { false } } - /** - * Confirm if MicroG bundle is installed - * Considering the following: - * 1. GmsCore is installed and it is a microG huawei variant - * 2. Play Store is installed - (microG Companion) - */ - fun isMicroGBundleInstalled(context: Context): Boolean = - hasSupportedMicroGVariant(context) && isInstalled(context, PACKAGE_NAME_PLAY_STORE) - - fun getInstalledVersionName(context: Context, packageName: String): String = try { - getPackageInfo(context, packageName).versionName ?: "" - } catch (_: PackageManager.NameNotFoundException) { - "" + fun getInstalledVersionName(context: Context, packageName: String): String { + return try { + getPackageInfo(context, packageName).versionName ?: "" + } catch (e: PackageManager.NameNotFoundException) { + "" + } } - fun getInstalledVersionCode(context: Context, packageName: String): Long = try { - PackageInfoCompat.getLongVersionCode(getPackageInfo(context, packageName)) - } catch (_: PackageManager.NameNotFoundException) { - 0 + fun getInstalledVersionCode(context: Context, packageName: String): Long { + return try { + PackageInfoCompat.getLongVersionCode(getPackageInfo(context, packageName)) + } catch (e: PackageManager.NameNotFoundException) { + 0 + } } - fun isTv(context: Context): Boolean = - context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK) + fun isTv(context: Context): Boolean { + return context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK) + } fun getLaunchIntent(context: Context, packageName: String?): Intent? { val intent = if (isTv(context)) { context.packageManager.getLeanbackLaunchIntentForPackage(packageName!!) } else { context.packageManager.getLaunchIntentForPackage(packageName!!) - } ?: return null - - return intent.apply { - addCategory( - if (isTv(context)) { - Intent.CATEGORY_LEANBACK_LAUNCHER - } else { - Intent.CATEGORY_LAUNCHER - } - ) + } + + return if (intent == null) { + null + } else { + intent.addCategory(if (isTv(context)) Intent.CATEGORY_LEANBACK_LAUNCHER else Intent.CATEGORY_LAUNCHER) + intent } } @RequiresApi(Build.VERSION_CODES.R) fun getStorageManagerIntent(context: Context): Intent { - val intent = Intent( + var intent = Intent( Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, - "package:${BuildConfig.APPLICATION_ID}".toUri() + Uri.parse("package:${BuildConfig.APPLICATION_ID}") ) + if (isHuawei) { + intent = Intent( + Settings.ACTION_APPLICATION_DETAILS_SETTINGS, + Uri.parse("package:${BuildConfig.APPLICATION_ID}") + ) + } + // Check if the intent can be resolved val packageManager = context.packageManager val isIntentAvailable = packageManager.queryIntentActivities( @@ -246,13 +202,15 @@ object PackageUtil { } } - fun getInstallUnknownAppsIntent(): Intent = if (isOAndAbove) { - Intent( - Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, - "package:${BuildConfig.APPLICATION_ID}".toUri() - ) - } else { - Intent(Settings.ACTION_SECURITY_SETTINGS) + fun getInstallUnknownAppsIntent(): Intent { + return if (isOAndAbove) { + Intent( + Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, + Uri.parse("package:${BuildConfig.APPLICATION_ID}") + ) + } else { + Intent(Settings.ACTION_SECURITY_SETTINGS) + } } fun canRequestPackageInstalls(context: Context): Boolean { @@ -262,8 +220,7 @@ object PackageUtil { @Suppress("DEPRECATION") val secureResult = Settings.Secure.getInt( context.contentResolver, - Settings.Secure.INSTALL_NON_MARKET_APPS, - 0 + Settings.Secure.INSTALL_NON_MARKET_APPS, 0 ) return secureResult == 1 @@ -271,8 +228,8 @@ object PackageUtil { } @Throws(Exception::class) - fun getPackageInfo(context: Context, packageName: String, flags: Int = 0): PackageInfo = - if (isTAndAbove) { + fun getPackageInfo(context: Context, packageName: String, flags: Int = 0): PackageInfo { + return if (isTAndAbove) { context.packageManager.getPackageInfo( packageName, PackageInfoFlags.of(flags.toLong()) @@ -280,18 +237,21 @@ object PackageUtil { } else { context.packageManager.getPackageInfo(packageName, flags) } + } - fun getIconForPackage(context: Context, packageName: String): Bitmap? = try { - val packageInfo = context.packageManager.getPackageInfo(packageName, 0) - val icon = packageInfo.applicationInfo!!.loadIcon(context.packageManager) - if (icon.intrinsicWidth > 0 && icon.intrinsicHeight > 0) { - icon.toBitmap(96, 96) - } else { - context.packageManager.defaultActivityIcon.toBitmap(96, 96) + fun getIconForPackage(context: Context, packageName: String): Bitmap? { + return try { + val packageInfo = context.packageManager.getPackageInfo(packageName, 0) + val icon = packageInfo.applicationInfo!!.loadIcon(context.packageManager) + if (icon.intrinsicWidth > 0 && icon.intrinsicHeight > 0) { + icon.toBitmap(96, 96) + } else { + context.packageManager.defaultActivityIcon.toBitmap(96, 96) + } + } catch (exception: Exception) { + Log.e(TAG, "Failed to get icon for package!", exception) + null } - } catch (exception: Exception) { - Log.e(TAG, "Failed to get icon for package!", exception) - null } fun getIconDrawableForPackage(context: Context, packageName: String): Drawable? { @@ -308,14 +268,15 @@ object PackageUtil { } } - private fun getAllSharedLibraries(context: Context, flags: Int = 0): List = - if (isTAndAbove) { + private fun getAllSharedLibraries(context: Context, flags: Int = 0): List { + return if (isTAndAbove) { context.packageManager.getSharedLibraries(PackageInfoFlags.of(flags.toLong())) } else if (isOAndAbove) { context.packageManager.getSharedLibraries(flags) } else { emptyList() } + } fun getFilter(): IntentFilter { val filter = IntentFilter() diff --git a/app/src/main/java/com/aurora/store/util/PathUtil.kt b/app/src/main/java/com/aurora/store/util/PathUtil.kt index fe7108cc7..88007b84e 100644 --- a/app/src/main/java/com/aurora/store/util/PathUtil.kt +++ b/app/src/main/java/com/aurora/store/util/PathUtil.kt @@ -21,10 +21,10 @@ package com.aurora.store.util import android.content.Context import android.os.Environment -import com.aurora.gplayapi.data.models.PlayFile import com.aurora.store.data.room.download.Download import java.io.File import java.util.UUID +import com.aurora.gplayapi.data.models.File as GPlayFile object PathUtil { @@ -32,39 +32,47 @@ object PathUtil { private const val DOWNLOADS = "Downloads" private const val SPOOF = "SpoofConfigs" - fun getOldDownloadDirectories(context: Context): List = listOf( - File(context.filesDir, DOWNLOADS), // till 4.4.2 - File(context.getExternalFilesDir(null), DOWNLOADS) // till 4.4.2 - ) + fun getOldDownloadDirectories(context: Context): List { + return listOf( + File(context.filesDir, DOWNLOADS), // till 4.4.2 + File(context.getExternalFilesDir(null), DOWNLOADS) // till 4.4.2 + ) + } - fun getDownloadDirectory(context: Context): File = File(context.cacheDir, DOWNLOADS) + fun getDownloadDirectory(context: Context): File { + return File(context.cacheDir, DOWNLOADS) + } - private fun getPackageDirectory(context: Context, packageName: String): File = - File(getDownloadDirectory(context), packageName) + private fun getPackageDirectory(context: Context, packageName: String): File { + return File(getDownloadDirectory(context), packageName) + } - fun getAppDownloadDir(context: Context, packageName: String, versionCode: Long): File = - File(getPackageDirectory(context, packageName), versionCode.toString()) + fun getAppDownloadDir(context: Context, packageName: String, versionCode: Int): File { + return File(getPackageDirectory(context, packageName), versionCode.toString()) + } fun getLibDownloadDir( context: Context, packageName: String, - versionCode: Long, + versionCode: Int, sharedLibPackageName: String - ): File = File( - getAppDownloadDir(context, packageName, versionCode), - "$LIBRARIES/$sharedLibPackageName" - ) + ): File { + return File( + getAppDownloadDir(context, packageName, versionCode), + "$LIBRARIES/$sharedLibPackageName" + ) + } /** - * Returns an instance of java's [File] class for the given [PlayFile] + * Returns an instance of java's [File] class for the given [GPlayFile] * @param context [Context] - * @param playFile [PlayFile] to download + * @param gFile [GPlayFile] to download * @param download An instance of [Download] */ - fun getLocalFile(context: Context, playFile: PlayFile, download: Download): File { - val sharedLib = download.sharedLibs.find { it.fileList.contains(playFile) } - return when (playFile.type) { - PlayFile.Type.BASE, PlayFile.Type.SPLIT -> { + fun getLocalFile(context: Context, gFile: GPlayFile, download: Download): File { + val sharedLib = download.sharedLibs.find { it.fileList.contains(gFile) } + return when (gFile.type) { + GPlayFile.FileType.BASE, GPlayFile.FileType.SPLIT -> { val downloadDir = if (sharedLib != null) { getLibDownloadDir( context, @@ -75,28 +83,32 @@ object PathUtil { } else { getAppDownloadDir(context, download.packageName, download.versionCode) } - return File(downloadDir, playFile.name) + return File(downloadDir, gFile.name) } - PlayFile.Type.OBB, PlayFile.Type.PATCH -> { - File(getObbDownloadDir(download.packageName), playFile.name) + GPlayFile.FileType.OBB, GPlayFile.FileType.PATCH -> { + File(getObbDownloadDir(download.packageName), gFile.name) } } } - fun getZipFile(context: Context, packageName: String, versionCode: Long): File = File( - getAppDownloadDir( - context, - packageName, - versionCode - ), - "${packageName}_$versionCode.apks" - ) + fun getZipFile(context: Context, packageName: String, versionCode: Int): File { + return File( + getAppDownloadDir( + context, + packageName, + versionCode, + ), "${packageName}_${versionCode}.apks" + ) + } - fun getObbDownloadDir(packageName: String): File = - File(Environment.getExternalStorageDirectory(), "/Android/obb/$packageName") + fun getObbDownloadDir(packageName: String): File { + return File(Environment.getExternalStorageDirectory(), "/Android/obb/$packageName") + } - fun getSpoofDirectory(context: Context): File = File(context.filesDir, SPOOF) + fun getSpoofDirectory(context: Context): File { + return File(context.filesDir, SPOOF) + } fun getNewEmptySpoofConfig(context: Context): File { val file = File(getSpoofDirectory(context), "${UUID.randomUUID()}.properties") diff --git a/app/src/main/java/com/aurora/store/util/Preferences.kt b/app/src/main/java/com/aurora/store/util/Preferences.kt index 38bf4f06d..d35871cbf 100644 --- a/app/src/main/java/com/aurora/store/util/Preferences.kt +++ b/app/src/main/java/com/aurora/store/util/Preferences.kt @@ -24,7 +24,6 @@ import android.content.SharedPreferences import androidx.core.content.edit import androidx.fragment.app.Fragment import androidx.preference.PreferenceManager -import com.aurora.store.BuildConfig object Preferences { @@ -35,6 +34,7 @@ object Preferences { const val PREFERENCE_THEME_STYLE = "PREFERENCE_THEME_STYLE" const val PREFERENCE_FOR_YOU = "PREFERENCE_FOR_YOU" const val PREFERENCE_DEFAULT_SELECTED_TAB = "PREFERENCE_DEFAULT_SELECTED_TAB" + const val PREFERENCE_SIMILAR = "PREFERENCE_SIMILAR" const val PREFERENCE_INTRO = "PREFERENCE_INTRO" const val PREFERENCE_FILTER_FDROID = "PREFERENCE_FILTER_FDROID" @@ -46,8 +46,7 @@ object Preferences { const val PREFERENCE_PROXY_URL = "PREFERENCE_PROXY_URL" const val PREFERENCE_PROXY_INFO = "PREFERENCE_PROXY_INFO" - - const val PREFERENCE_MICROG_AUTH = "PREFERENCE_MICROG_AUTH" + const val PREFERENCE_PROXY_ENABLED = "PREFERENCE_PROXY_ENABLED" const val PREFERENCE_DISPENSER_URLS = "PREFERENCE_DISPENSER_URLS" const val PREFERENCE_VENDING_VERSION = "PREFERENCE_VENDING_VERSION" @@ -55,25 +54,16 @@ object Preferences { const val PREFERENCE_UPDATES_EXTENDED = "PREFERENCE_UPDATES_EXTENDED" const val PREFERENCE_UPDATES_AUTO = "PREFERENCE_UPDATES_AUTO" const val PREFERENCE_UPDATES_CHECK_INTERVAL = "PREFERENCE_UPDATES_CHECK_INTERVAL" - const val PREFERENCES_UPDATES_RESTRICTIONS = "PREFERENCES_UPDATES_RESTRICTIONS" - const val PREFERENCES_UPDATES_RESTRICTIONS_METERED = "PREFERENCES_UPDATES_RESTRICTIONS_METERED" - const val PREFERENCES_UPDATES_RESTRICTIONS_IDLE = "PREFERENCES_UPDATES_RESTRICTIONS_IDLE" - const val PREFERENCES_UPDATES_RESTRICTIONS_BATTERY = "PREFERENCES_UPDATES_RESTRICTIONS_BATTERY" const val PREFERENCE_MIGRATION_VERSION = "PREFERENCE_MIGRATION_VERSION" private var prefs: SharedPreferences? = null - fun getPrefs(context: Context): SharedPreferences = when (BuildConfig.FLAVOR) { - "vanilla" -> { - prefs ?: PreferenceManager.getDefaultSharedPreferences(context).also { prefs = it } - } - - else -> { - val prefName = "${context.packageName}_${BuildConfig.FLAVOR}_preferences" - prefs ?: context.getSharedPreferences(prefName, Context.MODE_PRIVATE) - .also { prefs = it } + fun getPrefs(context: Context): SharedPreferences { + if (prefs == null) { + prefs = PreferenceManager.getDefaultSharedPreferences(context) } + return prefs!! } fun remove(context: Context, key: String) { @@ -108,24 +98,33 @@ object Preferences { getPrefs(context).edit(true) { putBoolean(key, value) } } - fun getString(context: Context, key: String, default: String = ""): String = - getPrefs(context).getString(key, default).toString() + fun getString(context: Context, key: String, default: String = ""): String { + return getPrefs(context).getString(key, default).toString() + } fun getStringSet( context: Context, key: String, default: Set = emptySet() - ): Set = getPrefs(context).getStringSet(key, default) ?: emptySet() + ): Set { + return getPrefs(context).getStringSet(key, default) ?: emptySet() + } - fun getInteger(context: Context, key: String, default: Int = 0): Int = - getPrefs(context).getInt(key, default) + fun getInteger(context: Context, key: String, default: Int = 0): Int { + return getPrefs(context).getInt(key, default) + } - fun getFloat(context: Context, key: String): Float = getPrefs(context).getFloat(key, 0.0f) + fun getFloat(context: Context, key: String): Float { + return getPrefs(context).getFloat(key, 0.0f) + } - fun getLong(context: Context, key: String): Long = getPrefs(context).getLong(key, 0L) + fun getLong(context: Context, key: String): Long { + return getPrefs(context).getLong(key, 0L) + } - fun getBoolean(context: Context, key: String, default: Boolean = false): Boolean = - getPrefs(context).getBoolean(key, default) + fun getBoolean(context: Context, key: String, default: Boolean = false): Boolean { + return getPrefs(context).getBoolean(key, default) + } } /*Preference Extensions*/ @@ -140,6 +139,7 @@ fun Context.save(key: String, value: Set) = Preferences.putStringSet(thi fun Context.remove(key: String) = Preferences.remove(this, key) + fun Fragment.save(key: String, value: Int) = requireContext().save(key, value) fun Fragment.save(key: String, value: Boolean) = requireContext().save(key, value) diff --git a/app/src/main/java/com/aurora/store/util/ShortcutManagerUtil.kt b/app/src/main/java/com/aurora/store/util/ShortcutManagerUtil.kt index 660277f6b..b23f8f187 100644 --- a/app/src/main/java/com/aurora/store/util/ShortcutManagerUtil.kt +++ b/app/src/main/java/com/aurora/store/util/ShortcutManagerUtil.kt @@ -11,9 +11,10 @@ object ShortcutManagerUtil { private const val TAG = "ShortcutManagerUtil" - fun canPinShortcut(context: Context, packageName: String): Boolean = - ShortcutManagerCompat.isRequestPinShortcutSupported(context) && - context.packageManager.getLaunchIntentForPackage(packageName) != null + fun canPinShortcut(context: Context, packageName: String): Boolean { + return ShortcutManagerCompat.isRequestPinShortcutSupported(context) && + context.packageManager.getLaunchIntentForPackage(packageName) != null + } fun requestPinShortcut(context: Context, packageName: String) { val packageManager = context.packageManager diff --git a/app/src/main/java/com/aurora/store/view/custom/RatingView.kt b/app/src/main/java/com/aurora/store/view/custom/RatingView.kt new file mode 100644 index 000000000..deeb961ec --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/custom/RatingView.kt @@ -0,0 +1,55 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.custom + +import android.content.Context +import android.util.AttributeSet +import android.widget.RelativeLayout +import com.aurora.store.R +import com.aurora.store.databinding.ViewRatingBinding + +class RatingView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : RelativeLayout(context, attrs, defStyleAttr) { + + private lateinit var binding: ViewRatingBinding + + var number = 0 + var max = 0 + var rating = 0 + + constructor(context: Context, number: Int, max: Int, rating: Int) : this(context) { + this.number = number + this.max = max + this.rating = rating + init(context) + } + + private fun init(context: Context) { + val view = inflate(context, R.layout.view_rating, this) + binding = ViewRatingBinding.bind(view) + + binding.avgNum.text = number.toString() + binding.avgRating.max = max + binding.avgRating.progress = rating + } +} diff --git a/app/src/main/java/com/aurora/store/view/custom/layouts/ActionHeaderLayout.kt b/app/src/main/java/com/aurora/store/view/custom/layouts/ActionHeaderLayout.kt index e43045fca..eabd6f2ad 100644 --- a/app/src/main/java/com/aurora/store/view/custom/layouts/ActionHeaderLayout.kt +++ b/app/src/main/java/com/aurora/store/view/custom/layouts/ActionHeaderLayout.kt @@ -79,4 +79,4 @@ class ActionHeaderLayout : RelativeLayout { binding.imgAction.visibility = View.VISIBLE binding.imgAction.setOnClickListener(onclickListener) } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/view/custom/layouts/DevInfoLayout.kt b/app/src/main/java/com/aurora/store/view/custom/layouts/DevInfoLayout.kt new file mode 100644 index 000000000..457e06936 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/custom/layouts/DevInfoLayout.kt @@ -0,0 +1,101 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.custom.layouts + +import android.content.Context +import android.util.AttributeSet +import android.widget.RelativeLayout +import androidx.annotation.ColorInt +import androidx.appcompat.widget.AppCompatImageView +import androidx.core.view.isVisible +import com.aurora.store.R +import com.aurora.store.databinding.ViewDevInfoBinding + +class DevInfoLayout : RelativeLayout { + + private lateinit var binding: ViewDevInfoBinding + + val icon: AppCompatImageView get() = binding.img + + var title: String + get() = binding.txtTitle.text.toString() + set(value) = setTxtTitle(value) + + var subTitle: String? + get() = binding.txtSubtitle.text.toString() + set(value) = setTxtSubtitle(value) + + @get:ColorInt + var titleColor: Int + get() = binding.txtTitle.currentTextColor + set(value) = binding.txtTitle.setTextColor(value) + + @get:ColorInt + var subTitleColor: Int + get() = binding.txtSubtitle.currentTextColor + set(value) = binding.txtSubtitle.setTextColor(value) + + constructor(context: Context) : super(context) { + init(context, null) + } + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + init(context, attrs) + } + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) { + init(context, attrs) + } + + private fun init(context: Context, attrs: AttributeSet?) { + val view = inflate(context, R.layout.view_dev_info, this) + binding = ViewDevInfoBinding.bind(view) + + val typedArray = context.obtainStyledAttributes(attrs, R.styleable.DevInfoLayout) + val icon = typedArray.getResourceId( + R.styleable.DevInfoLayout_imgIcon, + R.drawable.ic_map_marker + ) + + val textPrimary = typedArray.getString(R.styleable.DevInfoLayout_txtTitle) + val textSecondary = typedArray.getString(R.styleable.DevInfoLayout_txtSubtitle) + + binding.img.setImageResource(icon) + binding.txtTitle.text = textPrimary + binding.txtSubtitle.text = textSecondary + typedArray.recycle() + } + + private fun setTxtTitle(text: String?) { + binding.txtTitle.text = text + binding.txtTitle.isVisible = text != null + invalidate() + } + + private fun setTxtSubtitle(text: String?) { + binding.txtSubtitle.text = text + binding.txtSubtitle.isVisible = text != null + invalidate() + } +} diff --git a/app/src/main/java/com/aurora/store/view/custom/layouts/PermissionGroup.kt b/app/src/main/java/com/aurora/store/view/custom/layouts/PermissionGroup.kt new file mode 100644 index 000000000..e0e2cd540 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/custom/layouts/PermissionGroup.kt @@ -0,0 +1,155 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ +package com.aurora.store.view.custom.layouts + +import android.content.Context +import android.content.pm.PackageManager +import android.content.pm.PermissionInfo +import android.graphics.drawable.Drawable +import android.util.AttributeSet +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.core.content.ContextCompat +import com.aurora.extensions.showDialog +import com.aurora.store.R +import com.aurora.store.data.model.PermissionGroupInfo +import java.util.Locale + +class PermissionGroup @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr) { + + private lateinit var permissionGroupInfo: PermissionGroupInfo + private lateinit var packageManager: PackageManager + + private val permissionMap: MutableMap = HashMap() + + constructor(context: Context?, permissionGroupInfo: PermissionGroupInfo) : this(context) { + if (context != null) { + inflate(context, R.layout.layout_permission, this) + + layoutParams = LayoutParams( + LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT + ) + + this.packageManager = context.packageManager + this.permissionGroupInfo = permissionGroupInfo + + val imageView = findViewById(R.id.img) + imageView.setImageDrawable(getPermissionGroupIcon(permissionGroupInfo)) + } + } + + fun addPermission(permissionInfo: PermissionInfo, currentPerms: List = emptyList()) { + val title = permissionInfo.loadLabel(packageManager) + val description = permissionInfo.loadDescription(packageManager) + + permissionMap[getReadableLabel(title.toString(), permissionInfo.packageName)] = + if (description.isNullOrEmpty()) + "No description" + else + description.toString() + + val permissionLabels: List = ArrayList(permissionMap.keys) + val permissionLabelsView = findViewById(R.id.permission_labels) + permissionLabelsView.removeAllViews() + + permissionLabels + .filter { it.isNotEmpty() } + .sortedBy { it } + .forEach { + addPermissionLabel( + permissionLabelsView, + it, + permissionMap[it], + if (currentPerms.isNotEmpty()) permissionInfo.name !in currentPerms else false + ) + } + } + + private fun addPermissionLabel( + permissionLabelsView: LinearLayout, + label: String, + description: String?, + isNewPerm: Boolean = false + ) { + val textView = TextView(context) + textView.text = label + if (isNewPerm) textView.setTextColor(ContextCompat.getColor(context, R.color.colorGreen)) + textView.setOnClickListener { + var title: String = permissionGroupInfo.label + + if (title.contains("UNDEFINED")) { + title = "Android" + } + + title = title.replaceFirstChar { + if (it.isLowerCase()) { + it.titlecase(Locale.getDefault()) + } else { + it.toString() + } + } + + context.showDialog(title, description) + } + + permissionLabelsView.addView(textView) + } + + private fun getPermissionGroupIcon(permissionGroupInfo: PermissionGroupInfo): Drawable? { + return ContextCompat.getDrawable(context, permissionGroupInfo.icon) + } + + private fun getReadableLabel(label: String, packageName: String): String { + val prefixes: MutableList = mutableListOf( + "android", + packageName + ) + + if (label.contains("UNDEFINED")) { + return "Android" + } + + prefixes + .map { "$it.permission." } + .forEach { + if (label.startsWith(it)) { + return it.replace(it, "") + .replace("_", " ") + .lowercase(Locale.getDefault()) + .replaceFirstChar { + if (it.isLowerCase()) { + it.titlecase(Locale.getDefault()) + } else { + it.toString() + } + } + } + } + + return label.replaceFirstChar { + it.titlecase(Locale.getDefault()) + } + } +} diff --git a/app/src/main/java/com/aurora/store/view/custom/layouts/button/StateButton.kt b/app/src/main/java/com/aurora/store/view/custom/layouts/button/StateButton.kt index 1fce7497a..ac9e1060b 100644 --- a/app/src/main/java/com/aurora/store/view/custom/layouts/button/StateButton.kt +++ b/app/src/main/java/com/aurora/store/view/custom/layouts/button/StateButton.kt @@ -64,11 +64,11 @@ class StateButton : RelativeLayout { } fun updateProgress(isVisible: Boolean) { - if (isVisible) { + if (isVisible) binding.progress.visibility = View.VISIBLE - } else { + else + binding.progress.visibility = View.INVISIBLE - } } fun addOnClickListener(onClickListener: OnClickListener) { diff --git a/app/src/main/java/com/aurora/store/view/custom/preference/AuroraListPreference.kt b/app/src/main/java/com/aurora/store/view/custom/preference/AuroraListPreference.kt index 58b249022..263e32ffa 100644 --- a/app/src/main/java/com/aurora/store/view/custom/preference/AuroraListPreference.kt +++ b/app/src/main/java/com/aurora/store/view/custom/preference/AuroraListPreference.kt @@ -42,9 +42,11 @@ class AuroraListPreference : ListPreference { defStyleRes: Int ) : super(context, attrs, defStyleAttr, defStyleRes) - override fun getPersistedString(defaultReturnValue: String?): String = - getPersistedInt(defaultReturnValue?.toInt() ?: -1).toString() + override fun getPersistedString(defaultReturnValue: String?): String { + return getPersistedInt(defaultReturnValue?.toInt() ?: -1).toString() + } - override fun persistString(value: String?): Boolean = - if (value != null) persistInt(Integer.valueOf(value)) else false + override fun persistString(value: String?): Boolean { + return if (value != null) persistInt(Integer.valueOf(value)) else false + } } diff --git a/app/src/main/java/com/aurora/store/view/custom/preference/M3EditTextPreference.kt b/app/src/main/java/com/aurora/store/view/custom/preference/M3EditTextPreference.kt index 0e496b427..c9dfcd7a1 100644 --- a/app/src/main/java/com/aurora/store/view/custom/preference/M3EditTextPreference.kt +++ b/app/src/main/java/com/aurora/store/view/custom/preference/M3EditTextPreference.kt @@ -6,6 +6,7 @@ import android.view.WindowManager import androidx.preference.EditTextPreferenceDialogFragmentCompat import com.google.android.material.dialog.MaterialAlertDialogBuilder + class M3EditTextPreference : EditTextPreferenceDialogFragmentCompat() { companion object { @@ -39,6 +40,7 @@ class M3EditTextPreference : EditTextPreferenceDialogFragmentCompat() { return builder.create() } + override fun onResume() { super.onResume() dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE) diff --git a/app/src/main/java/com/aurora/store/view/custom/recycler/EndlessRecyclerOnScrollListener.kt b/app/src/main/java/com/aurora/store/view/custom/recycler/EndlessRecyclerOnScrollListener.kt index 5e0dea093..1e20b9ca9 100644 --- a/app/src/main/java/com/aurora/store/view/custom/recycler/EndlessRecyclerOnScrollListener.kt +++ b/app/src/main/java/com/aurora/store/view/custom/recycler/EndlessRecyclerOnScrollListener.kt @@ -54,20 +54,16 @@ abstract class EndlessRecyclerOnScrollListener : RecyclerView.OnScrollListener { private fun findFirstVisibleItemPosition(recyclerView: RecyclerView): Int { val child = findOneVisibleChild(0, layoutManager.childCount, true, false) - return if (child == null) { - RecyclerView.NO_POSITION - } else { - recyclerView.getChildAdapterPosition(child) - } + return if (child == null) RecyclerView.NO_POSITION else recyclerView.getChildAdapterPosition( + child + ) } private fun findLastVisibleItemPosition(recyclerView: RecyclerView): Int { val child = findOneVisibleChild(recyclerView.childCount - 1, -1, false, true) - return if (child == null) { - RecyclerView.NO_POSITION - } else { - recyclerView.getChildAdapterPosition(child) - } + return if (child == null) RecyclerView.NO_POSITION else recyclerView.getChildAdapterPosition( + child + ) } private fun findOneVisibleChild( @@ -76,15 +72,12 @@ abstract class EndlessRecyclerOnScrollListener : RecyclerView.OnScrollListener { completelyVisible: Boolean, acceptPartiallyVisible: Boolean ): View? { - if (layoutManager.canScrollVertically() != isOrientationHelperVertical || - orientationHelper == null - ) { + if (layoutManager.canScrollVertically() != isOrientationHelperVertical || orientationHelper == null) { isOrientationHelperVertical = layoutManager.canScrollVertically() - orientationHelper = if (isOrientationHelperVertical) { + orientationHelper = if (isOrientationHelperVertical) OrientationHelper.createVerticalHelper(layoutManager) - } else { + else OrientationHelper.createHorizontalHelper(layoutManager) - } } val mOrientationHelper = this.orientationHelper ?: return null @@ -125,9 +118,12 @@ abstract class EndlessRecyclerOnScrollListener : RecyclerView.OnScrollListener { ?: throw RuntimeException("A LayoutManager is required") } + if (visibleThreshold == RecyclerView.NO_POSITION) { - visibleThreshold = findLastVisibleItemPosition(recyclerView) - - findFirstVisibleItemPosition(recyclerView) + visibleThreshold = + findLastVisibleItemPosition(recyclerView) - findFirstVisibleItemPosition( + recyclerView + ) } visibleItemCount = recyclerView.childCount @@ -141,9 +137,7 @@ abstract class EndlessRecyclerOnScrollListener : RecyclerView.OnScrollListener { } } - if (!isLoading && - totalItemCount - visibleItemCount <= firstVisibleItem + visibleThreshold - ) { + if (!isLoading && totalItemCount - visibleItemCount <= firstVisibleItem + visibleThreshold) { currentPage++ onLoadMore(currentPage) isLoading = true @@ -170,4 +164,4 @@ abstract class EndlessRecyclerOnScrollListener : RecyclerView.OnScrollListener { } abstract fun onLoadMore(currentPage: Int) -} +} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/view/epoxy/controller/CategoryCarouselController.kt b/app/src/main/java/com/aurora/store/view/epoxy/controller/CategoryCarouselController.kt index 0975afd97..87f8c4bb5 100644 --- a/app/src/main/java/com/aurora/store/view/epoxy/controller/CategoryCarouselController.kt +++ b/app/src/main/java/com/aurora/store/view/epoxy/controller/CategoryCarouselController.kt @@ -24,6 +24,6 @@ import com.aurora.gplayapi.data.models.StreamCluster class CategoryCarouselController(callbacks: Callbacks) : GenericCarouselController(callbacks) { override fun applyFilter(streamBundle: StreamCluster): Boolean { - return streamBundle.clusterAppList.isNotEmpty() // Filter empty clusters + return streamBundle.clusterAppList.isNotEmpty() //Filter empty clusters } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/view/epoxy/controller/DetailsCarouselController.kt b/app/src/main/java/com/aurora/store/view/epoxy/controller/DetailsCarouselController.kt new file mode 100644 index 000000000..299b2ae38 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/controller/DetailsCarouselController.kt @@ -0,0 +1,45 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.controller + +import com.aurora.gplayapi.data.models.StreamBundle +import com.aurora.store.view.epoxy.groups.CarouselModelGroup +import com.aurora.store.view.epoxy.groups.CarouselShimmerGroup + +class DetailsCarouselController(private val callbacks: Callbacks) : + GenericCarouselController(callbacks) { + + override fun buildModels(streamBundle: StreamBundle?) { + setFilterDuplicates(true) + if (streamBundle == null) { + for (i in 1..2) { + add( + CarouselShimmerGroup() + .id(i) + ) + } + } else { + streamBundle.streamClusters.values.filter { applyFilter(it) } + .forEach { streamCluster -> + add(CarouselModelGroup(streamCluster, callbacks)) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/view/epoxy/controller/DeveloperCarouselController.kt b/app/src/main/java/com/aurora/store/view/epoxy/controller/DeveloperCarouselController.kt new file mode 100644 index 000000000..cf5b1c697 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/controller/DeveloperCarouselController.kt @@ -0,0 +1,54 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.controller + +import com.aurora.gplayapi.data.models.StreamBundle +import com.aurora.gplayapi.data.models.StreamCluster +import com.aurora.store.view.epoxy.groups.CarouselShimmerGroup +import com.aurora.store.view.epoxy.groups.DeveloperModelGroup + +open class DeveloperCarouselController(private val callbacks: Callbacks) : + GenericCarouselController(callbacks) { + + override fun applyFilter(streamBundle: StreamCluster): Boolean { + return streamBundle.clusterTitle.isNotBlank() //Filter noisy cluster + && streamBundle.clusterAppList.isNotEmpty() //Filter empty clusters + } + + override fun buildModels(streamBundle: StreamBundle?) { + setFilterDuplicates(true) + if (streamBundle == null) { + for (i in 1..2) { + add( + CarouselShimmerGroup() + .id(i) + ) + } + } else { + streamBundle + .streamClusters + .values + .filter { applyFilter(it) } + .forEach { streamCluster -> + add(DeveloperModelGroup(streamCluster, callbacks)) + } + } + } +} \ No newline at end of file diff --git a/app/src/preload/java/com/aurora/store/data/receiver/InstallerStatusReceiver.kt b/app/src/main/java/com/aurora/store/view/epoxy/controller/EarlyAccessCarouselController.kt similarity index 63% rename from app/src/preload/java/com/aurora/store/data/receiver/InstallerStatusReceiver.kt rename to app/src/main/java/com/aurora/store/view/epoxy/controller/EarlyAccessCarouselController.kt index 440a1070d..cf93bccf8 100644 --- a/app/src/preload/java/com/aurora/store/data/receiver/InstallerStatusReceiver.kt +++ b/app/src/main/java/com/aurora/store/view/epoxy/controller/EarlyAccessCarouselController.kt @@ -16,9 +16,15 @@ * along with Aurora Store. If not, see . * */ -package com.aurora.store.data.receiver -import dagger.hilt.android.AndroidEntryPoint +package com.aurora.store.view.epoxy.controller -@AndroidEntryPoint -class InstallerStatusReceiver : BaseInstallerStatusReceiver() +import com.aurora.gplayapi.data.models.StreamCluster + +class EarlyAccessCarouselController(callbacks: Callbacks) : GenericCarouselController(callbacks) { + + override fun applyFilter(streamBundle: StreamCluster): Boolean { + return streamBundle.clusterTitle.isNotBlank() //Filter noisy cluster + && streamBundle.clusterAppList.isNotEmpty() //Filter empty clusters + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/view/epoxy/controller/GenericCarouselController.kt b/app/src/main/java/com/aurora/store/view/epoxy/controller/GenericCarouselController.kt index f9d7ccb16..17e723a8f 100644 --- a/app/src/main/java/com/aurora/store/view/epoxy/controller/GenericCarouselController.kt +++ b/app/src/main/java/com/aurora/store/view/epoxy/controller/GenericCarouselController.kt @@ -41,11 +41,9 @@ open class GenericCarouselController(private val callbacks: Callbacks) : } open fun applyFilter(streamBundle: StreamCluster): Boolean { - return streamBundle.clusterTitle.isNotBlank() && - // Filter noisy cluster - streamBundle.clusterAppList.isNotEmpty() && - // Filter empty clusters - streamBundle.clusterAppList.count() > 1 // Filter clusters with single apps (promotions) + return streamBundle.clusterTitle.isNotBlank() //Filter noisy cluster + && streamBundle.clusterAppList.isNotEmpty() //Filter empty clusters + && streamBundle.clusterAppList.count() > 1 //Filter clusters with single apps (mostly promotions) } override fun buildModels(streamBundle: StreamBundle?) { @@ -81,6 +79,7 @@ open class GenericCarouselController(private val callbacks: Callbacks) : ) } } + } else { streamBundle .streamClusters @@ -89,13 +88,13 @@ open class GenericCarouselController(private val callbacks: Callbacks) : .forEach { streamCluster -> add(CarouselModelGroup(streamCluster, callbacks)) } + } - if (streamBundle.hasNext()) { + if (streamBundle.hasNext()) add( CarouselShimmerGroup() .id("progress") ) - } } } } diff --git a/app/src/main/java/com/aurora/store/view/epoxy/groups/CarouselHorizontal.kt b/app/src/main/java/com/aurora/store/view/epoxy/groups/CarouselHorizontal.kt index 8a57ae393..bd77894a2 100644 --- a/app/src/main/java/com/aurora/store/view/epoxy/groups/CarouselHorizontal.kt +++ b/app/src/main/java/com/aurora/store/view/epoxy/groups/CarouselHorizontal.kt @@ -28,8 +28,9 @@ import com.airbnb.epoxy.ModelView @ModelView(saveViewState = true, autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT) class CarouselHorizontal(context: Context?) : Carousel(context) { - override fun createLayoutManager(): LayoutManager = - LinearLayoutManager(context, RecyclerView.HORIZONTAL, false) + override fun createLayoutManager(): LayoutManager { + return LinearLayoutManager(context, RecyclerView.HORIZONTAL, false) + } override fun getSnapHelperFactory(): Nothing? = null -} +} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/view/epoxy/groups/CarouselModelGroup.kt b/app/src/main/java/com/aurora/store/view/epoxy/groups/CarouselModelGroup.kt index ced922487..18fcb3c30 100644 --- a/app/src/main/java/com/aurora/store/view/epoxy/groups/CarouselModelGroup.kt +++ b/app/src/main/java/com/aurora/store/view/epoxy/groups/CarouselModelGroup.kt @@ -34,8 +34,7 @@ class CarouselModelGroup( callbacks: GenericCarouselController.Callbacks ) : EpoxyModelGroup( - R.layout.model_carousel_group, - buildModels( + R.layout.model_carousel_group, buildModels( streamCluster, callbacks ) diff --git a/app/src/main/java/com/aurora/store/view/epoxy/groups/CarouselShimmerGroup.kt b/app/src/main/java/com/aurora/store/view/epoxy/groups/CarouselShimmerGroup.kt index 8429a64f1..9eb743385 100644 --- a/app/src/main/java/com/aurora/store/view/epoxy/groups/CarouselShimmerGroup.kt +++ b/app/src/main/java/com/aurora/store/view/epoxy/groups/CarouselShimmerGroup.kt @@ -28,8 +28,7 @@ import java.util.UUID class CarouselShimmerGroup : EpoxyModelGroup( - R.layout.model_carousel_group, - buildModels() + R.layout.model_carousel_group, buildModels() ) { companion object { private fun buildModels(): List> { @@ -51,7 +50,7 @@ class CarouselShimmerGroup : models.add( CarouselHorizontalModel_() - .id("cluster_$idPrefix") + .id("cluster_${idPrefix}") .models(clusterViewModels) ) return models diff --git a/app/src/main/java/com/aurora/store/view/epoxy/groups/DeveloperModelGroup.kt b/app/src/main/java/com/aurora/store/view/epoxy/groups/DeveloperModelGroup.kt new file mode 100644 index 000000000..6e4950aa3 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/groups/DeveloperModelGroup.kt @@ -0,0 +1,128 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.groups + +import android.util.Log +import com.airbnb.epoxy.EpoxyModel +import com.airbnb.epoxy.EpoxyModelGroup +import com.aurora.gplayapi.data.models.StreamCluster +import com.aurora.store.R +import com.aurora.store.view.epoxy.controller.GenericCarouselController +import com.aurora.store.view.epoxy.views.HeaderViewModel_ +import com.aurora.store.view.epoxy.views.app.AppListViewModel_ +import com.aurora.store.view.epoxy.views.app.AppViewModel_ +import com.aurora.store.view.epoxy.views.details.ScreenshotViewModel_ + +class DeveloperModelGroup( + streamCluster: StreamCluster, + callbacks: GenericCarouselController.Callbacks +) : + EpoxyModelGroup( + R.layout.model_developer_carousel_group, buildModels( + streamCluster, + callbacks + ) + ) { + companion object { + private const val TAG = "DeveloperModelGroup" + + private fun buildModels( + streamCluster: StreamCluster, + callbacks: GenericCarouselController.Callbacks + ): List> { + val models = ArrayList>() + val clusterViewModels = mutableListOf>() + val screenshotsViewModels = mutableListOf>() + + val idPrefix = streamCluster.id + + models.add( + HeaderViewModel_() + .id("${idPrefix}_header") + .title(streamCluster.clusterTitle) + .browseUrl(streamCluster.clusterBrowseUrl) + .click { _ -> + callbacks.onHeaderClicked(streamCluster) + } + ) + + if (streamCluster.clusterAppList.size == 1) { + val app = streamCluster.clusterAppList[0] + + for (artwork in app.screenshots) { + screenshotsViewModels.add( + ScreenshotViewModel_() + .id(artwork.url) + .artwork(artwork) + ) + } + + clusterViewModels.add( + AppListViewModel_() + .id(app.id) + .app(app) + .click { _ -> + callbacks.onAppClick(app) + } + ) + } else { + for (app in streamCluster.clusterAppList) { + clusterViewModels.add( + AppViewModel_() + .id(app.id) + .app(app) + .click { _ -> + callbacks.onAppClick(app) + } + .longClick { _ -> + callbacks.onAppLongClick(app) + false + } + .onBind { _, _, position -> + val itemCount = clusterViewModels.count() + if (itemCount >= 2) { + if (position == clusterViewModels.count() - 2) { + callbacks.onClusterScrolled(streamCluster) + Log.i(TAG, "Cluster ${streamCluster.clusterTitle} Scrolled") + } + } + } + ) + } + } + + if (screenshotsViewModels.isNotEmpty()) { + models.add( + CarouselHorizontalModel_() + .id("${idPrefix}_screenshots") + .models(screenshotsViewModels) + ) + } + + models.add( + CarouselHorizontalModel_() + .id("${idPrefix}_cluster") + .models(clusterViewModels) + ) + + return models + } + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/AppProgressView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/AppProgressView.kt index 765baa871..841fe7565 100644 --- a/app/src/main/java/com/aurora/store/view/epoxy/views/AppProgressView.kt +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/AppProgressView.kt @@ -29,4 +29,4 @@ class AppProgressView @JvmOverloads constructor( context: Context?, attrs: AttributeSet? = null, defStyleAttr: Int = 0 -) : BaseView(context, attrs, defStyleAttr) +) : BaseView(context, attrs, defStyleAttr) \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/BaseView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/BaseView.kt index 8f6b86fd4..3fc5573e1 100644 --- a/app/src/main/java/com/aurora/store/view/epoxy/views/BaseView.kt +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/BaseView.kt @@ -38,8 +38,8 @@ abstract class BaseView : RelativeLayout { @Suppress("UNCHECKED_CAST") private fun inflateViewBinding(inflater: LayoutInflater): ViewBindingType { - val type = (javaClass.genericSuperclass as ParameterizedType) - .actualTypeArguments[0] as Class + val type = + (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class val method = type.getMethod( "inflate", LayoutInflater::class.java, @@ -48,4 +48,4 @@ abstract class BaseView : RelativeLayout { ) return method.invoke(null, inflater, this, false) as ViewBindingType } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/BlackListView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/BlackListView.kt new file mode 100644 index 000000000..c16ea3ab6 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/BlackListView.kt @@ -0,0 +1,80 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views + +import android.content.Context +import android.content.pm.PackageInfo +import android.util.AttributeSet +import android.widget.CompoundButton +import androidx.core.content.pm.PackageInfoCompat +import coil3.load +import coil3.request.placeholder +import coil3.request.transformations +import coil3.transform.RoundedCornersTransformation +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.store.R +import com.aurora.store.databinding.ViewBlackBinding +import com.aurora.store.util.PackageUtil + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class BlackListView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp(options = [ModelProp.Option.IgnoreRequireHashCode]) + fun packageInfo(packageInfo: PackageInfo) { + val appInfo = packageInfo.applicationInfo!! + binding.imgIcon.load(PackageUtil.getIconForPackage(context, appInfo.packageName)) { + placeholder(R.drawable.bg_placeholder) + transformations(RoundedCornersTransformation(25F)) + } + + binding.txtLine1.text = appInfo.loadLabel(context.packageManager) + binding.txtLine2.text = appInfo.packageName + binding.txtLine3.text = ("${packageInfo.versionName}.${PackageInfoCompat.getLongVersionCode(packageInfo)}") + } + + @ModelProp + fun markChecked(isChecked: Boolean) { + binding.checkbox.isChecked = isChecked + } + + @CallbackProp + fun checked(onCheckedChangeListener: CompoundButton.OnCheckedChangeListener?) { + binding.checkbox.setOnCheckedChangeListener(onCheckedChangeListener) + } + + @CallbackProp + fun click(onClickListener: OnClickListener?) { + binding.root.setOnClickListener(onClickListener) + } + + @CallbackProp + fun longClick(onClickListener: OnLongClickListener?) { + binding.root.setOnLongClickListener(onClickListener) + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/DispenserView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/DispenserView.kt new file mode 100644 index 000000000..a0735ad69 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/DispenserView.kt @@ -0,0 +1,34 @@ +package com.aurora.store.view.epoxy.views + +import android.content.Context +import android.util.AttributeSet +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.store.databinding.ViewDispenserBinding + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class DispenserView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp + fun url(url: String) { + binding.url.text = url + } + + @CallbackProp + fun copy(onClickListener: OnClickListener?) { + binding.url.setOnClickListener(onClickListener) + } + + @CallbackProp + fun clear(onClickListener: OnClickListener?) { + binding.btnAction.setOnClickListener(onClickListener) + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/DownloadView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/DownloadView.kt new file mode 100644 index 000000000..100a46b96 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/DownloadView.kt @@ -0,0 +1,91 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views + +import android.content.Context +import android.util.AttributeSet +import coil3.load +import coil3.request.placeholder +import coil3.request.transformations +import coil3.transform.RoundedCornersTransformation +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.store.R +import com.aurora.store.data.model.DownloadStatus +import com.aurora.store.data.room.download.Download +import com.aurora.store.databinding.ViewDownloadBinding +import com.aurora.store.util.CommonUtil.getDownloadSpeedString +import com.aurora.store.util.CommonUtil.getETAString + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class DownloadView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp + fun download(download: Download) { + binding.imgDownload.load(download.iconURL) { + placeholder(R.drawable.bg_placeholder) + transformations(RoundedCornersTransformation(32F)) + } + binding.txtTitle.text = download.displayName + binding.txtStatus.text = context.getString(download.downloadStatus.localized) + + binding.progressDownload.apply { + progress = download.progress + isIndeterminate = download.progress <= 0 && !download.isFinished + } + binding.txtProgress.text = ("${download.progress}%") + + binding.txtEta.text = getETAString(context, download.timeRemaining) + binding.txtSpeed.text = getDownloadSpeedString( + context, + download.speed + ) + + when (download.downloadStatus) { + DownloadStatus.DOWNLOADING, DownloadStatus.QUEUED -> { + binding.txtSpeed.visibility = VISIBLE + binding.txtEta.visibility = VISIBLE + } + + else -> { + binding.txtSpeed.visibility = INVISIBLE + binding.txtEta.visibility = INVISIBLE + } + } + } + + @CallbackProp + fun click(onClickListener: OnClickListener?) { + binding.root.setOnClickListener(onClickListener) + } + + @CallbackProp + fun longClick(onClickListener: OnLongClickListener?) { + binding.root.setOnLongClickListener(onClickListener) + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/FavouriteView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/FavouriteView.kt new file mode 100644 index 000000000..96fd8ef5d --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/FavouriteView.kt @@ -0,0 +1,65 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views + +import android.content.Context +import android.util.AttributeSet +import coil3.load +import coil3.request.placeholder +import coil3.request.transformations +import coil3.transform.RoundedCornersTransformation +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.store.R +import com.aurora.store.data.room.favourite.Favourite +import com.aurora.store.databinding.ViewFavBinding + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class FavouriteView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp + fun favourite(favourite: Favourite) { + binding.imgIcon.load(favourite.iconURL) { + placeholder(R.drawable.bg_placeholder) + transformations(RoundedCornersTransformation(25F)) + } + + binding.txtLine1.text = favourite.displayName + binding.txtLine2.text = favourite.packageName + } + + @CallbackProp + fun onClick(onClickListener: OnClickListener?) { + binding.root.setOnClickListener(onClickListener) + } + + @CallbackProp + fun onFavourite(onClickListener: OnClickListener?) { + binding.btnFavourite.setOnClickListener(onClickListener) + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/HeaderView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/HeaderView.kt index 1d8b097d1..aa5d23bc4 100644 --- a/app/src/main/java/com/aurora/store/view/epoxy/views/HeaderView.kt +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/HeaderView.kt @@ -45,9 +45,8 @@ class HeaderView @JvmOverloads constructor( @JvmOverloads @ModelProp fun browseUrl(browseUrl: String? = String()) { - if (browseUrl.isNullOrEmpty()) { + if (browseUrl.isNullOrEmpty()) binding.imgAction.visibility = INVISIBLE - } } @CallbackProp diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/InstalledAppView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/InstalledAppView.kt new file mode 100644 index 000000000..efaa492c4 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/InstalledAppView.kt @@ -0,0 +1,66 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views + +import android.content.Context +import android.util.AttributeSet +import coil3.load +import coil3.request.placeholder +import coil3.request.transformations +import coil3.transform.RoundedCornersTransformation +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.store.R +import com.aurora.store.data.model.MinimalApp +import com.aurora.store.databinding.ViewPackageBinding + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class InstalledAppView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp(options = [ModelProp.Option.IgnoreRequireHashCode]) + fun packageInfo(app: MinimalApp) { + binding.imgIcon.load(app.icon) { + placeholder(R.drawable.bg_placeholder) + transformations(RoundedCornersTransformation(25F)) + } + + binding.txtLine1.text = app.displayName + binding.txtLine2.text = app.packageName + binding.txtLine3.text = ("${app.versionName} (${app.versionCode})") + } + + @CallbackProp + fun click(onClickListener: OnClickListener?) { + binding.root.setOnClickListener(onClickListener) + } + + @CallbackProp + fun longClick(onClickListener: OnLongClickListener?) { + binding.root.setOnLongClickListener(onClickListener) + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/SearchSuggestionView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/SearchSuggestionView.kt new file mode 100644 index 000000000..df12d8c7c --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/SearchSuggestionView.kt @@ -0,0 +1,72 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views + +import android.content.Context +import android.util.AttributeSet +import androidx.core.content.ContextCompat +import coil3.load +import coil3.request.transformations +import coil3.transform.RoundedCornersTransformation +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.gplayapi.SearchSuggestEntry +import com.aurora.store.R +import com.aurora.store.databinding.ViewSearchSuggestionBinding + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class SearchSuggestionView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp + fun entry(searchSuggestEntry: SearchSuggestEntry) { + if (searchSuggestEntry.hasImageContainer()) { + binding.img.load(searchSuggestEntry.imageContainer.imageUrl) { + transformations(RoundedCornersTransformation(8F)) + } + } else { + binding.img.setImageDrawable( + ContextCompat.getDrawable( + context, + R.drawable.ic_search_suggestion + ) + ) + } + + binding.txtTitle.text = searchSuggestEntry.title + } + + @CallbackProp + fun click(onClickListener: OnClickListener?) { + binding.root.setOnClickListener(onClickListener) + } + + @CallbackProp + fun action(onClickListener: OnClickListener?) { + binding.action.setOnClickListener(onClickListener) + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/TextDividerView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/TextDividerView.kt new file mode 100644 index 000000000..1317b5465 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/TextDividerView.kt @@ -0,0 +1,42 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views + +import android.content.Context +import android.util.AttributeSet +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.store.databinding.ViewTextDividerBinding + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class TextDividerView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp + fun title(title: String) { + binding.txtTitle.text = title + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/UpdateHeaderView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/UpdateHeaderView.kt index 2f9607652..8faaf1a90 100644 --- a/app/src/main/java/com/aurora/store/view/epoxy/views/UpdateHeaderView.kt +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/UpdateHeaderView.kt @@ -27,6 +27,7 @@ import com.airbnb.epoxy.ModelView import com.airbnb.epoxy.OnViewRecycled import com.aurora.store.databinding.ViewHeaderUpdateBinding + @ModelView( autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, baseModelClass = BaseModel::class diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/app/AppListView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/app/AppListView.kt index 105026465..0664ea50f 100644 --- a/app/src/main/java/com/aurora/store/view/epoxy/views/app/AppListView.kt +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/app/AppListView.kt @@ -60,20 +60,17 @@ class AppListView @JvmOverloads constructor( extras.add(if (app.size > 0) CommonUtil.addSiPrefix(app.size) else app.downloadString) extras.add("${app.labeledRating}★") extras.add( - if (app.isFree) { + if (app.isFree) ContextCompat.getString(context, R.string.details_free) - } else { + else ContextCompat.getString(context, R.string.details_paid) - } ) - if (app.containsAds) { + if (app.containsAds) extras.add(ContextCompat.getString(context, R.string.details_contains_ads)) - } - if (app.dependencies.dependentPackages.isNotEmpty()) { + if (app.dependencies.dependentPackages.isNotEmpty()) extras.add(ContextCompat.getString(context, R.string.details_gsf_dependent)) - } binding.txtLine3.text = extras.joinToString(separator = " • ") } diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/app/AppUpdateView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/app/AppUpdateView.kt index 693f67ca4..f29244cc3 100644 --- a/app/src/main/java/com/aurora/store/view/epoxy/views/app/AppUpdateView.kt +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/app/AppUpdateView.kt @@ -76,15 +76,14 @@ class AppUpdateView @JvmOverloads constructor( binding.txtLine2.text = developerName binding.txtLine3.text = ("${CommonUtil.addSiPrefix(size)} • $updatedOn") - binding.txtLine4.text = ("$versionName ($versionCode)") - binding.txtChangelog.text = if (changelog.isNotEmpty()) { + binding.txtLine4.text = ("$versionName (${versionCode})") + binding.txtChangelog.text = if (changelog.isNotEmpty()) HtmlCompat.fromHtml( changelog, HtmlCompat.FROM_HTML_OPTION_USE_CSS_COLORS ) - } else { + else context.getString(R.string.details_changelog_unavailable) - } binding.headerIndicator.setOnClickListener { if (binding.cardChangelog.isVisible) { @@ -103,8 +102,8 @@ class AppUpdateView @JvmOverloads constructor( @ModelProp fun download(download: Download?) { if (download != null) { - binding.btnAction.updateState(download.status) - when (download.status) { + binding.btnAction.updateState(download.downloadStatus) + when (download.downloadStatus) { DownloadStatus.VERIFYING, DownloadStatus.QUEUED -> { binding.progressDownload.isIndeterminate = true @@ -163,13 +162,11 @@ class AppUpdateView @JvmOverloads constructor( val isDownloadVisible = binding.progressDownload.isShown // Avoids flickering when the download is in progress - if (isDownloadVisible && scaleFactor != 1f) { + if (isDownloadVisible && scaleFactor != 1f) return - } - if (!isDownloadVisible && scaleFactor == 1f) { + if (!isDownloadVisible && scaleFactor == 1f) return - } if (scaleFactor == 1f) { binding.progressDownload.invisible() @@ -193,11 +190,10 @@ class AppUpdateView @JvmOverloads constructor( iconDrawable?.let { binding.imgIcon.load(it) { transformations( - if (scaleFactor == 1f) { + if (scaleFactor == 1f) cornersTransformation - } else { + else CircleCropTransformation() - } ) } } diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/app/AppView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/app/AppView.kt index 5ea989447..c78e23492 100644 --- a/app/src/main/java/com/aurora/store/view/epoxy/views/app/AppView.kt +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/app/AppView.kt @@ -53,11 +53,10 @@ class AppView @JvmOverloads constructor( transformations(RoundedCornersTransformation(32F)) } - if (app.size > 0) { + if (app.size > 0) binding.txtSize.text = CommonUtil.addSiPrefix(app.size) - } else { + else binding.txtSize.text = app.downloadString - } } @CallbackProp diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/app/NoAppAltView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/app/NoAppAltView.kt new file mode 100644 index 000000000..0575683a9 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/app/NoAppAltView.kt @@ -0,0 +1,45 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views.app + +import android.content.Context +import android.util.AttributeSet +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.store.databinding.ViewNoAppAltBinding +import com.aurora.store.view.epoxy.views.BaseModel +import com.aurora.store.view.epoxy.views.BaseView + + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class NoAppAltView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp + fun message(message: String) { + binding.txtMsg.text = message + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/details/AppDependentView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/details/AppDependentView.kt new file mode 100644 index 000000000..fd5db8c94 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/details/AppDependentView.kt @@ -0,0 +1,65 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views.details + +import android.content.Context +import android.util.AttributeSet +import coil3.load +import coil3.request.placeholder +import coil3.request.transformations +import coil3.transform.RoundedCornersTransformation +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.gplayapi.data.models.App +import com.aurora.store.R +import com.aurora.store.databinding.ViewAppDependentBinding +import com.aurora.store.view.epoxy.views.BaseModel +import com.aurora.store.view.epoxy.views.BaseView + +@ModelView( + autoLayout = ModelView.Size.WRAP_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class AppDependentView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp + fun app(app: App) { + binding.txtName.text = app.displayName + binding.imgIcon.load(app.iconArtwork.url) { + placeholder(R.drawable.bg_placeholder) + transformations(RoundedCornersTransformation(32F)) + } + } + + @CallbackProp + fun click(onClickListener: OnClickListener?) { + binding.root.setOnClickListener(onClickListener) + } + + @CallbackProp + fun longClick(onClickListener: OnLongClickListener?) { + binding.root.setOnLongClickListener(onClickListener) + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/details/BadgeView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/details/BadgeView.kt new file mode 100644 index 000000000..8e4fa9d21 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/details/BadgeView.kt @@ -0,0 +1,58 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views.details + +import android.content.Context +import android.util.AttributeSet +import coil3.load +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.gplayapi.data.models.details.Badge +import com.aurora.store.databinding.ViewBadgeBinding +import com.aurora.store.view.epoxy.views.BaseModel +import com.aurora.store.view.epoxy.views.BaseView + +@ModelView( + autoLayout = ModelView.Size.WRAP_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class BadgeView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp + fun badge(badge: Badge) { + if (badge.textMajor.isEmpty()) { + if (badge.textMinor.isEmpty()) { + binding.txt.text = badge.textDescription + } else { + binding.txt.text = badge.textMinor + } + } else { + binding.txt.text = badge.textMajor + } + + badge.artwork?.let { + binding.img.load(it.url) + } + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/details/ExodusView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/details/ExodusView.kt new file mode 100644 index 000000000..8bdc12182 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/details/ExodusView.kt @@ -0,0 +1,58 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views.details + +import android.content.Context +import android.util.AttributeSet +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.airbnb.epoxy.OnViewRecycled +import com.aurora.store.data.model.ExodusTracker +import com.aurora.store.databinding.ViewExodusBinding +import com.aurora.store.view.epoxy.views.BaseModel +import com.aurora.store.view.epoxy.views.BaseView + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class ExodusView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp + fun tracker(report: ExodusTracker) { + binding.txtTitle.text = report.name + binding.txtSubtitle.text = report.signature + binding.txtDescription.text = report.date + } + + @CallbackProp + fun click(onClickListener: OnClickListener?) { + binding.root.setOnClickListener(onClickListener) + } + + @OnViewRecycled + fun clear() { + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/details/FileView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/details/FileView.kt new file mode 100644 index 000000000..5b23f8686 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/details/FileView.kt @@ -0,0 +1,47 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views.details + +import android.content.Context +import android.util.AttributeSet +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.gplayapi.data.models.File +import com.aurora.store.databinding.ViewFileBinding +import com.aurora.store.util.CommonUtil +import com.aurora.store.view.epoxy.views.BaseModel +import com.aurora.store.view.epoxy.views.BaseView + +@ModelView( + autoLayout = ModelView.Size.WRAP_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class FileView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp + fun file(file: File) { + binding.line1.text = file.name + binding.line2.text = CommonUtil.addSiPrefix(file.size) + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/details/InfoView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/details/InfoView.kt new file mode 100644 index 000000000..13fa11e2d --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/details/InfoView.kt @@ -0,0 +1,62 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views.details + +import android.content.Context +import android.util.AttributeSet +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.airbnb.epoxy.OnViewRecycled +import com.aurora.store.databinding.ViewInfoBinding +import com.aurora.store.view.epoxy.views.BaseModel +import com.aurora.store.view.epoxy.views.BaseView +import java.util.Locale + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class InfoView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp(options = [ModelProp.Option.IgnoreRequireHashCode]) + fun badge(info: Map.Entry) { + binding.txtTitle.text = info.key + .replace("_", " ") + .lowercase(Locale.getDefault()) + .replaceFirstChar { + if (it.isLowerCase()) { + it.titlecase(Locale.getDefault()) + } else { + it.toString() + } + } + binding.txtSubtitle.text = info.value + } + + @OnViewRecycled + fun clear() { + binding.txtTitle.text = null + binding.txtSubtitle.text = null + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/details/LargeScreenshotView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/details/LargeScreenshotView.kt new file mode 100644 index 000000000..a3f6e6815 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/details/LargeScreenshotView.kt @@ -0,0 +1,52 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views.details + +import android.content.Context +import android.content.res.Resources +import android.util.AttributeSet +import coil3.load +import coil3.request.placeholder +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.gplayapi.data.models.Artwork +import com.aurora.store.R +import com.aurora.store.databinding.ViewScreenshotLargeBinding +import com.aurora.store.view.epoxy.views.BaseModel +import com.aurora.store.view.epoxy.views.BaseView + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_MATCH_HEIGHT, + baseModelClass = BaseModel::class +) +class LargeScreenshotView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp + fun artwork(artwork: Artwork) { + val displayMetrics = Resources.getSystem().displayMetrics + binding.img.load("${artwork.url}=rw-w${displayMetrics.widthPixels}-v1-e15") { + placeholder(R.drawable.bg_placeholder) + } + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/details/MiniScreenshotView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/details/MiniScreenshotView.kt new file mode 100644 index 000000000..9d5a4fba7 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/details/MiniScreenshotView.kt @@ -0,0 +1,102 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views.details + +import android.content.Context +import android.util.AttributeSet +import coil3.load +import coil3.request.placeholder +import coil3.request.transformations +import coil3.transform.RoundedCornersTransformation +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.extensions.px +import com.aurora.gplayapi.data.models.Artwork +import com.aurora.store.R +import com.aurora.store.databinding.ViewScreenshotMiniBinding +import com.aurora.store.view.epoxy.views.BaseModel +import com.aurora.store.view.epoxy.views.BaseView + +@ModelView( + autoLayout = ModelView.Size.WRAP_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class MiniScreenshotView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + private var position: Int = 0 + + interface ScreenshotCallback { + fun onClick(position: Int = 0) + } + + @ModelProp + fun position(pos: Int) { + position = pos + } + + @ModelProp + fun artwork(artwork: Artwork) { + normalizeSize(artwork) + binding.img.load("${artwork.url}=rw-w480-v1-e15") { + placeholder(R.drawable.bg_rounded) + transformations(RoundedCornersTransformation(8.px.toFloat())) + } + } + + private fun normalizeSize(artwork: Artwork) { + if (artwork.height != 0 && artwork.width != 0) { + + val artworkHeight = artwork.height + val artworkWidth = artwork.width + + val normalizedHeight: Float + val normalizedWidth: Float + + when { + artworkHeight == artworkWidth -> { + normalizedHeight = 120f + normalizedWidth = 120f + } + + else -> { + val factor = artworkHeight / 120f + normalizedHeight = 120f + normalizedWidth = (artworkWidth / factor) + } + } + + binding.img.layoutParams.height = normalizedHeight.px.toInt() + binding.img.layoutParams.width = normalizedWidth.px.toInt() + binding.img.requestLayout() + } + } + + @CallbackProp + fun callback(screenshotCallback: ScreenshotCallback?) { + binding.img.setOnClickListener { + screenshotCallback?.onClick(position) + } + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/details/MoreBadgeView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/details/MoreBadgeView.kt new file mode 100644 index 000000000..17e41fe6d --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/details/MoreBadgeView.kt @@ -0,0 +1,69 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views.details + +import android.content.Context +import android.util.AttributeSet +import androidx.core.text.HtmlCompat +import coil3.load +import coil3.request.placeholder +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.gplayapi.data.models.details.Badge +import com.aurora.store.R +import com.aurora.store.databinding.ViewMoreBadgeBinding +import com.aurora.store.view.epoxy.views.BaseModel +import com.aurora.store.view.epoxy.views.BaseView + +@ModelView( + autoLayout = ModelView.Size.WRAP_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class MoreBadgeView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp + fun badge(badge: Badge) { + binding.line1.text = badge.textMajor + + badge.textMinorHtml?.let { + if (it.isNotEmpty()) { + binding.line2.text = HtmlCompat.fromHtml(it, HtmlCompat.FROM_HTML_MODE_COMPACT) + } else { + binding.line2.text = badge.textMinor + } + } + + badge.textDescription?.let { + if (it.isNotEmpty()) { + binding.line2.text = it + } + } + + badge.artwork?.let { + binding.img.load(it.url) { + placeholder(R.drawable.ic_arrow_right) + } + } + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/details/ReviewView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/details/ReviewView.kt new file mode 100644 index 000000000..59f1fc73d --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/details/ReviewView.kt @@ -0,0 +1,71 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views.details + +import android.content.Context +import android.util.AttributeSet +import coil3.load +import coil3.request.placeholder +import coil3.request.transformations +import coil3.transform.RoundedCornersTransformation +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.extensions.toDate +import com.aurora.gplayapi.data.models.Review +import com.aurora.store.R +import com.aurora.store.databinding.ViewReviewBinding +import com.aurora.store.view.epoxy.views.BaseModel +import com.aurora.store.view.epoxy.views.BaseView + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class ReviewView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp + fun review(review: Review) { + binding.txtAuthor.text = review.userName + binding.txtTime.text = ("${review.timeStamp.toDate()} • v${review.appVersion}") + binding.txtComment.text = review.comment + + binding.img.load(review.userPhotoUrl) { + placeholder(R.drawable.bg_placeholder) + transformations(RoundedCornersTransformation(32F)) + } + + binding.rating.rating = review.rating.toFloat() + } + + @CallbackProp + fun click(onClickListener: OnClickListener?) { + binding.root.setOnClickListener(onClickListener) + } + + @CallbackProp + fun longClick(onClickListener: OnLongClickListener?) { + binding.root.setOnLongClickListener(onClickListener) + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/details/ScreenshotView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/details/ScreenshotView.kt new file mode 100644 index 000000000..cad000ac4 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/details/ScreenshotView.kt @@ -0,0 +1,102 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views.details + +import android.content.Context +import android.util.AttributeSet +import coil3.load +import coil3.request.placeholder +import coil3.request.transformations +import coil3.transform.RoundedCornersTransformation +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.extensions.px +import com.aurora.gplayapi.data.models.Artwork +import com.aurora.store.R +import com.aurora.store.databinding.ViewScreenshotBinding +import com.aurora.store.view.epoxy.views.BaseModel +import com.aurora.store.view.epoxy.views.BaseView + +@ModelView( + autoLayout = ModelView.Size.WRAP_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class ScreenshotView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + private var position: Int = 0 + + interface ScreenshotCallback { + fun onClick(position: Int = 0) + } + + @ModelProp + fun position(pos: Int) { + position = pos + } + + @ModelProp + fun artwork(artwork: Artwork) { + normalizeSize(artwork) + binding.img.load("${artwork.url}=rw-w480-v1-e15") { + placeholder(R.drawable.bg_rounded) + transformations(RoundedCornersTransformation(8.px.toFloat())) + } + } + + private fun normalizeSize(artwork: Artwork) { + if (artwork.height != 0 && artwork.width != 0) { + + val artworkHeight = artwork.height + val artworkWidth = artwork.width + + val normalizedHeight: Float + val normalizedWidth: Float + + when { + artworkHeight == artworkWidth -> { + normalizedHeight = 192f + normalizedWidth = 192f + } + + else -> { + val factor = artworkHeight / 192f + normalizedHeight = 192f + normalizedWidth = (artworkWidth / factor) + } + } + + binding.img.layoutParams.height = normalizedHeight.px.toInt() + binding.img.layoutParams.width = normalizedWidth.px.toInt() + binding.img.requestLayout() + } + } + + @CallbackProp + fun callback(screenshotCallback: ScreenshotCallback?) { + binding.img.setOnClickListener { + screenshotCallback?.onClick(position) + } + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/preference/DashView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/preference/DashView.kt new file mode 100644 index 000000000..b49caa2fa --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/preference/DashView.kt @@ -0,0 +1,54 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views.preference + +import android.content.Context +import android.util.AttributeSet +import androidx.core.content.ContextCompat +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.store.data.model.Dash +import com.aurora.store.databinding.ViewDashBinding +import com.aurora.store.view.epoxy.views.BaseModel +import com.aurora.store.view.epoxy.views.BaseView + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class DashView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp + fun dash(dash: Dash) { + binding.line1.text = dash.title + binding.line2.text = dash.subtitle + binding.img.setImageDrawable(ContextCompat.getDrawable(context, dash.icon)) + } + + @CallbackProp + fun click(onClickListener: OnClickListener?) { + binding.root.setOnClickListener(onClickListener) + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/preference/DeviceView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/preference/DeviceView.kt new file mode 100644 index 000000000..3932c458e --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/preference/DeviceView.kt @@ -0,0 +1,65 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views.preference + +import android.content.Context +import android.util.AttributeSet +import android.widget.CompoundButton +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.store.R +import com.aurora.store.databinding.ViewDeviceBinding +import com.aurora.store.view.epoxy.views.BaseModel +import com.aurora.store.view.epoxy.views.BaseView +import java.util.Properties + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class DeviceView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp + fun properties(properties: Properties) { + binding.line1.text = properties.getProperty("UserReadableName") + binding.line2.text = resources.getString( + R.string.spoof_property, + properties.getProperty("Build.MANUFACTURER"), + properties.getProperty("Build.VERSION.SDK_INT") + ) + binding.line3.text = properties.getProperty("Platforms") + } + + @ModelProp + fun markChecked(isChecked: Boolean) { + binding.checkbox.isChecked = isChecked + binding.checkbox.isEnabled = !isChecked + } + + @CallbackProp + fun checked(onCheckedChangeListener: CompoundButton.OnCheckedChangeListener?) { + binding.checkbox.setOnCheckedChangeListener(onCheckedChangeListener) + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/preference/InstallerView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/preference/InstallerView.kt new file mode 100644 index 000000000..d3dd0e2a8 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/preference/InstallerView.kt @@ -0,0 +1,64 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views.preference + +import android.content.Context +import android.util.AttributeSet +import android.widget.CompoundButton +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.store.data.model.InstallerInfo +import com.aurora.store.databinding.ViewInstallerBinding +import com.aurora.store.view.epoxy.views.BaseModel +import com.aurora.store.view.epoxy.views.BaseView + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class InstallerView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp + fun installer(installer: InstallerInfo) { + binding.line1.text = context.getString(installer.title) + binding.line2.text = context.getString(installer.subtitle) + binding.line3.text = context.getString(installer.description) + } + + @ModelProp + fun markChecked(isChecked: Boolean) { + binding.radiobutton.isChecked = isChecked + } + + @CallbackProp + fun checked(onCheckedChangeListener: CompoundButton.OnCheckedChangeListener?) { + binding.radiobutton.setOnCheckedChangeListener(onCheckedChangeListener) + } + + @CallbackProp + fun click(onClickListener: OnClickListener?) { + binding.root.setOnClickListener(onClickListener) + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/preference/LinkView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/preference/LinkView.kt new file mode 100644 index 000000000..2c5319b58 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/preference/LinkView.kt @@ -0,0 +1,64 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views.preference + +import android.content.Context +import android.util.AttributeSet +import coil3.load +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.extensions.hide +import com.aurora.extensions.show +import com.aurora.store.data.model.Link +import com.aurora.store.databinding.ViewLinkBinding +import com.aurora.store.view.epoxy.views.BaseModel +import com.aurora.store.view.epoxy.views.BaseView + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class LinkView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp + fun link(link: Link) { + binding.line1.text = link.title + binding.line2.text = link.subtitle + + if (link.url.startsWith("http") || link.url.startsWith("upi")) { + binding.line3.hide() + } else { + binding.line3.show() + binding.line3.text = link.url + } + + binding.imgIcon.load(link.icon) + } + + @CallbackProp + fun click(onClickListener: OnClickListener?) { + binding.root.setOnClickListener(onClickListener) + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/preference/LocaleView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/preference/LocaleView.kt new file mode 100644 index 000000000..c8525f5b7 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/preference/LocaleView.kt @@ -0,0 +1,59 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views.preference + +import android.content.Context +import android.util.AttributeSet +import android.widget.CompoundButton +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.store.databinding.ViewLocaleBinding +import com.aurora.store.view.epoxy.views.BaseModel +import com.aurora.store.view.epoxy.views.BaseView +import java.util.Locale + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class LocaleView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp + fun locale(locale: Locale) { + binding.line1.text = locale.displayName + binding.line2.text = locale.getDisplayLanguage(locale) + } + + @ModelProp + fun markChecked(isChecked: Boolean) { + binding.checkbox.isChecked = isChecked + binding.checkbox.isEnabled = !isChecked + } + + @CallbackProp + fun checked(onCheckedChangeListener: CompoundButton.OnCheckedChangeListener?) { + binding.checkbox.setOnCheckedChangeListener(onCheckedChangeListener) + } +} diff --git a/app/src/main/java/com/aurora/store/view/epoxy/views/preference/PermissionView.kt b/app/src/main/java/com/aurora/store/view/epoxy/views/preference/PermissionView.kt new file mode 100644 index 000000000..4d5414aa1 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/epoxy/views/preference/PermissionView.kt @@ -0,0 +1,65 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.epoxy.views.preference + +import android.content.Context +import android.util.AttributeSet +import androidx.core.content.ContextCompat +import com.airbnb.epoxy.CallbackProp +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView +import com.aurora.store.R +import com.aurora.store.data.model.Permission +import com.aurora.store.databinding.ViewPermissionBinding +import com.aurora.store.view.epoxy.views.BaseModel +import com.aurora.store.view.epoxy.views.BaseView + +@ModelView( + autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT, + baseModelClass = BaseModel::class +) +class PermissionView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseView(context, attrs, defStyleAttr) { + + @ModelProp + fun permission(installer: Permission) { + binding.line1.text = installer.title + binding.line2.text = installer.subtitle + } + + @ModelProp + fun isGranted(granted: Boolean) { + if (granted) { + binding.btnAction.isEnabled = false + binding.btnAction.text = ContextCompat.getString(context, R.string.action_granted) + } else { + binding.btnAction.isEnabled = true + binding.btnAction.text = ContextCompat.getString(context, R.string.action_grant) + } + } + + @CallbackProp + fun click(onClickListener: OnClickListener?) { + binding.btnAction.setOnClickListener(onClickListener) + } +} diff --git a/app/src/main/java/com/aurora/store/view/theme/Theme.kt b/app/src/main/java/com/aurora/store/view/theme/Theme.kt new file mode 100644 index 000000000..bd47e756d --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/theme/Theme.kt @@ -0,0 +1,33 @@ +package com.aurora.store.view.theme + +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Typography +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.colorResource +import com.aurora.store.R + +@Composable +fun AuroraTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) { + val colorScheme = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + if (darkTheme) { + dynamicDarkColorScheme(LocalContext.current) + } else { + dynamicLightColorScheme(LocalContext.current) + } + } else { + if (darkTheme) { + darkColorScheme(primary = colorResource(id = R.color.colorAccent)) + } else { + lightColorScheme(primary = colorResource(id = R.color.colorAccent)) + } + } + + MaterialTheme(colorScheme = colorScheme, typography = Typography(), content = content) +} diff --git a/app/src/main/java/com/aurora/store/view/ui/about/AboutDialog.kt b/app/src/main/java/com/aurora/store/view/ui/about/AboutDialog.kt new file mode 100644 index 000000000..041d8a93d --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/ui/about/AboutDialog.kt @@ -0,0 +1,21 @@ +package com.aurora.store.view.ui.about + +import android.app.Dialog +import android.os.Bundle +import androidx.fragment.app.DialogFragment +import com.aurora.store.R +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class AboutDialog: DialogFragment() { + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return MaterialAlertDialogBuilder(requireContext()) + .setIcon(R.mipmap.ic_launcher) + .setTitle(R.string.about_aurora_store_title) + .setMessage(R.string.about_aurora_store_summary) + .setPositiveButton(getString(android.R.string.ok)) { _, _ -> dialog?.dismiss() } + .create() + } +} diff --git a/app/src/main/java/com/aurora/store/view/ui/about/AboutFragment.kt b/app/src/main/java/com/aurora/store/view/ui/about/AboutFragment.kt new file mode 100644 index 000000000..b089165d8 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/ui/about/AboutFragment.kt @@ -0,0 +1,114 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.ui.about + +import android.os.Bundle +import android.view.View +import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import coil3.load +import com.aurora.extensions.browse +import com.aurora.extensions.copyToClipBoard +import com.aurora.store.BuildConfig +import com.aurora.store.R +import com.aurora.store.data.model.Link +import com.aurora.store.databinding.FragmentAboutBinding +import com.aurora.store.view.epoxy.views.preference.LinkViewModel_ +import com.aurora.store.view.ui.commons.BaseFragment +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class AboutFragment : BaseFragment() { + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + // Toolbar + binding.toolbar.setNavigationOnClickListener { findNavController().navigateUp() } + + // About Details + binding.imgIcon.load(R.mipmap.ic_launcher) + binding.line2.text = view.context.getString( + R.string.version, + BuildConfig.VERSION_NAME, + BuildConfig.VERSION_CODE + ) + binding.line3.text = getString(R.string.made_with_love, String(Character.toChars(0x2764))) + + binding.epoxyRecycler.layoutManager = + LinearLayoutManager(view.context, RecyclerView.VERTICAL, false) + + updateController() + } + + private fun updateController() { + val linkURLS = resources.getStringArray(R.array.link_urls) + val linkTitles = resources.getStringArray(R.array.link_titles) + val linkSummary = resources.getStringArray(R.array.link_subtitle) + + val linkIcons = intArrayOf( + R.drawable.ic_menu_about, + R.drawable.ic_help, + R.drawable.ic_xda, + R.drawable.ic_telegram, + R.drawable.ic_gitlab, + R.drawable.ic_fdroid, + R.drawable.ic_bitcoin_btc, + R.drawable.ic_bitcoin_bch, + R.drawable.ic_ethereum_eth, + R.drawable.ic_bhim, + R.drawable.ic_paypal, + R.drawable.ic_libera_pay, + ) + + binding.epoxyRecycler.withModels { + for (i in linkURLS.indices) { + val link = Link( + id = i, + title = linkTitles[i], + subtitle = linkSummary[i], + url = linkURLS[i], + icon = linkIcons[i] + ) + add( + LinkViewModel_() + .id(i) + .link(link) + .click { _ -> + if (link.id == 0) { + findNavController().navigate(R.id.aboutDialog) + } else { + processUrl(link.url) + } + } + ) + } + } + } + + private fun processUrl(url: String) { + when { + url.startsWith("http") -> context?.browse(url) + url.startsWith("upi") -> context?.browse(url) + else -> context?.copyToClipBoard(url) + } + } +} diff --git a/app/src/main/java/com/aurora/store/view/ui/account/AccountFragment.kt b/app/src/main/java/com/aurora/store/view/ui/account/AccountFragment.kt new file mode 100644 index 000000000..f3f48979f --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/ui/account/AccountFragment.kt @@ -0,0 +1,74 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.ui.account + +import android.os.Bundle +import android.view.View +import androidx.fragment.app.viewModels +import androidx.navigation.fragment.findNavController +import coil3.load +import coil3.request.placeholder +import coil3.request.transformations +import coil3.transform.RoundedCornersTransformation +import com.aurora.Constants.URL_DISCLAIMER +import com.aurora.Constants.URL_LICENSE +import com.aurora.Constants.URL_TOS +import com.aurora.extensions.browse +import com.aurora.store.R +import com.aurora.store.databinding.FragmentAccountBinding +import com.aurora.store.view.ui.commons.BaseFragment +import com.aurora.store.viewmodel.account.AccountViewModel +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class AccountFragment : BaseFragment() { + + private val viewModel: AccountViewModel by viewModels() + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + // Toolbar + binding.toolbar.setNavigationOnClickListener { findNavController().navigateUp() } + + // Chips + view.context.apply { + binding.chipDisclaimer.setOnClickListener { browse(URL_DISCLAIMER) } + binding.chipLicense.setOnClickListener { browse(URL_LICENSE) } + binding.chipTos.setOnClickListener { browse(URL_TOS) } + } + + viewModel.authProvider.authData?.userProfile?.let { + val avatar = + if (viewModel.authProvider.isAnonymous) R.mipmap.ic_launcher else it.artwork.url + binding.imgAvatar.load(avatar) { + placeholder(R.drawable.bg_placeholder) + transformations(RoundedCornersTransformation(32F)) + } + binding.txtName.text = if (viewModel.authProvider.isAnonymous) "Anonymous" else it.name + binding.txtEmail.text = + if (viewModel.authProvider.isAnonymous) "anonymous@gmail.com" else it.email + } + + binding.btnLogout.addOnClickListener { + findNavController().navigate(R.id.logoutDialog) + } + } +} diff --git a/app/src/main/java/com/aurora/store/view/ui/account/GoogleFragment.kt b/app/src/main/java/com/aurora/store/view/ui/account/GoogleFragment.kt index 3ba18ccdb..c0a5e7603 100644 --- a/app/src/main/java/com/aurora/store/view/ui/account/GoogleFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/account/GoogleFragment.kt @@ -110,25 +110,29 @@ class GoogleFragment : BaseFragment() { } viewLifecycleOwner.lifecycleScope.launch { - AuroraApp.events.authEvent.collect { event -> - if (event is AuthEvent.GoogleLogin) onEventReceived(event) - } + AuroraApp.events.authEvent.collect { onEventReceived(it) } } } - private fun onEventReceived(event: AuthEvent.GoogleLogin) { - if (event.success) { - viewModel.buildGoogleAuthData(event.email, event.token, AuthHelper.Token.AAS) - } else { - Toast.makeText( - requireContext(), - getString(R.string.toast_aas_token_failed), - Toast.LENGTH_LONG - ).show() - } + private fun onEventReceived(event: AuthEvent) { + when (event) { + is AuthEvent.GoogleLogin -> { + if (event.success) { + viewModel.buildGoogleAuthData(event.email, event.token, AuthHelper.Token.AAS) + } else { + Toast.makeText( + requireContext(), + getString(R.string.toast_aas_token_failed), + Toast.LENGTH_LONG + ).show() + } - findNavController().navigate( - GoogleFragmentDirections.actionGoogleFragmentToSplashFragment() - ) + findNavController().navigate( + GoogleFragmentDirections.actionGoogleFragmentToSplashFragment() + ) + } + + else -> {} + } } } diff --git a/app/src/main/java/com/aurora/store/view/ui/account/LogoutDialog.kt b/app/src/main/java/com/aurora/store/view/ui/account/LogoutDialog.kt new file mode 100644 index 000000000..49c536d84 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/ui/account/LogoutDialog.kt @@ -0,0 +1,28 @@ +package com.aurora.store.view.ui.account + +import android.app.Dialog +import android.os.Bundle +import androidx.fragment.app.DialogFragment +import androidx.navigation.fragment.findNavController +import com.aurora.store.R +import com.aurora.store.data.providers.AccountProvider +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class LogoutDialog: DialogFragment() { + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.action_logout_confirmation_title) + .setMessage(R.string.action_logout_confirmation_message) + .setPositiveButton(getString(android.R.string.ok)) { _, _ -> logout() } + .setNegativeButton(getString(android.R.string.cancel)) { _, _ -> dialog?.dismiss()} + .create() + } + + private fun logout() { + AccountProvider.logout(requireContext()) + findNavController().navigate(LogoutDialogDirections.actionLogoutDialogToSplashFragment()) + } +} diff --git a/app/src/main/java/com/aurora/store/view/ui/all/AppsGamesFragment.kt b/app/src/main/java/com/aurora/store/view/ui/all/AppsGamesFragment.kt new file mode 100644 index 000000000..8ed316a21 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/ui/all/AppsGamesFragment.kt @@ -0,0 +1,170 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.ui.all + +import android.net.Uri +import android.os.Bundle +import android.text.Editable +import android.text.TextWatcher +import android.view.View +import androidx.activity.result.contract.ActivityResultContracts +import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope +import androidx.navigation.fragment.findNavController +import com.aurora.Constants +import com.aurora.extensions.toast +import com.aurora.gplayapi.data.models.App +import com.aurora.store.AuroraApp +import com.aurora.store.R +import com.aurora.store.data.event.InstallerEvent +import com.aurora.store.data.model.MinimalApp +import com.aurora.store.databinding.FragmentGenericWithSearchBinding +import com.aurora.store.view.epoxy.views.HeaderViewModel_ +import com.aurora.store.view.epoxy.views.app.AppListViewModel_ +import com.aurora.store.view.epoxy.views.shimmer.AppListViewShimmerModel_ +import com.aurora.store.view.ui.commons.BaseFragment +import com.aurora.store.viewmodel.all.InstalledViewModel +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch +import java.util.Calendar + +@AndroidEntryPoint +class AppsGamesFragment : BaseFragment() { + + private val viewModel: InstalledViewModel by viewModels() + + private val startForDocumentExport = + registerForActivityResult(ActivityResultContracts.CreateDocument(Constants.JSON_MIME_TYPE)) { + if (it != null) exportInstalledApps(it) else toast(R.string.toast_fav_export_failed) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + viewLifecycleOwner.lifecycleScope.launch { + viewModel.apps.collect { + updateController(it) + } + } + + viewLifecycleOwner.lifecycleScope.launch { + AuroraApp.events.installerEvent.collect { + when (it) { + is InstallerEvent.Installed, + is InstallerEvent.Uninstalled -> { + viewModel.fetchApps() + } + + else -> {} + } + } + } + + // Toolbar + binding.toolbar.apply { + inflateMenu(R.menu.menu_import_export) + + // TODO: Add support for batch install + menu.findItem(R.id.action_import).isEnabled = false + + setNavigationOnClickListener { findNavController().navigateUp() } + setOnMenuItemClickListener { + when (it.itemId) { + R.id.action_export -> { + startForDocumentExport.launch( + "aurora_store_apps_${Calendar.getInstance().time.time}.json" + ) + true + } + + else -> false + } + } + } + + binding.searchBar.addTextChangedListener(object : TextWatcher { + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { + if (s.isNullOrEmpty()) { + updateController(viewModel.apps.value) + } else { + val filteredPackages = viewModel.apps.value?.filter { + it.displayName.contains(s, true) || it.packageName.contains(s, true) + } + updateController(filteredPackages) + } + } + + override fun afterTextChanged(s: Editable?) {} + override fun beforeTextChanged( + s: CharSequence?, + start: Int, + count: Int, + after: Int + ) { + } + }) + } + + private fun updateController(packages: List?) { + binding.recycler.withModels { + setFilterDuplicates(true) + if (packages == null) { + for (i in 1..10) { + add( + AppListViewShimmerModel_() + .id(i) + ) + } + } else { + add( + HeaderViewModel_() + .id("header") + .title(getString(R.string.installed_apps_size, packages.size)) + ) + packages.forEach { app -> + add( + AppListViewModel_() + .id(app.packageName.hashCode()) + .app(app) + .click { _ -> + openDetailsFragment( + app.packageName, + app + ) + } + .longClick { _ -> + openAppMenuSheet( + MinimalApp.fromApp( + app + ) + ) + false + } + ) + } + } + } + } + + private fun exportInstalledApps(uri: Uri) { + viewModel.exportApps(requireContext(), uri) + toast(R.string.toast_fav_export_success) + } +} diff --git a/app/src/main/java/com/aurora/store/view/ui/apps/AppsContainerFragment.kt b/app/src/main/java/com/aurora/store/view/ui/apps/AppsContainerFragment.kt index d88f07fca..b46a2b5bd 100644 --- a/app/src/main/java/com/aurora/store/view/ui/apps/AppsContainerFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/apps/AppsContainerFragment.kt @@ -21,20 +21,14 @@ package com.aurora.store.view.ui.apps import android.os.Bundle import android.view.View -import android.view.ViewGroup -import androidx.core.view.ViewCompat -import androidx.core.view.WindowInsetsCompat -import androidx.core.view.updateLayoutParams import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.navigation.fragment.findNavController import androidx.viewpager2.adapter.FragmentStateAdapter -import com.aurora.extensions.navigate import com.aurora.store.MobileNavigationDirections import com.aurora.store.R -import com.aurora.store.compose.navigation.Screen import com.aurora.store.databinding.FragmentAppsGamesBinding import com.aurora.store.util.Preferences import com.aurora.store.view.ui.commons.BaseFragment @@ -54,22 +48,13 @@ class AppsContainerFragment : BaseFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - // Adjust FAB margins for edgeToEdge display - ViewCompat.setOnApplyWindowInsetsListener(binding.searchFab) { _, windowInsets -> - val insets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars()) - binding.searchFab.updateLayoutParams { - bottomMargin = insets.bottom + resources.getDimensionPixelSize(R.dimen.margin_large) - } - WindowInsetsCompat.CONSUMED - } - // Toolbar binding.toolbar.apply { title = getString(R.string.title_apps) setOnMenuItemClickListener { when (it.itemId) { R.id.menu_download_manager -> { - requireContext().navigate(Screen.Downloads) + findNavController().navigate(R.id.downloadFragment) } R.id.menu_more -> { @@ -96,7 +81,7 @@ class AppsContainerFragment : BaseFragment() { ) binding.pager.isUserInputEnabled = - false // Disable viewpager scroll to avoid scroll conflicts + false //Disable viewpager scroll to avoid scroll conflicts val tabTitles: MutableList = mutableListOf().apply { if (isForYouEnabled) { @@ -116,7 +101,7 @@ class AppsContainerFragment : BaseFragment() { }.attach() binding.searchFab.setOnClickListener { - requireContext().navigate(Screen.Search) + findNavController().navigate(R.id.searchSuggestionFragment) } } @@ -141,8 +126,12 @@ class AppsContainerFragment : BaseFragment() { add(CategoryFragment.newInstance(0)) } - override fun createFragment(position: Int): Fragment = tabFragments[position] + override fun createFragment(position: Int): Fragment { + return tabFragments[position] + } - override fun getItemCount(): Int = tabFragments.size + override fun getItemCount(): Int { + return tabFragments.size + } } } diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/BaseFragment.kt b/app/src/main/java/com/aurora/store/view/ui/commons/BaseFragment.kt index 50b93760b..75725406f 100644 --- a/app/src/main/java/com/aurora/store/view/ui/commons/BaseFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/commons/BaseFragment.kt @@ -28,22 +28,22 @@ import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController import androidx.viewbinding.ViewBinding import com.airbnb.epoxy.EpoxyRecyclerView -import com.aurora.extensions.TAG -import com.aurora.extensions.navigate +import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.Category import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.store.MobileNavigationDirections -import com.aurora.store.compose.navigation.Screen import com.aurora.store.data.model.MinimalApp import com.aurora.store.data.providers.PermissionProvider import java.lang.reflect.ParameterizedType abstract class BaseFragment : Fragment() { + private val TAG = BaseFragment::class.java.simpleName + lateinit var permissionProvider: PermissionProvider - protected open var viewBindingType: ViewBindingType? = null - protected val binding get() = viewBindingType!! + private var _binding: ViewBindingType? = null + protected val binding get() = _binding!! override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -52,19 +52,18 @@ abstract class BaseFragment : Fragment() { @Suppress("UNCHECKED_CAST") override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { - val type = (javaClass.genericSuperclass as ParameterizedType) - .actualTypeArguments[0] as Class + val type = + (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class val method = type.getMethod( "inflate", LayoutInflater::class.java, ViewGroup::class.java, Boolean::class.java ) - viewBindingType = method.invoke(null, inflater, container, false) as ViewBindingType + _binding = method.invoke(null, inflater, container, false) as ViewBindingType return binding.root } @@ -76,13 +75,13 @@ abstract class BaseFragment : Fragment() { override fun onDestroyView() { cleanupRecyclerViews(findAllRecyclerViews(requireView())) - viewBindingType = null + _binding = null super.onDestroyView() } - fun openDetailsFragment(packageName: String) { - requireContext().navigate( - Screen.AppDetails(packageName) + fun openDetailsFragment(packageName: String, app: App? = null) { + findNavController().navigate( + MobileNavigationDirections.actionGlobalAppDetailsFragment(packageName, app) ) } @@ -119,12 +118,17 @@ abstract class BaseFragment : Fragment() { ) } - fun openAppMenuSheet(app: MinimalApp) { - findNavController().navigate(MobileNavigationDirections.actionGlobalAppMenuSheet(app)) + fun openScreenshotFragment(app: App, position: Int) { + findNavController().navigate( + MobileNavigationDirections.actionGlobalScreenshotFragment( + position, + app.screenshots.toTypedArray() + ) + ) } - fun openGMSWarningFragment() { - // TODO: FIX ME + fun openAppMenuSheet(app: MinimalApp) { + findNavController().navigate(MobileNavigationDirections.actionGlobalAppMenuSheet(app)) } private fun cleanupRecyclerViews(recyclerViews: List) { diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/BlacklistFragment.kt b/app/src/main/java/com/aurora/store/view/ui/commons/BlacklistFragment.kt new file mode 100644 index 000000000..35a251b74 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/ui/commons/BlacklistFragment.kt @@ -0,0 +1,179 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.ui.commons + +import android.content.pm.PackageInfo +import android.net.Uri +import android.os.Bundle +import android.text.Editable +import android.text.TextWatcher +import android.view.View +import androidx.activity.result.contract.ActivityResultContracts +import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope +import androidx.navigation.fragment.findNavController +import com.aurora.Constants +import com.aurora.extensions.toast +import com.aurora.store.AuroraApp +import com.aurora.store.R +import com.aurora.store.data.event.BusEvent +import com.aurora.store.databinding.FragmentGenericWithSearchBinding +import com.aurora.store.view.epoxy.views.BlackListViewModel_ +import com.aurora.store.view.epoxy.views.shimmer.AppListViewShimmerModel_ +import com.aurora.store.viewmodel.all.BlacklistViewModel +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch +import java.util.Calendar + +@AndroidEntryPoint +class BlacklistFragment : BaseFragment() { + + private val viewModel: BlacklistViewModel by viewModels() + + private val startForDocumentImport = + registerForActivityResult(ActivityResultContracts.OpenDocument()) { + if (it != null) importBlacklist(it) else toast(R.string.toast_black_import_failed) + } + private val startForDocumentExport = + registerForActivityResult(ActivityResultContracts.CreateDocument(Constants.JSON_MIME_TYPE)) { + if (it != null) exportBlacklist(it) else toast(R.string.toast_black_export_failed) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + viewLifecycleOwner.lifecycleScope.launch { + viewModel.packages.collect { + updateController(it) + } + } + + // Toolbar + binding.toolbar.apply { + inflateMenu(R.menu.menu_blacklist) + setNavigationOnClickListener { + viewModel.blacklistProvider.blacklist = viewModel.selected + findNavController().navigateUp() + } + setOnMenuItemClickListener { + when (it.itemId) { + R.id.action_import -> { + startForDocumentImport.launch(arrayOf(Constants.JSON_MIME_TYPE)) + } + + R.id.action_export -> { + startForDocumentExport.launch( + "aurora_store_apps_${Calendar.getInstance().time.time}.json" + ) + } + + R.id.action_select_all -> { + viewModel.selectAll() + binding.recycler.requestModelBuild() + true + } + + R.id.action_remove_all -> { + viewModel.removeAll() + binding.recycler.requestModelBuild() + true + } + } + true + } + } + + binding.searchBar.addTextChangedListener(object : TextWatcher { + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { + if (s.isNullOrEmpty()) { + updateController(viewModel.packages.value) + } else { + val filteredPackages = viewModel.packages.value?.filter { + it.applicationInfo!!.loadLabel(requireContext().packageManager) + .contains(s, true) || it.packageName.contains(s, true) + } + updateController(filteredPackages) + } + } + + override fun afterTextChanged(s: Editable?) {} + override fun beforeTextChanged( + s: CharSequence?, + start: Int, + count: Int, + after: Int + ) { + } + }) + } + + override fun onPause() { + super.onPause() + viewModel.blacklistProvider.blacklist = viewModel.selected + } + + private fun updateController(packages: List?) { + binding.recycler.withModels { + setFilterDuplicates(true) + if (packages == null) { + for (i in 1..10) { + add( + AppListViewShimmerModel_() + .id(i) + ) + } + } else { + packages + .sortedByDescending { app -> + viewModel.blacklistProvider.isBlacklisted(app.packageName) + } + .forEach { + add( + BlackListViewModel_() + .id(it.packageName.hashCode()) + .packageInfo(it) + .markChecked(viewModel.selected.contains(it.packageName)) + .checked { _, isChecked -> + if (isChecked) { + viewModel.selected.add(it.packageName) + AuroraApp.events.send(BusEvent.Blacklisted(it.packageName)) + } else { + viewModel.selected.remove(it.packageName) + } + + requestModelBuild() + } + ) + } + } + } + } + + private fun importBlacklist(uri: Uri) { + viewModel.importBlacklist(requireContext(), uri) + binding.recycler.requestModelBuild() + toast(R.string.toast_black_import_success) + } + + private fun exportBlacklist(uri: Uri) { + viewModel.exportBlacklist(requireContext(), uri) + toast(R.string.toast_black_export_success) + } +} diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/CategoryBrowseFragment.kt b/app/src/main/java/com/aurora/store/view/ui/commons/CategoryBrowseFragment.kt index 319631470..7fc2cb8e4 100644 --- a/app/src/main/java/com/aurora/store/view/ui/commons/CategoryBrowseFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/commons/CategoryBrowseFragment.kt @@ -27,6 +27,8 @@ import androidx.navigation.fragment.navArgs import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.StreamBundle import com.aurora.gplayapi.data.models.StreamCluster +import com.aurora.gplayapi.helpers.contracts.StreamContract +import com.aurora.gplayapi.utils.CategoryUtil import com.aurora.store.data.model.ViewState import com.aurora.store.data.model.ViewState.Loading.getDataAs import com.aurora.store.databinding.FragmentGenericWithToolbarBinding @@ -37,17 +39,19 @@ import com.aurora.store.viewmodel.subcategory.CategoryStreamViewModel import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint -class CategoryBrowseFragment : - BaseFragment(), +class CategoryBrowseFragment : BaseFragment(), GenericCarouselController.Callbacks { private val args: CategoryBrowseFragmentArgs by navArgs() private val viewModel: CategoryStreamViewModel by activityViewModels() + private lateinit var category: StreamContract.Category private var streamBundle: StreamBundle? = StreamBundle() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + category = CategoryUtil.getCategoryFromUrl(args.browseUrl) + val genericCarouselController = CategoryCarouselController(this) // Toolbar @@ -60,11 +64,11 @@ class CategoryBrowseFragment : binding.recycler.setController(genericCarouselController) binding.recycler.addOnScrollListener(object : EndlessRecyclerOnScrollListener() { override fun onLoadMore(currentPage: Int) { - viewModel.observe(args.browseUrl) + viewModel.observe(category) } }) - viewModel.getStreamBundle(args.browseUrl) + viewModel.getStreamBundle(category) viewModel.liveData.observe(viewLifecycleOwner) { when (it) { is ViewState.Loading -> { @@ -73,7 +77,7 @@ class CategoryBrowseFragment : is ViewState.Success<*> -> { val stash = it.getDataAs>() - streamBundle = stash[args.browseUrl] + streamBundle = stash[category.value] genericCarouselController.setData(streamBundle) } @@ -88,13 +92,14 @@ class CategoryBrowseFragment : } override fun onClusterScrolled(streamCluster: StreamCluster) { - viewModel.observeCluster(args.browseUrl, streamCluster) + viewModel.observeCluster(category, streamCluster) } override fun onAppClick(app: App) { - openDetailsFragment(app.packageName) + openDetailsFragment(app.packageName, app) } override fun onAppLongClick(app: App) { + } } diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/CategoryFragment.kt b/app/src/main/java/com/aurora/store/view/ui/commons/CategoryFragment.kt index a81c6c344..48b694697 100644 --- a/app/src/main/java/com/aurora/store/view/ui/commons/CategoryFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/commons/CategoryFragment.kt @@ -39,9 +39,11 @@ class CategoryFragment : BaseFragment() { companion object { @JvmStatic - fun newInstance(pageType: Int): CategoryFragment = CategoryFragment().apply { - arguments = Bundle().apply { - putInt(Constants.PAGE_TYPE, pageType) + fun newInstance(pageType: Int): CategoryFragment { + return CategoryFragment().apply { + arguments = Bundle().apply { + putInt(Constants.PAGE_TYPE, pageType) + } } } } diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/ExpandedStreamBrowseFragment.kt b/app/src/main/java/com/aurora/store/view/ui/commons/ExpandedStreamBrowseFragment.kt index 667cb6da0..c1be4599d 100644 --- a/app/src/main/java/com/aurora/store/view/ui/commons/ExpandedStreamBrowseFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/commons/ExpandedStreamBrowseFragment.kt @@ -24,11 +24,15 @@ import android.view.View import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs +import com.airbnb.epoxy.EpoxyModel import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.store.databinding.FragmentGenericWithToolbarBinding import com.aurora.store.view.custom.recycler.EndlessRecyclerOnScrollListener +import com.aurora.store.view.epoxy.groups.CarouselHorizontalModel_ import com.aurora.store.view.epoxy.views.AppProgressViewModel_ import com.aurora.store.view.epoxy.views.app.AppListViewModel_ +import com.aurora.store.view.epoxy.views.details.MiniScreenshotView +import com.aurora.store.view.epoxy.views.details.MiniScreenshotViewModel_ import com.aurora.store.view.epoxy.views.shimmer.AppListViewShimmerModel_ import com.aurora.store.viewmodel.browse.ExpandedStreamBrowseViewModel import dagger.hilt.android.AndroidEntryPoint @@ -63,9 +67,8 @@ class ExpandedStreamBrowseFragment : BaseFragment>() + + for ((position, artwork) in it.screenshots.withIndex()) { + screenshotsViewModels.add( + MiniScreenshotViewModel_() + .id(artwork.url) + .position(position) + .artwork(artwork) + .callback(object : MiniScreenshotView.ScreenshotCallback { + override fun onClick(position: Int) { + openScreenshotFragment(it, position) + } + }) + ) + } + + if (screenshotsViewModels.isNotEmpty()) { + add( + CarouselHorizontalModel_() + .id("${it.id}_screenshots") + .models(screenshotsViewModels) + ) + } + add( AppListViewModel_() .id(it.packageName.hashCode()) .app(it) - .click { _ -> openDetailsFragment(it.packageName) } + .click { _ -> openDetailsFragment(it.packageName, it) } ) } diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/FavouriteFragment.kt b/app/src/main/java/com/aurora/store/view/ui/commons/FavouriteFragment.kt new file mode 100644 index 000000000..6bbf39e89 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/ui/commons/FavouriteFragment.kt @@ -0,0 +1,125 @@ +/* + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * + */ + +package com.aurora.store.view.ui.commons + +import android.net.Uri +import android.os.Bundle +import android.view.View +import androidx.activity.result.contract.ActivityResultContracts +import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope +import androidx.navigation.fragment.findNavController +import com.aurora.Constants +import com.aurora.extensions.toast +import com.aurora.store.R +import com.aurora.store.data.room.favourite.Favourite +import com.aurora.store.data.room.favourite.Favourite.Companion.toApp +import com.aurora.store.databinding.FragmentFavouriteBinding +import com.aurora.store.view.epoxy.views.FavouriteViewModel_ +import com.aurora.store.view.epoxy.views.app.NoAppViewModel_ +import com.aurora.store.view.epoxy.views.shimmer.AppListViewShimmerModel_ +import com.aurora.store.viewmodel.all.FavouriteViewModel +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch +import java.util.Calendar + +@AndroidEntryPoint +class FavouriteFragment : BaseFragment() { + private val viewModel: FavouriteViewModel by viewModels() + + private val startForDocumentImport = + registerForActivityResult(ActivityResultContracts.OpenDocument()) { + if (it != null) importFavourites(it) else toast(R.string.toast_fav_import_failed) + } + private val startForDocumentExport = + registerForActivityResult(ActivityResultContracts.CreateDocument(Constants.JSON_MIME_TYPE)) { + if (it != null) exportFavourites(it) else toast(R.string.toast_fav_export_failed) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + viewLifecycleOwner.lifecycleScope.launch { + viewModel.favouritesList.collect { + updateController(it) + } + } + + // Toolbar + binding.toolbar.apply { + setOnMenuItemClickListener { + when (it.itemId) { + R.id.action_import -> startForDocumentImport.launch(arrayOf(Constants.JSON_MIME_TYPE)) + R.id.action_export -> { + startForDocumentExport.launch( + "aurora_store_favourites_${Calendar.getInstance().time.time}.json" + ) + } + + else -> {} + } + true + } + setNavigationOnClickListener { findNavController().navigateUp() } + } + } + + private fun updateController(favourites: List?) { + binding.recycler.withModels { + setFilterDuplicates(true) + if (favourites == null) { + for (i in 1..10) { + add( + AppListViewShimmerModel_() + .id(i) + ) + } + } else if (favourites.isEmpty()) { + add( + NoAppViewModel_() + .id("no_app") + .icon(R.drawable.ic_favorite_unchecked) + .message(R.string.details_no_favourites) + ) + } else { + favourites.forEach { + add( + FavouriteViewModel_() + .id(it.packageName.hashCode()) + .favourite(it) + .onClick { _ -> openDetailsFragment(it.packageName, it.toApp()) } + .onFavourite { _ -> viewModel.removeFavourite(it.packageName) } + ) + } + } + } + } + + private fun importFavourites(uri: Uri) { + viewModel.importFavourites(requireContext(), uri) + binding.recycler.requestModelBuild() + toast(R.string.toast_fav_import_success) + } + + private fun exportFavourites(uri: Uri) { + viewModel.exportFavourites(requireContext(), uri) + toast(R.string.toast_fav_export_success) + } +} diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/ForYouFragment.kt b/app/src/main/java/com/aurora/store/view/ui/commons/ForYouFragment.kt index e8171bb74..92fe7cb5c 100644 --- a/app/src/main/java/com/aurora/store/view/ui/commons/ForYouFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/commons/ForYouFragment.kt @@ -38,8 +38,7 @@ import com.aurora.store.viewmodel.homestream.StreamViewModel import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint -class ForYouFragment : - BaseFragment(), +class ForYouFragment : BaseFragment(), GenericCarouselController.Callbacks { private val viewModel: StreamViewModel by activityViewModels() @@ -48,9 +47,11 @@ class ForYouFragment : companion object { @JvmStatic - fun newInstance(pageType: Int): ForYouFragment = ForYouFragment().apply { - arguments = Bundle().apply { - putInt(Constants.PAGE_TYPE, pageType) + fun newInstance(pageType: Int): ForYouFragment { + return ForYouFragment().apply { + arguments = Bundle().apply { + putInt(Constants.PAGE_TYPE, pageType) + } } } } @@ -105,9 +106,10 @@ class ForYouFragment : } override fun onAppClick(app: App) { - openDetailsFragment(app.packageName) + openDetailsFragment(app.packageName, app) } override fun onAppLongClick(app: App) { + } } diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/ForceRestartDialog.kt b/app/src/main/java/com/aurora/store/view/ui/commons/ForceRestartDialog.kt index 01aeed464..218cc7201 100644 --- a/app/src/main/java/com/aurora/store/view/ui/commons/ForceRestartDialog.kt +++ b/app/src/main/java/com/aurora/store/view/ui/commons/ForceRestartDialog.kt @@ -9,16 +9,17 @@ import com.jakewharton.processphoenix.ProcessPhoenix import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint -class ForceRestartDialog : DialogFragment() { +class ForceRestartDialog: DialogFragment() { - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = - MaterialAlertDialogBuilder(requireContext()) + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return MaterialAlertDialogBuilder(requireContext()) .setTitle(R.string.force_restart_title) .setMessage(R.string.force_restart_summary) .setPositiveButton(getString(R.string.action_restart)) { _, _ -> ProcessPhoenix.triggerRebirth(requireContext()) } .create() + } override fun onResume() { super.onResume() diff --git a/app/src/main/java/com/aurora/store/view/ui/commons/MoreDialogFragment.kt b/app/src/main/java/com/aurora/store/view/ui/commons/MoreDialogFragment.kt index c6809ffc3..11ce8cead 100644 --- a/app/src/main/java/com/aurora/store/view/ui/commons/MoreDialogFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/commons/MoreDialogFragment.kt @@ -57,13 +57,11 @@ import com.aurora.Constants import com.aurora.Constants.URL_TOS import com.aurora.extensions.browse import com.aurora.extensions.getStyledAttributeColor -import com.aurora.extensions.navigate import com.aurora.extensions.setAppTheme import com.aurora.store.MR import com.aurora.store.R -import com.aurora.store.compose.navigation.Screen -import com.aurora.store.compose.theme.AuroraTheme import com.aurora.store.util.Preferences +import com.aurora.store.view.theme.AuroraTheme import com.aurora.store.viewmodel.commons.MoreViewModel import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint @@ -78,105 +76,77 @@ class MoreDialogFragment : DialogFragment() { private var secondaryColor: Color = Color.White private var onSecondaryColor: Color = Color.Black - private abstract class Option( - @StringRes open val title: Int, - @DrawableRes open val icon: Int - ) - - private data class ViewOption( - override val title: Int, - override val icon: Int, + private data class Option( + @StringRes val title: Int, + @DrawableRes val icon: Int, @IdRes val destinationID: Int - ) : Option(title, icon) - - private data class ComposeOption( - override val title: Int, - override val icon: Int, - val screen: Screen - ) : Option(title, icon) + ) - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = - MaterialAlertDialogBuilder(requireContext()) + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return MaterialAlertDialogBuilder(requireContext()) .setView(customDialogView(requireContext())) .create() + } - private fun customDialogView(context: Context): ComposeView = ComposeView(context).apply { - setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) - setContent { - AuroraTheme { - primaryColor = - Color(requireContext().getStyledAttributeColor(MR.colorSurface)) - onPrimaryColor = - Color(requireContext().getStyledAttributeColor(MR.colorOnSurface)) - secondaryColor = - Color(requireContext().getStyledAttributeColor(MR.colorSecondaryContainer)) - onSecondaryColor = - Color( - requireContext().getStyledAttributeColor(MR.colorOnSecondaryContainer) - ) + private fun customDialogView(context: Context): ComposeView { + return ComposeView(context).apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + AuroraTheme { + primaryColor = + Color(requireContext().getStyledAttributeColor(MR.colorSurface)) + onPrimaryColor = + Color(requireContext().getStyledAttributeColor(MR.colorOnSurface)) + secondaryColor = + Color(requireContext().getStyledAttributeColor(MR.colorSecondaryContainer)) + onSecondaryColor = + Color(requireContext().getStyledAttributeColor(MR.colorOnSecondaryContainer)) - Column( - modifier = Modifier - .fillMaxWidth() - .background(color = primaryColor) - .verticalScroll(rememberScrollState()) - .padding(10.dp), - verticalArrangement = Arrangement.spacedBy( - 4.dp, - Alignment.CenterVertically - ) - ) { - AppBar(onBackgroundColor = onPrimaryColor) - AccountHeader( - backgroundColor = secondaryColor, - onBackgroundColor = onSecondaryColor - ) Column( modifier = Modifier - .clip( - RoundedCornerShape( - topStart = 2.dp, - topEnd = 2.dp, - bottomStart = 25.dp, - bottomEnd = 25.dp - ) - ) - .background(color = secondaryColor) + .fillMaxWidth() + .background(color = primaryColor) + .verticalScroll(rememberScrollState()) + .padding(10.dp), + verticalArrangement = Arrangement.spacedBy( + 4.dp, + Alignment.CenterVertically + ) ) { - getOptions().fastForEach { option -> + AppBar(onBackgroundColor = onPrimaryColor) + AccountHeader( + backgroundColor = secondaryColor, + onBackgroundColor = onSecondaryColor + ) + Column( + modifier = Modifier + .clip( + RoundedCornerShape( + topStart = 2.dp, + topEnd = 2.dp, + bottomStart = 25.dp, + bottomEnd = 25.dp + ) + ) + .background(color = secondaryColor) + ) { + getOptions().fastForEach { option -> + OptionItem( + option = option, + tintColor = onPrimaryColor, + textColor = onSecondaryColor + ) + } + } + getExtraOptions().fastForEach { option -> OptionItem( option = option, tintColor = onPrimaryColor, - textColor = onSecondaryColor, - onClick = { - when (option) { - is ViewOption -> { - findNavController().navigate(option.destinationID) - } - - is ComposeOption -> context.navigate(option.screen) - } - } + textColor = onPrimaryColor ) } + Footer(onPrimaryColor) } - getExtraOptions().fastForEach { option -> - OptionItem( - option = option, - tintColor = onPrimaryColor, - textColor = onPrimaryColor, - onClick = { - when (option) { - is ViewOption -> { - findNavController().navigate(option.destinationID) - } - - is ComposeOption -> context.navigate(option.screen) - } - } - ) - } - Footer(onPrimaryColor) } } } @@ -317,15 +287,11 @@ class MoreDialogFragment : DialogFragment() { } } OutlinedButton( - onClick = { requireContext().navigate(Screen.Accounts) }, + onClick = { findNavController().navigate(R.id.accountFragment) }, shape = RoundedCornerShape(12.dp), border = BorderStroke( 1.dp, - Color( - requireContext().getStyledAttributeColor( - androidx.appcompat.R.attr.colorControlHighlight - ) - ) + Color(requireContext().getStyledAttributeColor(androidx.appcompat.R.attr.colorControlHighlight)) ), modifier = Modifier.fillMaxWidth() ) { @@ -334,7 +300,7 @@ class MoreDialogFragment : DialogFragment() { color = onBackgroundColor, fontWeight = FontWeight.Normal, maxLines = 1, - overflow = TextOverflow.Ellipsis + overflow = TextOverflow.Ellipsis, ) } } @@ -344,13 +310,12 @@ class MoreDialogFragment : DialogFragment() { private fun OptionItem( option: Option, tintColor: Color = Color.Blue, - textColor: Color = Color.Black, - onClick: () -> Unit + textColor: Color = Color.Black ) { Row( modifier = Modifier .fillMaxWidth() - .clickable { onClick() } + .clickable { findNavController().navigate(option.destinationID) } .padding(12.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start) @@ -375,7 +340,9 @@ class MoreDialogFragment : DialogFragment() { } @Composable - fun ThreeStateIconButton(tint: Color = Color.White) { + fun ThreeStateIconButton( + tint: Color = Color.White + ) { var currentState by remember { mutableStateOf( Preferences.getInteger( @@ -419,42 +386,46 @@ class MoreDialogFragment : DialogFragment() { enum class State(val value: Int) { Auto(0), Light(1), - Dark(2) + Dark(2), } - private fun getOptions(): List diff --git a/app/src/main/res/layout/dialog_auto_updates_restrictions.xml b/app/src/main/res/layout/dialog_auto_updates_restrictions.xml deleted file mode 100644 index ff662396b..000000000 --- a/app/src/main/res/layout/dialog_auto_updates_restrictions.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - diff --git a/app/src/main/res/layout/dialog_text_input_edit_text.xml b/app/src/main/res/layout/dialog_text_input_edit_text.xml index f239079e1..9f3abab3b 100644 --- a/app/src/main/res/layout/dialog_text_input_edit_text.xml +++ b/app/src/main/res/layout/dialog_text_input_edit_text.xml @@ -3,7 +3,6 @@ android:id="@+id/textInputLayout" android:layout_width="match_parent" android:layout_height="wrap_content" - android:hint="@string/pref_network_proxy_url_hint" android:paddingHorizontal="@dimen/padding_large" android:paddingTop="@dimen/padding_normal"> @@ -11,7 +10,5 @@ android:id="@+id/textInputEditText" style="@style/Widget.Material3.TextInputEditText.OutlinedBox" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:inputType="text" - android:maxLines="1" /> + android:layout_height="wrap_content" /> diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/fragment_about.xml new file mode 100644 index 000000000..ecf3adfd4 --- /dev/null +++ b/app/src/main/res/layout/fragment_about.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_account.xml b/app/src/main/res/layout/fragment_account.xml new file mode 100644 index 000000000..ec65b74b1 --- /dev/null +++ b/app/src/main/res/layout/fragment_account.xml @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_app_links.xml b/app/src/main/res/layout/fragment_app_links.xml new file mode 100644 index 000000000..6d8e1e1e3 --- /dev/null +++ b/app/src/main/res/layout/fragment_app_links.xml @@ -0,0 +1,47 @@ + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_details.xml b/app/src/main/res/layout/fragment_details.xml new file mode 100644 index 000000000..87493c1cb --- /dev/null +++ b/app/src/main/res/layout/fragment_details.xml @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_details_more.xml b/app/src/main/res/layout/fragment_details_more.xml new file mode 100644 index 000000000..174611bea --- /dev/null +++ b/app/src/main/res/layout/fragment_details_more.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_details_review.xml b/app/src/main/res/layout/fragment_details_review.xml new file mode 100644 index 000000000..4c9a52450 --- /dev/null +++ b/app/src/main/res/layout/fragment_details_review.xml @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_details_screenshots.xml b/app/src/main/res/layout/fragment_details_screenshots.xml new file mode 100644 index 000000000..465f0618f --- /dev/null +++ b/app/src/main/res/layout/fragment_details_screenshots.xml @@ -0,0 +1,35 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_dispenser.xml b/app/src/main/res/layout/fragment_dispenser.xml new file mode 100644 index 000000000..7ea222f94 --- /dev/null +++ b/app/src/main/res/layout/fragment_dispenser.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_download.xml b/app/src/main/res/layout/fragment_download.xml new file mode 100644 index 000000000..c3475aafa --- /dev/null +++ b/app/src/main/res/layout/fragment_download.xml @@ -0,0 +1,46 @@ + + + + + + + + diff --git a/app/src/main/res/layout/fragment_favourite.xml b/app/src/main/res/layout/fragment_favourite.xml new file mode 100644 index 000000000..0bd7c51f5 --- /dev/null +++ b/app/src/main/res/layout/fragment_favourite.xml @@ -0,0 +1,46 @@ + + + + + + + + diff --git a/app/src/main/res/layout/fragment_installer.xml b/app/src/main/res/layout/fragment_installer.xml new file mode 100644 index 000000000..c41ea459b --- /dev/null +++ b/app/src/main/res/layout/fragment_installer.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_onboarding.xml b/app/src/main/res/layout/fragment_onboarding.xml new file mode 100644 index 000000000..326b56e01 --- /dev/null +++ b/app/src/main/res/layout/fragment_onboarding.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_onboarding_permissions.xml b/app/src/main/res/layout/fragment_onboarding_permissions.xml new file mode 100644 index 000000000..f40132a5f --- /dev/null +++ b/app/src/main/res/layout/fragment_onboarding_permissions.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_onboarding_welcome.xml b/app/src/main/res/layout/fragment_onboarding_welcome.xml new file mode 100644 index 000000000..f67665e9e --- /dev/null +++ b/app/src/main/res/layout/fragment_onboarding_welcome.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_screenshot.xml b/app/src/main/res/layout/fragment_screenshot.xml new file mode 100644 index 000000000..23483cc48 --- /dev/null +++ b/app/src/main/res/layout/fragment_screenshot.xml @@ -0,0 +1,43 @@ + + + + + + + + diff --git a/app/src/main/res/layout/fragment_search_result.xml b/app/src/main/res/layout/fragment_search_result.xml new file mode 100644 index 000000000..27ca80b36 --- /dev/null +++ b/app/src/main/res/layout/fragment_search_result.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_search_suggestion.xml b/app/src/main/res/layout/fragment_search_suggestion.xml new file mode 100644 index 000000000..ca8e29ccf --- /dev/null +++ b/app/src/main/res/layout/fragment_search_suggestion.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_spoof.xml b/app/src/main/res/layout/fragment_spoof.xml new file mode 100644 index 000000000..70d3b864d --- /dev/null +++ b/app/src/main/res/layout/fragment_spoof.xml @@ -0,0 +1,52 @@ + + + + + + + + + + diff --git a/app/src/main/res/layout/layout_details_app.xml b/app/src/main/res/layout/layout_details_app.xml new file mode 100644 index 000000000..d04bb6b16 --- /dev/null +++ b/app/src/main/res/layout/layout_details_app.xml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/layout_details_beta.xml b/app/src/main/res/layout/layout_details_beta.xml new file mode 100644 index 000000000..f423cef5f --- /dev/null +++ b/app/src/main/res/layout/layout_details_beta.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/layout_details_compatibility.xml b/app/src/main/res/layout/layout_details_compatibility.xml new file mode 100644 index 000000000..738d7838f --- /dev/null +++ b/app/src/main/res/layout/layout_details_compatibility.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/layout_details_data_safety.xml b/app/src/main/res/layout/layout_details_data_safety.xml new file mode 100644 index 000000000..4caabe496 --- /dev/null +++ b/app/src/main/res/layout/layout_details_data_safety.xml @@ -0,0 +1,35 @@ + + + + + + + + + + diff --git a/app/src/main/res/layout/layout_details_description.xml b/app/src/main/res/layout/layout_details_description.xml new file mode 100644 index 000000000..b0b46d01f --- /dev/null +++ b/app/src/main/res/layout/layout_details_description.xml @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/layout_details_dev.xml b/app/src/main/res/layout/layout_details_dev.xml new file mode 100644 index 000000000..0c3b9b7a8 --- /dev/null +++ b/app/src/main/res/layout/layout_details_dev.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_details_permissions.xml b/app/src/main/res/layout/layout_details_permissions.xml new file mode 100644 index 000000000..46c359713 --- /dev/null +++ b/app/src/main/res/layout/layout_details_permissions.xml @@ -0,0 +1,39 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_details_privacy.xml b/app/src/main/res/layout/layout_details_privacy.xml new file mode 100644 index 000000000..00dc5b3b7 --- /dev/null +++ b/app/src/main/res/layout/layout_details_privacy.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/layout_details_review.xml b/app/src/main/res/layout/layout_details_review.xml new file mode 100644 index 000000000..5ee028729 --- /dev/null +++ b/app/src/main/res/layout/layout_details_review.xml @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_permission.xml b/app/src/main/res/layout/layout_permission.xml new file mode 100644 index 000000000..d1b7a472b --- /dev/null +++ b/app/src/main/res/layout/layout_permission.xml @@ -0,0 +1,44 @@ + + + + + + + + diff --git a/app/src/main/res/layout/model_developer_carousel_group.xml b/app/src/main/res/layout/model_developer_carousel_group.xml new file mode 100644 index 000000000..8804d25f5 --- /dev/null +++ b/app/src/main/res/layout/model_developer_carousel_group.xml @@ -0,0 +1,40 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/sheet_download_menu.xml b/app/src/main/res/layout/sheet_download_menu.xml new file mode 100644 index 000000000..074d30f28 --- /dev/null +++ b/app/src/main/res/layout/sheet_download_menu.xml @@ -0,0 +1,34 @@ + + + + + + diff --git a/app/src/main/res/layout/sheet_filter.xml b/app/src/main/res/layout/sheet_filter.xml new file mode 100644 index 000000000..c4f5246e1 --- /dev/null +++ b/app/src/main/res/layout/sheet_filter.xml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/sheet_install_error.xml b/app/src/main/res/layout/sheet_install_error.xml new file mode 100644 index 000000000..6216bd365 --- /dev/null +++ b/app/src/main/res/layout/sheet_install_error.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/sheet_manual_download.xml b/app/src/main/res/layout/sheet_manual_download.xml new file mode 100644 index 000000000..3ec96446b --- /dev/null +++ b/app/src/main/res/layout/sheet_manual_download.xml @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/sheet_permissions.xml b/app/src/main/res/layout/sheet_permissions.xml new file mode 100644 index 000000000..6a70e6127 --- /dev/null +++ b/app/src/main/res/layout/sheet_permissions.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_app_dependent.xml b/app/src/main/res/layout/view_app_dependent.xml new file mode 100644 index 000000000..18f6fce06 --- /dev/null +++ b/app/src/main/res/layout/view_app_dependent.xml @@ -0,0 +1,46 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_badge.xml b/app/src/main/res/layout/view_badge.xml new file mode 100644 index 000000000..a3497b78b --- /dev/null +++ b/app/src/main/res/layout/view_badge.xml @@ -0,0 +1,45 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_black.xml b/app/src/main/res/layout/view_black.xml new file mode 100644 index 000000000..c2e70325b --- /dev/null +++ b/app/src/main/res/layout/view_black.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_dash.xml b/app/src/main/res/layout/view_dash.xml new file mode 100644 index 000000000..d27df0ea6 --- /dev/null +++ b/app/src/main/res/layout/view_dash.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_dev_info.xml b/app/src/main/res/layout/view_dev_info.xml new file mode 100644 index 000000000..370a47885 --- /dev/null +++ b/app/src/main/res/layout/view_dev_info.xml @@ -0,0 +1,57 @@ + + + + + + + + + + diff --git a/app/src/main/res/layout/view_device.xml b/app/src/main/res/layout/view_device.xml new file mode 100644 index 000000000..66005edb0 --- /dev/null +++ b/app/src/main/res/layout/view_device.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_dispenser.xml b/app/src/main/res/layout/view_dispenser.xml new file mode 100644 index 000000000..fd317c640 --- /dev/null +++ b/app/src/main/res/layout/view_dispenser.xml @@ -0,0 +1,30 @@ + + + + + + + diff --git a/app/src/main/res/layout/view_download.xml b/app/src/main/res/layout/view_download.xml new file mode 100644 index 000000000..779dc1046 --- /dev/null +++ b/app/src/main/res/layout/view_download.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/view_exodus.xml b/app/src/main/res/layout/view_exodus.xml new file mode 100644 index 000000000..8c6cb05cc --- /dev/null +++ b/app/src/main/res/layout/view_exodus.xml @@ -0,0 +1,58 @@ + + + + + + + + + + diff --git a/app/src/main/res/layout/view_fav.xml b/app/src/main/res/layout/view_fav.xml new file mode 100644 index 000000000..1296c1ddc --- /dev/null +++ b/app/src/main/res/layout/view_fav.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/view_file.xml b/app/src/main/res/layout/view_file.xml new file mode 100644 index 000000000..c248993fe --- /dev/null +++ b/app/src/main/res/layout/view_file.xml @@ -0,0 +1,48 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_installer.xml b/app/src/main/res/layout/view_installer.xml new file mode 100644 index 000000000..29f5c0f42 --- /dev/null +++ b/app/src/main/res/layout/view_installer.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_link.xml b/app/src/main/res/layout/view_link.xml new file mode 100644 index 000000000..8161870aa --- /dev/null +++ b/app/src/main/res/layout/view_link.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_no_app_alt.xml b/app/src/main/res/layout/view_no_app_alt.xml new file mode 100644 index 000000000..d0d347892 --- /dev/null +++ b/app/src/main/res/layout/view_no_app_alt.xml @@ -0,0 +1,33 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_package.xml b/app/src/main/res/layout/view_package.xml new file mode 100644 index 000000000..cfc884982 --- /dev/null +++ b/app/src/main/res/layout/view_package.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/view_permission.xml b/app/src/main/res/layout/view_permission.xml new file mode 100644 index 000000000..50910bf5a --- /dev/null +++ b/app/src/main/res/layout/view_permission.xml @@ -0,0 +1,54 @@ + + + + + + + + + + diff --git a/app/src/main/res/layout/view_rating.xml b/app/src/main/res/layout/view_rating.xml new file mode 100644 index 000000000..a28afae3a --- /dev/null +++ b/app/src/main/res/layout/view_rating.xml @@ -0,0 +1,54 @@ + + + + + + + + + diff --git a/app/src/main/res/layout/view_review.xml b/app/src/main/res/layout/view_review.xml new file mode 100644 index 000000000..c786db62a --- /dev/null +++ b/app/src/main/res/layout/view_review.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_screenshot.xml b/app/src/main/res/layout/view_screenshot.xml new file mode 100644 index 000000000..5a6f384f8 --- /dev/null +++ b/app/src/main/res/layout/view_screenshot.xml @@ -0,0 +1,29 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_screenshot_large.xml b/app/src/main/res/layout/view_screenshot_large.xml new file mode 100644 index 000000000..51d05c47e --- /dev/null +++ b/app/src/main/res/layout/view_screenshot_large.xml @@ -0,0 +1,28 @@ + + + + + + diff --git a/app/src/main/res/layout/view_screenshot_mini.xml b/app/src/main/res/layout/view_screenshot_mini.xml new file mode 100644 index 000000000..96eca2c8f --- /dev/null +++ b/app/src/main/res/layout/view_screenshot_mini.xml @@ -0,0 +1,29 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_search_suggestion.xml b/app/src/main/res/layout/view_search_suggestion.xml new file mode 100644 index 000000000..3a19514af --- /dev/null +++ b/app/src/main/res/layout/view_search_suggestion.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_text_divider.xml b/app/src/main/res/layout/view_text_divider.xml new file mode 100644 index 000000000..9ac907296 --- /dev/null +++ b/app/src/main/res/layout/view_text_divider.xml @@ -0,0 +1,35 @@ + + + + + + diff --git a/app/src/main/res/layout/view_two_column.xml b/app/src/main/res/layout/view_two_column.xml new file mode 100644 index 000000000..83eea5d55 --- /dev/null +++ b/app/src/main/res/layout/view_two_column.xml @@ -0,0 +1,49 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_blacklist.xml b/app/src/main/res/menu/menu_blacklist.xml new file mode 100644 index 000000000..072968921 --- /dev/null +++ b/app/src/main/res/menu/menu_blacklist.xml @@ -0,0 +1,33 @@ + + + + + + + + diff --git a/app/src/main/res/menu/menu_details.xml b/app/src/main/res/menu/menu_details.xml new file mode 100644 index 000000000..4319b4837 --- /dev/null +++ b/app/src/main/res/menu/menu_details.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/menu/menu_download_main.xml b/app/src/main/res/menu/menu_download_main.xml new file mode 100644 index 000000000..dd592c783 --- /dev/null +++ b/app/src/main/res/menu/menu_download_main.xml @@ -0,0 +1,30 @@ + + + + + + + diff --git a/app/src/main/res/menu/menu_download_single.xml b/app/src/main/res/menu/menu_download_single.xml new file mode 100644 index 000000000..3fdef0d0d --- /dev/null +++ b/app/src/main/res/menu/menu_download_single.xml @@ -0,0 +1,36 @@ + + + + + + + + + diff --git a/app/src/main/res/menu/menu_search.xml b/app/src/main/res/menu/menu_search.xml new file mode 100644 index 000000000..fd45127de --- /dev/null +++ b/app/src/main/res/menu/menu_search.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml index a3218ea8a..6b6dae974 100644 --- a/app/src/main/res/navigation/mobile_navigation.xml +++ b/app/src/main/res/navigation/mobile_navigation.xml @@ -23,12 +23,18 @@ android:id="@+id/mobile_navigation" app:startDestination="@id/splashFragment"> + + @@ -56,19 +62,53 @@ android:name="com.aurora.store.view.ui.updates.UpdatesFragment" android:label="@string/title_updates" tools:layout="@layout/fragment_updates" /> + + + + + + + tools:layout="@layout/fragment_setting" > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/app/src/main/res/raw/google_roots_ca.pem b/app/src/main/res/raw/google_roots_ca.pem index e94a83107..bf10a6732 100644 --- a/app/src/main/res/raw/google_roots_ca.pem +++ b/app/src/main/res/raw/google_roots_ca.pem @@ -1,3 +1,33 @@ +# Operating CA: DigiCert +# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Label: "Baltimore CyberTrust Root" +# Serial: 33554617 +# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4 +# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74 +# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + # Operating CA: DigiCert # Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com # Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com @@ -243,6 +273,257 @@ r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ -----END CERTIFICATE----- +# Operating CA: Entrust Datacard +# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. +# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. +# Label: "Entrust Root Certification Authority" +# Serial: 1164660820 +# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4 +# SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9 +# SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw +NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw +NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy +ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV +BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo +Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 +4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 +KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI +rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi +94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB +sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi +gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo +kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE +vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t +O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua +AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP +9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ +eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m +0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +# Operating CA: Entrust Datacard +# Issuer: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - EC1" +# Serial: 51543124481930649114116133369 +# MD5 Fingerprint: b6:7e:1d:f0:58:c5:49:6c:24:3b:3d:ed:98:18:ed:bc +# SHA1 Fingerprint: 20:d8:06:40:df:9b:25:f5:12:25:3a:11:ea:f7:59:8a:eb:14:b5:47 +# SHA256 Fingerprint: 02:ed:0e:b2:8c:14:da:45:16:5c:56:67:91:70:0d:64:51:d7:fb:56:f0:b2:ab:1d:3b:8e:b0:70:e5:6e:df:f5 +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 +d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu +dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq +RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy +MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD +VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g +Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi +A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt +ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH +Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC +R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX +hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- + +# Operating CA: Entrust Datacard +# Issuer: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - G2" +# Serial: 1246989352 +# MD5 Fingerprint: 4b:e2:c9:91:96:65:0c:f4:0e:5a:93:92:a0:0a:fe:b2 +# SHA1 Fingerprint: 8c:f4:27:fd:79:0c:3a:d1:66:06:8d:e8:1e:57:ef:bb:93:22:72:d4 +# SHA256 Fingerprint: 43:df:57:74:b0:3e:7f:ef:5f:e4:0d:93:1a:7b:ed:f1:bb:2e:6b:42:73:8c:4e:6d:38:41:10:3d:3a:a7:f3:39 +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE----- + +# Operating CA: Entrust Datacard +# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Label: "Entrust.net Premium 2048 Secure Server CA" +# Serial: 946069240 +# MD5 Fingerprint: ee:29:31:bc:32:7e:9a:e6:e8:b5:f7:51:b4:34:71:90 +# SHA1 Fingerprint: 50:30:06:09:1d:97:d4:f5:ae:39:f7:cb:e7:92:7d:7d:65:2d:34:31 +# SHA256 Fingerprint: 6d:c4:71:72:e0:1c:bc:b0:bf:62:58:0d:89:5f:e2:b8:ac:9a:d4:f8:73:80:1e:0c:10:b9:c8:37:d2:1e:b1:77 +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 +MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub +j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo +U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b +u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ +bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er +fF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- + +# Operating CA: Entrust Datacard +# Issuer: CN=AffirmTrust Commercial O=AffirmTrust +# Subject: CN=AffirmTrust Commercial O=AffirmTrust +# Label: "AffirmTrust Commercial" +# Serial: 8608355977964138876 +# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7 +# SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7 +# SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7 +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP +Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr +ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL +MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 +yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr +VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ +nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG +XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj +vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt +Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g +N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC +nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +# Operating CA: Entrust Datacard +# Issuer: CN=AffirmTrust Networking O=AffirmTrust +# Subject: CN=AffirmTrust Networking O=AffirmTrust +# Label: "AffirmTrust Networking" +# Serial: 8957382827206547757 +# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f +# SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f +# SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y +YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua +kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL +QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp +6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG +yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i +QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO +tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu +QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ +Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u +olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 +x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +# Operating CA: Entrust Datacard +# Issuer: CN=AffirmTrust Premium O=AffirmTrust +# Subject: CN=AffirmTrust Premium O=AffirmTrust +# Label: "AffirmTrust Premium" +# Serial: 7893706540734352110 +# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57 +# SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27 +# SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz +dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG +A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U +cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf +qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ +JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ ++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS +s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 +HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 +70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG +V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S +qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S +5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia +C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX +OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE +FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 +KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B +8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ +MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc +0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ +u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF +u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH +YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 +GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO +RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e +KeC2uAloGRwYQw== +-----END CERTIFICATE----- + +# Operating CA: Entrust Datacard +# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust +# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust +# Label: "AffirmTrust Premium ECC" +# Serial: 8401224907861490260 +# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d +# SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb +# SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23 +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC +VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ +cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ +BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt +VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D +0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 +ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G +A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs +aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I +flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== +-----END CERTIFICATE----- + # Operating CA: GlobalSign # Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA # Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA @@ -433,6 +714,106 @@ pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 -----END CERTIFICATE----- +# Operating CA: GoDaddy +# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority +# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority +# Label: "Starfield Class 2 CA" +# Serial: 0 +# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24 +# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a +# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58 +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl +MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp +U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw +NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE +ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp +ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 +DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf +8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN ++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 +X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa +K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA +1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G +A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR +zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 +YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD +bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 +L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D +eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp +VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY +WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +# Operating CA: GoDaddy +# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority +# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority +# Label: "Go Daddy Class 2 CA" +# Serial: 0 +# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67 +# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4 +# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4 +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh +MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE +YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 +MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo +ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg +MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN +ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA +PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w +wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi +EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY +avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ +YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE +sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h +/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 +IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy +OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P +TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER +dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf +ReYNnyicsbkqWletNw+vHX/bvZ8= +-----END CERTIFICATE----- + +# Operating CA: Sectigo +# Issuer: CN=AAA Certificate Services O=Comodo CA Limited +# Subject: CN=AAA Certificate Services O=Comodo CA Limited +# Label: "Comodo AAA Services root" +# Serial: 1 +# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0 +# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49 +# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4 +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj +YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM +GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua +BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe +3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 +YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR +rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm +ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU +oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v +QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t +b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF +AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q +GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 +G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi +l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 +smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + # Operating CA: Sectigo # Issuer: CN=COMODO Certification Authority O=COMODO CA Limited # Subject: CN=COMODO Certification Authority O=COMODO CA Limited diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index b7da6deb7..19e3d2969 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -10,11 +10,11 @@ أربع خمس يتم التقدير - حساب Google + حساب قوقل برمجيات التتبع المعروفة الموجودة في مدير المحاكاة الوهمية الإذن الممنوح - شغِّل إعدادات المطور من إعدادات الجهاز لفتحها. + قم بتشغيل إعدادات المطور من إعدادات الجهاز لفتحها. نُسخ الى الحافظة مدرج في القائمة البيضاء اللغة @@ -26,16 +26,17 @@ التنزيلات الجهاز مدير القائمة السوداء + تطبيقات بسعر مخفض تطبيقات في المكتبة التطبيقات الحسابات - انشر + ارسال حول المتصدرة افضل التطبيقات المدفوعة الاكثر شهرة المجانية المتصدرة - أعلى القوائم + الاعلى تقييما لك انت اختيار المحرر الفئات @@ -45,11 +46,11 @@ فشل التنزيل التخصيص طريقة التثبيت - مثبِّت الجلسة - خدمات Aurora (مهمل) - مثبِّت الجذر - المثبت الأصلي (مهمل) - احذف APK بعد التثبيت + مثبت الجلسة + خدمات Aurora(مهمل) + مثبت الجذر + المثبت الأصلي(مهمل) + حذف APK بعد التثبيت تصفية تطبيقات F-Droid إذن المثبت مدير التخزين الخارجي @@ -60,11 +61,11 @@ المثبت متوفر تحديث جديد الرجاء تعطيل تحسينات MIUI للسماح بالتثبيتات، وإلا يمكنك اختيار مثبت الجذر أو الخدمات. - اكتُشف MIUI! + تم الكشف عن جهاز MIUI! شروط الخدمة الرخصة اخلاء المسؤوليه - ثُبِّت بنجاح + تم التثبيت بنجاح مساحة التخزين غير كافية تطبيق غير متوافق توجد حزمة متعارضة @@ -72,22 +73,22 @@ فشل التثبيت إيجابية الحرجه - الكل - اعرض التقرير + الجميع + عرض التقرير التحقق من وجود برمجيات تتبع… - بدعم من Exodus Privacy + بدعم من خصوصية Exodus لا يحتوي على برمجيات تتبع معروفة - استكمل الكل + استئناف الكل في قائمة الإنتظار - ألبِث + إيقاف الكل مؤقتًا لا يوجد تنزيلات الحصول على البيانات الوصفية - افرض مسح الكل + فرض مسح الكل فشل التنزيل جارِ الحساب اكتمل التنزيل - أُلغِيَ - ألغِ الكل + ألغيت + إلغاء الكل التقييمات والمراجعات الخصوصية الأذونات @@ -104,63 +105,63 @@ سجل التغييرات برنامج تجريبي القائمة البيضاء - حدِّث الكل - حدِّث + تحديث الكل + تحديث معلومات التطبيق - ألغِ التثبيت - شارك - ابحث - استكمل - أعد تشغيل + إلغاء التثبيت + مشاركة + البحث + إستئناف + إعادة تشغيل قيد الانتظار - افتح + فتح حسناً التالي تسجيل خروج غادر - لاحقًا - انضم - جارِ التثبيت + لاحقا + الانضمام + جاري التثبيت التثبيتات - ثبِّت + تثبيت تجاهل مدفوع متفرقات يعتمد على خدمات قوقل GSF - طبّق - الكل - عوامل التصفية + تطبيق + الجميع + عوامل التصفيه ممنوح - امنح - أنهِ + المنح + إنهاء التقييمات التنزيلات لا توجد تحديثات متوفرة المزيد حول التطبيق لم يتم توفير سجل التغيير - احفظ حزمة التطبيق + حفظ حزمة التطبيق التطبيقات التي تتضمن إعلانات تعذر إنشاء الجلسة الانضمام إلى البرنامج التجريبي؟ أنت أحد مختبري الإصدارات التجريبية غير متوفر في الحسابات المجهولة - حدّد وضع تثبيت APK + حدد وضع تثبيت حزمة التطبيقات APK متجر Aurora يتطلب الأذونات التالية - سيتم حذف ملفات APK التي نُزلّت فورًا بعد التثبيت - لا تتحقق من تحديثات التطبيقات المثبتة من F-Droid + سيتم حذف حزم التطبيقات المحملة والتي قد تم تثبيتها بشكل مباشر + لا تتحقق من تحديثات التطبيقات التي تم تنزيلها أو تثبيتها من F - Droid السماح بتثبيت التطبيقات من متجر Aurora - لا تتوفر عمليات شراء التطبيق على الحسابات المجهولة. + لا تتوفر عمليات شراء التطبيقات على الحسابات المجهولة. انتهت صلاحية جلسة العمل، إعادة تسجيل الدخول للحصول على جلسة عمل جديدة. ما رأيك في هذا التطبيق؟ تأكد من إعادة تسجيل الدخول لتطبيق المحاكاة التحايلية خدمات Aurora متاحة وجاهزة للتثبيت. - لا توجد صلاحيات الجذر (root)، امنح حق الوصول إلى الجذر أو غيّر المثبت. + لا توجد صلاحيات الجذر (root)، امنح حق الوصول إلى الجذر أو قم بتغيير المثبت. لا يمكن لمثبت الجلسة تثبيت التطبيقات بسبب تحسينات MIUI. - قد يستغرق التسجيل بعض الوقت، يمكنك التحقق من الحالة لاحقًا. + قد يستغرق التسجيل بعض الوقت ، يمكنك التحقق من الحالة لاحقًا. لحفظ ملفات توسيع APK (OBBs) للتطبيقات والألعاب الكبيرة. إعداد خدمات Aurora ومنح كافة الأذونات أولا. اختياريا يمكنك اختيار المثبت الأصلي، ولكن بعد ذلك لا يمكنك تثبيت التطبيقات المجمعة (تقسيم) APKs، لذلك الخيار لك. - ثبِّت خدمات Aurora 1.0.9 أو أعلى أو غيِّر المثبت. + ثبت خدمات Aurora 1.0.9 أو أعلى، أو تغيير المثبت. سترى ميزات وأخطاء جديدة قبل أن يراها المستخدمون. قدم ملاحظاتك للمطورين لمساعدتهم على التحسين من جودة تطبيقاتهم. BHIM - UPI تم تطبيق المحاكاة التحايلية للجهاز . @@ -168,16 +169,16 @@ تعذر الحصول على الملفات في انتظار تأكيد المستخدم حزمة APK غير صالحة أو تالفة - صدِّر - عطّل + تصدير + تعطيل انسخ الرابط - انسخ - أغلق - امسح - ألغِ + إنسخ + اغلاق + مسح + إلغاء أضف إلى القائمة السوداء القائمة السوداء - ارجع + رجوع تسجيل الخروج من Aurora تسجيل الدخول باستخدام حساب مجهول @@ -189,7 +190,7 @@ باي بال كن داعما على Liberapay ليبراباي - احصل على المصدر البرمجي لمتجر Aurora من Aurora OSS على GitLab. + احصل على الشفرة المصدرية لمتجر Aurora من Aurora OSS على GitLab. جيت لاب احصل على متجر Aurora عبر F-Droid. اف-درويد @@ -208,56 +209,57 @@ المكتبة تأكد من إعادة تسجيل الدخول وإعادة تشغيل التطبيق لتطبيق التغييرات. الشبكات + عرض مجموعات متشابهة وذات صلة في صفحة تفاصيل التطبيق تطبيقات مشابهة و ذات صلة عرض صفحات لك على الشاشة الرئيسية صفحات لك - حدّد علامة التبويب الافتراضية + حدد علامة التبويب الافتراضية التخطيط الإضافات لم يتم العثور على تطبيق مماثل - تهانينا، كود الإصدار المطلوب متاح، جارِ تنزيله الآن. + تهانينا ، كود الإصدار المطلوب متاح ، يتم تنزيله الآن. رمز الإصدار الذي تطلبه غير متوفر. - تنزيل يدوي + تحميل يدوي لا يمكنك تثبيت تطبيقات المجمعة او (المقسمة) عبر Native Installer. قم بتغيير المثبت الخاص بك إلى جلسة أو خدمات أو الجذر. تعذر توليد الرمز المميز ل AAS تعذر إرسال التقييم - قيَّمتَ التطبيق، قد يستغرق الأمر بعض الوقت لعرضه + تم التقييم، قد يستغرق الأمر بعض الوقت لعرضه صفحة المتصفح غير متوفرة - تعذر تصدير تضبيط الجهاز - صُدِّر تضبيط الجهاز + تعذر تصدير تكوين الجهاز + تم تصدير اعدادات الجهاز تنزيل تطبيق في الخلفية - يفعِّل تنزيل التطبيق في الخلفية - ثبِّت مدير التطبيقات أو غيِّر المثبت. + تفعيل تنزيل التطبيق في الخلفية + قم بتثبيت مدير التطبيقات أو تغيير المثبت. مثبِّت AM - مُلبَث • %1$d / %2$d + متوقف مؤقتا • %1$d / %2$d بقي %1$d دقيقة %2$d ثانية بقي %1$d ثانية - تعذّر تسجيل الدخول عبر Google + تعذّر تسجيل الدخول عبر جوجل تم إلغاء الجلسة الأخيرة التحقق من الجلسة - جارِ التحقق من جلسة Google + التحقق من جلسة قوقل حدث خطأ! القائمة توسع - رُفض الإذن المطلوب يُرجى منحها لمواصلة العمل + تم رفض الإذن المطلوب يرجى منحها لمواصلة العمل البحث عن التطبيقات والألعاب - جارِ تنزيل • %1$d / %2$d %3$s + جار التحميل • %1$d / %2$d %3$s الإشعارات إرسال إشعارات بخصوص حالة التثبيت - سجّل الدخول واستمتع. + سجيل الدخول واستمتع. واو! كل شيء جيد. تجهيز الأمور… متقدم - يتوفر تحديثات - يتوفر تحديث + التحديثات المتاحة + التحديث متاح بقي %1$d ساعة %2$d دقيقة %3$d ثانية %1$s • معرف الخدمة الفريد %2$s طلب جلسة جديدة الخادم معطل للصيانة - استورد - تعذر استيراد تضبيط الجهاز + استيراد + تعذر استيراد تكوين الجهاز تنزيل ملفات إضافية لـ %1$s - استُورد تضبيط الجهاز + تم استيراد تكوين الجهاز يتوفر أصدار جديد من %1$s متاح %1$s, %2$s, %3$s والمزيد %4$d إشعارات التحديثات @@ -265,14 +267,14 @@ تحديثات %1$d متوفرة %1$s و %2$s %1$s, %2$s و %3$s - مثبِّت شيزوكو + مثبت شيزوكو لم يتم تثبيت Shizuku أو إعداده بشكل صحيح. اقتراح البحث خطأ داخلي! من فضلك أعد المحاولة بعد فترة - الحساب محدود + عفوا ، الحساب محدود نتائج البحث فشل في الحصول على تقرير الخصوصية - رُفض الوصول! هل تستخدم VPN أو تور؟ + تم رفض الوصول! هل تستخدم VPN أو Tor؟ لا يمكن الوصول إلى الخادم فشل توليد جلسة عمل، رمز الخطأ: %1$d لغة التطبيق @@ -284,30 +286,34 @@ Google Play، المعروف أيضًا باسم متجر Google Play و Android Market سابقًا. Android Market هو متجر على الإنترنت يقدم تطبيقات برمجية مصممة لأجهزة Android، وتم إيقافه في عام 2017. عنوان المراجعة - اضبط الفواصل الزمنية للتحديثات التلقائية والذاتية، في ساعة. - تصفية التطبيقات من مصادر أخرى - لا تبحث عن تحديثات للتطبيقات المثبتة من مصادر خارج متجر أورورا - إعدادات التطبيق + المزود - bestappsales.com + تكوين الفواصل الزمنية للتحديثات التلقائية والذاتية، في ساعة. + تطبيقات متجر Aurora فقط + تحقق فقط من تحديثات التطبيقات المثبتة بواسطة متجر أورورا + إعدادات التطبيقات تردد التحديثات التلقائية + تفعيل الوكيل عنوان URL الوكيل + وكيل عنوان URL للوكيل غير صالح، تحقق من التنسيق! - عُيِّن الوكيل بنجاح + عينت الوكيل بنجاح فشل في تعيين الوكيل - الافتراضي (من تضبيط الجهاز) - نُسخة Google Play + السماح لجميع حركة المرور من التطبيق بالمرور عبر الوكيل + الافتراضي (من تكوين الجهاز) + نسخة جوجل بلاي تنزيلات الخلفية السماح لـAurora Store بتنزيل التطبيقات وتحديثها في الخلفية - التحديثات التلقائية + تحديث التطبيقات تلقائيًا التحقق والإشعار بالتحديثات المتاحة - لا تحدِّث التطبيقات تلقائيًا - اضبط سلوك التحديثات التلقائية + لا تقم بتحديث التطبيقات تلقائيًا + تكوين سلوك التحديثات التلقائية التحقق من التحديثات المتوفرة وتثبيتها تلقائيًا طلب تحليل جديد فشل تصدير ملفات APK مسح المكتملة - أظهِر التحديثات التي قد تفشل - اعرض التحديثات للتطبيقات غير المتوافقة أو المعطلة التي قد يفشل تثبيتها - أضف إلى الشاشة الرئيسية + التحديثات غير المتوافقة + عرض التحديثات للتطبيقات غير المتوافقة أو المعطلة التي قد يفشل تثبيتها + أضِف إلى الشاشة الرئيسية أداة التثبيت المستندة إلى الجلسة لملفات APK المجمعة/المقسمة موصى به ومدمج ويدعم جميع إصدارات Android المثبت القائم على النية، متاح على جميع الأجهزة @@ -323,12 +329,12 @@ المساءلة والمسؤولية أدخل رمز الإصدار الذي ترغب في تنزيله هل لديك أسئلة؟ تعرف على الإجابات - المصدر البرمجي + الكود المصدري اكتشف ما بداخله سياسة الخصوصية تعرف على كيفية استخدام Aurora Store لبياناتك المزيد - أدر حسابك + إدارة حسابك مسح مالك الجهاز يزيل Aurora Store باعتباره تطبيق مالك الجهاز سيؤدي هذا إلى إلغاء إذن مثبت الجلسة لتثبيت التطبيق بصمت. هل ترغب في متابعة مسح ملكية الجهاز؟ @@ -337,40 +343,45 @@ إضافة موزع رابط غير صالح عنوان URL للموزع - إزالة الموزع؟ + قم بإزالة الموزع يمكنك العثور على إجابات للأسئلة المتداولة (الأسئلة الشائعة) وخطوات استكشاف الأخطاء وإصلاحها والمزيد إدارة الموزعات هل ترغب في إزالة الموزع \"%1$s\"؟ عرض وإدارة موزعات الرمز المميز لتسجيلات الدخول المجهولة أضف موزع العملات الرمزية إلى متجر Aurora. توفر موزعات الرمز المميز بيانات اعتماد الحساب إلى Aurora Store لتسجيل الدخول بشكل مجهول. - أضف - أزِل + إضافة + إزالة يُرجى تسجيل الدخول إلى حساب Google Play الخاص بك عن متجر Aurora اعرف المزيد عن متجر Aurora - يمكّنك متجر Aurora من البحث عن التطبيقات وتنزيلها من متجر Google Play الرسمي. يمكنك التحقق من أوصاف التطبيق ولقطات الشاشة والتحديثات وتعليقات المستخدمين الآخرين وتنزيل APK مباشرة من Google Play على جهازك. لاستخدام متجر Aurora، يجب أن يكون لديك حساب Google Play، وأن تقوم بتسجيل الدخول إلى حساب Google Play الخاص بك عند فتح متجر Aurora وتضبيطه لأول مرة. \n \nعلى عكس متجر التطبيقات التقليدي، لا يمتلك متجر Aurora أي تطبيقات أو يرخصها أو يوزعها. يمكن الوصول إلى جميع التطبيقات وأوصاف التطبيقات ولقطات الشاشة والمحتويات الأخرى الموجودة في متجر Aurora مباشرة و/أو تنزيلها و/أو عرضها من Google Play. يعمل متجر Aurora تمامًا مثل الباب أو المتصفح، مما يسمح لك بتسجيل الدخول إلى حساب Google Play الخاص بك والعثور على التطبيقات من Google Play. \n \nيُرجى ملاحظة أن متجر Aurora لا يحصل على أي موافقة أو رعاية أو ترخيص من Google أو Google Play أو أي تطبيقات تم تنزيلها من خلال متجر Aurora أو أي من مطوري التطبيقات؛ ولا يوجد لدى متجر Aurora أي انتماء أو تعاون أو اتصال معهم. + يمكّنك متجر Aurora من البحث عن التطبيقات وتنزيلها من متجر Google Play الرسمي. يمكنك التحقق من أوصاف التطبيق ولقطات الشاشة والتحديثات وتعليقات المستخدمين الآخرين وتنزيل APK مباشرة من Google Play على جهازك. لاستخدام متجر Aurora، يجب أن يكون لديك حساب Google Play، وأن تقوم بتسجيل الدخول إلى حساب Google Play الخاص بك عند فتح متجر Aurora وتكوينه لأول مرة. +\n +\nعلى عكس متجر التطبيقات التقليدي، لا يمتلك متجر Aurora أي تطبيقات أو يرخصها أو يوزعها. يمكن الوصول إلى جميع التطبيقات وأوصاف التطبيقات ولقطات الشاشة والمحتويات الأخرى الموجودة في متجر Aurora مباشرة و/أو تنزيلها و/أو عرضها من Google Play. يعمل متجر Aurora تمامًا مثل الباب أو المتصفح، مما يسمح لك بتسجيل الدخول إلى حساب Google Play الخاص بك والعثور على التطبيقات من Google Play. +\n +\nيُرجى ملاحظة أن متجر Aurora لا يحصل على أي موافقة أو رعاية أو ترخيص من Google أو Google Play أو أي تطبيقات تم تنزيلها من خلال متجر Aurora أو أي من مطوري التطبيقات؛ ولا يوجد لدى متجر Aurora أي انتماء أو تعاون أو اتصال معهم. التطبيق غير متوفر لجهازك المفضلة - صُدِّرت المفضلة! - صُدِّرت حزمة التطبيق بنجاح + تم تصدير المفضلة! + تم تصدير حزمة التطبيق بنجاح تعذر تصدير حزمة التطبيق لم يتم العثور على تطبيقات مفضلة التطبيقات المفضلة فشل استيراد المفضلة! فشل تصدير المفضلة! - ‌استوردت المفضلة! - أُلغِيَ تثبيت التطبيق بنجاح + ‌تم استيراد المفضلة! + تم إلغاء تثبيت التطبيق بنجاح أدخل عنوان URL صالح للوكيل لتمرير جميع البيانات من خلال الوكيل. تسجيل الخروج؟ هل أنت متأكد من أنك تريد تسجيل الخروج؟ - تحقق من التحديثات + التحقق من التحديثات المطلوبة سلامة البيانات خصوصية البيانات والممارسات الأمنية التي أعلنها المطور السماح بتركيب التطبيقات من مصادر مجهولة الاختياري - عليك أن تمنح المثبت الإذن أولاً - أعد تشغيل متجر أورورا + عليك أن تمنح الإذن بالإنتقال أولاً + قد تضطر إلى إعادة منح الإذن بسبب خطأ في إطار الوصول إلى التخزين + إعادة تشغيل متجر أورورا يجب إعادة تشغيل متجر أورورا لتطبيق الإعدادات التي تم تغييرها حديثًا مصدِّر الملفات انتظر، يتم تصدير ملفك @@ -385,20 +396,21 @@ تنزيل إشعار متعلق بالحساب التوثيق مطلوب - يُرجى تسجيل الدخول إلى حساب Google Play الخاص بك لإلغاء أرشفة التطبيق! + يرجى تسجيل الدخول إلى حساب Google Play الخاص بك لإلغاء أرشفة التطبيق! البحث عن تحديثات صُنع بـ %1$s في الهند الافتراضي متوفر فشل تصدير القائمة السوداء! استوردت القائمة السوداء! - أزِل الكل - حدّد الكل + أزل الكل + حدد الكل فشل استيراد القائمة السوداء! صُدّرت القائمة السوداء! الأحدث + قد يتعين عليك إعادة تشغيل التطبيق ليعكس منحة الأذونات. جارِ التحقق - ألغِ الأرشفة + إلغاء الأرشفة غير قادر على فتح التطبيق مدعوم من Plexus التحقق من التوافق… @@ -415,64 +427,4 @@ غير معروف: لم يتم التحقق منه بعد يعمل هذا التطبيق بدون مكتبة Google الخاصة. ومع ذلك، قد يتطلب الأمر استخدام مكتبات أخرى تابعة لجهات خارجية ليعمل بشكل صحيح. لا توجد تطبيقات متاحة - استخدم microG لتسجيل الدخول إلى الحسابات - استوثق باستخدام microG عند تسجيل الدخول إلى حسابات Google لتسهيل عملية تسجيل الدخول - عيّن - عطّل - عُطّل الوكيل بنجاح - اعرض وأدر تضبيط وكيل - اضبط قيود الجهاز للتحديثات التلقائية - فقط على الشبكات غير المقيدة - عندما يكون الجهاز ساكنًا - عندما لا تكون البطارية منخفضة - التحديثات التلقائية مقيدة - فشل في التحقق من الملفات المُنزلة - متقدّم - مصدر التطبيق - التنزيلات - آخر تحديث - الحد الأدنى لإصدار أندرويد - مستوى API المستهدف - %1$d الأذونات - ثبِّت حزمة microG - توافق التطبيق - اعتماديات مفقودة - لقد قرأت ووافقت على شروط خدمة microG وسياسة الخصوصية - لم نتمكن من العثور على خدمات جوجل بلاي على جهازك، فالعديد من التطبيقات الشائعة تتطلبها الآن لتعمل بشكل صحيح! - برنامج microG مجاني ومفتوح المصدر يوفر وظائف مشابهة لتشغيل التطبيقات التي تعتمد على خدمات جوجل بلاي لأجهزة أندرويد من خلال إعادة التنفيذ.\n\nيتيح microG للتطبيقات الوصول إلى واجهات برمجة تطبيقات جوجل هذه، مما يعزز التوافق للمستخدمين مع توفير مزايا الخصوصية.\n\nسيعمل microG تلقائيًا في الخلفية عند فتح التطبيقات التي تعتمد على خدمات جوجل للأجهزة المحمولة. - اقرأ سياسة الخصوصية لـ microG - اقرأ ترخيص واتفاقية microG - زر موقع مشروع microG - البيانات التي قد يجمعها هذا التطبيق - يقول المطوِّر إن هذا التطبيق لا يجمع بيانات المستخدم. - البيانات التي قد يشاركها هذا التطبيق - يقول المطوِّر إن هذا التطبيق لا يشارك بيانات المستخدم مع شركات أو منظمات أخرى. - قد لا يزال هذا الإصدار من التطبيق يحتوي على المزيد من أدوات التتبع غير الموجودة بعد في قاعدة بيانات Exodus Privacy. - عُثر على متتبعات معروفة عددها %1$d في %2$s - لا يوجد وصف متاح - مزيد من المعلومات - يستهدف - اسم الحزمة - تقييم المحتوى - اختر تطبيقًا لمزيد من التفاصيل - لا إعلانات - لا توجد خدمات play - يجب أن يحتوي رمز الإصدار على أرقام فقط - يجهز للتثبيت - - لا أذونات مطلوبة - إذن مطلوب - مطلوب إذنان - الأذونات مطلوبة - الأذونات مطلوبة - إذن مطلوب - - فشل مثبت MicroG في تثبيت التطبيق، ويرجع ذلك على الأرجح إلى سوء التضبيط. - مثبت MicroG - يتطلب تثبيت تطبيق microG المصاحب - يساعدك على تجاوز فحص سلامة التطبيق (المثبت فقط) - جارِ التحميل - صفحة %1$d - تخطي - أعد التشغيل لتطبيق التغييرات؟ diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml index 8df6c0caa..09163a195 100644 --- a/app/src/main/res/values-ast/strings.xml +++ b/app/src/main/res/values-ast/strings.xml @@ -56,6 +56,7 @@ Desaniciar los APKs dempués d\'instalales D\'acuerdu La compra d\'aplicaciones nun ta disponible nes cuentes anónimes. + Aplicaciones en venta Nun tien dependencies Distribución Pa guardar los ficheros d\'espansión d\'APK (OBBs) p\'aplicaciones y xuegos grandes. @@ -180,6 +181,7 @@ Instalador AM Seleiciona\'l métodu d\'instalación de los archivos APK Aplicaciones asemeyaes y rellacionaes + Amuesa les aplicaciones asemeyaes y rellacionaes nes páxines de detalles de les aplicaciones Pa ti Instalóse App Installer @@ -280,7 +282,10 @@ Updates notifications Server unreachable Nun s\'atopó nenguna aplicación favorita + Proxy + Permite que tol tránsitu vaiga pel proxy Show updates for incompatible or disabled apps that may fail to install + Fornidor - bestappsales.com L\'aplicación nun ta disponible pa esti preséu Importóse la configuración del preséu Hai %1$d anovamientos disponibles @@ -337,6 +342,7 @@ Search suggestion Search results You need to grant Installer Permission first + You may have to re-grant the permission due to bug in Storage Access Framework Required Optional Hai un anovamientu de: %1$s @@ -372,6 +378,7 @@ Descargues en segundu planu Versión de Google Play La predeterminada (de la configuración del preséu) + Activar el proxy %1$s, %2$s, %3$s y %4$d más Nun se pudo xenerar la sesión Permite qu\'Aurora abra los enllaces compatibles diff --git a/app/src/main/res/values-az/strings.xml b/app/src/main/res/values-az/strings.xml index 98b38ea2a..f26d4a1aa 100644 --- a/app/src/main/res/values-az/strings.xml +++ b/app/src/main/res/values-az/strings.xml @@ -32,7 +32,7 @@ Davam et Paylaş Sil - Tətbiq məlumatı + Tətbiq Məlumatı Sınaq proqramına qoşulsun? Yenilə Ağ siyahı @@ -44,8 +44,8 @@ Qeydiyyat bir müddət ola bilər, vəziyyəti sonra yoxlaya bilərsiniz. Dəyişiklik jurnalı təmin edilməyib Açıqlama - Tərtibatçı əlaqə məlumatı - Reklamlar daxildir + Tərtibatçı ilə əlaqə + Reklamlar Daxildir Asılılıqlar E-poçt Müxtəlif @@ -60,10 +60,10 @@ Hesabata baxın Hamısı Bir - Aurora Xidmətləri 1.0.9 və ya yuxarısını quraşdır və ya quraşdırıcını dəyişdir. - Aurora Xidmətləri mövcuddur və quraşdırılmağa hazırdır. - Əsas ekranda Sizə özəl Səhifələri göstərin - Sizin üçün səhifələr + Aurora xidmətləri 1.0.9 və ya yuxarısını quraşdır və ya quraşdırıcını dəyişdir. + Aurora xidmətləri mövcuddur və quraşdırılmağa hazırdır. + Əsas ekranda Sizə Özəl Səhifələri göstərin + Sizin Üçün Səhifələr Dəyişiklikləri tətbiq etmək üçün yenidən daxil olduğunuza və tətbiqi yenidən başlatdığınıza əmin olun. Populyar Ən yüksək ödənişli @@ -79,7 +79,7 @@ Quraşdırıcı İcazələr Aurora Store-dan tətbiqləri quraşdırmağa icazə ver - F-Droid-dən quraşdırılan tətbiqlər üçün yeniləmələri yoxlama + F-Droid-dən endirilən yaxud quraşdırılan tətbiqlər üçün yeniləmələri yoxlama BHIM - UPI PayPal İxrac et @@ -104,10 +104,10 @@ Qara siyahı Qara siyahıya əlavə et Ləğv et - Təmizlə + Sil Bağla Köçür - Linki köçür + Linki Köçür Qeyri-aktiv et Uyğun tətbiq tapılmadı Asılılıq yoxdur @@ -139,7 +139,7 @@ İki App Manager quraşdırın və ya quraşdırıcını dəyişdirin. Root girişi yoxdur. İcazə ver və ya quraşdırıcını dəyişdir. - Aurora Xidmətlərin qur və əvvəlcə bütün icazələri qəbul et. + Aurora xidmətlərin qur və əvvəlcə bütün icazələri qəbul et. Quraşdırıcı uğursuz oldu Quraşdırma bloklandı Hesab yaratmaq mümkün olmadı @@ -159,10 +159,10 @@ Aurora Store aşağıdakı icazələri tələb edir Xoş Gəldiniz Nə etmək istəyirsiz? - Xarici yaddaş girişi + Xarici Yaddaş Girişi Böyük tətbiqlər & oyunlar üçün APK genişlətmə faylların (OBB) saxlamaq üçün. - Xarici yaddaş meneceri - Quraşdırıcı icazəsi + Xarici Yaddaş Meneceri + Quraşdırıcı İcazəsi Əlavələr F-Droid tətbiqlərini filtrlə Yüklənən APK-lar quraşdırıldıqdan sonra dərhal silinəcək @@ -179,7 +179,8 @@ Tərtibat İlkin səhifəni seç Oxşar və əlaqəli tətbiqlər - Endirmə alınmadı + Tətbiq təfərrüatları səhifəsində oxşar və əlaqəli qrupları göstər + Endirmə Alınmadı Tətbiq satın alınmayıb Tətbiq dəstəklənmir Tətbiq tapılmadı @@ -196,24 +197,25 @@ Tətbiqlər Tətbiqlərim və oyunlarım Kitabxanadakı tətbiqlər + Satışdakı tətbiqlər Qara siyahı meneceri Cihaz Endirmələr Play Market Quraşdırma Quraşdırıldı - Tətbiq quraşdırıcısı + Tətbiq Quraşdırıcısı Dil Kitabxana Alış tarixi Saxtalaşdırma meneceri - Yenilənmələr + Yeniləmələr Əl ilə yükləmə Gizli hesablarda mövcud deyil Qara siyahıya salındı Açmaq üçün cihaz tənzimləmələrindən yaradıcı seçimlərini aktiv edin. Cihaz hiyləsi tətbiq edildi. - Tətbiq alışları gizli hesablarda mövcud deyil. + Tətbiq alışları Gizli hesablarda mövcud deyil. İstədiyiniz versiya kodu mövcud deyil. Təbriklər, tələb olunan versiya kodu mövcuddur, indi endirilir. Baxış səhifəsi əlçatan deyil @@ -229,8 +231,8 @@ Telegram Müzakirələr və ya təkliflər üçün Aurora Dəstək qrupuna qoşulun. Haqqında - Endirilir • %1$d / %2$d %3$s - Dayandırıldı • %1$d / %2$d + Endirilir • %1$d / %2$d %3$s + Dayandırıldı • %1$d / %2$d %1$dsa %2$ddəq %3$dsn qalıb %1$dsan qalıb İdxal et @@ -241,19 +243,22 @@ Shizuku quraşdırıcısı Wiki Tez-tez verilən suallara (FAQ), problemlərin həlli addımlarına və s. cavablar tapın - Uğursuz olan yeniləmələri göstər + Uyuşmaz yeniləmələr Quraşdırma uğursuz ola biləcək uyuşmaz və ya qeyri-aktiv tətbiqlər üçün yeniləmələri göstər Tətbiqləri arxa planda endirmək və yeniləmək üçün Aurora Store-a icazə ver - Arxa plan yükləmələri + Arxa Plan Yükləmələri İlkin (cihaz quruluşundan) - Google Play versiyası + Google Play Versiyası Proksi URL - Digər mənbələrdən tətbiqləri filtrlə + Yalnız Aurora Store tətbiqləri Sevimli - Yeni yoxlama tələb et + Proksi-ni aktivləşdir + Yeni araşdırma tələb et Rəy başlığı Təmizləndi Naməlum mənbələrdən tətbiqlər quraşdırmağa icazə ver + Proksi + Tətbiqdən gələn bütün prosesin proksidən keçməsinə icazə ver Əsas ekrana əlavə et Uğurla silindi Sevimli tətbiqlər tapılmadı @@ -265,7 +270,7 @@ Hesabla əlaqəli bildiriş Son hesab ləğv edildi Gözəl! Hər şey yaxşıdır. - Aurora Store-dan xaric mənbələrdən quraşdırılan tətbiqlər üçün yeniləmələri yoxlamır + Təkcə Aurora Store ilə quraşdırılan tətbiqlər üçün yeniləmələri yoxla Xahiş olunur, Google Play hesabınıza daxil olun Google ilə daxil olmaq olmadı Tətbiq ixracı bildirişi @@ -273,18 +278,19 @@ Yükləmə bildirişi Daxil olun və həzz alın. Menyu - Server təmir səbəbilə işləmir - Birbaşa yeniləmələr + Server düzəliş səbəbilə işləmir + Tətbiqləri birbaşa yenilə Hesab yaratmaq alınmadı Mövcud yeniləmələri yoxla və bildir Yeniləmə bildirişləri Tətbiqləri birbaşa yeniləmir - Birbaşa yeniləmələr üçün vaxt intervalını saatla qur. - Tətbiq linkləri + Birbaşa və özünü yeniləmələr üçün aralıqları saatla qur. + Tətbiq Linkləri Aurora Store-un dəstəklənən linkləri açmasına icazə ver Genişləndir - Birbaşa yenilənmə davranışın qur + Birbaşa yenilənmə davranışın tərtib et Android Market, Android cihazları üçün hazırlanan sistem tətbiqlərin təklif edən, 2017-ci ildə sıradan çıxmış onlayn mağaza idi. + Təchizatçı - bestappsales.com %1$s • API %2$s Tələb olunur Zəruri deyil @@ -292,10 +298,10 @@ Qabaqcıl Proxy qurmaq olmadı Məxfilik hesabatını almaq olmadı - Server əlçatmazdır + Server data ötürmür %1$s, %2$s and %3$s Daxili xəta! Xahiş olunur, az sonra təkrar sına - Tətbiq və oyunlar axtar + Tətbiq və Oyunlar axtar yeniləmə var Yeni hesab tələb olunur yeniləmələr var @@ -303,7 +309,7 @@ Tələb olunan icazələr ləğv edildi. Fəaliyyəti davam etdirmək üçün onlara icazə ver %1$d yeniləmə var %1$s üçün yeni versiya var - Tətbiq dili + Tətbiq Dili Google Play, eləcə də Google Play Store və keçmişdə Android Market kimi bilinir. Əvvəlcə quraşdırıcı icazəsi verməlisiniz Cihaz quruluşun idxal etmək olmadı @@ -316,14 +322,15 @@ Axtarış nəticələri Cihaz quruluşu idxal edildi Proxy qurma uğurlu - %1$s, %2$s, %3$s and %4$d ədəd daha + %1$s, %2$s, %3$s and %4$d more Mövcud yeniləmələri birbaşa yoxla və quraşdır Yeni hesab təsdiqlənir İnternet bağlantısın yoxla - Google Hesabı təsdiqlənir - Tətbiq tənzimləmələri - Sevimli tətbiqlər + Google Hesabı Təsdiqlənir + Tətbiq Tənzimləmələri + Sevimli Tətbiqlər Tətbiq cihazınız üçün qüvvədə deyil + Storage Access Framework-dəki səhvə görə təkrar icazə verməli ola bilərsiniz %1$s üçün əlavə fayllar endirilir %1$s and %2$s Hamısın təmizlə @@ -331,6 +338,7 @@ Ən son Paketli/bölük APK-lar üçün hesab əsaslı quraşdırıcı APK-ları ixrac etmək olmadı + İcazə qəbulun öyrənmək üçün tətbiqi təkrar başlatmalı ola bilərsiniz. Intent əsaslı quraşdırıcı, bütün cihazlarda var Yaradıcı əlavə edin Gözləyin, faylınız ixrac edilir @@ -341,7 +349,7 @@ Gizli girişlər üçün nişan yaradanlara baxın və idarə edin Yaradıcı yoxdur Qara siyahını idxal etmək alınmadı! - Tətbiq paketi ixrac edilmədi + Tətbiq paketini ixrac etmək alınmadı Tətbiqi arxivdən çıxarmaq üçün Google Play hesabınıza daxil olun! Mənbə kodu Hesabat vermə və məsuliyyət @@ -379,14 +387,14 @@ Aurora Store-a nişan yaradıcı əlavə edin. Nişan yaradıcılar gizli şəkildə daxil olmaq üçün Aurora Store-a hesab etimadnaməsini təqdim edir. Yaradıcı URL Yaradıcını sil - Yaradıcını çıxarmaq istəyirsiniz\" %1$s \"? + Yaradıcını çıxarmaq istəyirsiniz?\" %1$s \" Əlavə et Sil Sevimlilər ixrac edildi! Qara siyahını ixrac etmək alınmadı! Qara siyahı idxal edildi! Qara siyahı ixrac edildi! - Fayl ixrac aləti + Fayl İxrac Aləti Çıxmaq istədiyinizə əminsiniz? Yeniləmələri yoxlayın Uğursuz oldu @@ -399,62 +407,5 @@ Aurora Store Haqqında Shizuku və ya Sui tələb olunur, quraşdırma və icazə tələb olunur Çıxılsın? - Aurora Store sizə rəsmi Google Play Mağazasından tətbiqlər axtarmağa və yükləməyə imkan verir. Tətbiq açıqlamalarını, ekran görüntülərini, yeniləmələri, digər istifadəçilərin şərhlərini yoxlaya və APK-nı birbaşa Google Play-dən cihazınıza endirə bilərsiniz. Aurora Store istifadə etmək üçün Google Play hesabınız olmalıdır və Aurora Store\'u ilk dəfə açıb quranda Google Play hesabınıza daxil olmalısınız.\n\nƏnənəvi tətbiq mağazasından fərqli olaraq, Aurora Store hər hansı tətbiqə sahiblik etmir, lisenziya vermir və ya paylaşmır. Aurora Store-dakı bütün tətbiqlər, tətbiq açıqlamaları, ekran görüntüləri və qalan məzmun birbaşa Google Play-dən əldə edilir, endirilir və/və ya göstərilir. Aurora Store məhz elə qapı və ya brauzer kimi işləyir, Google Play hesabınıza daxil olmağa və Google Play-dən tətbiqləri tapmağa imkan verir. \n\nNəzərə alın ki, Aurora Store- un Google, Google Play, Aurora Store vasitəsilə endirilən tətbiqlər və ya hər hansı tətbiq tərtibatçılarından təsdiqi, sponsorluğu və ya icazəsi yoxdur; nə də Aurora Store-un onlarla bağlılığı, əməkdaşlığı və ya əlaqəsi yoxdur. - microG Bundle Quraşdır - Bu tətbiqin toplaya biləcəyi məlumat - Tərtibatçı deyir ki, bu tətbiq istifadəçi məlumatını toplamır. - Bu tətbiqin paylaşa biləcəyi məlumat - Tərtibatçı deyir ki, bu tətbiq istifadəçi məlumatını digər şirkətlər və ya təşkilatlarla paylaşmır. - Tətbiqin bu versiyasında hələ Exodus Privacy məlumat bazasında olmayan daha çox izləyici ola bilər. - <xliff:gid=\"app_version_name\">%2$s</xliff:g> içində olan <xliff:gid=\"number_of_trackers\">\n%1$d</xliff:g> izləyici tapıldı - Əlçatan tətbiq yoxdur - Yükləmələr - Son yenilənmə - Ən Aşağı Android Versiyası - Hədəf API Səviyyəsi - Tətbiq Uyğunluğu - Çatışmayan asılılıqlar - Mən microG Xidmət Şərtləri və Məxfilik Siyasətini oxudum və razıyam - Cihazınızda Google Play Xidmətlərini tapa bilmədik, indi bir neçə məşhur tətbiq onun düzgün işləməsini tələb edir! - microG, Android cihazları üçün Google Play Xidmətlərindən asılı olan tətbiqləri təkrar həyata keçirməklə işlətmək üçün oxşar funksionallığı təmin edən pulsuz və açıq mənbəli proqramdır. \n\nmicroG tətbiqlərə həmin Google API-lərinə daxil olmaq imkanı verir, məxfilik üstünlükləri təklif edərkən istifadəçilər üçün uyğunluğu artırır.\n\nmicroG Google Mobil Xidmətlərindən asılı olan tətbiqləri açdığınız zaman birbaşa arxa planda işləyəcək. - microG Məxfilik Siyasətini Oxuyun - microG Lisenziyasını və Sazişini Oxuyun - microG Layihə Veb Saytın Ziyarət Et - Açıqlama yoxdur - %1$d icazə - Ətraflı məlumat - Hədəflər - Paket adı - Məzmun reytinqi - Plexus tərəfindən Gücləndirilib - Uyğunluq yoxlanılır… - Uyğunluq - Google Play Xidmətləri Tələb Edir - Google-un xüsusi kitabxanasını və ya microG kimi FOSS yenidən qurmasını quraşdırmalı ola bilərsiniz. - Google Play Xidmətləri olmadan işləyir - Bu tətbiq Google-un xüsusi kitabxanası olmadan işləyir. Hər halda, bu, hələ də digər üçüncü tərəf kitabxanalarının düzgün işləməsini tələb edə bilər. - microG Layihəsi ilə - Google Play Xidmətləri Yoxdur - Uyğun: Hər hansı problem olmadan işləyir - Məhdud: Məhdud funksiyalarla işləyir - Dəstəklənmir: İşlək deyil - Naməlum: Hələ yoxlanılmayıb - %1$d tətbiq quruldu - Hesablara daxil olmaq üçün microG istifadə et - Daha sadə giriş axını üçün Google hesablarına daxil olarkən microG istifadə edərək təsdiqləmə et - Təyin et - Qapat - Proksi uğurla qapadıldı - Proksi konfiqurasiyasına bax və idarə et - Qabaqcıl - Birbaşa yeniləmə məhdudiyyətləri - Avtomatlaşdırılan yeniləmələr üçün cihaz məhdudiyyətlərini konfiqurasiya edin. - Yalnız ölçülməyən şəbəkələrdə - Cihaz boş olduqda - Batareya zəif olmayanda - Tətbiq mənbəyi - Endirilmiş faylları təsdiqləmək alınmadı - Ətraflı məlumat üçün tətbiq seç - Reklam yoxdur - play xidmətləri yoxdur + Aurora Store sizə rəsmi Google Play mağazasından tətbiqlər axtarmağa və yükləməyə imkan verir. Tətbiq açıqlamalarını, ekran görüntülərini, yeniləmələri, digər istifadəçilərin şərhlərini yoxlaya və APK-nı birbaşa Google Play-dən cihazınıza endirə bilərsiniz. Aurora Store istifadə etmək üçün Google Play hesabınız olmalıdır və Aurora Store\'u ilk dəfə açıb quranda Google Play hesabınıza daxil olmalısınız.\n\nƏnənəvi tətbiq mağazasından fərqli olaraq, Aurora Store hər hansı tətbiqə sahiblik etmir, lisenziya vermir və ya paylaşmır. Aurora Store-dakı bütün tətbiqlər, tətbiq açıqlamaları, ekran görüntüləri və qalan məzmun birbaşa Google Play-dən əldə edilir, endirilir və/və ya göstərilir. Aurora Store məhz elə qapı və ya brauzer kimi işləyir, Google Play hesabınıza daxil olmağa və Google Play-dən tətbiqləri tapmağa imkan verir. \n\nNəzərə alın ki, Aurora Store- un Google, Google Play, Aurora Store vasitəsilə endirilən tətbiqlər və ya hər hansı tətbiq tərtibatçılarından təsdiqi, sponsorluğu və ya icazəsi yoxdur; nə də Aurora Store-un onlarla bağlılığı, əməkdaşlığı və ya əlaqəsi yoxdur. diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml index 772639789..b97fd0052 100644 --- a/app/src/main/res/values-be/strings.xml +++ b/app/src/main/res/values-be/strings.xml @@ -1,13 +1,13 @@ - Вікі - Знайдзіце адказы на частыя пытанні (F.A.Q.), крокі для вырашэння непаладак і шмат іншага + Wiki + Знайдзіце адказы на часта задаваныя пытанні (Ч.З.П.), непаладакі і многае іншае BHIM - UPI Ахвяраваць праз UPI Bitcoin Cash - Ахвяраваць праз Bitcoin Cash (BCH) + Ахвяраваць Bitcoin Cash (BCH) Bitcoin - Ахвяраваць праз Bitcoin (BTC) + Ахвяраваць Bitcoin (BTC) F-Droid Атрымаць Aurora Store праз F-Droid. GitLab @@ -15,271 +15,277 @@ Стаць мецэнатам на Liberapay Ахвяраваць праз PayPal Telegram - Далучыцца да суполкі Aurora Support для абмеркавання або прапаноў. - Форумы XDA - Далучайцеся да абмеркавання Aurora Store у адпаведным раздзеле вэб-сайта XDA. - Увайсці з дапамогай + Далучыцца да падтрымкі Aurora Support для падтрымкі альбо прапаноў. + XDA Forums + Праглядзець абгаворванне ў Aurora Store XDA. + Увайсці з дапамогаю Выйсці з Aurora Вярнуцца Чорны спіс - Дадаць у чорны спіс + Дадаць да чорнага спісу Скасаваць Ачысціць - Скапіяваць + Капіяваць Імпартаваць - Абраныя + Абранае Прымяніць - Праграмы з рэкламай + Прыкладанні з рэкламай Спампоўкі Рознае Платнае - Рэйтынг - Завяршыць + Рэйтынгі + Завершыць Дазволіць Дазволена Ігнараваць Далучыцца Пазней - Выйсці + Пакінуць Выйсці Далей - OK + Добра Адкрыць У чаканні - Апублікаваць - Запытаць новы аналіз + Даслаць + Запыт на новы аналіз Перазапусціць Працягнуць - Шукаць + Пошук Паспяхова выдалена - Дадаць на галоўны экран - Спіс змен - Вэб-сайт - Праграма не знойдзена - Абраныя праграмы не знойдзены + Дадаць на хатні экран + Спіс зменаў + Вебсайт + Адсутнічаюць супадзенні + Адсутнічаюць абраныя Адсутнічаюць дазволы Дазволы - Бяспека даных + Бяспека дадзеных Прыватнасць - Загаловак водгуку - Як вам гэта праграма? + Назва водгуку + Што думаеш наконт гэтага прыкладання? Скасавана Спампоўка завершана - Падлік - засталося %1$d сек - Збой спампоўкі - Прымусова ачысціць усе - Прыпыніць усе + Разлік + засталося %1$d секунд + Памылка спампоўкі + Прымусова ачысціць усё + Прыпыніць усё У чарзе - Працягнуць усе - Ацэнка - Не ўтрымлівае вядомых праграм сачэння - На платформе Exodus Privacy - Праверка на наяўнасць праграм сачэння… - знойдзены вядомыя праграмы сачэння + Працягнуць усё + Ацэньванне + Не ўтрымлівае вядомых трэкераў + Пры падтрымцы Exodus Privacy + Праверка трэкераў… + вядомы трэкер(ы) знайдзены ў Крытычны Пяць Чатыры - Адзін - Пазітыўны + Адна + Пазітыўныя Тры Два - Усталюйце менеджар праграм або змяніце ўсталёўшчык. - Адсутнічае доступ суперкарыстальніка. Дайце адпаведны дазвол або змяніце ўсталёўшчык. - Наладзьце сэрвісы Aurora і дайце ўсе дазволы. - Збой усталёўшчыка - Несумяшчальная праграма - Памылковы або пашкоджаны APK - Недастаткова месца на прыладзе - Чаканне пацвярджэння карыстальнікам + Усталюйце Мэнаджэр прыкладанняў альбо змяніце ўсталёўшчык. + Адсутнічае root. Дазвольце яго альбо змяніце ўсталёўшчык. + Найперш устлюйце сэрвісы Aurora і дазвольце доступы. + Памылка ўсталёўшчыка + Несумяшчальнае прыкладанне + Пашкоджаны альбо сапсаваны APK + Недастаткова прасторы памяці + Чаканне пацьверджання карыстальнікам Ліцэнзія - Выяўлены MIUI! - Усталёўшчык сеанса не можа ўсталёўваць праграмы з прычыны аптымізацыі MIUI. - Адключыце аптымізатар MIUI аптымізатар, каб дазволіць усталяванні. У адваротным выпадку скарыстайцеся функцыяй суперкарыстальніка або сэрвісамі Aurora. + MIUI выяўлены! + Сэсійны ўсталёўшчые не можа усталёўваць прыкладанні праз MIUI Аптымізатар. + Калі ласка, адключыце MIUI аптымізатар, каб дазволіць ўсталёўкі, інакш выкарыстоўвайце Root альбо Сэрвісны ўсталёўшчык. Усталёўшчык - Даступна новае абнаўленне - Пакетныя праграмы (.apks) немагчыма ўсталяваць сістэмным усталёўшчыкам. Змяніце спосаб усталявання на сеансавы, сэрвісны або суперкарыстальнік. + Новыя абнаўленні даступныя + Вы не можаце ўсталяваць раздзеленае прыкладанне праз родны ўсталёўчык. Змяніце свой ўсталёўшчык для сэсіі, сэрвіса, альбо root. Aurora Store запытвае наступныя дазволы - Як справы? - Доступ да знешняга сховішча - Дазволіць усталяванне праграмы з Aurora Store + Як яно? + Доступ да знешней памяці + Дазволіць усталёўку праз Aurora Store Дазвол усталёўшчыка - Фонавыя спампоўкі - Дазволіць Aurora Store усталёўваць і абнаўляць праграмы ў фоне - Фільтраваць праграмы з F-Droid - Не правяраць наяўнасць абнаўленняў для праграм, якія ўсталяваны з F-Droid - Спампаваныя APK будуць выдалены неадкладна пасля ўсталявання - Выдаляць APK пасля ўсталявання - Усталёўшчык AM - Усталёўшчык суперкарыстальніка - Сэрвісы Aurora (састарэлыя) - Выберыце варыянт усталявання APK - Версія Google Play - URL-адрас проксі - Увядзіце сапраўдны URL-адрас проксі для праходжання ўсяго трафіку праз яго. - Падобныя і звязаныя праграмы - Не правяраць наяўнасць абнаўленняў для праграм, якія ўсталяваны з крыніц па-за межамі Aurora Store - Збой спампоўкі - Немагчыма атрымаць файлы - Праграма не знойдзена - Апошні сеанс быў скасаваны - Спраўджанне сеанса - Рэкамендуем - Выбар рэдакцыі - Папулярныя - Налады праграмы - Мае праграмы і гульні - Кіраванне чорным спісам - Абраныя праграмы - Недаступна з ананімным уліковым запісам + Фонавая ўсталёўка + Дазволіць Aurora Store усталёўваць і абнаўляць прыкладанні ў фоне + Фільтар прыкладанняў F-Droid + Ігнараваць F-Droid прыкладанні ў Абнаўленні і Усталяваныя прыкладанні + Спампаваныя APK будуць выдаленыя адразу пасля ўсталявання + Выдаліць APK пасля ўсталявання + Кіраўнік прыкладанняў + Root усталёўшчык + Aurora Services (Састарэлы) + Абярыце варыянт усталявання APK + Google Play Version + URL проксі + Увядзіце сапраўдны URL для праходжання ўсяго трафіку праз проксі. + Падобнае + Паказваць падобныя ці звязаныя прыкладанні + Паказаваць толькі прыкладанні Aurora Store у Абнаўленні і Усталяваныя прыкладанні + Памылка спампоўкі + Не атрымалася атрымаць файл + Прыкладанне не знайдзена + Апошні сеанс скасаваны + Праверка сеансу + Парады + Выбар рэдактараў + Прарыўное + Налады прыкладання + Мае прыкладанні і гульні + Прыкладанні на распродажы + Прадстаўнік - bestappsales.com + Чорны спіс + Абраныя прыкладанні + Не магчыма праз ананімны акаўнт У чорным спісе - Не ўдалося адкрыць налады распрацоўшчыка. Пераканайцеся, што вы іх уключылі ў наладах прылады. - Купля праграм немагчыма з ананімнымі ўліковымі запісамі. - Запытаны вамі код версіі недаступны. - Немагчыма адправіць ацэнку - Немагчыма стварыць токен AAS - Канфігурацыі прылады экспартавана - Немагчыма экспартаваць канфігурацыю прылады - Канфігурацыя прылады імпартавана - Немагчыма імпартаваць канфігурацыю прылады - Памылковы URL-адрас проксі. Праверце яго фармат! - Проксі паспяхова зададзены - Не ўдалося задаць проксі - Фонавая спампоўка праграм - Уключае фонавую спампоўку праграм - даступна абнаўленне - даступна абнаўленняў - Абавязкова - Апавяшчэнні аб абнаўленні - %1$s, %2$s, %3$s і яшчэ %4$d - Правяраць і ўсталёўваць даступныя абнаўленні аўтаматычна - Не ўдалося атрымаць справаздачу аб прыватнасці - Не ўдалося згенерыраваць сеанс, код памылкі: %1$d - Праверце падключэнне да інтэрнэту + Для пераключэння ў рэжым распрацоўніка пераключыце іх ў адпаведных наладах. + Набыццё прыкладанняў немагчыма праз ананімныя акаўнты. + Запыт на код версію недаступны. + Не атрымалася адаслаць адзнаку + Не атрымалася стварыць токен AAS + Канфігурацыі прылады экспартаваны + Не атрымалася экспартаваць налады прылады + Канфігурацыі прылады імпартаваны + Не атрымалася імпартаваць канфігурацыі налад + Памылковы URL проксі, праверце фармат! + Проксі задзейчаны паспяхова + Памылка пры задзеянні проксі + Фонавая спампоўка прыкладання + Задзейнічана фонавая спампоўка прыкладання + даступнае абнаўленне + даступныя абнаўленні + Неабходна + Паведамленні аб абнаўленнях + %1$s, %2$s, %3$s і %4$d больш + Праверыць і ўсталяваць даступныя абнаўленні аўтаматычна + Памылка запыту спаваздачы прыватнасці + Атрыманне новай сэсіі, код памылкі: %1$d + Праверка інтэрнэт злучэння Макет - Праграма ўсталявання для раздзеленых/пакетных файлаў APK - Усталёўшчык на базе Shell з выкарыстаннем правоў суперкарыстальніка - Патрабуюцца прывілеі суперкарыстальніка для падтрымкі ўсіх версій Android. - Рэкамендавана, убудаваны і падтрымлівае ўсе версіі Android - Менеджар праграм з\'яўляецца абавязковым. Для яго ўсталявання неабходны рэжым adb/root пры ўключанай аптымізацыя MIUI - Поўнафункцыянальны менеджар пакетаў з адкрытым зыходным кодам + прыкладанняўа ўсталёўкі на аснове сеанса для пакетных/падзеленых APK + Усталёўка на аснове абалонкі з выкарыстаннем root правоў + Патрабуе прывілеяў root/superuser, падтрымлівае ўсе Android версіі. + Рэкамендуецца, убудаваны і падтрымліваючы ўсе версіі Android + Патрабуецца кіраўнік прыкладанняў, патрэбны рэжым adb/root для ўстаноўкі, калі ўключана аптымізацыя miui + Поўнафункцыянальны кіраўнік пакетаў з адкрытым зыходным кодам Зыходны код - Засталіся пытанні? Знаходзьце адказы - Увядзіце код версіі, якую хочаце спампаваць + Маеце пытанні? Знаходзьце адказы + Увядзіце код версіі, якую неабходна спампаваць Палітыка прыватнасці Даведайцеся, што ўнутры - Дадаткова - Кіраванне ўліковым запісам - Ачысціць прыладу ўладальніка + Падрабязней + Кіруй сваім акаўнтам + Ачысціць прыладу уладальніка Дадаць размеркавальнік Прагляд і кіраванне размеркавальнікамі токенаў для ананімных уваходаў - Размеркавальнікі недаступны - URL-адрас размеркавальніка - Памылковы URL-адрас + Размеркавальнікі адсутнічаюць + Размеркавальнік URL + Памылковы URL Абранае імпартавана! Абранае экспартавана! - Пачакайце... Адбываецца экспартаванне файла - Вы сапраўды хочаце выйсці? - Праграма экспарту файлаў - Абнавіць усе - Сеанс завершаны. Увайдзіце яшчэ раз, каб пачаць новы сеанс. - Даступна %1$d абнаўленне - Канфігурацыя паводзін аўтаматычных абнаўленняў - Сканфігурыруйце інтэрвал аўтаматычных абнаўленняў, у гадзінах. - Мова праграмы - Выберыце прадвызначаную ўкладку - Не ўдалося экспартаваць APK - Дазволіць Aurora Store адкрываць спасылкі, якія падтрымліваюцца - Android Market - гэта сеткавая крама, якая прапаноўвала праграмы адмыслова для прылад на базе АС Android. Праца была згорнута ў 2017 годзе. - Класічны ўсталёўшчык. Даступна на ўсіх прыладах - Скапіяваць спасылку - Усталяванні + Пачакайце, экспартую файл + Сапраўды жадаеш выйсці? + Праглядчык файлаў + Абнавіць усё + Сэсія завяршылася, перазайдзіце пад новай сэсіяй. + %1$d абнаўленне даступнае + Налады аўтаабнаўленняў + Наладзіць час для аўтаматычнага абнаўлення. + Мова прыкладання + Абярыце макет па-змаўчанні + Памылка пры экспартаванні APK + Дазволіць Aurora Store для адкрыцця спасылак + Android Market - анлайн крама па распаўсюду прыкладанняў, прыпыніла працу ў 2017. + Усталёўка грунтуецца на намерах, даступная на ўсіх прыладах + Капіяваць спасылку + Усталёўкі Ethereum - Закрыць + Зачыніць Ахвяраваць праз Ethereum (ETH) - Атрымаць зыходны код Aurora Store з Aurora OSS на GitLab. + Атрымаць зыходны код Aurora Store праз Aurora OSS на GitLab. PayPal - Ананімна + Ананім Google Адключыць Экспартаваць Фільтры - Усе - Залежны ад GSF - Бэта-тэсціраванне + Усё + GSF залежны + Бэта версія Усталяваць Усталяванне - Абагуліць + Падзяліцца Выдаліць - Інфармацыя аб праграме + Падрабязней Абнавіць Белы спіс - Вы з\'яўляецеся бэта-тэсціроўшчыкам - Электронная пошта - У вас будзе магчымасць бачыць новыя функцыі і памылкі да таго, як іх убачыць большасць карыстальнікаў. Пакіньце водгук распрацоўшчыкам, каб дапамагчы ім удасканаліць праграму. - Спіс змен не забяспечаны + Ты бэта тэсціроўшчык + Электронная скрынка + Атрымаць магчымасць пабачыць новы функцыянал і дэфекты перад усеагульным доступам. Дасылайце водгук распрацоўшчыкам для ўдасканальвання прадукту. + Спіс зменаў адсутнічае Залежнасці Платнае - Ацэнкі і водгукі + Агляды і адзнакі Профіль распрацоўшчыка - Бясплатна + Безкаштоўна Апісанне Адрас Адсутнічаюць абнаўленні Звязацца з распрацоўшчыкам - Патрабуецца GSF - Больш аб гэтай праграме - Без рэкламы - Паглядзець справаздачу - Заяўленыя распрацоўшчыкам практыкі бяспекі і прыватнасць даных - Скасаваць усе + Патрабуе GSF + Больш аб гэтым прыкладанні + Адсутнічае рэклама + Праглядзець справаздачу + Прыватныя дадзеныя і практыкі прыватнасці задэклараваныя распрацоўшчыкам + Скасаваць усё Ачысціць завершаныя - Спампоўкі адсутнічаюць - засталося %1$d гадз %2$d хв %3$d сек - засталося %1$d хв %2$d сек - Атрыманне метаданых + Адсутнічаюць спампоўкі + засталося %1$d гадзін %2$d хвілін %3$d секунд< + засталося %1$d хвілін %2$d секунд + Атрыманне метададзеных Прыпынена • %1$d / %2$d - Спампоўванне • %1$d / %2$d%3$s + Спампоўка • %1$d / %2$d%3$s Усе - Shizuku не ўсталяваны або няправільна наладжаны. + Shizuku не ўсталяваны альбо мае памылку. Канфліктуе з існуючым пакетам Сэрвісы Aurora даступны і гатовы да ўсталявання. - Немагчыма стварыць сеанс - Усталюйце сэрвісы Aurora 1.0.9 або вышэй. Таксама вы можаце змяніць усталёўшчык. - Усталяванне было заблакіравана + Не атрымалася стварыць сеанс + Усталюйце сэрвісы Aurora 1.0.9 ці вышэй, альбо змяніце ўсталёўшчык. + Усталёўка была заблакавана Паспяхова ўсталявана Адмова ад адказнасці Умовы абслугоўвання - Адпраўляць апавяшчэнні аб статусе ўсталявання - Патрабуецца Shizuku або Sui. Нешта з гэтага павінна быць усталявана з адпаведным дазволам - Паказваць абнаўленні для несумяшчальных або адключаных праграм, якія могуць не ўсталявацца - Гэта можа заняць пэўны час. Статус можна праверыць пазней. - Далучыцца да бэта-тэсціравання? - Залежнасці адсутнічаюць - Прысутнічае рэклама - Усталёўшчык сеанса - Спосаб усталявання - Паказвае старонку «Для вас» на галоўным экране + Дасылаць паведамленнем пра стан усталявання + Патрабуецца Shizuku або Sui, павінен быць усталяваны і дазвол прадастаўлены + Паказваць абнаўленні для несумяшчальных ці адключаныя прыкладанняў які могуць мець памылку пры ўсталяванні + Гэта можа заняць пэўны час, статус можна праверыць пазней. + Далучыцца да бэта тэставання? + Адсутнічаюць залежнасці + Утрымлівае рэкламу + Усталёўка праз сэсію + Варыянт усталявання + Паказвае старонку з парадамі на хатнім экране Скапіявана ў буфер абмену - Абавязковыя дазволы былі адхілены. Забяспечце іх, каб працягнуць дзеянне - Захаваць пакет праграмы - Пры жаданні вы можаце выкарыстоўваць убудаваны ўсталёўшчык, але ў вас не будзе магчымасці ўсталёўваць раздзеленыя APK (.apks). Выбар за вамі. - Дазволіць усталяванне праграм з невядомых крыніц - Прагляд старонкі недаступны - Патрабуецца, каб Aurora Services было ўсталявана з пашыранымі сістэмнымі прывілеямі + Запыт быў адхілены. Калі ласка надайце іх для працягу + Захаваць APK прыкладання + Па змаўчанні можа выкарыстоўваць убудаваны ўсталёўшчык, але будзе адстунічаць раздзяленне APKs, выбар за карыстальнікам. + Дазволіць ўсталёўку прыкладанняў праз невядомыя крыніцы + Прагляд старонкі немагчымы + Патрабуецца ўстаноўка Aurora Services як прыкладанне прывілеяванай сістэмы Дазволы - Вітаем - Для захавання файлаў з пашырэннем APK (OBB) для вялікі праграм і гульняў. - Менеджар знешняга сховішча - Апавяшчэнні + Вітайма + ля захавання APK (OBBs), цяжкіх прыкладанняў ці гульняў. + Кіраўнік знешняй памяці + Паведамленні Апавяшчэнне аб экспарце праграмы Апавяшчэнне аб усталяванні Апавяшчэнне аб спампоўках Дадаткова Усталёўшчык Shizuku - Сістэмны ўсталёўшчык (састарэлы) - Прадвызначана (праз налады прылады) + Родны ўсталёўшчык (Састарэлы) + Па змаўчанні (праз налады прылады) Сетка + Проксі + Задзейнічаць проксі + Дазволіць увесь трафік з прыкладання праходзіць праз проксі Прапановы пошуку Вынікі пошуку Абнаўленні @@ -287,190 +293,95 @@ Адсутнічае сетка Гісторыя купленага Налады - Менеджар падмены - Пашыраныя - Спампаваць уручную + Кіраўнік падменай + Пашыраны + Спампаваць уласнаруч У белым спісе - Праграма недаступна на гэтай прыладзе + Прыкладанне не даступнае на гэтай прыладзе Дазвол атрыманы - Спачатку неабходна даць неабходныя дазволы ўсталёўшчыку + Найперш неабходна атрымаць дазвол на ўсталяванне + Магчыма спатрэбіцца даць паўторны дазвол у фрэймворку доступу памяці Прыменена падмена прылады. - Віншуем! Даступны код запытанай версіі. Пачалося спампоўванне. - Ацэнка адпраўлена. Можа спатрэбіцца пэўны час перад тым, як яна будзе паказана - Персаналізацыя - Старонкі з рэкамендацыямі - Самае папулярнае - Аб праграме - Праграмы ў бібліятэцы + Віншую, запыт на код версію даступны, спампоўваецца зараз. + Ацэнена, гэта можа заняць пэўны час + Знешні выгляд + Парады + Найпапулярнае + Падрабязней + Прыкладанні ў бібліятэцы Прылада Спампоўкі - Крама Play + Play Store Гульні - Усталяванне + Усталёўка Усталявана - Усталёўшчык праграм + Усталёўшчык Мова Адбылася памылка! Меню Разгарнуць Не абавязкова - Пошук праграм і гульняў - Даступна %1$d абнаўленні - Аўтаматычныя абнаўленні - Не абнаўляць праграмы аўтаматычна - Праверыць і апавясціць аб даступных абнаўленнях - Частата аўтаматычных абнаўленняў + Пошук сярод прыкладанняў і гульнаў + %1$d абнаўленні даступныя + Аўтаабнаўленне + Не аўтаабнаўляць + Праверыць і паведаміць даступнасць абнаўленняў + Аўтаматычныя абнаўленні ў пэўны час Сервер недаступны - Спасылкі праграмы - Google Play, таксама вядомы як Google Play Store (раней быў вядомы пад назвай Android Market). - Лепш за ўсё падыходзіць для прылад з Android 4.4 і ніжэй + Спасылкі прыкладання + Google Play, гэтак жа вядомы як Google Play Store, а раней - Android Market. + Лепш за ўсё падыходзіць для прылад з Android ніжэй 4.4 Даведайцеся, як Aurora Store выкарыстоўвае вашы даныя - Усталёўшчык для фонавых усталяванняў + Усталёўшчык для фонавай ўстаноўкі Непасрэднае выкарыстанне сістэмных API з прывілеямі adb/root - Аб Aurora Store - Справаздачнасць і адказнасць - Даведайцеся больш аб Aurora Store - Патрабуецца перазапуск Aurora Store, каб прымяніць змены + Пра Aurora Store + Падсправаздачнасць і адказнасць + Даведайцеся больш пра Aurora Store + Aurora Store трэба перазапусціць, каб прымяніць змены Перазапусціць Aurora Store Праверыць наяўнасць абнаўленняў - Выйсці? - Не ўдалося экспартаваць набор праграм - Набор праграм паспяхова экспартаваны - Не ўдалося экспартаваць абраныя! - Не ўдалося імпартаваць абранае! + Выходзім? + Не атрымалася экспартаваць набор прыкладанняў + Набор прыкладанняў паспяхова экспартаваны + Памылка экспартавання абранага! + Памылка імпартавання абранага! Выдаліць Дадаць - Вы сапраўды хочаце выдаліць размеркавальнік \" %1$s\"? - Выдаліць размеркавальнік? + Вы хочаце выдаліць размеркавальнік\\\" %1$s\\\"? + Выдаліць размеркавальнік Выдаляе Aurora Store як праграму ўладальніка прылады - Гэта дзеянне адклікае дазвол усталёўшчыка на бясшумнае ўсталяванне праграмы. Вы сапраўды хочаце працягнуць? + Гэта адкліча дазвол праграмы ўсталёўкі сеанса на бясшумную ўстаноўку праграмы. Працягнуць ачыстку прылады карыстальніка? Кіраванне размеркавальнікамі - Дадайце размеркавальнік токенаў у Aurora Store. Размеркавальнікі токенаў забяспечваюць уліковыя даныя ў Aurora Store для ананімнага ўваходу. - Фільтраваць праграмы з іншых крыніц - Праграма не куплена - Праграма не падтрымліваецца + Дадайце размеркавальнік жэтонаў у Aurora Store. Размеркавальнік жэтонаў перадае уліковыя даныя ўліковага запісу ў Aurora Store для ананімнага ўваходу. + Толькі прыкладанні Aurora Store + Прыкладанне не набыта + Прыкладанне не падтрымліваецца Увайдзіце і атрымлівайце асалоду. - Ура! Усё ў парадку. - Паказваць абнаўленні, якія могуць не спрацаваць + Так! Усё атрымалася. + Несумяшчальнае Падрыхтоўка… - Увайдзіце ў свой уліковы запіс Google Play - Немагчыма ўвайсці праз Google - Спраўджанне сеанса Google - Пераканайцеся, што вы паўторна ўвайшлі ў сістэму, каб прымяніць падмену - Пераканайцеся, што вы паўторна ўвайшлі ў сістэму і перазапусціце праграму, каб прымяніць змены. + Калі ласка, увайдзіце ў свой Google Play акаўнт + Не атрымалася ўвайсці праз Google + Праверка Google сеансу + Пераканайцеся, што адбыўся перазаход у сістэму з падменай + Пераканайцеся, што паўторна ўвайшлі ў сістэму і перазапусціце прыкладанне, для прыняцця змен. Катэгорыі - Лепшыя бясплатныя - Самыя касавыя - Лепшыя платныя - Уліковыя запісы - Праграмы + Безкаштоўнае + Спампоўваемае + Платнае + Акаўнты + Прыкладанні %1$s • API %2$s - Запыт новага сеанса - Сервер адключаны для тэхнічнага абслугоўвання - Спампоўванне дадатковых файлаў для %1$s - Даступна новая версія %1$s + Запыт новай сэсіі + Сервер адключаны праз тэхнічныя работы + Спампоўка дадатковых файлаў для %1$s + Новая версія %1$s даступная %1$s і %2$s %1$s, %2$s і %3$s - Запыт адхілены! Выкарыстоўваеце VPN або Tor? - Унутраная памылка! Паўтарыце спробу пазней - Занадта шмат спроб уваходу - Немагчыма стварыць сеанс - Спраўджанне новага сеанса - Aurora Store дазваляе шукаць і спампоўваць праграмы з афіцыйнай крамы Google Play. Вы можаце праглядаць апісанні праграм, здымкі экрана, абнаўленні, каментарыі іншых карыстальнікаў і спампоўваць APK непасрэдна з Google Play на сваю прыладу. Вам неабходна мець уліковы запіс Google Play. З яго дапамогай неабходна аўтарызавацца пры першым адкрыцці і канфігурацыі Aurora Store для далейшага выкарыстання праграмы.\n\nAurora Store не валодае, не ліцэнзуе і не распаўсюджвае ніякія праграмы ў адрозненне ад традыцыйнай крамы з праграмамі. Усе праграмы, апісанні праграм, здымкі экрана і іншае змесціва ў Aurora Store непасрэдна даступна, спампоўваецца і/або адлюстроўваецца з Google Play. Aurora Store працуе аналагічна дзвярам або вэб-браўзеру, што дазваляе вам ўвайсці ў свой уліковы запіс Google Play і знайсці праграмы з Google Play.\n\nЗвярніце ўвагу, што Aurora Store не мае ніякага ўхвалення, спонсарства або аўтарызацыі ад Google, Google Play, ніякіх праграм спампаваных праз Aurora Store або ніякіх распрацоўшчыкаў праграм; Aurora Store таксама не мае з імі ніякіх стасункаў, супрацоўніцтва або сувязі. - Выбраць усе - Выдаліць усе - Апошнія - Апавяшчэнні, якія звязаны з уліковым запісам - Няма даступных праграм - Зроблена з %1$s у Індыі - Не ўдалося экспартаваць чорны спіс! - Чорны спіс імпартаваны! - Збой - Скасавана - Завершана - Патрабуецца аўтэнтыфікацыя - Прадвызначана - Выняць з архіва - Немагчыма адкрыць праграму - На платформе Plexus - Усталявана %1$d праграм - Выкарыстоўваць microG для ўваходу ва ўліковыя запісы - Задаць - Адключыць - Проксі паспяхова выключана - Сканфігурыраваць абмежаванні прылады для аўтаматычных абнаўленняў - Калі акумулятар зараджаны - Прайдзіце аўтэнтыфікацыю з дапамогай microG пры ўваходзе ва ўліковыя запісы Google, каб спрасціць працэс уваходу - Магчыма, што спатрэбіцца ўсталяваць прапрыетарную бібліятэку Google або свабодную рэалізацыю, такую як microG. - Чорны спіс экспартаваны! - Прагляд і кіраванне наладамі проксі - Толькі ў сетках з безлімітным трафікам - Абмежаванні па аўтаматычным абнаўленням - Патрабуюцца Google Play Services - Спраўджанне - Калі прылада не выкарыстоўваецца - Не ўдалося імпартаваць чорны спіс! - Спампоўванне - Сумяшчальнасць - Праверка сумяшчальнасці… - Працуе без сэрвісаў Google Play - Без сэрвісаў Google Play - Сумяшчальнасць: працуе без праблем - Гэта праграма працуе без прапрыетарнай бібліятэкі Google. Звярніце ўвагу, што могуць спатрэбіцца староннія бібліятэкі для правільнай працы. - З праектам microG - Абмежавана: працуе з абмежаваным функцыяналам - Не падтрымліваецца: не працуе - Невядома: яшчэ не праверана - Даступна - Праверка наяўнасці абнаўленняў - У чарзе - Недаступна - Увайдзіце ў свой уліковы запіс Google Play, каб выняць праграму з архіва! - Не ўдалося спраўдзіць спампаваныя файлы - Спампоўкі - Мінімальная версія Android - Мэтавы ўзровень API - Апошняе абнаўленне - Пашыраныя - Крыніца праграмы - %1$d дазволы - Усталяваць пакет microG - Сумяшчальнасць праграмы - Адсутныя залежнасці - Я прачытаў(-ла) і згаджаюся з умовамі абслугоўвання і палітыкай прыватнасці microG - Сэрвісы Google Play не выяўлены на вашай прыладзе. Некаторыя папулярныя праграмы патрабуюць іх для карэктнай працы! - Прачытайце ліцэнзію і пагадненне microG - Наведаць вэб-сайт праекта microG - microG — бясплатная рэалізацыя з адкрытым зыходным кодам, якая забяспечвае аналагічны функцыянал для запуску праграм, якія залежаць ад сэрвісаў Google Play для прылад з АС Android праз паўторную рэалізацыю.\n\nmicroG дазваляе праграмам звяртацца да API Google, паляпшаючы сумяшчальнасць для карыстальнікаў і пры гэтым прапануючы перавагі прыватнасці.\n\nmicroG будзе аўтаматычна запускацца ў фоне пры адкрыцці праграм, якія залежаць ад Google Mobile Services. - Прачытайце палітыку прыватнасці microG - Даныя, якія можа збіраць гэта праграма - Распрацоўшчык сцвярджае, што праграма не збірае даныя карыстальнікаў. - Даныя, якія можа абагульваць гэта праграма - Распрацоўшчык сцвярджае, што праграма не абагульвае даныя карыстальнікаў з іншымі кампаніямі або арганізацыямі. - Гэта версія праграмы ўсё яшчэ можа змяшчаць больш праграм сачэння, якія адсутнічаюць у базе даных Exodus Privacy. - Знойдзена вядомых праграм сачэння: %1$d. У %2$s - Усталёўшчык MicroG не змог усталяваць праграму. Хутчэй за ўсё гэта адбылося з прычыны няправільнай канфігурацыі. - Усталёўшчык MicroG - Патрабуецца ўсталяванне спадарожнай праграмы microG - Дапамагае абыходзіць праверку праграмы на цэласнасць (толькі ўсталёўшчык) - Код версіі можа змяшчаць толькі лічбы - Апісанне недаступна - Дадатковыя звесткі - Мэты - Назва пакета - Рэйтынг змесціва - Падрыхтоўка да ўсталявання - - Патрэбны дазвол - Патрэбныя дазволы - Патрэбныя дазволы - Патрэбныя дазволы - - Выберыце праграму для атрымання дадатковых звестак - Без рэкламы - Без сэрвісаў Google Play - Адбываецца загрузка - Старонка %1$d - Прапусціць - Перазапусціць, каб прымяніць змены? + Запыт адхілены! Выкарыстоўваеце VPN альбо Tor? + Унутраная памылка! Калі ласка, паўтарыць пазней + Ой, маюцца абмежаванні + Не атырмалася стварыць сэсію + Праверка новай сэсіі + Aurora Store дазваляе шукаць і спампоўваць прыкладанні з афіцыйнай крамы Google Play. Вы можаце праверыць апісанні прыкладанняў, скрыншоты, абнаўленні, каментарыяў іншых карыстальнікаў і спампуйце APK непасрэдна з Google Play на сваю прыладу, каб выкарыстоўваць Aurora Store, вам неабходна мець уліковы запіс Google Play і ўвайсці ў Google Play уліковы запіс пры першым адкрыцці і наладзе Aurora Store. \n\nУ адрозненне ад традыцыйнай крамы прыкладанняў, Aurora Store не валодае, не ліцэнзуе і не распаўсюджвае якія-небудзь прыкладанні. Усе прыкладанні, апісанні прыкладанняў, скрыншоты і іншы кантэнт у Aurora Store даступны непасрэдна, спампоўваюцца і/або адлюстроўваецца з Google Play. Aurora Store працуе гэтак жа, як дзверы або браўзер, дазваляючы вам трэба ўвайсці ў свой уліковы запіс Google Play і знайсці прыкладанні з Google Play.\n\nЗвярніце ўвагу што Aurora Store не мае адабрэння, спонсарства або аўтарызацыі ад Google, Google Play, любыя прыкладанні, спампаваныя праз Aurora Store або любыя распрацоўшчыкі прыкладанняў; таксама не робіць Aurora Store мае з імі якія-небудзь адносіны, супрацоўніцтва або сувязі. diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index 8b7231af1..c4da3caa9 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -139,6 +139,7 @@ Услуги на Aurora Изберете режим на инсталиране на APK Показва страници за вас на началния екран + Показва подобни и свързани клъстери на страницата с подробности за приложението Изтеглянето се провали Приложението не се поддържа Приложението не е намерено @@ -194,6 +195,7 @@ С най-големи приходи Най-добре платени Приложения в библиотеката + Приложения в разпродажба Мениджър на черния списък Тенденция Инсталиран @@ -263,19 +265,4 @@ Добавяне към началния екран Любими Успешно деинсталиране - Намери отговори на често задавани въпроси, стъпки за отстраняване на грешки и още - Премахни всички - Поискаи нов анализ - Избери всички - Не са намерени любими приложения - Данни, които това приложение може да събира - Разработчикът твърди, че приложението не събира потребителски данни. - Данни, които това приложение може да споделя - Разработчикът твърди, че това приложение не споделя потребителски данни с компании или организации. - %1$dч %2$dм %3$dс остават - %1$dм %2$dс остават - %1$dс остават - %1$d тракер(и) намерени в %2$s - Най-нови - Грешка при инсталирането на MicroG, най-вероятно поради грешка в конфигурацията. diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index dfeaf4cf4..78b7d4299 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -17,7 +17,7 @@ Liberapay PayPal Uniu-vos al grup d\'ajuda d\'Aurora per a debats o suggeriments. - Fil de desenvolupament XDA Forums + Fil de desenvolupament Consulteu el fil d\'Aurora Store a XDA per a debats o suggeriments. Anònim Feu-vos mecenes a Liberapay @@ -42,11 +42,11 @@ Valoració i revisions Què en penses d\'aquesta aplicació\? Cancel·lat - No conté rastrejadors coneguts + No conté elements de seguiment S\'estan comprovant els elements de seguiment… - element(s) de seguiment trobat(s) a - Instal·la els serveis d\'Aurora 1.0.9 o superior, o canvia l\'instal·lador. - Configureu els serveis d\'Aurora i concediu abans tots els permisos. + Element(s) de seguiment trobats a + Instal·li els serveis d\'Aurora 1.0.9 o superior, o canviï l\'instal·lador. + Configureu els serveis d\'Aurora i concediu tots els permisos primer. Quatre Dos Tot @@ -54,15 +54,15 @@ Cinc Ha fallat la instal·lació S\'ha bloquejat la instal·lació - Propulsat per Exodus ·Privacy + Propulsat per Exodus Veure informe Tres Instal·leu App Manager o canvieu l\'instal·lador. - Els serveis d\'Aurora estan disponibles i preparats per instal·lar. + Els serveis d\'Aurora estan disponibles i estan llestos per instal·lar. No hi ha accés root. Concedeix-l o canvia l\'instal·lador. Aurora Store requereix els permisos següents Instal·lat correctament - No podeu instal·lar aplicacions apilades mitjançant l\'instal·lador natiu. Canvieu el vostre instal·lador a Sessió, Serveis o Root. + No podeu instal·lar aplicacions agrupades (dividir) mitjançant l\'instal·lador natiu. Canvieu el vostre instal·lador a Sessió, Serveis o Root. Instal·lador Permisos Benvingut @@ -70,12 +70,12 @@ Reiniciar Reprendre Enrere - Afig a la llista negra + Afegeix a la llista negra Cancel·lar Netejar Tancar Copiar - Copia l\'enllaç + Copiar l\'enllaç Desactivar Exportar Filtres @@ -117,7 +117,7 @@ Més sobre l\'aplicació Sense anuncis No s\'ha trobat cap coincidència d\'aplicació - Cap dependència + Sense dependències Sense permissions No hi ha actualitzacions disponibles Pagant @@ -153,19 +153,19 @@ Com va\? Habilita la baixada d\'aplicacions en segon pla Gestor d\'emmagatzematge extern - Per desar fitxers d\'expansió d\'APKs (OBBs) per a aplicacions i jocs pesats. + Per desar les descàrregues (APKs i OBBs), exporteu i importeu les configuracions del dispositiu a i des d\'emmagatzematge extern. Instal·lador root Xarxes Permís de l\'instal·lador Permet instal·lar aplicacions des d\'Aurora Store Extres - No comproves actualitzacions per a les aplicacions F-Droid + Suprimeix les aplicacions F-Droid de les llistes d\'aplicacions Filtra les aplicacions de F-Droid - Les APKs baixades es suprimiran després d\'instal·lar + Els APKs se suprimiran per defecte Elimina l\'APK després de la instal·lació - Instal·lador GA - Instal·lador natiu (obsolet) - Serveis d\'Aurora (obsolet) + Instal·lador GA. + Instal·lador natiu + Serveis Aurora Instal·lador de sessió Seleccionar el mode d\'instal·lació de l\'APK Mètode d\'instal·lació @@ -176,9 +176,10 @@ Aplicacions similars i relacionades Aplicació no compatible No s\'ha trobat l\'aplicació - Error en baixar + Mostrar grups similars i relacionats a la pàgina detalls de l\'aplicació + Error en descarregar Gestor de llistes negres - Visualitzar les pàgines per a tu a la pantalla d\'inici + Visualitzar les Pàgines per a tu a la pantalla d\'inici Categories Top gratuït Comptes @@ -216,10 +217,11 @@ S\'ha exportat la configuració del dispositiu No s\'ha pogut exportar la configuració del dispositiu No s\'han pogut obtenir els fitxers - Qualificat, pot tardar un poc en mostrar-se + Qualificat Descàrrega d\'aplicacions en segon pla La sessió ha caducat, torna a iniciar una sessió nova. S\'ha aplicat la falsificació del dispositiu. + Aplicacions en oferta Dispositiu Play Store Instal·lat @@ -237,239 +239,4 @@ Descarregant • %1$d / %2$d%3$s Notificacions Instal·lador de Shizuku - Wiki - Troba respostes a les preguntes freqüents (F.A.Q.), passos de resolució de problemes i més - Elimina-ho tot - Notificació relacionada amb el compte - Selecciona-ho tot - No s\'ha trobat cap aplicació preferida - Neteja finalitzada - Últim - Shizuku no està instal·lat o configurat correctament. - Preferit - Sol·licita una nova anàlisi - Seguretat de les dades - Privadesa de dades i pràctiques de seguretat declarades pel desenvolupador - Afig a la pantalla d\'inici - S\'ha desinstal·lat correctament - Permet que l\'Aurora Store descarregui i actualitzi aplicacions en segon pla - Filtra aplicacions d\'altres fonts - Títol de la ressenya - Per defecte (des de la configuració del dispositiu) - Mostra actualitzacions que poden fallar - Ai! Tot bé. - Versió del Google Play - Notificació de la descarrega - Baixades en segon pla - Inicia sessió i gaudeix. - Preparant les coses… - Envia notificacions sobre l\'estat de les instal·lacions - Permet la instal·lació d\'aplicacions de fonts desconegudes - Mostra les actualitzacions d\'aplicacions incompatibles o deshabilitades que poden fallar en la instal·lació - Comprova només les actualitzacions de les aplicacions instal·lades amb l\'Aurora Store - Introduïu una URL del Proxy vàlid per a passar totes les dades a través del servidor intermediari. - Notificació d\'exportació d\'aplicacions - Notificació de l\'instalació - Proxy URL - Instal·lador del MicroG - Per favor, inicia sessió al teu compte de Google Play - No s\'ha pogut iniciar sessió a Google - Verificant sessió - Verificant sessió de Google - Configuració de l\'aplicació - Aplicacions preferides - Suggeriment de cerca - Resultats de cerca - Avançat - L\'aplicació no està disponible al teu dispositiu - Primer necessites donar permís d\'instal·lació - Configuració de dispositiu importada - No s\'ha pogut importar la configuració del dispositiu - L\'URL del servidor intermediari és invàlid, comprova el format! - Servidor intermediari configurat satisfactòriament - Ha fallat la configuració del servidor intermediari - actualització disponible - actualitzacions disponibles - Un error ha ocorregut! - Menú - Expandir - Requerit - Opcional - Els permisos requerits han estat denegats. Si us plau, atorga\'ls per a continuar l\'acció - Cerca aplicacions i jocs - Demanant una sessió nova - Servidor caigut per manteniment - Baixant fitxers addicionals per a %1$s - Notificacions d\'actualització - Actualitzacions automàtiques - Configura el comportament de les actualitzacions automàtiques - No actualitzes les aplicacions automàticament - Comprova i notifica les actualitzacions disponibles - Comprova i instal·la actualitzacions disponibles automàticament - Freqüència d\'actualitzacions automàtiques - Configura el interval de temps entre actualitzacions automàtiques, en hores. - Error obtenint el resum de privacitat - Accés denegat! Pot ser estàs fent us d\'una VPN o Tor? - Error intern! Per favor, torna a intentar-ho en una estona - La teva velocitat està limitada - No es pot aplegar al servidor - No s\'ha pogut generar la sessió - Verificant nova sessió - No s\'ha pogut generar la sessió, codi d\'error: %1$d - Comprovant connexió a internet - Idioma de l\'aplicació - Enllaços d\'aplicació - Permet a l\'Aurora Store obrir enllaços admesos - Google Play, també coneguda com la Google Play Store i anteriorment Android Market. - Android Market fou una tenda en línia que oferia aplicacions dissenyades per a dispositius Android, retirada al 2017. - Error al exportar APKs - Cap aplicació disponible - Baixades - Actualitzat per última vegada - Versió mínima de l\'Android - Compatibilitat d\'aplicació - Falten dependències - He llegit i estic d\'acord amb els Termes de Servici i la Política de Privacitat de MicroG - No hem pogut trobar els serveis de Google Play al teu telèfon, moltes aplicacions populars els requereixen per a funcionar correctament! - microG es una implementació lliure i de codi obert que proporciona funcionalitats similars per a executar aplicacions dependents dels serveis de Google Play als dispositius Android amb re-implementacions.\n\nmicroG habilita a les aplicacions per a accedir a les APIs de Google, millorant la compatibilitat per a usuaris al temps que ofereix beneficis en privacitat.\n\nmicroG s\'executarà automàticament en segon pla quan obris les aplicacions dependents dels serveis de Google Mobile. - Llig la Política de Privacitat de microG - Llig l\'Acord de Llicència de microG - Visita la pàgina web del projecte microG - Instal·lador basat en sessió per a les APK apilades - Instal·lador basat en shell amb permisos d\'arrel - Requereix privilegis d\'arrel/superusuari, compatible amb totes les versions d\'Android. - Recomanat, integrat i compatible amb totes les versions d\'Android - Instal·lador basat en intenció, disponible a tots els dispositius - Més adequat per a dispositius amb versions inferiors a Android 4.4 - Instal·lador per a instal·lacions en segon pla - Requereix que els serveis d\'Aurora estiguen instal·lats com a aplicació de sistema amb privilegis - Requereix que el l\'aplicació microG Companion estiga instal·lada - T\'ajuda a ignorar la comprovació integritat d\'aplicacions (sols l\'instal·lador) - Gestor de paquets ric en característiques de codi obert - Requereix App Manager, necessita el mode adb/root per a instal·lar quan l\'optimització de MIUI està activada - Utilitza APIs de sistema directament amb privilegis adb/root - Requereix Shizuku o Sui, necessita posta a punt i concessió de permisos - Introdueix el codi de versió que vols baixar - El codi de versió sols pot contindre dígits - Tens dubtes? Troba respostes - Codi font - Esbrina què hi ha dins - Política de privacitat - Aprén com l\'Aurora Store gestiona les teues dades - Responsabilitat i obligacions - Fet amb %1$s en India - Quant a l\'Aurora Store - Aprén més sobre l\'Aurora Store - Aurora Store t\'habilita a cercar i baixar aplicacions des de la tenda oficial de Google Play. Pots comprovar descripcions, captures, actualitzacions i comentaris dels usuaris respecte a les aplicacions a més de baixar directament l\'APK al teu dispositiu. Per a utilitzar l\'Aurora Store necessites un compte de Google Play i iniciar sessió al compte la primera vegada que obris i configures l\'Aurora Store.\n\nA diferència de les tendes d\'aplicacions tradicionals, Aurora Store no es propietària de ninguna aplicació, tampoc les llicència ni distribueix. Totes les aplicacions, descripcions, captures i altres continguts en l\'Aurora Store son baixades, mostrades i accedides des de Google Play. Aurora Store funciona exactament com una porta o un navegador, et permet iniciar sessió al teu compte de Google Play i trobar aplicacions de Google Play.\n\nSi us plau, tingueu en comte que l\'Aurora Store not té cap aprovació, patrocini o autorització de Google, Google Play, aplicacions baixades a través de l\'Aurora Store ni cap desenvolupador d\'aplicacions; l\'Aurora Store tampoc està afiliada ni coopera o té connexió amb ells. - Més - Gestiona el teu compte - Neteja el propietari del dispositiu - Esborra l\'Aurora Store com a aplicació propietària del dispositiu - Açò revocarà el permís de l\'instal·lador de sessió per a instal·lar aplicacions de forma silenciosa. Procedir amb la neteja de propietat del dispositiu? - Gestionar dispensadors - Veu i gestiona dispensadors de tokens per a inicis de sessió anònims - Cap dispensador disponible - Afig dispensador - Afig un dispensador de tokens a l\'Aurora Store. Els dispensadors de tokens proveïxen les credencials del compte a l\'Aurora Store per a iniciar sessió anònimament. - URL invàlida - URL del dispensador - Esborrar dispensador? - Vols esborrar el dispensador \"%1$s\"? - Afig - Esborra - Error al importar preferits! - Error al exportar preferits! - Preferits importats! - Preferits exportats! - Error al importar llista negra! - Error al exportar llista negra! - Llista negra importada! - Llista negra exportada! - Explorador de fitxers - Espera, s\'està exportant el vostre fitxer - S\'ha exportat satisfactòriament l\'aplicació apilada - Error al exportar l\'aplicació apilada - Tancar sessió? - Segur que vols tancar sessió? - Comprova les actualitzacions - Comprovant les actualitzacions - Reinicia l\'Aurora Store - L\'Aurora Store necessita ser reiniciada per a aplicar els canvis - Baixant - Error - Cancel·lat - Completat - En cua - No disponible - Verificant - Autenticació requerida - Si us plau, inicia sessió al teu compte de Google Play per a extreure l\'aplicació! - Per defecte - Disponible - Cap descripció disponible - %1$d permisos - Més informació - Objectius - Nom del paquet - Valoració del contingut - Extreu - No es pot obrir l\'aplicació - Desenvolupat per Plexus - Comprovant compatibilitat… - Compatibilitat - Requereix serveis de Google Play - Pot ser tingues que instal·lar llibreries propietàries de Google o una re-implementació de codi obert com microG. - Funciona sense serveis de Google Play - Aquest aplicació funciona sense llibreries propietàries de Google. De totes formes, pot ser que necessite altres llibreries de tercers per a funcionar correctament. - Amb el projecte microG - Sense serveis de Google Play - Compatible: Funciona sense cap problema - Limitat: Funciona amb funcions limitades - No suportat: No funciona - Desconegut: No s\'ha comprovat encara - Preparant per a instal·lar - %1$d aplicacions instal·lades - Utilitza microG per a iniciar sessió als comptes - Autentica\'t amb microG quan inicies sessió al compte de Google per a simplificar el procés - Aplica - Deshabilita - Servidor intermediari deshabilitat satisfactòriament - Veu i gestiona la configuració del servidor intermediari - Avançat - Restriccions d\'actualitzacions automàtiques - Configura restriccions al dispositiu per a les actualitzacions automàtiques - Sols en xarxes no mesurades - Quan el dispositiu està desocupat - Quan la bateria és molt baixa - Font de l\'aplicació - Error al verificar fitxers baixats - Selecciona una aplicació per a veure més detalls - Cap anunci - Cap servei de Google Play - Carregant - Pàgina %1$d - Instal·la el paquet microG - Dades que aquesta aplicació pot recopilar - El desenvolupador diu que aquesta aplicació no recull dades de l\'usuari. - Dades que aquesta aplicació pot compartir - El desenvolupador diu que aquesta aplicació no comparteix dades de l\'usuari amb altres companyies ni organitzacions. - Aquesta versió de l\'aplicació pot contenir encara més rastrejadors que no surten de moment a la base de dades de privacitat d\'Exodus. - %1$d element(s) de seguiment trobat(s) a %2$s - L\'instal·lador de microG ha fallat en instal·lar l\'aplicació, segurament a causa d\'una configuració incorrecta. - %1$s • API %2$s - %1$d actualitzacions disponibles - %1$d actualització disponible - Una nova versió de %1$s està disponible - %1$s i %2$s - %1$s, %2$s i %3$s - %1$s, %2$s, %3$s i %4$d més - Nivell de l\'API objectiu - - Permís requerit - Permisos requerits - Permisos requerits - - L\'última sessió s\'ha descartat - Ometre - Reiniciar per tal d\'aplicar els canvis? diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 48f741e23..2f296e754 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -10,7 +10,7 @@ Byl použit spoofing zařízení. Na whitelistu Chcete-li použít změny, nezapomeňte se znovu přihlásit a restartovat aplikaci. - Gratulujeme, požadovaný kód verze je k dispozici, probíhá stahování. + Gratuluji, požadovaný kód verze je k dispozici, nyní stahuji. Nákupy aplikací nejsou na anonymních účtech dostupné. Oprávnění uděleno Chcete-li otevřít nastavení pro vývojáře, zapněte je v nastavení zařízení. @@ -31,6 +31,7 @@ Obchod Play Stahování Zařízení + Aplikace ve slevě Aplikace v knihovně Moje aplikace a hry Aplikace @@ -51,8 +52,9 @@ Aplikace není kompatibilní Aplikace nebyla zakoupena Stažení se nezdařilo + Zobrazit podobné a související skupiny na stránce s detaily aplikace Podobné a související aplikace - Zobrazit stránky pro vás na domovské obrazovce + Zobrazení stránek pro vás na domovské obrazovce Stránky pro vás Vybrat výchozí kartu Rozložení @@ -67,7 +69,7 @@ Odstranit soubor APK po instalaci Stažené soubory APK budou po ihned po instalaci odstraněny Filtrovat aplikace F-Droid - Nekontrolovat aktualizace u aplikací nainstalovaných z obchodu F-Droid + Nekontrolovat aktualizace u aplikací stažených nebo nainstalovaných z obchodu F-Droid Doplňky Povolit instalaci aplikací z obchodu Aurora Instalační oprávnění @@ -97,7 +99,7 @@ Instalace byla zablokována Nainstalujte služby Aurora 1.0.9 nebo vyšší, nebo změňte instalační program. Instalace selhala - Nejprve nastavte Služby Aurora a udělte všechna oprávnění. + Nejprve nastavte služby Aurora a udělte všechna oprávnění. Služby Aurora jsou k dispozici a jsou připraveny k instalaci. Nedostupné oprávnění root, udělte root oprávnění nebo změnte instalátor. Dvě @@ -188,7 +190,7 @@ Filtry Exportovat Zakázat - Kopírovat odkaz + Kopírovat Link Kopírovat Zavřít Vymazat @@ -218,7 +220,7 @@ Bitcoin Cash Přispějte prostřednictvím UPI BHIM - UPI - Přes nativní instalátor nelze instalovat zabalené (rozdělené) aplikace. Změňte typ instalátoru na Relační, Služby nebo Root. + Přes nativní instalátor nelze instalovat skupiny aplikací. Změňte typ instalátoru na Relační, Služby nebo Root. Nepodařilo se vygenerovat token AAS Nelze odeslat hodnocení Ohodnoceno, může chvíli trvat, než se recenze ukáže @@ -226,7 +228,7 @@ Nelze exportovat konfiguraci zařízení Konfigurace zařízení exportována Umožňuje stahování aplikací na pozadí - Stahování aplikací na pozadí + Stahování na pozadí Nainstalujte si aplikaci App Manager nebo změnte instalátor. AM instalátor Stahování • %1$d / %2$d%3$s @@ -248,12 +250,12 @@ Poslední relace zrušena Požadovaná oprávnění byla odepřena. Pro pokračování v akci je prosím udělte Ověřování relace - Ověřování relace Google + Ověření relace Google Pokročilé Nabídka Vyskytla se chyba! Výpadek serveru z důvodu údržby - Žádání o novou relaci + Žádost o novou relaci Importovat Konfigurace zařízení importována Nepodařilo se importovat konfiguraci zařízení @@ -269,7 +271,7 @@ Shizuku instalátor Návrh vyhledávání Výsledky vyhledávání - Vaše požadavky byly dočasně omezeny + Jejda, váš účet je omezen Nepodařilo se vygenerovat relaci, kód chyby: %1$d Přístup zamítnut! Používáte VPN nebo Tor\? Server je nedostupný @@ -284,28 +286,32 @@ Google Play, také známý jako Obchod Google Play a původně jako Android Market. Android Market byl online obchod se softwarovými aplikacemi navržený pro zařízení Android, který byl ukončen v roce 2017. Nadpis recenze - Nastavit časové intervaly pro automatické aktualizace, v hodinách. - Filtrovat aplikace z ostatních zdrojů - Nekontrolovat aktualizace aplikací nainstalovaných z jiného zdroje, než je Aurora Store + Poskytovatel - bestappsales.com + Nastavit intervaly pro automatické a vlastní aktualizace, v hodinách. + Pouze aplikace Aurora Store + Kontrolovat pouze aktualizace aplikací nainstalovaných z aplikace Aurora Store Nastavení aplikace Frekvence automatických aktualizací + Zapnout proxy Adresa URL proxy + Proxy Neplatná adresa URL proxy, zkontrolujte formát! Proxy úspěšně nastavena Nepodařilo se nastavit proxy + Přesměrovat veškerý síťový provoz skrz proxy Výchozí (z konfigurace zařízení) Verze Google Play Stahování na pozadí Umožnit aplikaci Aurora Store stahovat a aktualizovat aplikace na pozadí - Automatické aktualizace + Automaticky aktualizovat aplikace Kontrolovat a oznamovat dostupné aktualizace Neaktualizovat automaticky aplikace - Nastavit chování automatických aktualizací + Nastavení chování automatických aktualizací Kontrolovat a automaticky instalovat dostupné aktualizace Požádat o novou analýzu Nepodařilo se exportovat soubory APK Vymazat dokončené - Zobrazit aktualizace, které se nemusí povést + Aktualizovat nekompatibilní Zobrazit aktualizace pro nekompatibilní nebo zakázané aplikace, jejichž instalace může selhat Přidat na domovskou obrazovku Instalátor založený na relacích pro rozdělené/balíčkované soubory APK @@ -334,7 +340,7 @@ Tato akce zruší oprávnění instalátoru k instalaci aplikací na pozadí. Opravdu chcete pokračovat? Neplatná adresa URL Adresa URL vydavače - Odstranit vydavač? + Odstranit vydavač Chcete odebrat vydavač „%1$s“? Přidat Odstranit @@ -347,7 +353,11 @@ Přidat vydavač tokenů do Aurora Store. Vydavače tokenů poskytují údaje o účtech, které Aurora Store používá pro anonymní přihlašování. O aplikaci Aurora Store Zjistěte více informací o aplikaci Aurora Store - Aplikace Aurora Store umožňuje vyhledávat a stahovat aplikace z oficiálního Obchodu Google Play. Můžete si prohlédnout popisy aplikací, snímky obrazovky, aktualizace, komentáře ostatních uživatelů a stáhnout APK přímo z Google Play do svého zařízení. Chcete-li aplikaci Aurora Store používat, musíte mít účet Google a při prvním otevření a konfiguraci aplikace Aurora Store se k němu přihlásit. \n \nNa rozdíl od tradičního obchodu s aplikacemi aplikace Aurora Store nevlastní, nelicencuje ani nedistribuuje žádné aplikace. Všechny aplikace, popisy aplikací, snímky obrazovky a další obsah v aplikaci Aurora Store jsou přímo přístupné, stažené a/nebo zobrazené z Obchodu Google Play. Aplikace Aurora Store funguje přesně jako dveře nebo prohlížeč, umožňuje přihlášení k účtu Google a vyhledávání aplikací z Obchodu Google Play. \n \nUpozornění: aplikace Aurora Store nemá žádné schválení, sponzoring ani autorizaci od společnosti Google, Google Play, aplikací stažených prostřednictvím aplikace Aurora Store ani od vývojářů aplikací; aplikace Aurora Store s nimi také nemá žádné spojení, spolupráci ani vazbu. + Aplikace Aurora Store umožňuje vyhledávat a stahovat aplikace z oficiálního Obchodu Google Play. Můžete si prohlédnout popisy aplikací, snímky obrazovky, aktualizace, komentáře ostatních uživatelů a stáhnout APK přímo z Google Play do svého zařízení. Chcete-li aplikaci Aurora Store používat, musíte mít účet Google a při prvním otevření a konfiguraci aplikace Aurora Store se k němu přihlásit. +\n +\nNa rozdíl od tradičního obchodu s aplikacemi aplikace Aurora Store nevlastní, nelicencuje ani nedistribuuje žádné aplikace. Všechny aplikace, popisy aplikací, snímky obrazovky a další obsah v aplikaci Aurora Store jsou přímo přístupné, stažené a/nebo zobrazené z Obchodu Google Play. Aplikace Aurora Store funguje přesně jako dveře nebo prohlížeč, umožňuje přihlášení k účtu Google a vyhledávání aplikací z Obchodu Google Play. +\n +\nUpozornění: aplikace Aurora Store nemá žádné schválení, sponzoring ani autorizaci od společnosti Google, Google Play, aplikací stažených prostřednictvím aplikace Aurora Store ani od vývojářů aplikací; aplikace Aurora Store s nimi také nemá žádné spojení, spolupráci ani vazbu. Přihlaste se prosím do vašeho účtu Google Aplikace není dostupná pro vaše zařízení Nenalezeny žádné oblíbené aplikace @@ -370,6 +380,7 @@ Volitelné Nejprve musíte udělit oprávnění instalátoru Postupy ochrany soukromí a zabezpečení dat poskytnuté vývojářem + Možná budete muset oprávnění znovu udělit z důvodu chyby ve Storage Access Framework Restartovat Aurora Store Aplikace Aurora Store, potřebuje restartovat pro použití nového nastavení Čekejte prosím, probíhá export vašeho souboru @@ -390,6 +401,7 @@ Vytvořeno s %1$s v Indii Výchozí Dostupné + Možná bude nutné restartovat aplikaci, aby se promítlo udělení oprávnění. Odstranit vše Vybrat vše Nepodařilo se importovat černou listinu! @@ -404,73 +416,15 @@ Vyžaduje Služby Google Play Možná bude nutná instalace proprietární knihovny společnosti Google nebo svobodné implementace, jako je microG. Tato aplikace funguje bez proprietární knihovny společnosti Google. Může nicméně ke správné funkčnosti stále vyžadovat další knihovny třetích stran. - Se službou microG + S projektem microG Bez Služeb Google Play Omezené: funguje s omezeními Nepodporované: nefunguje Neznámé: zatím nezkontrolováno Funguje bez Služeb Google Play - Kompatibilní – funguje bez problémů + Kompatibilní: funguje bez problémů Kontrola kompatibility… Využívá službu Plexus Nainstalováno %1$d aplikací Nejsou dostupné žádné aplikace - Použít microG k přihlášení k účtům - Během přihlašování do účtů Google použít službu microG pro jednodušší proces přihlášení - Nastavit - Když je zařízení nečinné - Když je baterie dostatečně nabitá - Omezení automatických aktualizací - Zobrazit a spravovat nastavení proxy - Nastavit omezení zařízení pro automatické aktualizace - Zakázat - Síť proxy úspěšně zakázána - Pouze na neměřených sítích - Nepodařilo se ověřit stažené soubory - Pokročilé - Zdroj aplikací - Stahování - Naposledy aktualizováno - Minimální verze Androidu - Cílová úroveň API - %1$d oprávnění - Nainstalovat balíček microG - Kompatibilita aplikací - Chybějící závislosti - Přečetl/a jsem si a souhlasím se Smluvními podmínkami a Zásadami ochrany osobních údajů microG - Na vašem zařízení se nám nepodařilo nalézt Služby Google Play. Mnoho populárních aplikací je nyní vyžaduje pro správnou funkčnost! - microG je bezplatná a otevřená implementace, která poskytuje podobnou funkčnost pro běh aplikací závislých na Službách Google Play pro zařízení Android skrze reimplementaci.\n\nmicroG umožňuje aplikacím přístup k daným rozhraním API Google, čímž zlepšuje kompatibilitu pro uživatele a poskytuje výhody ve formě soukromí.\n\nmicroG se spustí automaticky na pozadí, jakmile otevřete aplikace závislé na Mobilních službách Google. - Přečtěte si Zásady ochrany údajů microG - Přečtěte si Licenci a Smlouvu microG - Navštivte web projektu microG - Data, která může tato aplikace shromažďovat - Vývojář uvedl, že tato aplikace neshromažďuje údaje o uživatelích. - Data, která může tato aplikace sdílet - Vývojář uvedl, že tato aplikace nesdílí údaje o uživatelích s jinými společnostmi nebo organizacemi. - Tato verze aplikace může obsahovat více sledovacích prvků, které se zatím nenachází v databázi služby Exodus Privacy. - Ve verzi %2$s bylo nalezeno %1$d známých sledovacích prvků - Není dostupný žádný popis - Další informace - Cíle - Název balíčku - Hodnocení obsahu - Vyberte aplikaci pro více podrobností - Bez reklam - Bez Služeb Play - Kód verze může obsahovat pouze čísla - Příprava na instalaci - - Vyžadováno oprávnění - Vyžadována oprávnění - Vyžadována oprávnění - Vyžadována oprávnění - - Instalátoru microG se nepodařilo nainstalovat aplikaci, nejspíše z důvodu chybné konfigurace. - Instalátor microG - Vyžaduje nainstalovanou Doprovodnou aplikaci microG - Pomáhá obejít kontrolu integrity aplikací (pouze instalátor) - Probíhá načítání - Stránka %1$d - Přeskočit - Restartovat pro použití změn? diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 16c58b5f2..2150cc834 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -101,10 +101,11 @@ MIUI registreret! Du kan også vælge Native-installationsprogram, men så kan du ikke installere medfølgende (split) APK\'er. Du kan ikke installere medfølgende (split) apps via Native-installationsprogram. Skift dit installationsprogram til Session, Services eller Root. - Søg ikke efter opdateringer til apps installeret fra F-Droid + Søg ikke efter opdateringer til apps hentet eller installeret fra F-Droid AM-installationsprogram Layout Appen blev ikke fundet + Vis lignende og relaterede samlinger på appens detaljeside Sørg for at logge ind igen for at anvende spoofen Manuel download Hvidlistet @@ -199,6 +200,7 @@ Apps Mine apps og spil Apps i biblioteket + Apps på tilbud Sortliste-administrator Enhed Downloads @@ -228,6 +230,7 @@ Enhedskonfiguration eksporteret Henter app i baggrund Aktiverer baggrundsdownload af apps + Aktivér proxy Wiki %1$ds tilbage Baggrundsdownloads @@ -239,18 +242,20 @@ Tillad Aurora Store at hente og opdatere apps i baggrunden Om Shizuku er ikke installeret eller opsat korrekt. - Vis opdateringer, der kan fejle + Inkompatible opdateringer Gør tingene klar… + Leverandør - bestappsales.com Notifikationer Anmod om ny analyse Ryd færdige %1$dt %2$dm %3$ds tilbage %1$dm %2$ds tilbage Send notifikationer om installationsstatus + Proxy Proxy-URL Indtast en gyldig proxy-URL for at sende alle data gennem proxyen. - Filtrér apps fra andre kilder - Søg ikke efter opdateringer til apps installeret fra andre kilder end Aurora Store + Kun Aurora Store-apps + Søg kun efter opdateringer til apps installeret af Aurora Store Verificerer Google-session App-indstillinger Føj til hjemmeskærm @@ -258,7 +263,7 @@ Log venligst ind på din Google Play-konto Datasikkerhed Databeskyttelse og sikkerhedspraksis erklæret af udvikleren - På pause • %1$d / %2$d + På pause •%1$d / %2$d Tillad at installere apps fra ukendte kilder Vis opdateringer til inkompatible eller deaktiverede apps, som muligvis ikke kan installeres Verificerer session @@ -270,7 +275,7 @@ Ugyldig proxy-URL. Tjek formatet! Appen er ikke tilgængelig for din enhed opdatering tilgængelig - Konfigurer adfærd for automatiske opdateringer + Konfigurer adfærd for auto-opdateringer Opdater ikke apps automatisk Søg efter og underret om tilgængelige opdateringer Søg efter og installer tilgængelige opdateringer automatisk @@ -290,7 +295,7 @@ Lær mere om Aurora Store Ugyldig URL Kunne ikke hente privatlivsrapport - Konfigurer tidsinterval for automatiske opdateringer i timer. + Konfigurer intervaller for auto- og selvopdateringer i timer. Kunne ikke generere session. Fejlkode: %1$d Tillad Aurora Store at åbne understøttede links Tilføj @@ -309,7 +314,7 @@ %1$s • API %2$s Fjern alle Vælg alle - Henter • %1$d / %2$d%3$s + Henter •%1$d / %2$d%3$s Standard (fra enhedskonfiguration) Udvid En ny version af %1$s er tilgængelig @@ -330,7 +335,7 @@ Påkrævet Valgfri Påkrævede tilladelser blev nægtet. Giv dem venligst for at fortsætte handlingen - Du er hastighedsbegrænset + Ups, du er hastighedsbegrænset Google Play-version Favoritapps Kræver Shizuku eller Sui; skal opsættes og have tilladelse @@ -343,12 +348,13 @@ opdateringer tilgængelige Lavet med %1$s i Indien Android Market var en onlinebutik med softwareapplikationer designet til Android-enheder, som blev lukket i 2017. + Tillad al trafik fra appen at gå gennem proxyen %1$d opdateringer tilgængelige Kunne ikke indstille proxy Kræver App Manager. Har brug for adb/root-tilstand for at installere, når MIUI-optimering er slået til Bruger system-API\'er direkte med adb/root-rettigheder %1$s, %2$s, %3$s og %4$d mere - Automatiske opdateringer + Auto-opdater apps %1$s, %2$s og %3$s Google Play, også kendt som Google Play Butik og tidligere Android Market. Titel på anmeldelse @@ -363,7 +369,8 @@ App-pakke eksporteret Annulleret Fuldført - Meddelelser om opdatering + Du skal muligvis genstarte appen før tilladelsen gælder. + Meddelelser om opdateringer Henter Mislykket Standard @@ -384,59 +391,7 @@ Sortliste eksporteret! Kunne ikke importere sortliste! Sortliste importeret! + Du skal muligvis give tilladelsen igen grundet en fejl i Storage Access Framework Meddelelse om app-eksport Installationsmeddelelse - Dispenser-URL - Ingen tilgængelige dispensere - Ingen tilgængelige apps - Tilføj dispenser - Tilføj en token-dispenser til Aurora Store. Token-dispensere leverer kontooplysninger til Aurora Store for anonymt login. - Drevet af Plexus - Kræver Google Play-tjenester - Kompatibilitet - Du skal muligvis installere Google’s proprietære bibliotek eller en FOSS-implementering som microG. - Virker uden Google Play-tjenester - Administrer dispensere - Server utilgængelig - Dette fjerner sessioninstallatørens tilladelse til at installere apps lydløst. Fortsæt med at fjerne enhedsadministration? - Fjern dispenser - Ønsker du at fjerne dispenseren \"%1$s\"? - Tjekker kompatibilitet… - Denne app virker uden Google’s proprietære bibliotek. Den kan dog stadig kræve andre tredjepartsbiblioteker for at fungere korrekt. - Med microG Project - Uden Google Play-tjenester - Kompatibel: Virker uden problemer - Begrænset: Virker med begrænsede funktioner - Favorit - Ansvarlighed og forpligtelse - Kan ikke åbne app - Fjerner Aurora Store som enhedsadministrator - Se og administrer token-dispensere til anonyme logins - Indstil - Deaktivér - Brug microG til at logge ind på konti - Godkend med microG, når du logger ind på Google-konti for en enklere login-proces - Se og administrer proxy-konfiguration - Proxy blev deaktiveret - Kun på ubegrænsede netværk - Restriktioner for automatiske opdateringer - Når batteriet ikke er lavt - Kunne ikke verificere hentede filer - Ikke understøttet: Virker ikke - Ukendt: Ikke tjekket endnu - %1$d apps installeret - Når enheden er inaktiv - Konfigurer enhedsrestriktioner for automatiske opdateringer. - Downloads - Sidst opdateret - Minimum Android-version - Mål-API-niveau - Avanceret - App-kilde - Data, som denne app kan indsamle - Udvikleren siger, at denne app ikke indsamler brugerdata. - Data, som denne app kan dele - Udvikleren siger, at denne app ikke deler brugerdata med andre virksomheder eller organisationer. - Denne version af appen kan stadig indeholde flere trackere, der endnu ikke findes i Exodus Privacys database. - %1$d kendt(e) tracker(e) fundet i %2$s diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 69f6d9dd2..a6986ebd8 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -52,6 +52,7 @@ In die Zwischenablage kopiert Auf der Erlaubnisliste Installationsmethode + Apps im Angebot Apps in der Bibliothek Meine Apps & Spiele Apps @@ -59,7 +60,7 @@ App wird nicht unterstützt App nicht gekauft F-Droid-Apps filtern - Keine Updates für Apps, die von F-Droid installiert wurden + Keine Updates für Apps, die von F-Droid heruntergeladen oder installiert wurden Erforderlich für die Installation von Apps aus dem Aurora Store Inkompatible App Mehr über die App @@ -140,10 +141,10 @@ Alle Bericht ansehen bekannte(r) Tracker gefunden in - Es wird auf Tracker geprüft… + Es wird auf Tracker geprüft … Bereitgestellt von Exodus Privacy Enthält keine bekannten Tracker - Geschwindigkeit wird ermittelt… + Geschwindigkeit wird ermittelt … Alle fortsetzen In der Warteschlange Alle anhalten @@ -151,7 +152,7 @@ Metadaten werden geladen Alle löschen Download fehlgeschlagen - Übertragungsdauer wird berechnet… + Übertragungsdauer wird berechnet … Heruntergeladen Abgebrochen Alle abbrechen @@ -208,6 +209,7 @@ App-Käufe sind für anonyme Konten nicht verfügbar. Bitte neu anmelden und die App neu starten, um die Änderungen zu übernehmen. Netzwerk + Ähnliche und verwandte Apps in der App-Detailansicht anzeigen Ähnliche Apps „Für dich“-Tab auf der Startseite anzeigen „Für dich“-Tab @@ -231,7 +233,7 @@ Mit App Manager Anmelden und genießen. Boah! Alles gut. - Vorbereitung läuft… + Vorbereitung läuft … Anmeldung via Google fehlgeschlagen Letzte Sitzung wurde abgebrochen Sitzung wird überprüft @@ -268,7 +270,7 @@ %1$d vorhandene Updates %1$s und %2$s Zugriff verweigert! Verwendest du ein VPN oder Tor\? - Deine Anfragehäufigkeit ist begrenzt + Hoppla, deine Anfragehäufigkeit ist begrenzt Datenschutzbericht konnte nicht abgerufen werden Suchvorschlag Suchergebnisse @@ -284,20 +286,24 @@ Google Play, auch bekannt als Google Play Store (ehemals Android Market). Android Market war ein Online-Store, der Softwareanwendungen für Android-Geräte anbot und 2017 eingestellt wurde. Titel bewerten + Anbieter: bestappsales.com App-Einstellungen - Zeitintervall (in Stunden) für automatische Updates konfigurieren. - Apps aus anderen Quellen ausfiltern - Nicht nach Updates für Apps suchen, die aus Quellen außerhalb des Aurora Store installiert wurden + Konfiguriere die Intervalle (in Stunden) für automatische und selbsttätige Updates. + Nur Aurora-Store-Apps + Nur nach Updates für Apps suchen, die von Aurora Store installiert wurden Häufigkeit der automatischen Updates + Proxy aktivieren URL des Proxyservers + Proxy Ungültige Proxy-URL, bitte Aufbau der URL überprüfen! Proxy erfolgreich festgelegt Fehler beim Festlegen des Proxys + Gesamten Netzwerkverkehr der App über den Proxyserver leiten Standard (aus Gerätekonfiguration) Google-Play-Version Downloads im Hintergrund Aurora Store das Herunterladen und Aktualisieren von Apps im Hintergrund erlauben - Automatische Updates + Automatisches App-Update Bei verfügbaren Updates nur benachrichtigen Apps nicht automatisch aktualisieren Verfügbare Updates automatisch installieren @@ -305,7 +311,7 @@ Neue Analyse anfordern Exportieren der APKs fehlgeschlagen Fertige löschen - Updates anzeigen, die fehlschlagen könnten + Inkompatible Updates Updates für inkompatible oder deaktivierte Apps anzeigen, die möglicherweise nicht installiert werden können Zur Startseite hinzufügen Quellcode @@ -339,15 +345,19 @@ Dispenser-URL Hinzufügen Entfernen - Möchtest du den Dispenser „%1$s“ entfernen? + Möchtest du den Dispenser \\<xliff:g id=“url„>%1$s</xliff:g>\" entfernen? Wiki Antworten auf häufig gestellte Fragen (FAQs), Maßnahmen zur Fehlerbehebung und mehr finden Dispenser hinzufügen Hinzufügen eines Token-Dispensers zum Aurora Store. Token-Dispenser stellen dem Aurora Store Kontodaten zur Verfügung, um sich anonym anzumelden. - Dispenser entfernen? + Dispenser entfernen Über Aurora Store Erfahre mehr über Aurora Store - Der Aurora Store ermöglicht es dir, Apps im offiziellen Google Play Store zu suchen und herunterzuladen. Du kannst App-Beschreibungen, Screenshots, Updates und Kommentare anderer Nutzer einsehen und die APK direkt von Google Play auf dein Gerät herunterladen. Um den Aurora Store nutzen zu können, musst du ein Google-Play-Konto haben und dich dort anmelden, wenn du den Aurora Store zum ersten Mal öffnest und konfigurierst. \n \nAnders als ein herkömmlicher App-Store besitzt, lizenziert oder vertreibt Aurora Store keine Apps. Alle Apps, App-Beschreibungen, Screenshots und andere Inhalte im Aurora Store werden direkt von Google Play abgerufen, heruntergeladen und/oder angezeigt. Der Aurora Store funktioniert genau wie eine Tür oder ein Browser, mit dem du dich in dein Google-Play-Konto einloggen und die Apps von Google Play finden kannst. \n \nBitte beachte, dass der Aurora Store weder von Google, Google Play, den über den Aurora Store heruntergeladenen Apps oder den App-Entwicklern genehmigt, gesponsert oder autorisiert wurde, noch steht der Aurora Store in irgendeiner Verbindung mit ihnen. + Der Aurora Store ermöglicht es dir, Apps im offiziellen Google Play Store zu suchen und herunterzuladen. Du kannst App-Beschreibungen, Screenshots, Updates und Kommentare anderer Nutzer einsehen und die APK direkt von Google Play auf dein Gerät herunterladen. Um den Aurora Store nutzen zu können, musst du ein Google-Play-Konto haben und dich dort anmelden, wenn du den Aurora Store zum ersten Mal öffnest und konfigurierst. +\n +\nAnders als ein herkömmlicher App-Store besitzt, lizenziert oder vertreibt Aurora Store keine Apps. Alle Apps, App-Beschreibungen, Screenshots und andere Inhalte im Aurora Store werden direkt von Google Play abgerufen, heruntergeladen und/oder angezeigt. Der Aurora Store funktioniert genau wie eine Tür oder ein Browser, mit dem du dich in dein Google-Play-Konto einloggen und die Apps von Google Play finden kannst. +\n +\nBitte beachte, dass der Aurora Store weder von Google, Google Play, den über den Aurora Store heruntergeladenen Apps oder den App-Entwicklern genehmigt, gesponsert oder autorisiert wurde, noch steht der Aurora Store in irgendeiner Verbindung mit ihnen. Bitte melde dich bei deinem Google-Play-Konto an App für das Gerät nicht verfügbar Favorit @@ -367,6 +377,7 @@ Installation von Apps aus unbekannten Quellen zulassen Erforderlich Optional + Möglicherweise muss die Berechtigung aufgrund eines Fehlers im Storage Access Framework erneut erteilt werden Datensicherheit Vom Entwickler erklärte Datenschutz- und Sicherheitspraktiken Du musst zuerst die Installer-Berechtigung erteilen @@ -390,6 +401,7 @@ Hergestellt mit %1$s in Indien Standard Verfügbar + Möglicherweise muss die App neu gestartet werden, damit die Berechtigung übernommen wird. Alles entfernen Alles auswählen Exportieren der Sperrliste fehlgeschlagen! @@ -401,7 +413,7 @@ Entpacken App kann nicht geöffnet werden Bereitgestellt von Plexus - Es wird auf Kompatibilität geprüft… + Es wird auf Kompatibilität geprüft … Kompatibilität Erfordert Google-Play-Dienste Möglicherweise muss Googles proprietäre Bibliothek oder eine FOSS-Neuimplementierung wie microG installiert werden. @@ -415,60 +427,4 @@ %1$d Apps installiert Unbekannt: Noch nicht geprüft Keine Apps verfügbar - microG zur Anmeldung bei Konten verwenden - Um den Anmeldevorgang bei Google-Konten zu vereinfachen, authentifiziere dich dort mit microG - Übernehmen - Proxy erfolgreich deaktiviert - Proxy-Konfiguration anzeigen und verwalten - Einschränkungen für automatische Updates - Wenn das Gerät inaktiv ist - Nur in nicht getakteten Netzen - Konfigurieren von Geräteeinschränkungen für automatische Updates - Deaktivieren - Wenn der Akkustand nicht niedrig ist - Heruntergeladene Dateien konnten nicht überprüft werden - App-Quelle - Erweitert - Zuletzt aktualisiert - Downloads - Erforderliche Android-Version - Ziel-API-Level - %1$d Berechtigungen - microG-Paket installieren - App-Kompatibilität - Fehlende Abhängigkeiten - Ich habe die Nutzungsbedingungen und Datenschutzerklärung von microG gelesen und stimme ihnen zu - Es konnten keine Google-Play-Dienste auf deinem Gerät gefunden werden. Mehrere beliebte Apps benötigen sie mittlerweile, um ordnungsgemäß zu funktionieren! - microG ist eine kostenlose Open-Source-Implementierung, die ähnliche Funktionen bereitstellt, um Apps, die von Google-Play-Diensten für Android-Geräte abhängig sind, durch Neuimplementierung auszuführen. \n\nmicroG ermöglicht Apps den Zugriff auf diese Google-APIs, verbessert die Kompatibilität für Nutzer und bietet gleichzeitig Vorteile für den Datenschutz. \n\nmicroG wird automatisch im Hintergrund ausgeführt, wenn Anwendungen geöffnet werden, die von Google Mobile Services abhängig sind. - Datenschutzerklärung von microG lesen - microG-Lizenzvereinbarung lesen - microG-Projektwebsite besuchen - Daten, die mit anderen Unternehmen oder Organisationen geteilt werden können - Daten, die diese App erfassen darf - Der Entwickler gibt an, dass diese App keine Nutzerdaten erfasst. - Der Entwickler gibt an, dass diese App keine Nutzerdaten an andere Unternehmen oder Organisationen weitergibt. - Diese Version der App kann noch weitere Tracker enthalten, die noch nicht in der Datenbank von Exodus Privacy vorhanden sind. - %1$d bekannte Tracker in %2$s gefunden - Keine Beschreibung verfügbar - Weitere Infos - Ziel-API - Paketname - Altersfreigabe - Eine App auswählen, um weitere Details anzuzeigen - Ohne Werbung - Ohne Play-Dienste - Der Versionscode darf nur Ziffern enthalten - Vorbereiten zur Installation - - Berechtigung erforderlich - Berechtigungen erforderlich - - Der MicroG-Installer konnte die App nicht installieren, wahrscheinlich aufgrund einer Fehlkonfiguration. - MicroG-Installer - Erfordert die Installation der microG-Companion-App - Hilft, die App-Integritätsprüfung (nur Installer) zu umgehen - Ladevorgang läuft - Seite %1$d - Überspringen - Neu starten, um Änderungen zu übernehmen? diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 28d98b48c..cb5ca5d5a 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -12,7 +12,7 @@ Γίνετε μέλος Εγκαταστάσεις Εγκατάσταση - Αγνόηση + Παράλειψη Παραχωρήθηκε Παραχώρηση Τέλος @@ -135,20 +135,20 @@ Εντοπίστηκε MIUI! Το πρόγραμμα δεν μπορεί να εγκαταστήσει εφαρμογές λόγω βελτιστοποιήσεων της MIUI. Το Aurora Store απαιτεί τα ακόλουθα δικαιώματα - Οι Υπηρεσίες Aurora είναι διαθέσιμες και έτοιμες για εγκατάσταση. + Οι υπηρεσίες Aurora είναι διαθέσιμες και έτοιμες για εγκατάσταση. Όροι χρήσης Διατίθεται νέα ενημέρωση Καλώς ήρθατε Μη συμβατή εφαρμογή Υπάρχει αντικρουόμενο πακέτο Ανεπαρκής χώρος μνήμης - Εγκαταστήστε τις Υπηρεσίες Aurora 1.0.9 ή νεότερο ή αλλάξτε το πρόγραμμα εγκατάστασης. - Ρυθμίστε τις Υπηρεσίες Aurora και παραχωρήστε πρώτα όλα τα δικαιώματα. + Εγκαταστήστε τις υπηρεσίες Aurora 1.0.9 ή νεότερες εκδόσεις ή αλλάξτε το πρόγραμμα εγκατάστασης. + Ρυθμίστε τις υπηρεσίες Aurora και εκχωρήστε πρώτα όλα τα δικαιώματα. Εγκαταστάθηκε επιτυχώς Aδεια Προαιρετικά, μπορείτε να επιλέξετε τοπικό πρόγραμμα εγκατάστασης, αλλά στη συνέχεια δεν μπορείτε να εγκαταστήσετε πακέτα (χωρισμένα) APK, οπότε η επιλογή είναι δική σας. Εγκαταστάτης - Δεν μπορείτε να εγκαταστήσετε ομαδοποιημένες (διαχωρισμένες) εφαρμογές με Τοπική Εγκατάσταση. Αλλάξτε το πρόγραμμα εγκατάστασης σε Session, Services ή Root. + Δεν μπορείτε να εγκαταστήσετε ομαδοποιημένες (διαχωρισμένες) εφαρμογές με τοπική εγκατάσταση. Αλλάξτε το πρόγραμμα εγκατάστασης σε Session, Services ή Root. Μη έγκυρο ή κατεστραμμένο APK Απενεργοποιήστε τις βελτιστοποιήσεις MIUI για να επιτρέψετε της εγκαταστάσεις, διαφορετικά μπορείτε να επιλέξετε το πρόγραμμα εγκατάστασης Root ή Services. Δικαιώματα @@ -158,16 +158,17 @@ Κατηγορίες Δεν ήταν δυνατή η λήψη αρχείων Πρόσβαση εξωτερικού χώρου αποθήκευσης - Διαχειριστής εξωτερικής αποθήκευσης + Εξωτερική αποθήκευση Επιτρέψτε την εγκατάσταση εφαρμογών από το Aurora Store Εγκαταστάτης συνεδρίας - Να μην γίνεται έλεγχος για ενημερώσεις εφαρμογών που εγκαταστάθηκαν από το F-Droid + Αγνοεί εφαρμογές F-Droid από Ενημερώσεις και Εγκατεστημένες εφαρμογές Επιλέξτε προεπιλεγμένη καρτέλα Τα κατεβασμένα APK θα διαγραφούν αμέσως μετά την εγκατάσταση Δικτύωση Προσαρμογή - Εμφάνιση σελίδων για εσάς στην αρχική οθόνη + Εμφάνιση σελίδων για Εσάς στην αρχική οθόνη Η εφαρμογή δεν υποστηρίζεται + Εμφάνιση παρόμοιων και σχετικών ομάδων στη σελίδα λεπτομερειών εφαρμογής Η συνεδρία έληξε, συνδεθείτε ξανά για να λάβετε νέα. Κορυφαίες επί πληρωμή Συσκευή @@ -178,7 +179,7 @@ Βεβαιωθείτε ότι έχετε συνδεθεί ξανά και επανεκκινήστε την εφαρμογή για να εφαρμόσετε αλλαγές. Επιλογές συντακτών Λογαριασμοί - Εγκαταστάτης εφαρμογής + Εγκατάσταση εφαρμογής Ενεργοποιήστε τις ρυθμίσεις προγραμματιστή από τις ρυθμίσεις συσκευής για να τις ανοίξετε. Υπηρεσίες Aurora (Απαρχαιωμένο) Για εσάς @@ -204,10 +205,11 @@ Διαχείριση μαύρης λίστας Εφαρμογές στη βιβλιοθήκη Σχετικά με - Σελίδες για εσάς + Σελίδες για Εσάς Εγκατάσταση Κορυφαίες εφαρμογές Τάσεις + Eφαρμογές προς πώληση Παιχνίδια Δεν διατίθεται σε ανώνυμους λογαριασμούς Αντιγράφηκε στο πρόχειρο @@ -228,7 +230,7 @@ Δεν ήταν δυνατή η δημιουργία AAS Token Οι αγορές εφαρμογών δεν είναι διαθέσιμες σε ανώνυμους λογαριασμούς. Εγκατάστησε το Διαχειριστή εφαρμογών ή άλλαξε το πρόγραμμα εγκατάστασης. - Προσθήκη στην αρχική οθόνη + Προσθήκη στην Αρχική οθόνη Απομένουν %1$dδλ Εγκαταστάτης Shizuku Αξιολόγηση τίτλου @@ -240,30 +242,34 @@ Εισαγωγή Απομένουν %1$dλ %2$dδλ Αποστολή ειδοποιήσεων ανεξάρτητα της κατάστασης εγκατάστασης - Λήψεις παρασκηνίου + Λήψεις Παρασκηνίου Επιτρέψτε στο Aurora Store να κατεβάσει και να ενημερώσει εφαρμογές στο παρασκήνιο Έκδοση Google Play + Μεσολάβηση Το Shizuku δεν έχει εγκατασταθεί ή ρυθμιστεί σωστά. Αίτηση νέας ανάλυσης Η εκκαθάριση ολοκληρώθηκε - Εμφάνιση ενημερώσεων που ενδέχεται να αποτύχουν - Εμφάνιση ενημερώσεων για μη συμβατές ή απενεργοποιημένες εφαρμογές που μπορεί να αποτύχουν να εγκατασταθούν + Μη συμβατές ενημερώσεις + Εμφάνιση ενημερώσεων από μη συμβατές ή απενεργοποιημένες εγαρμογές που μπορεί να αποτύχουν να εγκατασταθούν Προεπιλογή (από καταγραφές συσκευής) + Ενεργοποίηση μεσολάβησης + Επιτρέψτε όλη την κίνηση από την εφαρμογή να περνάει από τη μεσολάβηση URL μεσολάβησης - Φιλτράρισμα εφαρμογών από άλλες πηγές + Μόνο εφαρμογές Aurora Store Δεν ήταν δυνατή η σύνδεση μέσω Google + Προμηθευτής - bestappsales.com Ουαου! Όλα καλά. Συνδεθείτε και απολαύστε. Επαλήθευση συνεδρίας Η τελευταία συνεδρία πετάχτηκε Πρόταση αναζήτησης Αποτελέσματα αναζήτησης - Όχι έλεγχος για ενημερώσεις για εφαρμογές που έχουν εγκατασταθεί από πηγές εκτός του Aurora Store + Εμφάνιση μόνο εφαρμογών εγκατεστημένων από το Aurora Store στο Ενημερώσεις και Εγκατεστημένες εφαρμογές Ετοιμάζοντας τα πράγματα… Ρύθμιση συσκευής εισήχθη - Επαλήθευση συνεδρίας Google + Επαλήθευση Συνεδρίας Google Προχωρημένα - Ρυθμίσεις εφαρμογής + Ρυθμίσεις Εφαρμογής Η μεσολάβηση ρυθμίστηκε επιτυχώς διαθέσιμες ενημερώσεις Μενού @@ -277,7 +283,7 @@ Αιτείται νέα συνεδρία %1$d διαθέσιμη ενημέρωση %1$s και %2$s - Αναζήτηση για εφαρμογές & παιχνίδια + Αναζήτηση για Εφαρμογές & Παιχνίδια Αποτυχία ρύθμισης μεσολάβησης διαθέσιμη ενημέρωση Λήψη επιπρόσθετων αρχείων για %1$s @@ -285,7 +291,7 @@ Συχνότητα αυτόματων ενημερώσεων Ειδοποιήσεις ενημέρωσης Μια νέα έκδοση της %1$s είναι διαθέσιμη - Αυτόματες ενημερώσεις + Αυτόματη ενημέρωση εφαρμογών Ρύθμιση συμπεριφοράς αυτόματων ενημερώσεων Να μη γίνει αυτόματη ενημέρωση εφαρμογών Έλεγχος & ειδοποίηση για διαθέσιμες ενημερώσεις @@ -311,7 +317,7 @@ Κατάλληλο για συσκευές που τρέχουν κάτω από Android 4.4 Γλώσσα εφαρμογής Αποτυχία δημιουργίας συνεδρίας, κώδικας σφάλματος: %1$d - Έχετε περιορισμένο τιμολόγιο + Ουπς, αυτός ο λογαριασμός έχει όριο Google Play, ή αλλιώς Google Play Store και πρώην Android Market. Διακομιστής μη διαθέσιμος Επαλήθευση νέας συνεδρίας @@ -339,18 +345,22 @@ Παρακαλώ συνδεθείτε στο λογαριασμό σας στο Google Play Θέλετε να αφαιρέσετε τον διανομέα \"%1$s\"; Διαχείριση διανομέων - Αφαίρεση διανομέα; + Αφαιρέστε τον διανομέα Σχετικά με το κατάστημα Aurora Μάθετε περισσότερα για το κατάστημα Aurora Δεν υπάρχουν διαθέσιμοι διανομείς Προσθήκη διανομέα Wiki Αγαπημένο - Αγαπημένες εφαρμογές + Αγαπημένες Εφαρμογές Απεγκαταστάθηκε επιτυχώς Δε βρέθηκαν αγαπημένες εφαρμογές Η εφαρμογή δεν είναι διαθέσιμη για τη συσκευή σου - Το Aurora Store σού δίνει τη δυνατότητα να κάνεις αναζήτηση και λήψη εφαρμογών από το επίσημο κατάστημα Google Play. Μπορείς να ελέγξεις περιγραφές εφαρμογών, στιγμιότυπα οθόνης, ενημερώσεις, σχόλια άλλων χρηστών και να κάνεις λήψη του APK απευθείας από το Google Play στη συσκευή σου. Για να χρησιμοποιήσεις το Aurora Store, πρέπει να έχεις λογαριασμό Google Play και να συνδεθείς σε αυτόν όταν ανοίγεις και ρυθμίζεις για πρώτη φορά το Aurora Store. \n \nΣε αντίθεση με ένα παραδοσιακό κατάστημα εφαρμογών, το Aurora Store δεν κατέχει, δεν διαθέτει άδεια χρήσης ή δεν διανέμει κάποια εφαρμογή. Όλες οι εφαρμογές, οι περιγραφές εφαρμογών, τα στιγμιότυπα οθόνης και άλλο περιεχόμενο στο Aurora Store έχουν άμεση πρόσβαση, λήψη και/ή προβολή από το Google Play. Το Aurora Store λειτουργεί ακριβώς όπως μια πόρτα ή ένα πρόγραμμα περιήγησης, επιτρέποντάς σου να συνδεθείς στον λογαριασμό σου στο Google Play και να βρείτε τις εφαρμογές από το Google Play. \n \nΛάβε υπόψη ότι το Aurora Store δεν έχει καμία έγκριση, χορηγία ή εξουσιοδότηση από την Google, το Google Play, τυχόν εφαρμογές που έχουν ληφθεί μέσω του Aurora Store ή οποιονδήποτε προγραμματιστή εφαρμογών, ούτε το Aurora Store έχει καμία σχέση, συνεργασία ή σχέση μαζί τους. + Το Aurora Store σού δίνει τη δυνατότητα να κάνεις αναζήτηση και λήψη εφαρμογών από το επίσημο κατάστημα Google Play. Μπορείς να ελέγξεις περιγραφές εφαρμογών, στιγμιότυπα οθόνης, ενημερώσεις, σχόλια άλλων χρηστών και να κάνεις λήψη του APK απευθείας από το Google Play στη συσκευή σου. Για να χρησιμοποιήσεις το Aurora Store, πρέπει να έχεις λογαριασμό Google Play και να συνδεθείς σε αυτόν όταν ανοίγεις και ρυθμίζεις για πρώτη φορά το Aurora Store. +\n +\nΣε αντίθεση με ένα παραδοσιακό κατάστημα εφαρμογών, το Aurora Store δεν κατέχει, δεν διαθέτει άδεια χρήσης ή δεν διανέμει κάποια εφαρμογή. Όλες οι εφαρμογές, οι περιγραφές εφαρμογών, τα στιγμιότυπα οθόνης και άλλο περιεχόμενο στο Aurora Store έχουν άμεση πρόσβαση, λήψη και/ή προβολή από το Google Play. Το Aurora Store λειτουργεί ακριβώς όπως μια πόρτα ή ένα πρόγραμμα περιήγησης, επιτρέποντάς σου να συνδεθείς στον λογαριασμό σου στο Google Play και να βρείτε τις εφαρμογές από το Google Play. +\n +\nΛάβε υπόψη ότι το Aurora Store δεν έχει καμία έγκριση, χορηγία ή εξουσιοδότηση από την Google, το Google Play, τυχόν εφαρμογές που έχουν ληφθεί μέσω του Aurora Store ή οποιονδήποτε προγραμματιστή εφαρμογών, ούτε το Aurora Store έχει καμία σχέση, συνεργασία ή σχέση μαζί τους. Δες και διαχειρίσου απορρίμματα διακριτικών από ανώνυμες συνδέσεις Εισήγαγε μια έγκυρη διεύθυνση URL διακομιστή μεσολάβησης για να περνάνε όλα τα δεδομένα μέσω αυτού. Προσθέστε ένα διανομέα διακριτικού στο Aurora Store. Οι διανομείς Διακριτικών παρέχουν διαπιστευτήρια λογαριασμού στο Aurora Store για την ανώνυμη καταγραφή. @@ -360,19 +370,20 @@ Τα αγαπημένα εισήχθησαν! Τα αγαπημένα εξήχθησαν! Επιτυχής εξαγωγή πακέτου app - Αποτυχία εξαγωγής πακέτου εφαρμογής + Αποτυχία εξαγωγής πακέτου app Αποσύνδεση; Είστε σίγουροι ότι θέλετε να αποσυνδεθείτε; Έλεγχος για ενημερώσεις Ασφάλεια δεδομένων Ιδιωτικότητα δεδομένων και πρακτικές ασφάλειες ορισμένες από τον προγραμματιστή Να επιτρέπεται η εγκατάσταση εφαρμογών από άγνωστες πηγές - Πρέπει να αποδεχτείτε την άδεια εγκατάστασης πρώτα + Πρέπει να αποδεχτείς την Άδεια Εγκατάστασης πρώτα + ίσως χρειαστεί να τη παραχωρήσεις ξανά εξαιτίας ενός σφάλματος στο Πλαίσιο Πρόσβασης Μνήμης Απαιτείται Προαιρετικό Επανεκκίνηση Aurora Store Το Aurora Store χρείαζεται να επανεκκινηθεί για να εφαρμοστούν οι πρόσφατες αλλαγές - Εξαγωγέας αρχείου + Εξαγωγέας Αρχείου Περίμενε λίγο, εξάγουμε το αρχείο σου Φτιαγμένο με %1$s στην Ινδία Ειδοποίηση σχετική με λογαριασμό @@ -388,87 +399,4 @@ Ειδοποίηση εξαγωγής εφαρμογής Ειδοποίηση εγκατάστασης Ειδοποίηση λήψεων - Επαληθεύεται - Μη αρχειοθέτηση - Απαιτεί Google Play Services - Το proxy απενεργοποιήθηκε με επιτυχία - Μόνο σε απεριόριστα δίκτυα - Όταν η συσκευή είναι αδρανής - Αφαίρεση όλων - Επιλογή όλων - Τελευταία - Αποτυχία επαλήθευσης αρχείων λήψης - Αποτυχία εξαγωγής μαύρης λίστας! - Προεπιλογή - Διαθέσιμο - Αδυναμία ανοίγματος εφαρμογής - %1$d εγκατεστημένες εφαρμογές - Λειτουργεί χωρίς Υπηρεσίες Google Play - Μπορεί να χρειαστεί να εγκαταστήσετε την ιδιόκτητη βιβλιοθήκη της Google ή μια FOSS επανέκδοση, όπως microG. - Αυτή η εφαρμογή λειτουργεί χωρίς την ιδιόκτητη βιβλιοθήκη της Google. Ωστόσο, μπορεί να απαιτεί άλλες βιβλιοθήκες τρίτων να λειτουργούν σωστά. - Απενεργοποίηση - Αποτυχία εισαγωγής σε μαύρη λίστα! - Δεν υπάρχουν διαθέσιμες εφαρμογές - Συμβατότητα - Συμβατό: Λειτουργεί χωρίς προβλήματα - Δεν υποστηρίζεται: Μη λειτουργική - Έλεγχος συμβατότητας… - Όταν η μπαταρία δεν είναι χαμηλή - Εμφάνιση και διαχείριση της διαμόρφωσης του proxy - Η μαύρη λίστα εξήχθη! - Η μαύρη λίστα εισήχθη! - Με την υποστήριξη του Plexus - Με το Έργο microG - Χωρίς Υπηρεσίες Google Play - Περιορισμένη: Λειτουργεί με περιορισμένα χαρακτηριστικά - Άγνωστο: Δεν ελέγχθηκε ακόμα - Χρήση microG για σύνδεση σε λογαριασμούς - Ταυτοποίηση με microG κατά τη σύνδεση σε λογαριασμούς Google για μια απλούστερη ροή σύνδεσης - Ορισμός - Περιορισμοί αυτόματων ενημερώσεων - Ρύθμιση περιορισμών συσκευής για αυτοματοποιημένες ενημερώσεις - Εγκατάσταση Πακέτου microG - Δεδομένα που ενδέχεται να συλλέγει αυτή η εφαρμογή - Ο προγραμματιστής λέει ότι αυτή η εφαρμογή δεν συλλέγει δεδομένα χρήστη. - Δεδομένα που ενδέχεται να κοινοποιήσει αυτή η εφαρμογή - Ο προγραμματιστής λέει ότι αυτή η εφαρμογή δεν κοινοποιεί δεδομένα χρηστών σε άλλες εταιρείες ή οργανισμούς. - Αυτή η έκδοση της εφαρμογής ενδέχεται να περιέχει περισσότερους ιχνηλάτες που δεν υπάρχουν ακόμη στη βάση δεδομένων απορρήτου Exodus . - Λήψεις - Ελάχιστη έκδοση Android - Συμβατότητα Εφαρμογής - Λείπουν εξαρτήσεις - Διάβασε την Πολιτική Απορρήτου της microG - Διάβασε την Άδεια Χρήσης και Συμφωνίας της microG - Περισσότερες πληροφορίες - Στόχοι - Όνομα πακέτου - Πηγή εφαρμογής - Επιλέξτε μια εφαρμογή για περισσότερες λεπτομέρειες - Δεν υπάρχουν διαφημίσεις - %1$d γνωστοί ιχνηλάτες βρέθηκαν στο %2$s - Το πρόγραμμα εγκατάστασης του MicroG απέτυχε να εγκαταστήσει την εφαρμογή, πιθανώς λόγω λανθασμένης διαμόρφωσης. - Πρόγραμμα Εγκατάστασης MicroG - Τελευταία ενημέρωση - Στοχευμένο Επίπεδο API - Παράλειψη - Έχω διαβάσει και συμφωνώ με τους Όρους Παροχής Υπηρεσιών και την Πολιτική Απορρήτου του microG - Δεν μπορέσαμε να βρούμε τις Υπηρεσίες Google Play στη συσκευή σας, αρκετές δημοφιλείς εφαρμογές τις απαιτούν πλέον για να λειτουργήσουν σωστά! - Το microG είναι μια δωρεάν και ανοιχτού κώδικα υλοποίηση που παρέχει παρόμοια λειτουργικότητα για την εκτέλεση εφαρμογών που εξαρτώνται από τις Υπηρεσίες Google Play για συσκευές Android μέσω επαναυλοποίησης.\n\nΤο microG επιτρέπει στις εφαρμογές να έχουν πρόσβαση σε αυτά τα API της Google, βελτιώνοντας τη συμβατότητα για τους χρήστες, προσφέροντας παράλληλα πλεονεκτήματα απορρήτου.\n\nΤο microG θα εκτελείται αυτόματα στο παρασκήνιο όταν ανοίγετε εφαρμογές που εξαρτώνται από τις Υπηρεσίες Google Mobile. - Επισκεφθείτε την Ιστοσελίδα του Πρότζεκτ microG - Απαιτείται η εγκατάσταση της συνοδευτικής εφαρμογής microG - Σας βοηθά να παρακάμψετε τον Έλεγχο Ακεραιότητας Εφαρμογής (μόνο για το πρόγραμμα εγκατάστασης) - Ο κωδικός έκδοσης μπορεί να περιέχει μόνο ψηφία - Επανεκκίνηση για εφαρμογή αλλαγών; - Δεν υπάρχει διαθέσιμη περιγραφή - %1$d δικαιώματα - - Απαιτείται δικαίωμα - Απαιτούνται δικαιώματα - - Αξιολόγηση περιεχομένου - Προετοιμασία για εγκατάσταση - Προχωρημένες - Δεν υπάρχουν υπηρεσίες play - Φόρτωση σε εξέλιξη - Σελίδα %1$d diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml index ae364befe..e424ab6e4 100644 --- a/app/src/main/res/values-eo/strings.xml +++ b/app/src/main/res/values-eo/strings.xml @@ -125,6 +125,7 @@ Pri Miaj apoj kaj ludoj Apoj biblioteke + Apoj rabataj Aparato Ludoj Instalado @@ -176,6 +177,7 @@ ankoraŭ %1$d m %2$d s Agordo \"Por vi\" paĝoj + Vidigi similajn kaj rilatajn apojn sur la paĝo de la apon detaloj Shizuku instalilo AM instalilo Peti novan analizon @@ -282,6 +284,7 @@ Permeso donita Vi devas doni la Instalilo-Permeso unue Apo maldisponebla por via aparato + Vi eble devas redoni la permeson kaŭze de cimo en Storage Access Framework Aparaton ŝajnigo aktivata. Importo de la aparaton agordo fiaskis Fone apon elŝutado @@ -344,9 +347,12 @@ Eksportis sukcese apkunligaĵon Eksportado apkunligaĵon fiaskis Restarti Aurora Store + Prokura servilo (aŭ “proxy”) Prokuran servilon sukcese finaranĝis Kopita en la poŝon Prokuran servilon agordado fiaskis + Aktivigi prokuran servilon + Permisi tutan datumtrafikon pasi tra la prokura servilo Prokuran servilon URL Malvalida prokuran servilon URL, kontrolu la formaton! Enigu validan prokuran servilon URL por pasigi ĉiujn datuĵmojn tra la prokura servilo. @@ -355,6 +361,7 @@ Vidi kaj administri ĵetondistribuilojn por anonimaj ensalutadoj Vi vidos novajn funkciarojn kaj cimojn pli frue ol la publiko. Donu vian opinion al programistoj por helpi ilin plibonigi la apon. Anigado eble daŭros iom tempon, vi povos kontroli la anigstaton poste. + Provizanto - bestappsales.com Vidi la Aurora Store XDA fadenon por priparoloj aŭ sugestoj. Android Market estis reta butiko ofertinta programaraplikaĵojn dizajnitajn por Androidaparatojn, retirigita en 2017. Ŝaltu la programistajn agordojn en la aparaton agordoj por malfermi ĝin. @@ -362,5 +369,9 @@ Eksteran storon administrilo Google Play, ankaŭ konata tiel Google Play Store kaj estinte Android market. Eksteran storon atingo - Aurora Store ebligi serĉi kaj elŝuti apojn el la oficiala Google Play Store. Vi povas vidi apojn priskribojn, ekrankopiojn, ĝisdatigojn, komentojn kaj elŝuti la APKjn rekte el Google Play al via aparato. Por uzi Aurora Store, necesas, ke vi havas Google Play konton kaj ensalutas tiun konton kiam vi malfermi kaj agordi Aurora Store je la unua fojo. \n \nMalkiel tradiciaj apbutikoj, Aurora Store ne posedas, donas permesilon aŭ disdonas iun ajn apon. Ĉiuj apoj, appriskriboj, ekrankopiojn kaj aliaj enhavoj en Aurora Store estas rekte atingataj, elŝutataj aŭ montriĝataj el Google Play. Aurora Store funkcias ekzakte tiel pordo aŭ retumilo, ebligante vin saluti vian Google Play konton kaj trovi apojn el Google Play. \n \nBonvolu rimarki ke Aurora Store ne havas ajn aprobon, patronadon aŭ rajtigon el Google, Google Play, iu ajn apo elŝutita tra Aurora Store aŭ iu ajn approgramisto; nek havas Aurora Store iun ajn filion, kunlaboron aŭ interligecon kun ili. + Aurora Store ebligi serĉi kaj elŝuti apojn el la oficiala Google Play Store. Vi povas vidi apojn priskribojn, ekrankopiojn, ĝisdatigojn, komentojn kaj elŝuti la APKjn rekte el Google Play al via aparato. Por uzi Aurora Store, necesas, ke vi havas Google Play konton kaj ensalutas tiun konton kiam vi malfermi kaj agordi Aurora Store je la unua fojo. +\n +\nMalkiel tradiciaj apbutikoj, Aurora Store ne posedas, donas permesilon aŭ disdonas iun ajn apon. Ĉiuj apoj, appriskriboj, ekrankopiojn kaj aliaj enhavoj en Aurora Store estas rekte atingataj, elŝutataj aŭ montriĝataj el Google Play. Aurora Store funkcias ekzakte tiel pordo aŭ retumilo, ebligante vin saluti vian Google Play konton kaj trovi apojn el Google Play. +\n +\nBonvolu rimarki ke Aurora Store ne havas ajn aprobon, patronadon aŭ rajtigon el Google, Google Play, iu ajn apo elŝutita tra Aurora Store aŭ iu ajn approgramisto; nek havas Aurora Store iun ajn filion, kunlaboron aŭ interligecon kun ili. diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 55b4dd7f9..ce9d8cbfe 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1,14 +1,14 @@ - Suplantación de dispositivo aplicada. + Suplantación de identidad del dispositivo aplicada. Permiso concedido - Activa los ajustes de desarrollador desde las opciones del dispositivo. + Active los ajustes de desarrollador desde las opciones del dispositivo. Copiado al portapapeles En la lista blanca En la lista negra No disponible en cuentas anónimas Actualizaciones - Gestor de suplantación de dispositivo + Gestor del simulador de dispositivo Ajustes Historial de compras Sin conexión @@ -22,6 +22,7 @@ Descargas Dispositivo Gestión de la lista negra + Apps en oferta Apps en la biblioteca Mis apps y juegos Aplicaciones @@ -35,13 +36,13 @@ Para ti Selección de los editores Categorías - Asegúrate de volver a iniciar sesión para aplicar la suplantación de dispositivo + Asegúrese de volver a acceder a su cuenta para aplicar la suplantación de dispositivo No se pueden obtener los archivos Aplicación no adquirida La descarga falló Personalización Método de instalación - Selecciona el modo de instalación del APK + Seleccione el modo de instalación del APK Instalador de sesión Servicios de Aurora (Obsoleto) Instalador root @@ -53,16 +54,16 @@ Permitir la instalación de aplicaciones desde Aurora Store Permiso del instalador Gestor de almacenamiento externo - Para guardar archivos de expansión APK (OBBs) de aplicaciones y juegos grandes. + Para almacenar tarjetas de expansión APK (OBB) para aplicaciones y juegos grandes. Acceso al almacenamiento externo - ¿Cómo te va? + ¿Cómo le va\? Bienvenido/a Permisos Instalador Aurora Store requiere los siguientes permisos Nueva actualización disponible - Opcionalmente puedes elegir el instalador nativo, pero entonces no podrás instalar los APKs empaquetados (divididos), así que la elección es tuya. - Por favor, desactiva las optimizaciones de MIUI para permitir las instalaciones, de lo contrario puedes elegir el instalador Root o Servicios. + Opcionalmente puede elegir el instalador nativo, pero entonces no podrá instalar los APKs empaquetados (divididos), así que la elección es suya. + Por favor, desactive las optimizaciones de MIUI para permitir las instalaciones, de lo contrario puede elegir el instalador Root o Servicios. La sesión de instalación no puede instalar aplicaciones debido a las optimizaciones de MIUI. ¡MIUI detectado! Términos del servicio @@ -77,10 +78,10 @@ No se ha podido crear la sesión La instalación se bloqueó El instalador falló - Configura los servicios de Aurora y concede primero todos los permisos. - Instala los servicios de Aurora 1.0.9 o superior, o cambia el instalador. + Configure los servicios de Aurora y conceda primero todos los permisos. + Instale los servicios de Aurora 1.0.9 o superior, o cambie el instalador. Los servicios de Aurora están disponibles y listos para ser instalados. - Sin acceso root. Concede el acceso o cambia el instalador. + Sin acceso root. Conceda el acceso o cambie el instalador. Ver informe rastreador(es) conocido(s) encontrado(s) en Comprobando los rastreadores… @@ -92,13 +93,13 @@ Pausar todo No hay descargas Obteniendo metadatos - Forzar limpieza de todo - Descarga fallida + Forzar limpiado de todo + Falló la descarga Calculando Descarga completa Cancelar todas Cancelada - ¿Qué opinas de esta aplicación? + ¿Qué opina de esta aplicación\? Permitido Permitir BHIM - UPI @@ -129,17 +130,17 @@ Descripción Dependencias Contiene anuncios - Registro de cambios no proporcionado - Registro de cambios - La inscripción puede llevar algún tiempo, puedes comprobar el estado más tarde. - Verás nuevas funciones y errores antes que el público. Comparte tu opinión con los desarrolladores para ayudarles a mejorar. + No se han proporcionado novedades + Novedades + La inscripción puede llevar algún tiempo, puede comprobar el estado más tarde. + Verá las nuevas funciones y los errores antes que el público. De su opinión a los desarrolladores para ayudarles a mejorar. Programa beta ¿Unirse al programa beta? - Eres un beta tester + Es un usuario beta Lista blanca Actualizar todo Actualizar - Información de la aplicación + Información de aplicación Desinstalar Compartir Buscar @@ -183,16 +184,16 @@ Iniciar sesión con Google Anónimo - Consulta el hilo de Aurora Store en XDA para debatir o hacer sugerencias. + Consulte el hilo de Aurora Store en XDA para debatir o hacer sugerencias. Foros XDA - Únete al grupo de asistencia de Aurora para debatir o hacer sugerencias. + Únase al grupo de asistencia de Aurora para debatir o hacer sugerencias. Telegram Donar vía Paypal PayPal Conviértete en patrocinador con Liberapay Liberapay - Obtén Aurora Store a través de F-Droid. - Obtén el código fuente de Aurora Store desde Aurora OSS en GitLab. + Consigue Aurora Store a través de F-Droid. + Obtenga el código fuente de Aurora Store desde Aurora OSS en GitLab. GitLab F-Droid Donar mediante Ethereum (ETH) @@ -200,17 +201,18 @@ Donar mediante Bitcoin (BTC) Bitcoin Donar mediante Bitcoin Cash (BCH) - Bitcoin Cash + Bitcoin Donar mediante UPI Aplicación no encontrada - Sesión caducada, vuelve a iniciar sesión para continuar. - Aplicación no compatible + La sesión expiró, vuelva a iniciar sesión para obtener una nueva sesión. + Aplicación no admitida Las compras de aplicaciones no están disponibles en cuentas anónimas. - Asegúrate de volver a iniciar sesión y reiniciar la aplicación para aplicar los cambios. + Asegúrese de volver a iniciar sesión y reiniciar la aplicación para aplicar los cambios. Redes Felicidades, el código de la versión solicitada está disponible, descargándolo ahora. - El código de versión que estás solicitando no está disponible. + El código de la versión que solicita no está disponible. Descarga manual + Mostrar grupos similares y relacionados en la página de detalles de la aplicación Aplicaciones similares y relacionadas Mostrar las páginas Para ti en la pantalla de inicio Páginas para ti @@ -218,10 +220,10 @@ Disposición Extras No se ha encontrado ninguna aplicación que coincida - No puedes instalar las apps (desglose) empaquetados por medio de Instalador Nativo. Cambia tu instalador a Sesión, Servicios o Root. + Los archivos APK empaquetados o divididos no se pueden instalar con el método de instalación nativo. Cambia el método de instalación a Sesión, Servicios o Root. No se ha podido generar el token AAS - No se ha podido enviar la valoración - Valorado, puede tardar un rato en aparecer + No se pudo enviar la calificación + Clasificado, puede tardar en aparecer Página de navegación no disponible No se ha podido exportar la configuración del dispositivo Configuración del dispositivo exportada @@ -229,11 +231,11 @@ Descarga de aplicaciones en segundo plano Instala App Manager o cambia el instalador. Instalador AM - En pausa •·%1$d / %2$d + En pausa •%1$d / %2$d Quedan %1$d horas, %2$d minutos, %3$d segundos Quedan %1$d minutos %2$d segundos Quedan %1$d segundos - Descargando •·%1$d / %2$d%3$s + Descargando •%1$d / %2$d%3$s Notificaciones ¡Guau! Todo está bien. Preparando las cosas… @@ -242,7 +244,7 @@ Verificando la sesión de Google Avanzado Expandir - Se denegaron los permisos requeridos. Por favor, otórgalos para continuar con la acción + Se han denegado los permisos necesarios. Por favor, concédelos para continuar la acción Buscar aplicaciones y juegos Enviar notificaciones sobre el estado de las instalaciones Inicia sesión y disfruta. @@ -253,62 +255,66 @@ actualizaciones disponibles %1$s • API %2$s Solicitando una nueva sesión - Servidor fuera de servicio por mantenimiento + El servidor no disponible por mantenimiento Importar - No se ha podido importar la configuración del dispositivo + No se pudo importar la configuración del dispositivo La configuración del dispositivo ha sido importada Descargando los archivos adicionales para %1$s %1$d actualización disponible %1$s y %2$s %1$s, %2$s, %3$s y %4$d más - Notificaciones de actualización + Notificaciones de actualizaciones %1$d actualizaciones disponibles Una nueva versión de %1$s está disponible %1$s, %2$s y %3$s Instalador de Shizuku Shizuku no está instalado o configurado correctamente. Resultados de la búsqueda - ¡Error interno! Por favor, inténtalo de nuevo más tarde - Límite de solicitudes alcanzado + ¡Error interno!. Por favor, vuelve a intentarlo después de algún tiempo + Ups, demasiado intentos Servidor no accesible - Sugerencia de búsqueda + Sugerencias para la búsqueda No se ha podido obtener el informe de privacidad ¡Acceso denegado! ¿Estás usando una VPN o Tor\? Fallo al generar la sesión, código de error: %1$d Idioma de la aplicación Comprobar la conexión Permitir que Aurora Store abra enlaces compatibles - No se ha podido generar la sesión + No se pudo generar la sesión Verificando la nueva sesión Enlaces de la aplicación Google Play, también conocido como Google Play Store y anteriormente Android Market. Android Market era una tienda online que ofrecía aplicaciones de software diseñadas para dispositivos Android, retirada en 2017. - Titulo de la reseña - Configurar el intervalo de tiempo para actualizaciones automáticas, en horas. - Filtrar aplicaciones de otras fuentes - No buscar actualizaciones para aplicaciones instaladas de fuentes externas a Aurora Store + Revisar el título + Proveedor - bestappsales.com + Configure los intervalos para las actualizaciones automáticas y en horas. + Sólo aplicaciones de Aurora Store + Solo comprobar actualizaciones de aplicaciones instaladas desde la Aurora Store Ajustes de la aplicación Frecuencia de las actualizaciones automáticas + Activar el proxy Dirección URL del proxy - Dirección URL del proxy no válida, ¡comprueba el formato! + Proxy + Dirección URL del proxy no válida, ¡compruebe el formato! Proxy configurado correctamente Error al establecer el proxy + Permitir que todo el tráfico de la aplicación pase por el proxy Por defecto (desde la configuración del dispositivo) - Versión de Google Play + Versión para Google Play Descargas en segundo plano Permitir que Aurora Store descargue y actualice aplicaciones en segundo plano - Actualizaciones automáticas - Comprobar y notificar sobre actualizaciones disponibles + Actualización automática de las aplicaciones + Comprobación y notificación de actualizaciones disponibles No actualizar automáticamente las aplicaciones Configurar el comportamiento de las actualizaciones automáticas - Comprobar e instalar actualizaciones disponibles automáticamente + Compruebe e instale automáticamente las actualizaciones disponibles Solicitar un nuevo análisis - Error al exportar los APKs + Error exportando APKs Limpiar lo finalizado - Mostrar actualizaciones que podrían fallar + Actualizaciones no compatibles Mostrar actualizaciones de aplicaciones incompatibles o desactivadas que pueden fallar al instalarse Añadir a la pantalla de inicio - Instalador basado en sesión para APKs empaquetados/divididos + Instalador en segundo plano para APKs empaquetados/divididos Recomendado, integrado y compatible con todas las versiones de Android Requiere privilegios de root/superusuario, es compatible con todas las versiones de Android. Instalador para instalaciones en segundo plano @@ -316,59 +322,64 @@ Ideal para dispositivos con versiones anteriores a Android 4.4 Código fuente Política de privacidad - Aprende cómo Aurora Store utiliza tus datos + Conozca cómo Aurora Store utiliza sus datos Requiere que los servicios de Aurora se instalen como una aplicación con privilegios de sistema Completo gestor de paquetes de código abierto Requiere App Manager, necesita modo adb/root para instalar cuando la optimización de miui está activada Uso directo de las API del sistema con privilegios adb/root Requiere que primero se configure y se le otorguen permisos a la aplicación Shizuku o Sui - Introduce el código de la versión que deseas descargar - ¿Tienes preguntas? Descubre las respuestas - Descubre qué hay dentro + Introduzca el código de la versión que desea descargar + ¿Tiene preguntas? Descubra las respuestas + Descubra qué hay dentro Responsabilidad - Instalador basado en intención, disponible en todos los dispositivos + Instalador disponible en todos los dispositivos Más Gestiona tu cuenta - Restablecer propietario del dispositivo - Elimina Aurora Store como la aplicación propietaria del dispositivo + Borrar el propietario del dispositivo + Elimina Aurora Store como aplicación propietaria del dispositivo Esto revocará el permiso del instalador de sesión para instalar silenciosamente la aplicación. ¿Proceder a borrar la propiedad del dispositivo? No hay dispensadores disponibles - Agregar dispensador + Añadir dispensador URL invalida - ¿Eliminar dispensador? - Agregar + Quitar dispensador + Añadir Wiki - Encuentra respuestas a preguntas frecuentes (P+F), pasos para la solución de problemas y más + Encuentra respuestas a preguntas frecuentes (FAQ), pasos para la solución de problemas y más Gestionar dispensadores Ver y administrar dispensadores de tokens para inicios de sesión anónimos - Agrega un dispensador de tokens a Aurora Store. Los dispensadores de tokens proporcionan credenciales de cuenta a Aurora Store para iniciar sesión de forma anónima. + Agregue un dispensador de tokens a Aurora Store. Los dispensadores de tokens proporcionan credenciales de cuenta a Aurora Store para iniciar sesión de forma anónima. URL del dispensador - ¿Deseas eliminar el dispensador \"%1$s\"? - Eliminar + ¿Deseas quitar el dispensador \"%1$s\"? + Quitar Acerca de Aurora Store Más información sobre Aurora Store - Aurora Store te permite buscar y descargar aplicaciones desde la tienda oficial de Google Play. Puedes consultar descripciones de aplicaciones, capturas de pantalla, actualizaciones, comentarios de otros usuarios y descargar el APK directamente desde Google Play a tu dispositivo. Para usar Aurora Store, necesitas tener una cuenta de Google Play e iniciar sesión en tu cuenta de Google Play la primera vez que abras y configures Aurora Store.\n\nA diferencia de una tienda de aplicaciones tradicional, Aurora Store no posee, licencia ni distribuye ninguna aplicación. Todas las aplicaciones, descripciones de aplicaciones, capturas de pantalla y otros contenidos en Aurora Store se acceden, descargan y/o muestran directamente desde Google Play. Aurora Store funciona exactamente como una puerta o un navegador, permitiéndote iniciar sesión en tu cuenta de Google Play y encontrar las aplicaciones de Google Play.\n\nTen en cuenta que Aurora Store no tiene ninguna aprobación, patrocinio ni autorización por parte de Google, Google Play, ninguna de las aplicaciones descargadas a través de Aurora Store ni de los desarrolladores de aplicaciones; tampoco tiene ninguna afiliación, cooperación ni conexión con ellos. + Aurora Store le permite buscar y descargar aplicaciones desde la tienda oficial de Google Play. Puede consultar descripciones de aplicaciones, capturas de pantalla, actualizaciones, comentarios de otros usuarios y descargar el APK directamente desde Google Play a su dispositivo. Para utilizar Aurora Store, debe tener una cuenta de Google Play e iniciar sesión en su cuenta de Google Play cuando abra y configure Aurora Store por primera vez. +\n +\nA diferencia de una tienda de aplicaciones tradicional, Aurora Store no posee, licencia ni distribuye ninguna aplicación. Se accede, descarga y/o muestra directamente desde Google Play a todas las aplicaciones, descripciones de aplicaciones, capturas de pantalla y otro contenido de Aurora Store. Aurora Store funciona exactamente como una puerta o un navegador, permitiéndole iniciar sesión en su cuenta de Google Play y encontrar las aplicaciones de Google Play. +\n +\nTenga en cuenta que Aurora Store no cuenta con ninguna aprobación, patrocinio o autorización de Google, Google Play, ninguna aplicación descargada a través de Aurora Store ni ningún desarrollador de aplicaciones; Aurora Store tampoco tiene ninguna afiliación, cooperación o conexión con ellos. Por favor, inicia sesión con tu cuenta de Google Play Aplicación no disponible para tu dispositivo - ¡Error al exportar favoritos! - ¡Favoritos importados! - ¡Favoritos exportados! + ¡No se han podido exportar los favoritos! + ¡Favoritas importados! + ¡Favoritas exportadas! El paquete de aplicaciones se ha exportado correctamente Error al exportar el paquete de aplicaciones Favorita No se encontraron aplicaciones favoritas Aplicaciones favoritas - ¡Error al importar favoritos! + ¡Error al importar favoritas! Desinstalado correctamente - Introduce una URL de proxy válida para enrutar todos los datos a través del proxy. + Introduzca una URL de un proxy válida para pasar todos los datos a través del. ¿Cerrar sesión? - ¿Seguro que quieres cerrar la sesión? + ¿Estás seguro que deseas cerrar la sesión? Buscar actualizaciones Obligatorio Seguridad de los datos - Prácticas de privacidad y seguridad de datos declaradas por el desarrollador + Prácticas de seguridad y privacidad de datos declaradas por el desarrollador Permitir la instalación de aplicaciones desde fuentes desconocidas Primero debes otorgar permisos de instalación + Es posible que tengas que volver a otorgar el permiso debido a un error en el marco de acceso al almacenamiento Opcional Reiniciar Aurora Store Es necesario reiniciar Aurora Store para aplicar la configuración recién modificada @@ -384,12 +395,13 @@ En espera Descargando Autenticación obligatoria - ¡Por favor, inicia sesión en tu cuenta de Google Play para desarchivar la aplicación! + ¡Por favor, inicie sesión en su cuenta de Google Play para descomprimir la aplicación! Notificación relacionada con la cuenta Buscando actualizaciones - Hecho con %1$s en India + Fabricado con %1$s en la India Disponible Por defecto + Es posible que tengas que reiniciar la aplicación para que los permisos surtan efecto. Seleccionar todo ¡Error al exportar la lista negra! ¡Lista negra importada! @@ -399,77 +411,4 @@ ¡Error al importar la lista negra! Verificando Desarchivar - Comprobando compatibilidad… - Necesita los Servicios de Google Play - No compatible: No funcional - Desconocido: No comprobado aún - %1$d aplicaciones instaladas - No es posible abrir la aplicación - Compatibilidad - Puede que necesites instalar la librería propietaria de Google o una reimplementación FOSS como microG. - Esta aplicación funciona sin la biblioteca propietaria de Google. Sin embargo, aún puede requerir otras bibliotecas de terceros para funcionar correctamente. - Con el Proyecto microG - Sin los Servicios de Google Play - Compatible: Funciona sin ningún problema - Limitado: Funciona con funciones limitadas - Impulsado por Plexus - Funciona sin los Servicios de Google Play - No hay aplicaciones disponibles - Usar microG para acceder a las cuentas - Autenticación mediante microG al iniciar sesión en cuentas de Google para simplificar el flujo de inicio de sesión - Ver y gestionar la configuración del proxy - Proxy desactivado con éxito - Establecer - Desactivar - Restricciones de actualizaciones automáticas - Solo en redes sin restricciones de uso - Cuando el dispositivo está inactivo - Cuando la batería no está baja - Configurar restricciones del dispositivo para actualizaciones automáticas - Ha fallado al verificar archivos descargados - Versión mínima de Android - Última actualización - Avanzado - Fuente de la aplicación - Instalar Paquete microG - Descargas - Nivel de Objetivo de la API - Compatibilidad de la aplicación - Dependencias faltantes - He leído y estoy de acuerdo con los Términos de Servicio y la Política de Privacidad de microG - No pudimos encontrar los Servicios de Google Play en tu dispositivo, ¡varias aplicaciones lo requieren ahora para funcionar correctamente! - microG es una implementación gratis y de código abierto que proporciona funcionalidades similar para ejecutar aplicaciones dependientes de los Servicios de Google Play para dispositivos Android mediante la reimplantación.\n\nmicroG permite a las aplicaciones acceder a las APIs de Google, mejorando la compatibilidad para los usuarios mientras se ofrecen beneficios para la privacidad. ­ \n\nmicroG se ejecutará automáticamente en segundo plano cuando abras aplicaciones dependientes de los Servicios Móviles de Google. - Leer la Política de Privacidad de microG - Leer la Licencia y Acuerdos de microG - Visita la Página Web del Proyecto microG - Datos que esta aplicación podría recopilar - El desarrollador afirma que esta aplicación no recopila datos de los usuarios. - Datos que esta aplicación podría compartir - El desarrollador afirma que esta aplicación no comparte los datos de los usuarios con otras empresas u organizaciones. - Es posible que esta versión de la aplicación aún contenga más rastreadores que aún no figuran en la base de datos de Exodus Privacy. - No hay descripción disponible - Más información - Objetivos - Nombre del paquete - Clasificación de contenido - Selecciona una aplicación para más detalles - Sin anuncios - Sin play services - %1$d permisos - %1$d rastreador(es) conocidos encontrados en %2$s - El código de versión solo puede contener números - Preparando para instalar - MicroG no ha podido instalar la aplicación, seguramente debido a una configuración incorrecta. - Instalador de microG - Requiere que la aplicación microG companion esté instalada - Te ayuda a ignorar la comprobación de integridad de las aplicaciones (solo instalador) - - Permiso requerido - Permisos requeridos - Permisos requeridos - - Se está cargando - Página %1$d - Omitir - ¿Reiniciar para aplicar los cambios? diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml deleted file mode 100644 index 0f5290478..000000000 --- a/app/src/main/res/values-et/strings.xml +++ /dev/null @@ -1,474 +0,0 @@ - - - Tagasi - Allalaadimised - E-post - Tühista - Otsi - Arendaja profiil - Tasuline - Lisa musta nimekirja - Eira - Paigalda - Rakenda - Eemalda kõik - Lisa avakuvale - Wiki - Leia vastuseid korduma kippuvatele küsimustele (KKK), tõrkeotsingu samme ja palju muud - BHIM - UPI - Anneta UPI kaudu - Bitcoin Cash - Anneta Bitcoin Cashi (BCH) kaudu - Bitcoin - Anneta Bitcoini (BTC) kaudu - Ethereum - F-Droid - Hangi Aurora pood F-Droidist. - GitLab - Hangi Aurora poe lähtekood GitLabis asuvast Aurora OSS-ist. - Liberapay - PayPal - Anneta PayPali kaudu - Telegram - Vestlusi ja soovitusi leiab Aurora poe XDA lõimest. - Anonüümne - Google - Logi Aurorast välja - Must nimekiri - Tühjenda - Sule - Kopeeri link - Lülita välja - Impordi - Lemmik - Filtrid - Reklaamidega rakendused - GSF sõltuvus - Salvesta rakenduse kogum - Luba - Lubatud - Paigaldused - Paigaldan - Logi välja - Edasi - Taotle uut analüüsi - Jätka - Eemalda - Edukalt eemaldatud - Uuenda - Uuenda kõik - Valge nimekiri - Beetaprogramm - Oled beetatestija - Näed uusi funktsioone ja vigu enne, kui avalikkus seda teeb. Anna arendajatele tagasisidet, et aidata neil täiustada. - Muudatuste logi pole esitatud - Sõltuvused - Kirjeldus - Arendaja kontakt - Veebileht - Rakenduse otsing ei leidnud vastet - Sõltuvusi pole - Lubasid pole - Andmete ohutus - Arendaja deklareeritud andmete privaatsus- ja turvatavad - Privaatsus - Hinnang ja arvustused - Hinda rakendust - Mida arvad sellest rakendusest? - Eemalda lõpetatud - Allalaadimine lõpetatud - Arvutamine - %1$dh %2$dm %3$ds jäänud - Kõik - Hakka Liberapay patrooniks - Ekspordi - Ava - Anneta Ethereumi (ETH) kaudu - Uuendusi pole - Logi sisse kasutades - Liitu Aurora tugirühmaga vestluste või ettepanekute jaoks. - XDA foorumid - Lõpeta - Kopeeri - Muud - Hinnangud - Tasuline - Olgu - Lahku - Muudatuste logi - Tasuta - Liitu - Ootel - Rakenduse teave - Kas liitud beetaprogrammiga? - Hiljem - Taaskäivita - Avalda - Registreerimine võib veidi aega võtta, võid olekut hiljem kontrollida. - Jaga - Vali kõik - Sisaldab reklaame - Aadress - Nõuab GSF-i - Reklaame pole - Lisateave rakenduse kohta - Lemmikrakendusi ei leitud - Luba - Tühista kõik - Tühistatud - %1$dm %2$ds jäänud - Positiivne - Vastutusest loobumine - Rakenduse ekspordi märguanded - Paigalda Aurora teenused 1.0.9 või uuem või muuda paigaldusrakendust. - Vaata aruannet - Metaandmete hankimine - Tühjenda kõik jõuga - Allalaadimisi pole - Peatatud • %1$d / %2$d - Ei sisalda teadaolevaid jälgijaid - Analüüsitud Exodus Privacy poolt - Jälgijate otsimine… - teadaolevat jälgijat leiti rakendusest - Neli - Kolm - Kaks - Paigalda rakenduste haldur või muuda paigaldusrakendust. - Root-juurdepääsu pole. Luba see või muuda paigaldusrakendust. - Shizuku pole paigaldatud või korralikult seadistatud. - Paigaldamine nurjus - Paigaldamine blokeeriti - Seansi loomine nurjus - Leiti vastuolus paketid - Ühildumatu rakendus - Vigane või rikutud APK - Ebapiisav mäluruum - Edukalt paigaldatud - Litsents - Kasutustingimused - Tuvastati MIUI! - Seansipaigaldaja ei saa MIUI optimeerimiste tõttu rakendusi paigaldada. - Saadaval on uuendus - Allalaadimiste märguanded - Paigalduse märguanded - Kontoga seotud märguanded - Aurora pood nõuab järgmisi lubasid - Paigaldaja - Load - Välise salvestusruumi haldur - Paigaldusrakenduse load - Luba paigaldada rakendusi Aurora poest - Luba tundmatutest allikatest pärit rakenduste paigaldamine - Märguanded - Saada märguandeid paigaldamise olekust - Allalaadimine taustal - Luba Aurora poel rakendusi taustal allalaadida ja uuendada - Ära kontrolli F-Droidist paigaldatud rakenduste uuendusi - Filtreeri F-Droidi rakendused - Järjekorras - Allalaadimine nurjus - %1$ds jäänud - Peata kõik - Allalaadimisel • %1$d / %2$d%3$s - Jätka kõiki - Kõik - Üks - Paigaldamise lubamiseks keela MIUI optimeerimised või vali root- või teenustepaigaldaja. - Kuidas läheb? - Viis - Aurora teenused on saadaval ja paigaldamiseks valmis. - Seadista esmalt Aurora teenused ja anna kõik load. - Kasutaja kinnituse ootel - Tere tulemast - Juurdepääs välisele salvestusruumile - APK laiendusfailide (OBB) salvestamiseks suurte rakenduste ja mängude jaoks. - Allalaaditud APK-d kustutatakse kohe pärast paigaldamist - Paigaldusmeetod - Aurora teenused (aegunud) - Vali APK paigaldamise moodus - Kustuta APK pärast paigaldamist - AM paigaldusrakendus - Google Play versioon - Vaikimisi (seadme seadetest) - Võrguühendus - Puhverserveri URL - Taotletav versioonikood pole saadaval. - Hinnatud, kuvamine võib veidi aega võtta - uuendus saadaval - uuendust saadaval - Ilmnes viga! - Menüü - Uuenduste märguanded - Vajalikud load on keelatud. Toimingu jätkamiseks luba need - Automaatsed uuendused - Käsitsi allalaadimine - Kopeeriti lõikelauale - Õnnitlused, taotletud versioonikood on saadaval, laadime alla. - Populaarsed tasulised - Filtreeri rakendusi muudest allikatest - Allalaadimine nurjus - Faile ei saanud hankida - Ära otsi uuendusi rakendustele, mis on paigaldatud Aurora poe välistest allikatest - Seansi kinnitamine - Seade - Otsingusoovitus - Lisatud valgesse nimekirja - Näita ühildumatute või keelatud rakenduste uuendusi, mille paigaldamine võib ebaõnnestuda - Trendid - Võrk puudub - Uuendused - Täiendavate failide allalaadimine rakendusele %1$s - Seadme konfiguratsioon imporditud - Seadme konfiguratsiooni ei saanud importida - Puhverserveri seadistamine õnnestus - Seadme konfiguratsioon eksporditud - Seadme konfiguratsiooni ei saanud eksportida - Lisatud musta nimekirja - Rakenduste ostmine pole anonüümse kontoga võimalik. - Google kaudu ei saanud sisse logida - Toimetaja valik - Kõige tulusamad - %1$d uuendust saadaval - Keel - %1$s, %2$s, %3$s ja %4$d veel - Kontod - Rakendused - Anonüümsetel kontodel saadaval pole saadaval - Sisesta kehtiv puhverserveri URL, et edastada kõik andmed puhverserveri kaudu. - Kõik on hästi. - AAS-i tunnust ei saanud luua - Rakendust ei toetata - Kategooriad - Rakendust ei ostetud - Rakendust ei leitud - Play pood - Populaarsed tasuta - Paigaldatud - Paigaldusrakendus - Rakendus pole sinu seadme jaoks saadaval - Nende avamiseks lülita seadme seadetes sisse arendaja valikud. - Populaarsed - Musta nimekirja haldur - Mängud - Seaded - Vale puhverserveri võrguaadress, kontrolli vormingut! - Rakenduse allalaadimine taustal - Laienda - Otsingutulemused - Otsi rakendusi ja mänge - Allalaadimised - Ostude ajalugu - Luba antud - %1$d uuendus saadaval - Kohandamine - Näita uuendusi, mille paigaldamine ei pruugi õnnestuda - Muudatuste rakendamiseks logi kindlasti uuesti sisse ja taaskäivita rakendus. - Minu rakendused ja mängud - Logi oma Google Play kontole sisse - Lemmikrakendused - Nõutav - Uue seansi taotlemine - Sarnased ja seotud rakendused - Logi sisse ja naudi. - Seanss aegus, uue seansi saamiseks logi uuesti sisse. - Google seansi kinnitamine - Valikuline - Asjade ettevalmistamine… - Viimane seanss tühistati - Sulle - Esmalt pead andma loa paigaldusrakendusele - Paigaldamine - Saadaval on %1$s uus versioon - %1$s, %2$s ja %3$s - Teave - Hinnet ei saanud esitada - Server on hoolduseks maas - %1$s ja %2$s - Puhverserveri seadistamine nurjus - Lubab taustal rakenduste allalaadimise - Uusimad - Kriitilised - Rakenduse seaded - Rakendused teegis - Teek - %1$s • API %2$s - Seadista automaatsete uuenduste käitumine - Ära uuenda rakendusi automaatselt - Automaatsete uuenduste sagedus - Seadista automaatsete uunduste ajavahemik tundides. - Vali vaikekaart - Luba Aurora poel toetatud linke avada - Asetus - APK-de eksport nurjus - Rakendusi pole saadaval - Täisfunktsionaalne avatud lähtekoodiga paketihaldur - Kas on küsimusi? Otsi vastuseid - Andmekaitsepõhimõtted - Vaata, kuidas Aurora pood sinu andmeid kasutab - Aurora poest - Halda oma kontot - Veel - Vigane võrguaadress - Lisa - Lemmikute import nurjus! - Lemmikud imporditud! - Musta nimekirja import nurjus! - Musta nimekirja eksport nurjus! - Must nimekiri imporditud! - Must nimekiri eksporditud! - Oota, faili eksporditakse - Kas logida välja? - Kas soovid kindlasti välja logida? - Otsi uuendusi - Uuenduste otsing - Taaskäivita Aurora pood - Äsja muudetud sätete rakendamiseks tuleb Aurora pood taaskäivitada - Nurjunud - Tühistatud - Vaikeväärtus - Saadaval - Ühilduvuse kontrollimine… - Töötab ilma Google Play teenusteta - Ilma Google Play teenusteta - Toetuseta: ei tööta - Teadmata: pole veel kontrollitud - %1$d rakendust paigaldatud - Kasuta kontodele sisselogimiseks microG-d - Määra - Puhverserveri keelamine õnnestus - Keela - Vaata ja halda puhverserveri seadistust - Automaatsete uuenduste piirangud - Seadista automaatsete uuenduste jaoks seadme piirangud - Kui seade on jõudeolekus - Allalaaditud failide kinnitamine nurjus - MicroG projektiga - Serveriga ei saa ühendust - Kontrolli internetiühendust - Google Play, tuntud ka kui Google Play pood ja varem Android Market. - Rakenduse keel - Kui aku tase ei ole madal - Otsi ja paigalda saadaolevaid uuendusi automaatselt - Sisesta versioonikood, mille soovid alla laadida - Seansi loomine nurjus, veakood: %1$d - Rakenduse lingid - Vastutus ja kohustus - Otsi saadaolevaid uuendusi ja teavita neist - Privaatsusaruande toomine nurjus - Uue seansi kinnitamine - Lähtekood - Uuri, mis on sees - Rakendust ei saa avada - Lemmikute eksport nurjus! - Lemmikud eksporditud! - Järjekorras - Pole saadaval - Lisateave Aurora poe kohta - Juurdepääs keelatud! Kas kasutuses on VPN või Tor? - Lõpetatud - Eemalda - Nõuab Google Play teenuseid - See rakendus töötab ilma Google teegita. Siiski võib see nõuda korralikuks töötamiseks muid kolmandate osapoolte teeke. - Kustuta seadme omanik - Failide eksportija - Ühilduvus - Allalaadimine - Vajalik autentimine - Ühilduv: töötab ilma probleemideta - Piiratud: töötab piiratud funktsioonidega - Sisemine viga! Proovi mõne aja pärast uuesti - Seanssi ei saanud luua - Kontrollimine - Hindamine - Võid valida ka süsteemse paigaldaja, kuid siis ei saa installida komplekteeritud (split) APK-sid, nii et valik on sinu. - Süsteemse paigaldaja abil ei saa paigaldada komplekteeritud (split) rakendusi. Vali paigaldajaks Seanss, Aurora teenused või Root. - Lisaks - Shizuku paigaldaja - Süsteemne paigaldaja (vananenud) - Root-paigalgaja - Seansi paigaldaja - Pettuse rakendamiseks logi kindlasti uuesti sisse - Pettuse haldur - Seadmepettus on rakendatud. - Leht pole saadaval - Liiga palju sisselogimiskatseid - Android Market oli Android-seadmetele mõeldud veebipood, mis lõpetas 2017. aastal. - Seansipõhine paigaldaja komplekteeritud/split APK-de jaoks - Soovitatav, sisseehitatud ja toetab kõiki Androidi versioone - Kestapõhine paigaldaja, mis kasutab eeldab juurkasutaja õigusi - Nõuab root/superkasutaja õigusi, toetab kõiki Androidi versioone. - Sobib kõige paremini alla Android 4.4 seadmetele - Paigaldaja,et paigaldada taustal - Nõuab, et Aurora teenused oleks paigaldatud privilegeeritud süsteemirakendusena - Süsteemi API-de kasutamine otse adb/root õigustega - Vajalik on Shizuku või Sui, tuleb seadistada ja anda luba - Protsessi lihtsustamiseks kasuta Google\'i kontodele sisselogimise autentimiseks microG-d - Ainult mahupiiranguteta võrkudes - Loodud %1$s kasutades Indias - See tühistab seansi paigaldaja loa rakendust vaikselt paigaldada. Kas jätkata? - Aurora Store võimaldab otsida ja alla laadida rakendusi ametlikust Google Play poest. Saad otsida rakenduste kirjeldusi, ekraanipilte, uuendusi, teiste kasutajate kommentaare ja laadida APK otse teenusest Google Play oma seadmesse. Aurora poe kasutamiseks peab olema Google Play konto ja Aurora poe esmakordsel avamisel ja seadistamisel tuleb Google Play kontole sisse logida.\n\nErinevalt traditsioonilisest rakendustepoest ei oma, litsentsi ega levita Aurora Store ühtegi rakendust. Kõikidele rakendustele, rakenduste kirjeldustele, ekraanipiltidele ja muule Aurora poe sisule pääseb otse juurde, laaditakse alla ja/või kuvatakse Google Playst. Aurora pood töötab täpselt nagu uks või brauser, võimaldades oma Google Play kontole sisse logida ja Google Playst rakendusi leida.\n\nPane tähele, et Aurora poel pole Google, Google Play, Aurora poe kaudu allalaaditud rakenduste ega rakenduste arendajate heakskiitu, sponsorlust ega volitusi; samuti ei ole Aurora poel nendega mingit seost, koostööd ega ühendust. - Täpsemalt - Võimalik, paigaldada tuleb Google teek või selle FOSS alternatiiv, näiteks microG. - Vahekaart \"Sinule\" - Kuva avalehel vahekaart „Sinule” - Klassikaline paigaldaja, saadaval kõikides seadmetes - Nõuab rakendust App Manager, paigaldamiseks on vaja adb/root-režiimi, kui miui optimeerimine on sisse lülitatud - Lõpetab Aurora Poe tegevuse rakenduse omanikuna - Halda sisselogimistunnuseid - Vaata ja halda tunnuslubade plokke, mida kasutatakse anonüümseks sisselogimiseks - Sisselogimistunnuseid pole saadaval - Lisa sisselogimistunnus - Lisa sisselogimistunnus Aurora Poodi. Neid kasutatakse anonüümsel sisselogimisel. - Sisselogimistunnuse võrguaadress - Kas eemaldad sisselogimistunnuse? - Kas sa soovid eemaldada sisselogimistunnuse \"%1$s\"? - Rakenduse kogumi eksportimine õnnestus - Rakenduse kogumi eksportimine ei õnnestunud - Selle rakenduse arhiivist eemaldamiseks logi sisse oma Google Play kasutajakontoga! - Eemalda arhiivist - Teenust toetab Plexus - Täiendavad seadistused - Rakenduse allikas - API versioon kompileerimisel - Allalaadimised - Viimati uuendatud - Androidi miinimumversioon - %1$d luba - Paigalda microG teekide kogumik - Rakenduse ühilduvus - Puuduvad sõltuvused - Ma olen lugenud microG kasutustingimusi ja privaatsusreegleid ning nõustun nendega - Sinu nutiseadmes ei leidu Google Play Services\'i teeke, aga mitmed populaarsed vajavad neid korralikuks toimimiseks! - Loe microG privaatsusreegleid - Loe microG litsentsitingimusi ja kasutuslepingut - Vaata microG projekti veebisaiti - microG on vaba ja avatud lähtekoodiga teekide komplekt, mis tagab Google Play teenuste olemasolust sõltuvatele rakendustele sarnase funktsionaalsuses.\n\nmicroG võimaldab kasutada vajalikke Google\'i API-sid ning tagab sellega korraga nii ühilduvuse kui vallasrežiimikohase ühilduvuse \n\nKui avad rakenduse, mis sõltub Google Mobile Services\'i olemasolust, siis microG käivitub taustal automaatselt. - Andmed, mida see rakendus võib koguda - Arendaja kinnitab, et see rakendus ei kogu kasutajate kohta andmeid. - Arendaja kinnitab, et see rakendus ei jaga kasutajate andmeid muude äriühingute või organisatsioonidega. - Andmed, mida see rakendus võib jagada - Siiski võib selles rakenduses leiduda jälitajaid, mida pole veel Exodus Privacy andmebaasis kirjeldatud. - %1$d teadaolev(at) jälitaja(t) leidub rakenduses %2$s - Kirjeldus pole saadaval - Lisateave - Sihtplatvorm - Paketi nimi - Hinnang sisule - Üksikasjade nägemiseks vali rakendus - Pole reklaame - Ei vaja Google Play teenuseid - Versiooni koodis võib olla vaid numbreid - Paigaldamine on ettevalmistamisel - - Õigus on vajalik - Õigused on vajalikud - - MicroG paigaldaja ei suutnud rakendust paigaldada. Ilmselt juhtus see vale seadistuse tõttu. - MicroG paigaldaja - Eeldab, et kaasnev MicroG rakendus on paigaldatud - Lubab sul jätta vahele rakenduse tervikluse kontrolli (vaid paigaldaja puhul) - Laadimine on töös - Leht %1$d - Jäta vahele - Kas käivitad muudatuste jõustamiseks uuesti? - diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index 39f5de8c6..5556370de 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -26,6 +26,7 @@ Deskargak Gailua Zerrenda beltzaren gestorea + Aplikazioen eskaintzak Aplikazioak bibliotekan Nire aplikazioak eta jokoak Aplikazioak @@ -56,7 +57,7 @@ APK ezabatu deskargatu ondoren Besterik adierazi ezean, deskargatutako APK-ak ezabatuko dira instalazioa bukatutakoan F-Droid aplikazioak kanpoan utzi - Ez egiaztatu F-Droid-etik instalatutako aplikazioen eguneraketak + Ez egiaztatu F-Droid-etik deskargatutako edo instalatutako aplikazioen eguneraketak Aurora Store-ri aplikazioak instalatzeko baimena eman Instalatzailearen baimena Kanpoko memoriaren gestorea @@ -84,7 +85,7 @@ Instalazioa blokeatu da Instalatzea huts egin du Konfiguratu Aurora zerbitzuak eta baimen guztiak onartu lehenik. - Instalatu Aurora zerbitzuak 1.0.9 edo berriago, edo aldatu instalatzailea. + Instalatu Aurora zerbitzuak 1.0.9 edo altuago, edo aldatu instalatzailea. Bi Hiru Positiboak @@ -216,6 +217,7 @@ Eskatzen ari zaren bertsio kodea ez dago erabilgarri. Eskuzko deskargatzea Ziurtatu berriro hasten duzula saioa eta berrabiarazi aplikazioa aldaketak aplikatzeko. + Erakutsi antzeko taldeak eta erlazionatuak aplikazioaren xehetasunen orrian Antzeko aplikazioak eta erlazionatuak Erakutsi zuretzako orriak hasierako pantailan Zuretzako orrialdeak @@ -261,29 +263,33 @@ Shizuku ez dago instalatuta edo egoki konfiguratuta. Lehenetsia (gailuko konfiguraziotik) %1$s, %2$s, %3$s eta %4$d gehiago + Gaitu proxy-a Google Play-eko bertsioa Proxy-aren URLa - Iragazi aplikazioak beste iturri batzuetatik + Aurora Store-ko aplikazioak soilik + Proxy Shizuku instalatzailea %1$s aplikazioaren bertsio berri bat eskuragarri dago Atzeko planoko deskargak Proxy-aren URL baliogabea, egiaztatu formatua! Bilaketarako iradokizuna - Ez bilatu Aurora Store-tik kanpoko iturrietatik instalatutako aplikazioen eguneratzerik dagoen + Egiaztatu Aurora dendak instalatutako aplikazioen eguneraketak soilik Proxy-a ezarri da Onartu Aurora Store-ri aplikazioak atzeko planoan deskargatzea eta eguneratzea Aplikazioaren ezarpenak + Hornitzailea: bestappsales.com %1$s, %2$s eta %3$s %1$d eguneratze eskuragarri Ezin izan da ezarri proxy-a Bilaketa-emaitzak Eguneratzeen jakinarazpenak + Onartu aplikazioko trafiko guztia proxy-tik joan dadin %1$s eta %2$s %1$d eguneratze eskuragarri Wiki Berrikusi izenburua Bilatu maiz egiten diren galderen erantzunak (F.A.Q.), arazoak konpontzeko urratsak eta beste batzuk - Tasa mugatua duzu + Ai, tasa mugatua duzu Barne akatsa! Mesedez, saiatu berriro zertxobait beranduago Google Play,gaur egun Google Play Store eta aurretik Android Market bezala ere ezaguna. Iturburu irekiko paketeen kudeatzaile osatua @@ -301,6 +307,7 @@ Indian egina honekin: %1$s Aurora Store berrabiarazi behar da aldatu berri diren ezarpenak aplikatzeko Kontuarekin lotutako jakinarazpena + Baliteke baimena berriro eman behar izatea Storage Access Framework-eko akats bat dela eta Hautazkoa Aplikazioaren hizkuntza Gomendatua, eraikia eta Android bertsio guztiak onartzen dituena @@ -312,15 +319,16 @@ Zerbitzaria eskuraezina Eguneratze automatikoen maiztasuna Ezin izan da eskuratu pribatutasun-txostena + Baliteke aplikazioa berrabiarazi behar izatea baimenaren esleipena islatzeko. Beharrezkoa - Konfiguratu eguneraketa automatikoentzako denbora-tarteak, ordutan. + Konfiguratu auto-eguneratzeetarako eta auto-eguneratzeetarako tarteak, ordutan. APK bildu/zatituetarako saioan oinarritutako instalatzailea Shell oinarritutako instalatzailea zeinak root baimenak darabiltzan Sistemaren APIak zuzenean erabiltzea adb/root pribilegioekin Pribatutasun-politika Aurora Store-i buruz gehiago jakin URL helbide banagailua - Banagailua ezabatu? + Banagailua ezabatu Ezin izan da esportatu aplikazio-sorta Deskargatzen Huts egin du @@ -331,8 +339,8 @@ Galderarik? Aurkitu erantzunak Horrek aplikazioa isilean instalatzeko saioaren instalatzailearen baimena kenduko du. Gailuaren jabetza garbitzen jarraitu nahi duzu? Baimendu iturri ezezagunetako aplikazioak instalatzea - Bistaratu instalatzen huts egin dezaketen aplikazio bateraezinen edo desgaituen eguneraketak - Eguneraketa automatikoak + Erakutsi instalatzen huts egin dezaketen aplikazio bateraezinen edo desgaituen eguneraketak + Aplikazioen eguneraketak automatizatu Sarbidea ukatu da! VPN edo Tor erabiltzen ari al zara? Aurora Store kentzen du, gailuaren jabearen aplikazio gisa Ezeztatu egin da @@ -350,7 +358,7 @@ Ezin izan dira inportatu zure gogokoenak! Ezin izan dira zure gogokoenak esportatu! Gogokoenak esportatu dira! - Erakutsi huts egin dezaketen eguneraketak + Eguneraketa bateraezinak Konfiguratu eguneratze automatikoen portaera Aplikazioaren estekak Eskatu azterketa berria @@ -415,60 +423,4 @@ Bateragarritasuna aztertzen… Bateragarritasuna Aplikazio eskuragarririk ez - Erabili microG kontuetara sartzeko - Autentifikatu microG erabiliz Google-ko kontuetan saioa hasteko, saioa hasteko fluxu errazagoa izateko - Ezarri - Desgaitu - Proxya desgaitu da - Ikusi eta kudeatu proxy konfigurazioa - Eguneratze automatikoen murrizketak - Konfiguratu gailuaren murrizketak eguneratze automatizatuetarako - Bateria gutxi dagoenean - Gailua inaktibo dagoenean - Neurririk gabeko sareetan bakarrik - Deskargatutako fitxategiak ezin izan dira egiaztatu - Aurreratua - Aplikazioaren iturria - Deskargak - Azken eguneraketa - Gutxieneko Android bertsioa - Helburuko API maila - %1$d baimenak - Instalatu microG paketea - Aplikazioen bateragarritasuna - Falta diren mendekotasunak - microG Zerbitzu Baldintzak eta Pribatutasun Politika irakurri eta onartzen ditut - Ezin izan ditugu Google Play zerbitzuak aurkitu zure gailuan, hainbat aplikazio ezagunek behar bezala funtzionatzeko behar dute orain! - microG doako eta kode irekiko inplementazio bat da, Google Play Zerbitzuen menpeko aplikazioak Android gailuetarako berriro inplementatuz exekutatzeko antzeko funtzionalitatea eskaintzen duena.\n\nmicroG-k aplikazioei Google API horietara sartzeko aukera ematen die, erabiltzaileen bateragarritasuna hobetuz eta pribatutasun onurak eskainiz.\n\nmicroG automatikoki exekutatuko da atzeko planoan Google Mobile Zerbitzuen menpeko aplikazioak irekitzen dituzunean. - Irakurri microG-ren pribatutasun politika - Irakurri microG Lizentzia eta Hitzarmena - Bisitatu microG Proiektuaren webgunea - Aplikazio honek hurrengo datuak bil ditzake - Garatzaileak dio aplikazio honek ez duela erabiltzaileen daturik biltzen. - Aplikazio honek hurrengo datuak parteka ditzake - Garatzaileak dio aplikazio honek ez dituela erabiltzaileen datuak beste enpresa edo erakundeekin partekatzen. - Aplikazioaren bertsio honek Exodus Privacy-ren datu-basean oraindik ez dauden jarraitzaile gehiago izan ditzake oraindik. - %1$d aztarnari ezagunak hemen aurkituta %2$s - Aplikazioaren xehetasunen zatia - Informazio gehiago - Helburuak - Paketearen izena - Edukiaren balorazioa - PantailaBilatu - Iragarkirik ez - Play zerbitzurik ez - Bertsio-kodeak digituak bakarrik izan ditzake - Instalatzeko prestatzen - - Baimena beharrezkoa da - Baimenak beharrezkoak dira - - MicroG instalatzaileak huts egin du aplikazioa instalatzeko, ziurrenik konfigurazio oker baten ondorioz. - MicroG instalatzailea - microG aplikazio osagarria instalatuta edukitzea eskatzen du - Aplikazioaren Osotasun egiaztapena (instalatzailearentzat bakarrik) saihesten laguntzen dizu - Kargatzen ari da - %1$d orrialdea - Saltatu - Aldaketak aplikatzeko berrabiarazi? diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 4c622f07c..dcf2ecaf8 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -29,6 +29,7 @@ اِف‌دروید بیت کوین مدیر لیست سیاه + برنامه های در حال فروش برنامه های موجود در کتابخانه بارگیری دستی بروزرسانی‌ها @@ -223,6 +224,7 @@ اجازه نصب برنامه‌ها از فروشگاه آرورا حذف APK پس از نصب نصب کننده AM. + نمایش خوشه های مشابه و مرتبط در صفحه جزئیات برنامه اطمینان حاصل کنید که برای اعمال پارامتر جعلی دوباره وارد سیستم شوید انتخاب سردبیران بدون شبکه diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 00434535c..4076877cc 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -59,8 +59,8 @@ Lisenssi Uusi päivitys saatavilla Tervetuloa - Älä tarkista päivityksiä F-Droid:sta asennetuille sovelluksille - Suodata F-Droid-sovellukset + Älä tarkista päivityksiä F-droidista ladatuille tai asennetuille sovelluksille + Suodata F-Droidi-sovellukset Sinulle-sivut Samankaltaiset ja vastaavat sovellukset Lataaminen epäonnistui @@ -122,7 +122,7 @@ Muutosloki Ilmoittautuminen voi viedä jonkin aikaa, voit tarkistaa tilan myöhemmin. Näet uusia ominaisuuksia ja virheitä ennen muuta yleisöä. Anna palautetta kehittäjille, jotta he voivat kehittyä. - Liity beetaohjelmaan? + Liity beetaohjelmaan ? Olet beetatestaaja Beetaohjelmisto Valkoinen lista @@ -179,6 +179,7 @@ Päivitykset Huijausten hallinta Mustan listan hallinta + Tarjouksessa Suosituimmat maksulliset Tuottavimmat Suosituimmat ilmaiset @@ -187,6 +188,7 @@ Varmista, että kirjaudut uudelleen ja käynnistät sovelluksen uudelleen ottaaksesi muutokset käyttöön. Varmista, että kirjaudut uudelleen ottaaksesi huijauksen käyttöösi Sessio päättyi, kirjaudu uudelleen uuden session aloittamiseksi. + Näytä sovelluksen lisätietosivulla sen kanssa samankaltaisia ja siihen liittyviä sovelluksia Näytä Sinulle räätälöity-sivut kotinäytöllä Valitse oletusvälilehti Ulkoasu @@ -222,18 +224,18 @@ Aurora Services on käytettävissä ja valmis asentamaan. Ei root-käyttöoikeutta. Anna käyttöoikeus tai muuta asennustapaa. GSF-riippuvuus - Keskusteluja ja ehdotuksia löytyy Aurora Storen XDA-ketjusta. - XDA-foorumit + Avaa Aurora Storen XDA-ketju keskusteluille ja ehdotuksille. + XDA -foorumi Liity tukijaksi Liberapayssa Mahdollistaa sovellusten lataamisen taustalla - Sovelluksen lataaminen taustalla + Taustalla sovelluksen lataaminen Asenna App Manager tai vaihda asennusohjelmaa. AM-asennusohjelma Lataus • %1$d / %2$d%3$s Ilmoitukset Kirjaudu sisään ja nauti. %1$s • API %2$s - Huh! Kaikki hyvin. + Vau! Kaikki hyvin. Uutta istuntoa pyydetään Valmistellaan asioita… Laitteen konfiguraatiota ei voitu tuoda @@ -273,7 +275,7 @@ Käyttö estetty! Onko käytössäsi VPN tai Tor\? Sisäinen virhe! Yritä uudelleen myöhemmin Istunnon luominen epäonnistui, virhekoodi: %1$d - Käyttöäsi on rajoitettu + Ups, käyttösi on rajoitettu Palvelimeen ei saada yhteyttä Tarkista verkkoyhteys Sovelluksen kieli @@ -284,16 +286,19 @@ Google Play, joka tunnetaan myös nimellä Google Play Store ja entinen Android Market. Android Market oli vuonna 2017 toimintansa päättänyt verkkokauppa, joka tarjosi sovelluksia Android-laitteille. Arvostele sovellus - Suodata sovellukset muista lähteistä + Vain Aurora Storen sovellukset + Välityspalvelin Salli Aurora Storen ladata ja päivittää sovelluksia taustalla + Ota välityspalvelin käyttöön Välityspalvelimen URL-osoite + Tarjoaja - bestappsales.com Google Play -versio Taustalla olevat lataukset - Automaattiset päivitykset + Päivitä sovellukset automaattisesti Tarkista ja ilmoita saatavilla olevista päivityksistä Älä päivitä sovelluksia automaattisesti Sovellusasetukset - Määritä automaattisten päivitysten toiminta + Automaattisten päivitysten määrittäminen Tarkista ja asenna saatavilla olevat päivitykset automaattisesti Poista valmiit Lisää kotinäytölle @@ -313,8 +318,8 @@ Sovellus poistettu onnistuneesti Sovelluksen vienti-ilmoitus Oletko varma, että haluat kirjautua ulos? - Aurora Store on käynnistettävä uudelleen juuri muutettujen asetusten käytöön ottamiseksi - Kirjaudu Google Play -tilillesi + Aurora Store on aloitettava uudelleen äskettäin muutettujen asetusten soveltamiseksi + Ole hyvä ja kirjaudu Google Play -tilillesi Salli sovellusten lataus tuntemattomista lähteistä Löydä vastauksia usein kysyttyihin kysymyksiin (U.K.K.), vianetsinnän vaiheisiin ja muihin asioihin Lähdekoodi @@ -333,7 +338,7 @@ Sinun täytyy myöntää Asennuslupa ensin Automaattipäivitysten tiheys Täysiominaisuuksinen avoimen lähdekoodin pakettimanageri - Määritä aikaväli automaattisille päivityksille, tunteina. + Aseta taajuus automaatti- ja itsepäivityksille, tunneissa. Powered by Plexus Vaatii Google Play Palvelut Saatat joutua asentamaan Googlen oman kirjaston tai vastaavan FOSS-toteutuksen kuten esim. microG. @@ -341,13 +346,13 @@ Tämä sovellus toimii ilman Google omaa kirjastoa. Tästä huolimatta se saattaa tarvita muita kolmannen osapuolen kirjastoja toimiakseen kunnolla. microG -projektin kanssa Ilman Google Play Palveluita - Ei tuettu: Ei toimi + Tukematon: Ei toimi Tuntematon: Ei varmistettu vielä Asennusilmoitukset Latausilmoitukset Oletus (laitteen asetuksista) Suositeltu, sisäänrakennettu ja tukee kaikki Android-versioita - Vaatii App Manager -sovelluksen, tarvitsee adb/root -tilan asennukseen, kun MIUI optimisaatio on päällä + Vaatii App Manager -sovelluksen, tarvitsee adb/root -tilan asennukseen kun MIUI optimisaatio on päällä Järjestelmän API:a suoraan adb/root -oikeuksilla käyttäen Syötä versiokoodi jonka haluat ladata Poistaa Aurora Storen laitteen omistajasovelluksena @@ -360,7 +365,7 @@ Hetki pieni, tiedostoasi viedään Sovellusnippu viety onnistuneesti Kirjaudutaanko ulos? - Käynnistä Aurora Store uudelleen + Uudelleenkäynnistä Aurora Store Luotu %1$s käyttäen Intiassa Varmistetaan Epäkelpo välityspalvelimen URL-osoite, tarkista muotoilu! @@ -377,10 +382,10 @@ Poista Sovellusta ei voitu avata Tarkistetaan päivityksiä - Kirjaudu sisään Google Play -tiliisi sovelluksen arkistoinnin poistamiseksi! + Kirjaudu sisään Google Play tililläsi sovelluksen arkistoinnin poistamiseksi! %1$d sovellusta asennettu - Näytä päivitykset jotka saattavat epäonnistua - Älä tarkista päivityksiä Aurora Store:n ulkopuolelta asennetuille sovelluksille + Yhteensopimattomat päivitykset + Tarkista päivitykset pelkästään Aurora Storen kautta asennetuille sovelluksille Tyhjennä laitteen omistaja Istuntopohjainen asentaja niputetuille/jaetuille APK-paketeille Vastuu ja velvollisuus @@ -393,7 +398,9 @@ Suosikit tuotu! Suosikkisovellukset Välityspalvelin asetettu onnistuneesti + Saatat joutua myöntämään luvan uudestaan Storage Access Frameworkin bugista johtuen Komentotulkkipohjainen asentaja root-oikeuksia käyttäen + Saatat joutua uudelleenkäynnistämään sovelluksen lupien muutosten käyttöönottamiseksi. Aikomuspohjainen asentaja, saatavilla kaikilla laitteilla Yhteensopivuus Rajoitettu: Toimii rajoitetuilla ominaisuuksilla @@ -411,64 +418,9 @@ Parhaiten soveltuva alle Android 4.4:ää käyttäville laitteille Näytä yhteensopimattomien tai käytöstä poistettujen sovellusten päivitykset, joiden asennus saattaa epäonnistua Syötä välityspalvelimen URL-osoite välittääksesi kaiken datan sen kautta. + Salli sovelluksen kaiken tiedonsiirron menevän välityspalvelimen kautta Lisää - Poistetaanko jakelija? + Poista jakelija Aurora Store mahdollistaa sovellusten etsimisen ja lataamisen virallisesta Google Play -kaupasta. Voit tutkia sovellusten kuvaksia, kuvankaappauksia, päivityksiä, muiden käyttäjien kommentteja ja ladata sovelluksia suoraan Google Play:stä laitteellesi. Käyttääksesi Aurora Store:a sinulla on oltava Google Play -tili sekä kirjauduttava sisään Google Play -tilillesi kun avaat ja asetat Aurora Store:n.\n\nToisin kuin perinteiset sovelluskaupat, Aurora Store ei omista, lisensoi tai jakele sovelluksia. Kaikki sovellukset, sovellusten kuvaukset, kuvankaappaukset ja muu sisältö Aurora Storessa ovat suoraan haettu, ladattu ja/tai näytetty Google Play -kaupasta. Aurora Store toimii kuten ovi tai selain, mahdollistaen sisäänkirjautumisen Google Play -tilillesi ja sovellusten hakemiseen Google Play -kaupasta.\n\nHuomaa, että Aurora Store ei ole Googlen tai Google Play:n hyväksymä, sponsoroima tai valtuuttama, eikä myöskään minkään Aurora Storen kautta ladatun sovelluksen tai sovelluksien kehittäjien hyväksymä; Aurora Store:lla ei myöskään ole mitään kytköstä, yhteistyötä tai yhteyttä niihin. Sovelluksia ei saatavilla - Käytä microG:tä tileihin sisäänkirjautumiseen - Todenna käyttäen microG:tä Googlen palveluihin sisäänkirjauduttaessa prosessin yksinkertaistamiseksi - Aseta - Poista käytöstä - Välityspalvelin poistettu käytöstä onnistuneesti - Katsele ja hallitse välityspalvelinasetuksia - Automaattisten päivitysten rajoitukset - Muokkaa rajoituksia automaattisille päivityksille - Vain maksuttomissa verkoissa - Kun laite on toimeton - Kun akun varaus ei ole vähäinen - Ladattujen tiedostojen varmentaminen epäonnistui - Edistynyt - Sovelluslähde - Minimi Android-versio - API:n kohdetaso - Viimeksi päivitetty - Lataukset - %1$d käyttöoikeutta - Asenna microG-paketti - Sovellusyhteensopivuus - Puuttuvat riippuvuudet - Olen lukenut ja hyväksynyt microG:n käyttöehdot ja tietosuojakäytännön - Emme löytäneet Google Play Palveluja laitteestasi, useat suositut sovellukset vaativat sitä toimiakseen kunnolla! - Lue microG:n tietosuojakäytäntö - Lue microG:n lisenssi ja käyttöehdot - Vieraile microG-projektin kotisivuilla - microG on ilmainen ja avoimen lähdekoodin uudelleentoteutus, joka tarjoaa alkuperäistä vastaavan toiminnallisuuden sovelluksille, jotka tarvitset Google Play Palveluita toimiakseen.\n\nmicroG luo sovelluksille pääsyn kyseisiin Googlen API:in, parantaen yhteensopivuutta käyttäjille sekä tarjoten samalla yksityisyyshyötyjä.\n\nmicroG käynnistyy automaattisesti taustalla kun avaat sovelluksia, jotka ovat riippuvaisia Google Play Palveluista. - Tiedot, joita tämä sovellus saattaa kerätä - Kehittäjän mukaan tämä sovellus ei kerää käyttäjätietoja. - Data, jota tämä sovellus saattaa jakaa - Kehittäjän mukaan tämä sovellus ei jaa käyttäjätietoja muiden yritysten tai organisaatioden kanssa. - Tämä versio sovelluksesta saattaa pitää sisällään seuraimia, joita ei vielä löydy Exodus Privacy:n tietokannasta. - %1$d tunnettu(a) seurain(ta) löydetty kohteesta %2$s - Versiokoodi voi pitää sisällään vain numeroita - Lisätietoja - Kohteet - Paketin nimi - Ikäkohderyhmä - Valitse sovellus lisätietojen näyttämiseksi - Ei mainoksia - Ei Play-palveluita - Ei kuvausta saatavilla - Valmistaudutaan asentamaan - - Lupa tarvitaan - Lupia tarvitaan - - MicroG-asentaja epäonnistui sovelluksen asennuksessa, todennäköisesti konfiguraatiovirheen johdosta. - MicroG-asentaja - Ohita - Vaatii microG-liitännäissovelluksen olevan asennettuna - Auttaa App Integrity -tarkistuksen ohittamisessa (vain asentajan osalta) - Uudelleenkäynnistä muutoksien käyttöönottamiseksi? - Lataus meneillään - Sivu %1$d diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 2afd7197f..faba14078 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -23,12 +23,13 @@ Comment allez-vous ? Bienvenue Programme d’installation - Filtrer les applis provenant de F-Droid + Filtrer les applis de F-droid Mode d’installation À propos Tendances Mes applis et jeux Gestionnaire de la liste d’exclusion + Applis à prix réduit Applis dans la logithèque N’est pas proposée pour les comptes anonymes Paramètres @@ -39,7 +40,7 @@ Installée Installation Jeux - Magasin Play Store + Play Store Téléchargements Appareil Pas de réseau @@ -70,7 +71,7 @@ Aucune mise à jour n’est proposée Aucune autorisation Aucune dépendance - Aucune publicité + Pas de publicités En savoir plus sur l’appli Le « Google Services Framework » est nécessaire Gratuite @@ -80,7 +81,7 @@ Adresse Description Dépendances - Présente des publicités + Présente des pubs Le journal des changements n’a pas été fourni Journal des changements Adresse courriel @@ -109,14 +110,14 @@ Installations Installer Ignorer - Enregistrer le paquet logiciel + Enregistrer le paquet d’appli Terminer Évaluations Payante Divers Dépend du Google Services Framework Téléchargements - Applis avec publicités + Applis avec pubs Appliquer Tout Filtres @@ -167,34 +168,34 @@ Les meilleures payantes Les plus rentables Les meilleures gratuites - Les mieux classées + Palmarès Reconnectez-vous pour appliquer l’usurpation d’appareil Facultativement, vous pouvez choisir le programme d’installation Natif, cependant vous ne pourrez pas installer les paquets APK (fractionnés). À vous de décider. - Afin de permettre les installations, désactivez les optimisations MIUI. Sinon, vous pouvez choisir le programme d’installation Superutilisateur ou Services. + Afin de permettre les installations, désactivez les optimisations MIUI. Sinon, vous pouvez choisir le programme d’installation Racine ou Services. Les optimisations MIUI empêchent l’installation d’applis par le programme d’installation de session. Choisir le mode d’installation des APK Programme d’installation de session Aurora Services (déconseillés) - Programme d’installation superutilisateur - Programme d’installation natif (déconseillé) + Programme d’installation Racine + Programme d’installation Natif (déconseillé) Supprimer l’APK après installation Les APK téléchargés seront supprimés immédiatement après installation - Ignorer les mises à jour d’applis installées avec F-Droid - Autoriser l’installation d’applis du Aurora Store + Ignorer les mises à jour d’applis téléchargées ou installées avec F-Droid + Autoriser l’installation d’applis par le Aurora Store Autorisation du programme d’installation Gestionnaire de mémoire externe - Pour enregistrer les fichiers d’extension APK (OBB) pour les applis et jeux volumineux. + Pour enregistrer les fichiers d’expansion APK (OBB) des applis et jeux volumineux Accès à la mémoire externe Autorisations Aurora Store a besoin des autorisations suivantes Une nouvelle mise à jour est proposée Configurez d’abord les services Aurora et accordez toutes les autorisations. - Installez les services Aurora 1.0.9 ou version ultérieure, ou changez de programme d’installation. + Installez les services Aurora 1.0.9 ou version ultérieure, ou changez de programme d’installation. Les services Aurora sont proposés et prêts à être installés. - L’accès superutilisateur manque. Accordez-le ou changez le programme d’installation. + L’accès racine manque. Accordez-le ou changez le programme d’installation. Tout Afficher le rapport - traqueurs connus trouvés dans + traqueur(s) connu(s) trouvé(s) dans Recherche de traqueurs… Analyse propulsée par Exodus Privacy Ne comprend aucun traqueur connu @@ -205,20 +206,21 @@ La session est expirée. Reconnectez-vous pour obtenir une nouvelle session. L’appli est introuvable L’appli n’est pas prise en charge - Les comptes anonymes ne peuvent pas acheter des applis. + Les achats d’applis ne sont pas possibles pour les comptes anonymes. Reconnectez-vous et redémarrez l’appli pour appliquer les changements. Mise en réseau Pages « Pour vous » - Applis semblables et apparentées + Afficher les grappes semblables et connexes sur la page des détails de l’appli + Applis semblables et connexes Afficher les pages « Pour vous » sur l’écran d’accueil Choisir l’onglet par défaut Disposition Autres options Aucune appli ne correspond - Félicitations, le code de version demandé est proposé ; le téléchargement est en cours. + Félicitations, le code de version demandé est proposé ; le téléchargement est lancé. Le code de version que vous demandez n’est pas proposé. Téléchargement manuel - Le programme d’installation natif ne permet pas d’installer des paquets d’applis (fractionnés). Choisissez une autre méthode d’installation : Session, Services ou Superutilisateur. + Le programme d’installation Natif ne permet pas d’installer des paquets d’appli (fractionnés). Choisissez une autre méthode d’installation, Session, Services ou Racine. Impossible de générer le jeton AAS Impossible de transmettre l’évaluation L’évaluation a été enregistrée. Son affichage peut prendre un certain temps @@ -238,7 +240,7 @@ Il reste %1$d min %2$d s Téléchargement • %1$d/%2$d%3$s Envoyer des notifications sur l’état des installations - Tout est bien. + Super ! Tout va bien. Développer Le serveur est hors service pour maintenance Avancé @@ -251,7 +253,7 @@ Dernière session supprimée mise à jour proposée mises à jour proposées - Une erreur est survenue ! + Une erreur s’est produite ! Les autorisations requises ont été refusées. Accordez-les afin de poursuivre l’action Chercher des applis et des jeux La configuration de l’appareil a été importée @@ -270,10 +272,10 @@ Suggestion de recherche Résultats de la recherche Échec de génération de la session. Code d’erreur : %1$d - Échec de récupération du relevé de confidentialité - L’accès a été refusé. Utilisez-vous un RPV/VPN ou Tor ? - Erreur interne ! Réessayez plus tard - Votre débit est limité + Échec de récupération du rapport sur la protection des renseignements personnels + L’accès a été refusé. Utilisez-vous un RPV ou Tor ? + Erreur interne. Réessayez plus tard + Oups, votre débit est limité Impossible d’accéder au serveur Autoriser Aurora Store à ouvrir les liens pris en charge Vérifiez votre connexion Internet @@ -281,31 +283,35 @@ Impossible de générer la session Vérification de la nouvelle session Liens de l’appli - Google Play, aussi connu sous le nom de magasin « Play Store » de Google, anciennement « Android Market ». + Google Play, aussi connu sous le nom de Google Play Store, anciennement Android Market. + Activer le mandataire Titre de l’avis URL du mandataire - Configurer la fréquence des mises à jour automatiques, en heures. - Filtrer les applis provenant d’autres sources - L’URL du mandataire est incorrecte, vérifiez le format ! - Ne pas chercher les mises à jour pour les applis qui n’ont pas été installées par Aurora Store + Configurer les intervalles des mises à jour automatiques et des automises à jours, en heures. + Seulement les applis d’Aurora Store + Mandataire + L’URL du mandataire est incorrecte. Vérifiez le format + Ne vérifier la présence de mises à jour que pour les applis installées par Aurora Store Le mandataire est défini - Paramètres de l’appli + Paramètres de l\'appli + Fournisseur – bestappsales.com Fréquence des mises à jour automatiques Échec de paramétrage du mandataire + Faire transiter tout le trafic de l’appli par le mandataire L’Android Market était un magasin en ligne qui offrait des applications conçues pour les appareils Android, fermé en 2017. Par défaut (selon la configuration de l’appareil) Version de Google Play Téléchargements en arrière-plan - Mises à jour automatiques - Chercher les mises à jour et les signaler + Mise à jour automatique des applis + Vérifier et signaler la présence de mises à jour Ne pas mettre les applis à jour automatiquement Autoriser Aurora Store à télécharger et à mettre à jour les applis en arrière-plan - Configurer le comportement des mises à jour automatiques - Chercher les mises à jour et les installer automatiquement + Configurer les mises à jour automatiques + Vérifier la présence de mises à jour et les installer automatiquement Demander une nouvelle analyse Échec d’exportation des APK Effacer les terminés - Afficher les mises à jour susceptibles d’échouer + Mises à jour incompatibles Afficher les mises à jour pour les applis incompatibles ou désactivées dont l’installation peut échouer Ajouter à l’écran d’accueil Des questions ? Trouvez les réponses @@ -313,20 +319,20 @@ Découvrez comment Aurora Store utilise vos données Saisissez le code de la version que vous voulez télécharger Découvrez ce qu’il y a à l’intérieur - Politique de confidentialité + Politique de protection des renseignements personnels Imputabilité et responsabilité Shizuku ou Sui est nécessaire. Doit être configuré et l’autorisation doit être accordée - Les privilèges racine, superutilisateur sont requis. Toutes les versions d’Android sont prises en charge. + Exige des privilèges racine, superutilisateur. Toutes les versions d’Android sont prises en charge. Programme d’installation de session pour les paquets APK (fractionnés) - Programme d’installation fondé sur l’intention, pour tous les appareils - Utilise directement les API système avec les privilèges adb/superutilisateur - Programme d’installation fondé sur l’interpréteur de commandes, qui utilise les droits superutilisateurs + Programme d’installation fondé sur l\'intention, pour tous les appareils + Utilise directement les API système avec les privilèges adb/racine + Programme d’installation fondé sur l’interpréteur de commandes, qui utilise les droits racine Recommandé, intégré et pris en charge pour toutes les versions d’Android Préférable pour les appareils sous Android 4.4 et versions antérieures Les services Aurora doivent être installés en tant qu’appli avec les privilèges système Programme d’installation pour les installations en arrière-plan Gestionnaire de paquet complet à code ouvert - « App Manager » est requis, le mode adb/superutilisateur est nécessaire pour l’installation si l’optimisation miui est activée + Le gestionnaire d’applis « App Manager » et le mode adb/racine sont nécessaires pour installer si l’optimisation MIUI est activée Plus Gérer mon compte Wiki @@ -340,42 +346,43 @@ Connectez-vous à votre compte Google Play Ajouter un distributeur de jetons à Aurora Store. Les distributeurs de jetons fournissent des identifiants de compte à Aurora Store pour les connexions anonymes. URL du distributeur de jetons - Supprimer le distributeur de jetons ? + Supprimer le distributeur de jetons Ajouter Consulter et gérer les distributeurs de jetons pour les connexions anonymes Aucun distributeur de jetons n’est proposé - Aurora Store vous permet de chercher et de télécharger des applis dans le magasin officiel Google Play. Vous pouvez consulter leurs descriptions, captures d’écran, mises à jour, les commentaires des utilisateurs et télécharger les APK directement de Google Play sur votre appareil. Pour utiliser Aurora Store, vous devez disposer d’un compte Google et vous y connecter lors du premier lancement et de la configuration d’Aurora Store.\n\nContrairement à un magasin d’applications traditionnel, Aurora Store n’est le propriétaire d’aucune appli, ne les distribue pas, ni n’émet de licence. Les applis, leurs descriptions, captures d’écran et autres contenus offerts par Aurora Store proviennent directement de Google Play. Aurora Store fonctionne exactement comme une porte d’accès ou un navigateur qui vous permet de vous connecter à votre compte Google Play et de trouver les applis dans Google Play.\n\nAurora Store ne reçoit aucune autorisation, aucun parrainage de Google, de Google Play, des applis téléchargées avec Aurora Store ni des équipes de développement de ces applis. Aurora Store n’a aucun lien d’affiliation, de coopération ou autres connexions avec ces entités. + Aurora Store vous permet de chercher des applications dans le magasin officiel Google Play et de les télécharger. Vous pouvez consulter leurs descriptions, captures d’écran, mises à jour, les commentaires des utilisateurs et télécharger les APK directement de Google Play sur votre appareil. Pour utiliser Aurora Store, vous devez avoir un compte Google et vous y connecter lors du premier lancement et de la configuration d’Aurora Store.\n\nContrairement à un magasin d\'applications traditionnel, Aurora Store n’est pas le propriétaire des applis, ne les distribue pas, ni n’émet de licence. Les applis, leurs descriptions, captures d’écran et autres contenus offerts par Aurora Store proviennent directement de Google Play. Aurora Store fonctionne exactement comme une porte d’accès, un navigateur qui vous permet de vous connecter à votre compte Google Play et de trouver les applis dans Google Play.\n\nAurora Store ne reçoit aucune autorisation, aucun parrainage de Google, Google Play, des applications téléchargées avec Aurora Store ni des équipes de développement de ces applications. Aurora Store n’a aucun lien d\'affiliation, de coopération ou autres connexions avec ces entités. À propos d’Aurora Store En savoir plus sur Aurora Store Le programme d’installation de session ne pourra plus installer silencieusement les applis. Confirmez-vous la révocation du droit de propriété de l’appareil ? Révoquer le droit de propriété de l’appareil L’appli n’est pas proposée pour votre appareil - Échec d’importation des favoris ! - Échec d’exportation des favoris ! + Échec d’importation des favoris + Échec d’exportation des favoris Favori Aucune appli favorite n’a été trouvée - Les favoris ont été importés ! + Les favoris ont été importés L’appli a été désinstallée Saisissez une URL de mandataire valide pour faire transiter toute les données par le mandataire. Applis favorites - Les favoris ont été exportés ! + Les favoris ont été exportés Vous déconnecter ? Voulez-vous vous déconnecter ? - Chercher des mises à jour + Vérifier la présence de mises à jour Sécurité des données Autoriser l’installation d’applis de sources inconnues Vous devez d’abord accorder l’autorisation au programme d’installation + Vous devrez peut-être accorder cette autorisation de nouveau en raison d\'un bogue de l’infrastructure d’accès à la mémoire Requis Optionnel Pratiques de sécurité et de protection des données déclarées par le développeur Redémarrer Aurora Store Aurora Store doit être redémarrée pour appliquer les changements de paramètres - Le paquet logiciel a été exporté - Échec d’exportation du paquet logiciel + Le paquet d’appli a été exporté + Échec d’exportation du paquet d’appli Exportateur de fichier Patience, l’exportation de votre fichier est en cours Notification d’installation - Notification d’exportation d’appli + Notification d’exportation d’application Notification de téléchargement Terminé En attente @@ -383,19 +390,20 @@ Annulé Échec Inaccessible - Connectez-vous à votre compte Google Play pour désarchiver l’appli ! - Notification relative au compte + Connectez-vous à votre compte Google Play pour désarchiver cette appli + Notification liée au compte L’authentification est requise - Recherche de mises à jour + Vérification de la présence de mises à jour Conçu en Inde avec %1$s Par défaut Proposées + L’autorisation ne sera peut-être effective qu’après redémarrage de l’appli. Récents - Échec d’exportation de la liste d’exclusion ! + Échec d’exportation de la liste d’exclusion La liste d’exclusion a été exportée Tout sélectionner Tout dessélectionner - Échec d’importation de la liste d’exclusion ! + Échec d’importation de la liste d’exclusion La liste d’exclusion a été importée Désarchiver Vérification @@ -404,72 +412,15 @@ Fonctionne sans les services Google Play Avec le projet microG Sans les services Google Play - Compatible : fonctionne sans problèmes - Partielle : les fonctions sont limitées - Indéterminée : n’a pas encore été vérifiée + Compatible : Fonctionne parfaitement + Partielle : Les fonctions sont limitées + Indéterminée : La fonctionnalité n’a pas encoré été vérifiée Vérification de la compatibilité… Cette appli fonctionne sans la bibliothèque propriétaire de Google. Cependant, elle peut nécessiter d’autres bibliothèques tierces pour bien fonctionner. Propulsé par Plexus Compatibilité Vous devrez peut-être installer la bibliothèque propriétaire de Google ou un équivalent libre tel que microG. - Incompatible : l’appli n’est pas fonctionnelle + Incompatible : L’appli n’est pas fonctionnelle %1$d applis installées Aucune appli n’est proposée - Utiliser microG pour se connecter aux comptes - Authentifiez-vous avec microG lors de la connexion aux comptes Google afin de simplifier le processus de connexion - Définir - Désactiver - Le mandataire a été désactivé - Afficher et gérer la configuration du mandataire - Configurer les restrictions de l’appareil relatives aux mises à jour automatiques - Seulement sur les réseaux illimités - Quand l’appareil est au repos - Quand le niveau de la batterie est suffisant - Restrictions des mises à jour automatiques - Échec de vérification des fichiers téléchargés - Avancé - Source des applis - Téléchargements - Dernière mise à jour - Version minimale d’Android - Niveau d’API cible - %1$d autorisations - Installer de le paquet d’appli microG - Compatibilité de l’appli - Dépendances manquantes - J’ai lu et accepte les conditions générales d’utilisation et la politique de confidentialité de microG - Les services Google Play ne se trouvent pas sur votre appareil. Plusieurs applis populaires ont besoin de ces services pour fonctionner correctement ! - microG est une implémentation gratuite et à code source ouvert qui offre des fonctions semblables pour exécuter, grâce à une réimplémentation, des applis qui dépendent des services Google Play pour les appareils Android.\n\nmicroG permet aux applis d’accéder à ces API Google, améliorant ainsi la compatibilité pour les utilisateurs tout en offrant des avantages en matière de confidentialité. \n\nmicroG s’exécute automatiquement en arrière-plan quand vous ouvrez des applis qui dépendent des services mobiles Google. - Lire la Politique de confidentialité de microG - Lire la licence et l’entente de microG - Consulter le site Web du projet microG - Données que cette appli peut recueillir - Le développeur affirme que cette appli ne collecte pas les données des utilisateurs. - Données que cette appli peut partager - Le développeur affirme que cette appli ne partage pas les données des utilisateurs avec d’autres entreprises ou organisations. - Cette version de l’appli peut encore comprendre d’autres traceurs qui n’apparaissent pas encore dans la base de données d’Exodus Privacy. - %1$d traceurs connus ont été trouvés dans %2$s - Aucune description n’est proposée - Plus de précisions - Cibles - Nom du paquet - Évaluation du contenu - Choisissez une appli pour afficher plus de détails - Aucune publicité - Pas de Services Play - La version du code ne peut comporter que des chiffres - Préparation de l’installation - - Une autorisation est nécessaire - Des autorisations sont nécessaires - Des autorisations sont nécessaires - - Le programme d’installation de MicroG n’a pas réussi à installer l’appli, probablement en raison d’une mauvaise configuration. - Programme d’installation de MicroG - L’appli compagnon microG doit être installée - Vous aide à contourner la vérification de l’intégrité des applis (programme d’installation seulement) - En cours de chargement - Page %1$d - Ignorer - Redémarrer pour appliquer les changements ? diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 16819e649..ed105cbec 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -17,8 +17,9 @@ Aplicación non soportada Aplicación non mercada Descarga fallida + Amosar grupos similares e relacionados na páxina de detalles da aplicación Aplicacións semellantes e relacionadas - Mostrar Suxestións Personalizadas na pantalla de inicio + Mostrar Suexestións Personalizadas na pantalla de inicio Suxestións personalizadas Seleccione a lapela por defecto Deseño @@ -27,19 +28,19 @@ Método de instalación Seleccione o modo de instalación do APK Instalador de sesión - Servizos Aurora (Obsoleto) + Servizos Aurora Instalador root - Instalador nativo (Obsoleto) + Instalador nativo Eliminar APK unha vez instalado - As APKs descargadas serán eliminadas por defecto tras a instalación + As APKs serán eliminadas por defecto Filtrar aplicacións de F-Droid - Non comprobar actualizacións para as aplicacións descargadas por F-Droid + Borra as aplicacións instaladas por F-Droid da lista de aplicacións Extras Permitir instalación de aplicacións desde a Aurora Store - Permisos do Instalador + Permiso do Instalador Xestor de Almacenamento Externo - Para gardar arquivos de expansión APK (OBBs) de aplicacións e xogos grandes. - Acceso ao almacenamento externo + Para gardar descargas (APKs & OBBs), exporte e importe as configuracións de dispositivos no almacenamento externo. + Acceso a almacenamento externo Como está\? Benvido/a Permisos @@ -63,7 +64,7 @@ Non foi posíbel crear a sesión A instalación foi bloqueada O instalador fallou - Configure os servizos de Aurora e permita todos os permisos primeiro. + Configure os servizos de Aurora e garanta todos os permisos primeiro. Instale os servizos de Aurora 1.0.9 ou superior, ou cambie o instalador. Os servizos de Aurora están dispoñíbeis e listos para seren instalados. Sen acceso root. Garántao ou cambie o instalador. @@ -78,7 +79,7 @@ Ver relatorio rastrexador(es) atopado(s) na versión A comprobar os rastrexadores… - Desenvolvido con Exodus Privacy + Disponibilizado por Exodus Non contén rastrexadores A estimar Retomar todas @@ -155,7 +156,7 @@ Google Anónimo Visite o fío de Aurora Store no XDA para participar en discusións e suxestións. - Foro XDA + Fío de desenvolvemento Xúntese ao grupo de soporte de Aurora para participar en discusións e suxestións. Telegram Doar por Paypal @@ -189,7 +190,7 @@ Copiar Fechar Limpar - As compras de aplicacións non están dispoñíbeis para contas anónimas. + As compras de aplicacións non están dispoñíbeis para contas Anónimas. Permiso concedido Engadida á lista branca Engadido á lista negra @@ -209,6 +210,7 @@ Descargas Dispositivo Xestionar lista negra + Aplicacións en venda Aplicacións na biblioteca As miñas apps & xogos Habilitar servizo de descarga de apps en segundo plano @@ -216,7 +218,7 @@ A configuración non puido ser exportada Configuracións do dispositivo exportadas A cualificación non puido ser entregada - Cualificado, pode tardar en amosarse + Cualificado Páxina de navegación non dispoñíbel Parabéns, o código da versión solicitada está dispoñíbel. Descargándoo agora. O código de versión solicitado non está dispoñíbel. @@ -227,12 +229,12 @@ Xestionar disfrace Asegúrese de volver a iniciar sesión para aplicar o disfrace Top da clasificación - Instalador AM. + Instalador XA. Instale o Xestor de Aplicacións ou mude o instalador. Importar Inicie sesión e desfrute. Guau! Todo ben. - Non se puido iniciar sesión con Google + Erro ao iniciar sesión con Google Non foi posíbel importar a configuración do dispositivo actualización dispoñíbel Expandir @@ -275,172 +277,4 @@ %1$d actualización dispoñíbel %1$s, %2$s, %3$s e %4$d máis Fallo ao xerar a sesión, código de erro: %1$d - Wiki - Atopar respostas a preguntas frequentes (FAQ), pasos para a soluciñon de problemas e máis - Favorito - Eliminar todo - Solicitar unha nova análise - Seleccionar todo - Desinstalado correctamente - Engadir á pantalla de inicio - Non se atoparon aplicación favoritas - Seguridade dos datos - Practicas de privacidade e seguridade de datos declarados polo desenvolvedor - Titulo da reseña - Limpar o finalizado - Máis recente - Notificación relacionada coa conta - Notificación de exportación da aplicación - Notificación de instalación - Notificación de descargas - Permitir a instalación de aplicacións de fontes descoñecidas - Descargas en segundo plano - Permitir a Aurora Store descargar e actualizar aplicacións en segundo plano - Versión de Google Play - Por defecto (segundo a configuración do dispositivo) - Dirección URL do proxy - Introduce unga URL de proxy válida para redirixir todos os datos a través do proxy. - Mostrar actualizacións que poden fallar - Mostrar actualización de aplicacións incomparibles ou desactivadas que poden fallar ao instalarse - Filtrar aplicacións de outras fontes - Non comprobar actualizacións para apliacións instaladas fora da Aurora Store - Por favor, inicia sesión na túa conta de Google Play - Axustes da aplicación - Aplicacións favoritas - Aplicación non dispoñible para o teu dispositivos - Primeiro debes otorgar permisos de instalación - URL do proxy non valida, comproba o formato! - Proxy configurado correctamente - Erro ao establecer o proxy - Obrigatorio - Opcional - Actualizacións automáticas - Configurar o comportamento das actualizacións automáticas - Non actualizar automáticamente as aplicacións - Comprobar e notificar sobre actualizacións dispoñibles - Comprobar e instalar actualizacións dispoñibles automáticamente - Frecuencia das actualizacións automáticas - Configurar intervalo de tempo para actualizacións automáticas, en horas. - Non se puido xerar a sesión - Verificando a nova sesión - Comprobar a conexión - Idioma da aplicación - Enlaces da aplicación - Permitir que Aurora Store abra enlaces compatibles - Google Play, tamén coñecido como Google Play Store e anteriormente Android Market - Android Market era unha tenda online que ofrecía aplicacións de software diseñadas para dispositivos Android, retirada en 2017. - Erro ao exportar os APKs - Non hai aplicacións dispoñibles - Descargas - Última actualización - Versión mínima de Android - Nivel de API obxetivo - Instalador baseado en sesión para APKs emaquetados/divididos - Recomendado, integrado e compatible con todas as versións de Android - Instalador basado en shell que usa permisos de root - Require privilexios de root/superusuario, compatible con todas as versións de Android. - Instalador baseado en intención, dispoñible en todos os dispositivos - Ideal para dispositivos con versións anteriores a Android 4.4 - Instalador para instalacións en segundo plano - Require que os servicios de Aurora se instalen como unha aplicación con privilexios de sistema - Xestor de paquetes completo de código aberto - Require App Manager, necesita modo ADB/root para instalar cando a optimización de MIUI está activada - Uso directo das API do sistema con privilexios ADB/root - Require que primeiro se configure e se lle concedan permisos a aplicación Shizuku ou Sui - Introduce o código da versión que desexas descargar - Tes preguntas? Descubre as respostas - Código Fonte - Descubre qué hai dentro - Política de privacidade - Aprende sobre como usa Aurora Store os teus datos - Responsabilidade - Feito con %1$s en India - Acerca de Aurora Store - Máis información sobre Aurora Store - Aurora Store permiteche buscar e descargar aplicacións da Google Play Store oficial. Podes ver as descripcións, capturas, actualizacións, comentarios de outros usuarios e descargar o APK da aplicación directamente de Google Play ao teu dispositivo. Para usar Aurora Store, necesitas unga conta de Google Play, e iniciar sesión coa túa conta de Google Play a ptimeira vez que abras e configures Aurora Store\n\nA diferenza da tenda de aplicacións tradicional, Aurora Store non lle pertenecen, licencia oy distribúe ningunha aplicación. Todas as aplicaciónd, descricións, capturas e outros contidos en Aurora Store directamente acceden, descargan e/ou se mostran dende Google Play. Aurora Store funciona exactamente como unha porta ou buscador, permitindoche iniciar sesión a túa conta de Google Play e atopar aplicacións de Google Play.\n\nPor favor, entende que Aurora Store non ten a aprobación, patrocinio ou autorización de Google, Google Play, ningunha das aplicacións descargadas dende Aurora Store nin ningún dos desenvolvedores; tampouto ten Aurora Store ningunha afiliación, cooperación oy conexión con eles. - Máis - Xestionar a túa conta - Restablecer propietario do dispositivo - Elimina Aurora Store como a aplicación propietaria do dispositivo - Isto revocará o permiso do instalador de sesión para instalar silenciosamente unha aplicación. Proceder a borrar a propiedade do dispositivo? - Xestionar dispensadores - Ver e administrar dispensadores de tokens para inicios de sesión anónimos - Non hai dispensadores dispoñibles - Engadir dispensador - Engadir un dispensador de tokens a Aurora Store. Os dispensadores de tokens proporcionan credenciales de conta a Aurora Store para iniciar sesión de forma anónima. - URL Inválida - URL do dispensador - Eliminar dispensador - Desexa eliminar o dispensador \"%1$s\"? - Engadir - Eliminar - Erro ao importar favoritos! - Erro ao exportar favoritos! - Favoritos importados! - Favoritos exportados! - Erro ao importar a lista negra! - Erro ao exportar a lista negra! - Lista negra importada! - Lista negra exportada! - Exportador de arquivos - Agarde, exportando o teu arquivo - O paquete da aplicación exportouse correctamente - Erro ao exportar o paquete da aplicación - Pechar a sesión? - Está seguro de que quere pechar a sesión? - Buscar actualizacións - Buscando actualizacións - Reiniciar Aurora Store - É necesario reiniciar Aurora Store para aplicar a configuración recén modificada - Descargando - Errou - Cancelada - Completada - En espera - Non dispoñible - Verificando - Autenticación obrigatoria - Por favor, inicia sesión na túa conta de Google Play para desarquivar a aplicación! - Por defecto - Dispoñible - %1$d permisos - Desarquivar - Non é posible abrir a aplicación - Desenvolvido por Plexus - Comprobando compatibilidade… - Compatibilidade - Requite os Servizos de Google Play - Pode que teñas que instalar a librería propietaria de Google ou unha reimplementación FOSS como microG. - Funciona sen os Servizos de Google Play - Esta aplicación funciona sen a biblioteca propietaria de Google. Sin embargo, pode requerir outras librerías de terceiros para funcionar correctamente. - Co Proxecto microG - Sen os Servizos de Google Play - Compatible: Funciona sen ningún problema - Limitado: Funciona con funcións limitadas - Non compatible: Non funcional - Descoñecido: Non comprobado índa - %1$d aplicacións instaladas - Usar microG para iniciar sesión nas contas - Autenticación mediante microG ao iniciar sesión en contas de Google para simplificar o fluxo de inicio de sesión - Establecer - Desactivar - Proxy desactivado con éxito - Ver e xestionar a configuración do proxy - Avanzado - Restricións das actualizacións automáticas - Configurar restricións para actualizacións automáticas. - Só en redes sen restrición de uso - Cando o dispositivo está inactivo - Cando a batería non está baixa - Fonte da aplicación - Fallou ao verificar os arquivos descargados - Instalar paquete de microG - Compatibilidade da App - Dependencias non atopadas - Lin e acepto os Termos de Servizo e a Politica de Privacidade de microG - Non puidemos atopar os Servizos de Google Play no seu dispositivo, varias aplicacións populares agora requíreno para funcionar adecuadamente! - microG é unha implementación gratuíta e de código aberto que prové funcionalidade similar para executar aplicacións dependentes dos Servizos de Google Play para dispositivos android medianta a re-implementación.\n\nmicroG permite ás aplicacións acceder a esas APIs de Google, mellorando a Compatibilidade para os usuarios mentras ofrece beneficios de privacidade. \n\nmicroG executarase automáticamente en segundo plano cando abras aplicacións que dependen dos Servicios de Google Mobile. - Ler Política de Privacidade de microG - Ler Acordo de Licenza de microG - Visitar web do Proxecto microG diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-he/strings.xml similarity index 73% rename from app/src/main/res/values-iw/strings.xml rename to app/src/main/res/values-he/strings.xml index 34d71cebf..0d07bebb3 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-he/strings.xml @@ -36,7 +36,7 @@ החלה הכול סינון - רכישות ביישום אינן זמינות בחשבונות אנונימיים. + רכישות מיישומים אינן זמינות בחשבונות בעילום שם. לא זמין בחשבונות אנונימיים בעילום שם חיפוש @@ -57,7 +57,7 @@ סגירה ביטול חזרה - הוספה לרשימה השחורה + הוסף לרשימה השחורה רשימה שחורה הצטרף לקבוצת Aurora Support לדיונים או הצעות. תמיכה ב-Liberapay @@ -72,7 +72,7 @@ ללא תלויות בתשלום המובילים בחינם - העתק קישור + העתקת הקישור התעלמות הענקה תנאי השימוש @@ -96,7 +96,7 @@ המובילים בתשלום הועתק ללוח מתבצעת הערכה - עמודים בשבילך + עמודי \"בשבילך\" עזיבה הרשאות הצטרפות @@ -129,6 +129,7 @@ שיתוף לעדכן הכול הרשאה + יישומים במבצע יצירת קשר עם המפתחים לבטל הכול שיטת התקנה @@ -141,7 +142,7 @@ נרשמת לתוכנית הבדיקה של גרסת הביתא הצגת הדו״ח נתוני העל מתקבלים - אל תבדוק עדכונים עבור יישומים שהותקנו מ-F-Droid + התעלם מיישומי F-Droid מעדכונים ויישומים מותקנים שיטת התקנה הורדה הושלמה בוטל @@ -165,7 +166,7 @@ מותקן התקנה באמצעות Root לא היה ניתן להוריד את הקבצים - מידע יישום + מידע על היישום תוכנית גרסת הביתא פרופיל המפתח נדרש GSF @@ -178,14 +179,14 @@ יישומים דומים וקשורים היישום לא נתמך התקנה - מתקין יישומים + מתקין היישומים היסטוריית רכישות הוענקה הרשאת גישה לא היה ניתן לשלוח את הדירוג הורדת יישומים ברקע אין גישת רוט. אשר גישה או שנה סוג מתקין. - התקנת שירותי אורורה גרסה 1.0.9 ומעלה, או שינוי מתקין. - הגדרת שירותי אורורה ואישור כל ההרשאות תחילה. + התקן את שירותי אורורה גרסה 1.0.9 ומעלה, או שנה סוג מתקין. + הגדר את שירותי אורורה ואשר את כל ההרשאות קודם. וודא שאתה מתחבר מחדש כדי להחיל את הזיוף אשר התקנת אפליקציות מחנות אורורה בחר שיטה להתקנות APK @@ -206,12 +207,13 @@ מתקין AM מתקין מערכת בחר עמוד ברירת מחדל - הצגת עמודים בשבילך במסך הבית + הצג את \"בשבילך\" במסך הבית + יישומים דומים וקשורים במסך פרטי היישום מנהל הזיוף אתה תראה תכונות חדשות ובאגים לפני כולם. תן משוב למפתחים כדי לעזור להם להשתפר. אפשרי לבחור מתקין נתיב, אבל לא תוכל להתקין התקנות מאוחדות (מפוצלות - split), אז הבחירה בידך. התהליך עלול לקחת זמן, אתה יכול לבדוק את הסטטוס שלך מאוחר יותר. - שירותי אורורה זמינים ומוכן להתקנה. + שירותי אורורה זמין ומוכן להתקנה. האחסון כמעט מלא זיוף המכשיר הוחל. Shizuku לא מותקן או לא הוגדר כראוי. @@ -222,6 +224,7 @@ לא ניתן לגשת לשרת %1$s, %2$s, %3$s ו %4$d ועוד מוריד קבצים נוספים בשביל %1$s + הפעל פרוקסי מאפשר הורדת יישום ברקע בדוק התחברות אינטרנט לא הצליח ליצור כניסה, קוד תקלה: %1$d @@ -230,8 +233,9 @@ מאמת כניסה כותרת סקירה URL פרוקסי - הגדרת מרווח זמן לעדכונים אוטומטיים, בשעות. - סינון יישומים ממקורות אחרים + הגדר תכיפות עדכונים אוטומטיים ועדכון עצמי, כל שעה. + יישומי חנות Aurora בלבד + פרוקסי מתקין Shizuku פרסום התראות @@ -242,18 +246,18 @@ מבקש כניסה חדשה תקלה פנימית! בבקשה נסה שוב אחרי זמן מה עדכון נמצא - חיפוש יישומים ומשחקים + ‬חפש אפליקציות ומשחקים ייבוא כתובת אתר פרוקסי לא חוקית, בדוק פורמט! עמוד הדפדוף לא קיים הצעות חיפוש מתקדם - אל תבדוק עדכונים עבור יישומים שהותקנו ממקורות שמחוץ לחנות אורורה + הצג רק יישומים שהותקנו מחנות Aurora בעדכונים וביישומים המותקנים ‏לא הצליח להיכנס עם גוגל תפריט %1$dדק %2$dשנ נותרו פרוקסי הוגדר בהצלחה - קישורי יישום + קישורי האפליקציה ייצוא תצורת מכשיר בוצעה בהצלחה מושהה • %1$d / %2$d דורג, אולי יקח לזה זמן עד שיוצג @@ -262,18 +266,19 @@ גוגל פליי, ידוע גם כ-Play Store של גוגל ובתור החנות האידיאלית של אנדרואיד. וואה! הכל טוב. לא הצליח להשיג דיווח פרטיות - שמור חבילת אפליקציה + שמור באנדל של אפליקציה מאמת כניסה חדשה ייבוא תצורת מכשיר בוצעה בהצלחה %1$dש %2$dדק %3$dשנ left הגדרות יישום - לא ניתן להתקין יישומים מחולקים באמצעות מתקין המקורי. יש לשנות את סוג המתקין ל־Session, Services או Root. + אתה לא יכול להתקין אפליקציות באנדל (מפוצלות) עם מתקין Native Installer, שנה את המתקין ל-Session, Services או Root. + ספק - bestappsales.com מכין כמה דברים… פורומים של XDA היכנסו ותהנו. השרת מושבת לצורך תחזוקה מזל טוב, קוד הגרסה המבוקש זמין, מוריד עכשיו. - מאמת את ההפעלה מול Google + מאמת כניסת גוגל תכיפות עדכונים אוטומטיים קרתה תקלה! %1$s, %2$s ו %3$s @@ -283,29 +288,30 @@ תוצאות חיפוש התראות עדכונים מוריד • %1$d / %2$d%3$s + אפשר את כל התעבורה מהיישום שתעבור דרך פרוקסי שלח התראות לגבי מצב ההתקנה החנות של אנדרואיד הייתה חנות אונליין שמציעה אפליקציות שעוצבו למכשירי אנדרואיד, עד 2017. הצג את העמוד של Aurora Store בפורום XDA לשוחח ולהציע הצעות. BHIM - UPI ההרשאות הנדרשות נדחו. אנא אשר אותן בשביל המשך הפעולה גישה נדחתה! אתה משתמש ב-VPN או Tor? - שפת היישום + שפת האפליקציה %1$s ו %2$s פג תוקף ההפעלה, התחבר מחדש כדי לקבל הפעלה חדשה. %1$d עדכון נמצא - הצגת עדכונים שעלולים להיכשל - הצגת עדכונים עבור יישומים לא תואמים או מושבתים שעלולים להיכשל בהתקנה + עדכונים לא תואמים + הצג עדכונים ליישומים לא נתמכים או מושבתים שעלולים להיכשל בהתקנה אל תעדכן-אוטומטית יישומים בדוק ותודיע על עדכונים זמינים בדוק והתקן עדכונים זמינים אוטומטית נכשל בייצוא קבצי Apk הורדות ברקע - עדכונים אוטומטיים - הגדרת אופן הפעולה של עדכונים אוטומטיים - הוספה למסך הבית + עדכון-אוטומטי ליישומים + הגדר התנהגות של עדכונים אוטומטיים + הוסף למסך הבית נקה הורדות שהסתיימו אפשר לחנות Aurora להוריד ולעדכן יישומים ברקע - גרסת Google Play + גרסת גוגל פליי ברירת מחדל (מתוך תצורת המכשיר) בקש ניתוח חדש אנא היכנס לחשבון Google Play שלך @@ -334,7 +340,11 @@ דורש התקנה של שירותי אורורה כאפליקציית מערכת מיוחסת מנהל חבילות קוד פתוח מלא יותר - חנות אורורה מאפשר לך לחפש ולהוריד יישומים מהחנות הרשמית של Google Play. ניתן לבדוק תיאורי יישומים, צילומי מסך, עדכונים, תגובות של משתמשים אחרים, ולהוריד את קובץ ה-APK ישירות מ-Google Play אל ההתקן שלך. כדי להשתמש בחנות אורורה, עליך להחזיק חשבון Google Play ולהתחבר אליו בעת פתיחה והגדרה ראשונית של חנות אורורה.\n\nבשונה מחנויות יישומים מסורתיות, חנות אורורה אינו מחזיק, רוכש רישוי או מפיץ יישומים. כל היישומים, תיאורי היישומים, צילומי המסך ותוכן נוסף בחנות אורורה ניגשים, מוצגים או מורדים ישירות מ-Google Play. חנות אורורה פועלת בדיוק כמו דפדפן או שער, המאפשר לך להתחבר לחשבון Google Play שלך ולמצוא יישומים מ-Google Play.\n\nלתשומת לבך: חנות אורורה אינה מאושרת, ממומנת או מורשה על ידי Google, Google Play, יישומים שהורדו דרך חנות אורורה או מפתחי יישומים; ואין לו כל שותפות, שיתוף פעולה או קשר איתם. + חנות אורורה מאפשר לך לחפש ולהוריד אפליקציות מחנות Google Play הרשמית. אתה יכול לבדוק תיאורי אפליקציה, צילומי מסך, עדכונים, הערות של משתמשים אחרים, ולהוריד את ה-APK ישירות מ-Google Play למכשיר שלך. כדי להשתמש בחנות אורורה, עליך להיות בעל חשבון Google Play ולהיכנס לחשבון Google Play שלך כאשר אתה פותח ומגדיר את חנות אורורה לראשונה. +\n +\n בניגוד לחנות אפליקציות מסורתית, חנות אורורה אינה מחזיקה, מעניקה רישיון או מפיצה אפליקציות כלשהן. כל האפליקציות, תיאורי האפליקציות, צילומי המסך ותוכן אחר ב-חנות אורורה נגישים, מורידים ו/או מוצגים ישירות מ-Google Play. חנות אורורה פועלת בדיוק כמו דלת או דפדפן, ומאפשרת לך להיכנס לחשבון Google Play שלך ולמצוא את האפליקציות מ- Google Play. +\n +\n לידיעתך, אין לחנות אורורה כל אישור, חסות או הרשאה מ-Google, Google Play, אפליקציות שהורדה דרך חנות אורורה או מפתחי אפליקציות כלשהם; גם לחנות אורורה אין שום זיקה, שיתוף פעולה או קשר איתם. נקה את בעל המכשיר מסיר את חנות אורורה כאפליקציה לבעלי המכשיר ניהול מתקנים @@ -359,10 +369,11 @@ בטיחות נתונים נהלי פרטיות ואבטחה שהוכרזו על ידי המפתח אפשר התקנה של אפליקציות ממקורות לא ידועים - עליך להעניק הרשאת מתקין תחילה + תחילה עליך להעניק הרשאת התקנה + ייתכן שיהיה עליך להעניק מחדש את ההרשאה עקב באג במסגרת Storage Access Framework נדרש אופציונלי - ייצוא חבילת היישום נכשל + ייצוא חבילת האפליקציות נכשל הוסר בהצלחה ייצוא המועדפים נכשל! המועדפים יובאו! @@ -370,7 +381,7 @@ להתנתק? לא נמצאו אפליקציות מועדפות הזן כתובת פרוקסי חוקית כדי להעביר את כל הנתונים דרך פרוקסי. - יישומים מעודפים + אפליקציות מועדפות ייבוא המועדפים נכשל! האם אתה בטוח שאתה רוצה להתנתק? חפש עדכונים @@ -386,65 +397,4 @@ התראת ייצוא אפליקציה התראת התקנה התראת הורדה - הורדות - עודכן לאחרונה - גרסת אנדרואיד מינימלית - בחר הכל - אחרון - אין אפליקציות זמינות - הסר הכל - רמת יעד API - התקנת חבילת microG - תאימות יישום - תלויות חסרות - קראתי ומסכים לתנאי השימוש ומדיניות הפרטיות של microG - לא הצלחנו למצוא את שירותי Google Play במכשיר שלך. יישומים פופולריות רבים דורשים אותם כדי לפעול בצורה תקינה! - microG היא מימוש חופשי וקוד פתוח המספק פונקציונליות דומה להפעלת אפליקציות שתלויות בשירותי Google Play עבור התקני Android באמצעות מימוש מחדש.\n\nmicroG מאפשר לאפליקציות לגשת ל־APIs של Google, ומשפר את התאימות עבור המשתמשים תוך כדי מתן יתרונות בתחום הפרטיות.\n\nmicroG תפעל באופן אוטומטי ברקע כאשר תפתח אפליקציות שתלויות בשירותי Google Mobile. - קריאת מדיניות הפרטיות של microG - קריאת רישיון השימוש וההסכם של microG - ביקור באתר הפרויקט של microG - נוצר עם %1$s בהודו - הייבוא של רשימת החסימה נכשל! - הייצוא של רשימת החסימה נכשל! - רשימת החסימה יובאה! - רשימת החסימה יוצאה! - מחפש עדכונים - מאמת - ברירת מחדל - זמין - %1$d הרשאות - ביטול ארכוב - לא ניתן לפתוח את היישום - מופעל על ידי Plexus - בודק תאימות… - תאימות - דורש את שירותי Google Play - ייתכן שיידרש להתקין את הספרייה הקניינית של Google או מימוש קוד פתוח כמו microG. - פועל ללא שירותי Google Play - יישום זה פועל ללא הספרייה הקניינית של Google. עם זאת, ייתכן שהוא עדיין דורש ספריות צד שלישי אחרות כדי לפעול בצורה תקינה. - עם פרויקט microG - ללא שירותי Google Play - תואם: פועל ללא בעיות - מוגבל: פועל עם תכונות מוגבלות - לא נתמך: לא פעיל - לא ידוע: טרם נבדק - הותקנו %1$d יישומים - שימוש ב-microG כדי להיכנס לחשבונות - אימות באמצעות microG בעת כניסה לחשבונות Google לקבלת תהליך כניסה פשוט יותר - הגדרה - השבתה - הפרוקסי הושבת בהצלחה - תצוגה וניהול תצורת Proxy - מתקדם - הגבלות על עדכונים אוטומטיים - הגדרת הגבלות התקן עבור עדכונים אוטומטיים. - ברשתות לא מוגבלות בלבד - כאשר ההתקן בהמתנה - כאשר הסוללה אינה חלשה - מקור היישום - אימות הקבצים שהורדו נכשל - נתונים שאפליקציה זו עשויה לאסוף - המפַתח מסר שהוא לא יאסוף את הנתונים שלך ולא ישתמש בהם. - האפליקציה הזאת עשויה לשתף את סוגי הנתונים האלה - המפַתח הזה מצהיר כי הנתונים שלך לא ישותפו עם חברות וארגונים אחרים. diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index a3b3b3647..e0d71ed08 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -12,7 +12,7 @@ कालीसूची वापस जाएं ऑरोरा से लॉगआउट करें - इनसे लॉगिन करें + इसके द्वारा लॉगिन करें गूगल अज्ञात चर्चा या सुझाव के लिए ऑरोरा स्टोर XDA थ्रेड देखें। @@ -32,7 +32,7 @@ Bitcoin (BTC) के द्वारा दान करें Bitcoin Bitcoin Cash (BCH) के द्वारा दान करें - बिटकॉइन कैश + Bitcoin Cash UPI के द्वारा दान करें वेबसाइट पता @@ -102,7 +102,7 @@ कोई नेटवर्क नहीं सभी को रोकें सभी अपडेट करें - 1.0.9 या ऊपर की Aurora Services इंस्टॉल करें, या इंस्टॉलर बदलें। + 1.0.9 या ऊपर की ऑरोरा सेवाएं इंस्टॉल करें, या इंस्टॉलर बदलें। अनुमति मेरे ऐप्स और गेम्स लाईब्रेरी @@ -113,7 +113,7 @@ F-Droid एप्स को फिल्टर करें अगला अस्वीकरण - App इंस्टॉलर + ऐप इंस्टॉलर सभी पुनः आरंभ करें अपडेट आप बीटा परीक्षक हैं @@ -122,7 +122,7 @@ डाउनलोड संपादकों की पसंद रुझान में - F-Droid से इंस्टॉल किए गए ऐप्स के अपडेट की जांच न करें + अपडेट और इंस्टॉल किए गए ऐप्स में से F-Droid ऐप्स को अनदेखा करें गेम्स सेटिंग इंस्टॉलर @@ -131,22 +131,23 @@ MIUI का पता चला! शीर्ष कमाई इंस्टॉलेशन - बेनामी खातों पर App खरीदारी उपलब्ध नहीं है। + बेनामी खातों पर ऐप खरीदारी उपलब्ध नहीं है। GSF आवश्यकता है सेवा शर्तें श्रेणियां छलावरण प्रबंधक ऐप के बारे में - डेवलपर संपर्क + विकासकर्ता संपर्क कोई अपडेट मौजूद नहीं अतिरिक्त ब्राउज़ पृष्ठ अनुपलब्ध है सत्र इंस्टॉलर - कस्टमाइजेशन (अनुकूलन) + अनुकूलन आकलन ठीक है इंस्टॉल करने का तरीका खाते + बिक्री पर ऐप्स रोके गए • %1$d / %2$d असंगत ऐप लाइसेंस @@ -161,14 +162,14 @@ निःशुल्क बीटा प्रोग्राम से जुड़ें? जानकारी - डेवलपर प्रोफाइल + विकासकर्ता प्रोफाइल अनाम खातों पर उपलब्ध नहीं है विरोधाभासी पैकेज मौजूद है ऑरोरा स्टोर से ऐप इंस्टॉल करने की अनुमति दें रेटिंग और समीक्षाएं कोई डाउनलोड नहीं कतारबद्ध - Aurora Services उपलब्ध हैं और इंस्टॉल करने के लिए तैयार हैं। + ऑरोरा सेवाएं उपलब्ध हैं और इंस्टॉल करने के लिए तैयार हैं। इंस्टालेशन अवरुद्ध किया गया ऑरोरा स्टोर को निम्नलिखित अनुमतियों की आवश्यकता है अनुमतियां @@ -182,7 +183,7 @@ पोस्ट करें पुनः प्रारंभ करें ऐप जानकारी - फिर शुरू करें + पुनः प्रारंभ गणना की जा रही है चार आप बाकि पब्लिक से पहले नए फीचर और बग देखेंगे। डेवलपरों को अपना फीडबैक दें ताकि वो ऐप बेहतर कर सकें। @@ -202,7 +203,7 @@ सकारात्मक गंभीर ऐप मैनेजर इंस्टॉल करें या इंस्टॉलर बदलें। - Aurora Services स्थापित करें और पहले सभी अनुमतियां प्रदान करें। + ऑरोरा सेवाएं स्थापित करें और पहले सभी अनुमतियां प्रदान करें। इंस्टॉलर असफल सत्र नहीं बना सके अपर्याप्त मेमोरी स्थान @@ -211,13 +212,14 @@ कृपया, इंस्टॉलेशन की अनुमति देने के लिए MIUI अनुकूलन अक्षम करें, अन्यथा आप रूट या सर्विसेज़ इंस्टॉलर चुन सकते हैं। MIUI अनुकूलन के कारण सेशन इंस्टॉलर ऐप्स इंस्टॉल नहीं कर सकता। वैकल्पिक रूप से आप नेटिव इंस्टॉलर चुन सकते हैं, लेकिन तब आप बंडल (स्प्लिट) APK इंस्टॉल नहीं कर सकते, इसलिए चुनाव आपका है। - आप नेटिव इंस्टॉलर के साथ बंडल (स्प्लिट) ऐप्स इंस्टॉल नहीं कर सकते। अपने इंस्टॉलर को सेशन, सर्विसेज़ या रूट में बदलें।। + आप नेटिव इंस्टालर के माध्यम से बंडल्ड (स्प्लिट) ऐप्स इंस्टॉल नहीं कर सकते। अपने इंस्टॉलर को सेशन, सर्विसेज या रूट में बदलें। बड़े ऐप्स और गेम के लिए APK विस्तार फाइलें (OBB) सहेजने के लिए। डाउनलोड किए गए APK इंस्टालेशन के तुरंत बाद मिटा दिए जाएंगे इंस्टॉल के बाद APK मिटाएं रूट इंस्टॉलर ऑरोरा सेवाएं (अस्वीकृत) सत्र समाप्त हो गया, नया सत्र प्राप्त करने के लिए पुनः लॉगिन करें। + ऐप विवरण पृष्ठ पर समान और संबंधित समूह प्रदर्शित करें सुनिश्चित करें कि आप छलावरण लागू करने के लिए पुनः लॉगिन करें ऐप समर्थित नहीं है श्वेतसूचीबद्ध @@ -272,7 +274,7 @@ खोज परिणाम पहुंच अस्वीकृत! क्या आप VPN या Tor का उपयोग कर रहे हैं? गोपनीयता रिपोर्ट लाने में विफल - आपकी दर सीमित है + उफ़, आपकी दर सीमित है सर्वर पहुंच योग्य नहीं है सत्र उत्पन्न करने में विफल, त्रुटि कोड: %1$d ऐप भाषा @@ -284,29 +286,33 @@ गूगल प्ले, जिसे गूगल प्ले स्टोर और पूर्व में एंड्रॉइड मार्केट के नाम से भी जाना जाता है। Android Market Android डिवाइसों के लिए डिज़ाइन किए गए सॉफ़्टवेयर एप्लिकेशन पेश करने वाला एक ऑनलाइन स्टोर था, जो 2017 में बंद हो गया। समीक्षा शीर्षक - अन्य स्रोतों से ऐप्स फ़िल्टर करें - ऑरोरा स्टोर के बाहर के स्रोतों से इंस्टॉल किए गए ऐप्स के अपडेट की जांच न करें - App सेटिंग्स + केवल ऑरोरा स्टोर ऐप्स + अपडेट और इंस्टॉल किए गए ऐप्स में केवल ऑरोरा स्टोर से इंस्टॉल किए गए ऐप्स दिखाएं + ऐप सेटिंग्स + प्रदाता - bestappsales.com स्वचालित अपडेट आवृत्ति - स्वतः अद्यतन के लिए घंटे में समय अंतराल विन्यसित करें। + स्वतः और स्वयं अपडेट के लिए अंतराल कॉन्फिगर करें, घंटे में। + प्रॉक्सी चालू करें प्रॉक्सी URL + प्रॉक्सी अमान्य प्रॉक्सी URL, प्रारूप जांचें! प्रॉक्सी सफलतापूर्वक निर्धारित हो गई प्रॉक्सी निर्धारित करने में विफल + ऐप से सभी ट्रैफिक को प्रॉक्सी के माध्यम से जाने की अनुमति दें तयशुदा (डिवाइस विन्यास से) गूगल प्ले संस्करण - बैकग्राउंड डाउनलोड + बेकग्राउंड डाउनलोड ऑरोरा स्टोर को पृष्ठभूमि में ऐप्स डाउनलोड करने और अपडेट करने की अनुमति दें - स्वचालित अद्यतन + ऐप्स को स्वतः अपडेट करें उपलब्ध अपडेट की जाँच करें और सूचित करें ऐप्स को स्वतः अपडेट न करें - स्वतः अद्यतन का व्यवहार विन्यस्त करें + स्वतः अपडेट व्यवहार विन्यस्त करें उपलब्ध अपडेट को स्वचालित रूप से जांचें और इंस्टॉल करें नए विश्लेषण का अनुरोध करें APK निर्यात करने में विफल असंगत या अक्षम ऐप्स के लिए अपडेट दिखाएं जो इंस्टॉल करने में विफल हो सकते हैं समाप्त हुए साफ करें - वे अपडेट दिखाएँ जो विफल हो सकते हैं + असंगत अपडेट होम स्क्रीन पर जोड़ें बंडल/विभाजित APK के लिए सत्र आधारित इंस्टॉलर अनुशंसित, अंतर्निर्मित और सभी Android संस्करणों का समर्थन करता है @@ -348,18 +354,22 @@ कृपया अपने गूगल प्ले खाते में लॉग इन करें ऑरोरा स्टोर के बारे में ऑरोरा स्टोर के बारे में अधिक जानें - ओरोरा स्टोर आपको आधिकारिक गूगल प्ले स्टोर से ऐप्स खोजने और डाउनलोड करने में सक्षम बनाता है। आप ऐप विवरण, स्क्रीनशॉट, अपडेट, अन्य उपयोगकर्ताओं की टिप्पणियाँ देख सकते हैं और गूगल प्ले से सीधे अपने डिवाइस पर APK डाउनलोड कर सकते हैं। ओरोरा स्टोर का उपयोग करने के लिए, आपके पास गूगल प्ले खाता होना चाहिए, और जब आप पहली बार ओरोरा स्टोर खोलते और कॉन्फ़िगर करते हैं तो अपने गूगल प्ले खाते में लॉग इन करें। \n \nपारंपरिक ऐप स्टोर के विपरीत, ऑरोरा स्टोर किसी भी ऐप का स्वामित्व, लाइसेंस या वितरण नहीं करता है। ऑरोरा स्टोर में सभी ऐप, ऐप विवरण, स्क्रीनशॉट और अन्य सामग्री सीधे गूगल प्ले से एक्सेस, डाउनलोड और/या प्रदर्शित की जाती है। ऑरोरा स्टोर बिल्कुल एक दरवाजे या ब्राउज़र की तरह काम करता है, जिससे आप अपने गूगल प्ले खाते में लॉग इन कर सकते हैं और गूगल प्ले से ऐप ढूंढ सकते हैं। \n \nकृपया ध्यान दें कि ऑरोरा स्टोर के पास गूगल, गूगल प्ले, ऑरोरा स्टोर के माध्यम से डाउनलोड किए गए किसी भी ऐप या किसी भी ऐप डेवलपर से कोई अनुमोदन, प्रायोजन या प्राधिकरण नहीं है; न ही ऑरोरा स्टोर का उनके साथ कोई संबद्धता, सहयोग या संबंध है। + ओरोरा स्टोर आपको आधिकारिक गूगल प्ले स्टोर से ऐप्स खोजने और डाउनलोड करने में सक्षम बनाता है। आप ऐप विवरण, स्क्रीनशॉट, अपडेट, अन्य उपयोगकर्ताओं की टिप्पणियाँ देख सकते हैं और गूगल प्ले से सीधे अपने डिवाइस पर APK डाउनलोड कर सकते हैं। ओरोरा स्टोर का उपयोग करने के लिए, आपके पास गूगल प्ले खाता होना चाहिए, और जब आप पहली बार ओरोरा स्टोर खोलते और कॉन्फ़िगर करते हैं तो अपने गूगल प्ले खाते में लॉग इन करें। +\n +\nपारंपरिक ऐप स्टोर के विपरीत, ऑरोरा स्टोर किसी भी ऐप का स्वामित्व, लाइसेंस या वितरण नहीं करता है। ऑरोरा स्टोर में सभी ऐप, ऐप विवरण, स्क्रीनशॉट और अन्य सामग्री सीधे गूगल प्ले से एक्सेस, डाउनलोड और/या प्रदर्शित की जाती है। ऑरोरा स्टोर बिल्कुल एक दरवाजे या ब्राउज़र की तरह काम करता है, जिससे आप अपने गूगल प्ले खाते में लॉग इन कर सकते हैं और गूगल प्ले से ऐप ढूंढ सकते हैं। +\n +\nकृपया ध्यान दें कि ऑरोरा स्टोर के पास गूगल, गूगल प्ले, ऑरोरा स्टोर के माध्यम से डाउनलोड किए गए किसी भी ऐप या किसी भी ऐप डेवलपर से कोई अनुमोदन, प्रायोजन या प्राधिकरण नहीं है; न ही ऑरोरा स्टोर का उनके साथ कोई संबद्धता, सहयोग या संबंध है। ऐप आपके डिवाइस के लिए उपलब्ध नहीं है पसंदीदा कोई पसंदीदा ऐप नहीं मिला पसंदीदा आयात करने में विफल! - पसंदीदा ऐप्स + पसंदीदा ऐप पसंदीदा निर्यात करने में विफल! पसंदीदा आयातित! पसंदीदा निर्यातित! सफलतापूर्वक ऐप ब॔डल निर्यात हुआ - ऐप बंडल निर्यात करने में विफल - अनइंस्टॉल सफल + ऐप ब॔डल निर्यात करने में विफल + सफलतापूर्वक अनइंस्टॉल हूई प्रॉक्सी में से सारा डाटा गुजारने के लिए एक वैध प्रॉक्सी का पता भरें। लागआऊट करें? क्या वाकई आप लागआऊट करना चाहतें हैं? @@ -370,93 +380,9 @@ वैकल्पिक अज्ञात स्रोतों से ऐप्स इंस्टॉल करने की अनुमति दें आपको पहले इंस्टॉलर की अनुमति देनी होगी + स्टोरेज एक्सेस फ्रेमवर्क में बग के कारण आपको अनुमति पुनः देनी पड़ सकती है ऑरोरा स्टोर रीस्टार्ट करें नई बदली गई सेटिंग्स को लागू करने के लिए ऑरोरा स्टोर को रीस्टार्ट करना होगा रुकिए, आपकी फाइल निर्यात हो रही है फाइल निर्यातक - काली सूची आयात करने में असफल! - सत्यापन जारी - प्रमाणीकरण आवश्यक - डिफॉल्ट - उपलब्ध - असंग्रहित करें - गूगल प्ले सेवायें आवश्यक - अक्षम करें - सेट - प्रॉक्सी सफलतापूर्वक अक्षम हुआ - स्वचालित अद्यतन प्रतिबंध - स्वचालित अद्यतन से जुड़े मशीन-प्रतिबंधों को विन्यासित करें। - केवल अमापित संजाल पर - जब मशीन निष्क्रीय हो - जब बैटरी कम नहीं हो - डाउनलोड सूचना - पंक्तिबद्ध - खाता-संबंधित सूचना - डाउनलोड जारी - सभी चुनें - नवीनतम - काली सूची आयात की गयी! - कोई ऐप उपलब्ध नहीं है - आपको गूगल का सांपत्तिक कोड-संग्रह या माइक्रो-जी जैसा एक फॉस पुनर्कार्यान्वयन संस्थापित करना पड़ सकता है। - सभी हटायें - काली सूची निर्यात करने में असफल! - काली सूची निर्यात की गयी! - प्रॉक्सी कॉन्फ़िगरेशन देखें और प्रबंधित करें - भारत में %1$s से निर्मित - अनुपलब्ध - प्लेक्षस द्वारा चालित - अनुकूलता जाँच जारी… - ऐप निर्यात सूचना - अनुकूलता - गूगल प्ले सेवाओं के बिना - सीमित - सीमित गुणों के साथ काम करता है - असमर्थित - काम नहीं करता है - संस्थापन सूचना - अद्यतन जाँच जारी - असफल हुआ - रद्द हुआ - पूर्ण हुआ - ऐप असंग्रहित करने के लिये अपने गूगल प्ले खाते में सत्रारंभ करें! - खातों में साइन इन करने के लिए microG का उपयोग करें - सरल साइन-इन के लिए Google खातों में साइन इन करते समय microG का उपयोग करके प्रमाणीकरण करें - ऐप खोलने में असक्षम - गूगल प्ले सेवाओं के साथ काम करता है - यह ऐप गूगल के सांपत्तिक कोड-संग्रह के साथ काम करता है। किंतु ठीक-प्रकार काम करने के लिये इसे अन्य तृतीय-पक्षी कोड-संग्रहों की आवश्यकता भी पड़ सकती है। - माइक्रो-जी परियोजना के साथ - अनुकूल - निर्विवाद काम करता है - अज्ञात - अब तक जाँच नहीं हुई है - %1$d ऐप संस्थापित - डाउनलोड की गई फ़ाइलें सत्यापित करने में विफल - microG बंडल इंस्टॉल करें - जो जानकारी यह ऐप एकत्र कर सकता है - डेवलपर ने बताया कि यह ऐप कोई प्रयोक्ता-जानकारी एकत्र नहीं करता है। - जो जानकारी यह ऐप साझा कर सकता है - डेवलपर का कहना है कि यह ऐप उपयोगकर्ता डेटा को अन्य कंपनियों या संगठनों के साथ साझा नहीं करता है। - ऐप के इस संस्करण में अभी भी अधिक ट्रैकर्स हो सकते हैं जो अभी तक एक्सोडस प्राइवेसी डेटाबेस में मौजूद नहीं हैं। - %1$d ज्ञात ट्रैकर %2$s में पाए गए - डाउनलोड - आखरी अपडेट - न्यूनतम Android वर्जन - टारगेट API लेवल - ऐप संगतता - अनुपलब्ध निर्भरताएँ - मैंने microG की सेवा की शर्तें और गोपनीयता नीति पढ़ ली है और मैं उनसे सहमत हूँ - हमें आपके डिवाइस पर Google Play सेवाएं नहीं मिल सकीं, कई लोकप्रिय ऐप्स को अब ठीक से काम करने के लिए इसकी आवश्यकता है! - microG एक मुफ़्त और ओपन-सोर्स कार्यान्वयन है जो पुनः कार्यान्वयन के माध्यम से एंड्रॉइड डिवाइसों के लिए Google Play सेवाओं पर निर्भर ऐप्स चलाने के लिए समान कार्यक्षमता प्रदान करता है।\n\nmicroG ऐप्स को उन Google API तक पहुँचने में सक्षम बनाता है, जिससे उपयोगकर्ताओं के लिए अनुकूलता बढ़ती है और गोपनीयता लाभ भी मिलते हैं।\n\nजब आप Google मोबाइल सेवाओं पर निर्भर एप्लिकेशन खोलेंगे, तो microG स्वचालित रूप से पृष्ठभूमि में चलेगा। - microG गोपनीयता नीति पढ़ें - microG लाइसेंस और अनुबंध पढ़ें - microG वेबसाइट पर जाएँ - वर्जन कोड में केवल अंक ही हो सकते हैं - कोई विवरण उपलब्ध नहीं - %1$d अनुमतियाँ - अधिक जानकारी - टारगेट - पैकेज का नाम - सामग्री मूल्यांकन - इंस्टॉल करने की तैयारी - उन्नत (एडवांस) - ऐप स्रोत - अधिक जानकारी के लिए कोई ऐप चुनें - कोई विज्ञापन नहीं - बिना Play Services के diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 32fb62be1..f02c13f50 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -3,7 +3,7 @@ Kontakt podaci programera Opis Zavisnosti - Sadrži oglase + Sadržava oglase Nema dnevnika promjena Dnevnik promjena Upis može ponešto potrajati, stoga provjeri status kasnije. @@ -11,7 +11,7 @@ Želiš se pridružiti beta programu? Ti si član beta programa Beta program - Popis neblokiranih + Poželjni Aktualiziraj sve Aktualiziraj Informacije o aplikaciji @@ -53,8 +53,8 @@ Zatvori Izbriši Prekini - Dodaj u popis blokiranih - Blokiraj + Dodaj u nepoželjne + Nepoželjni Natrag Odjavi se iz Aurore Prijavi se, koristeći @@ -89,8 +89,8 @@ Dozvola odobrena Za otvaranje, uključi postavke za programere u postavkama uređaja. Kopirano u međuspremnik - U popisu neblokiranih - U popisu blokiranih + Poželjni + Dodano na listu nepoželjnih Nije dostupno na anonimnim računima Aktualiziranja Upravljač lažnog predstavljanja @@ -106,7 +106,8 @@ Trgovina igrama Preuzimanja Uređaj - Upravljač popisa blokiranih + Upravljač nepoželjnih + Aplikacije u rasprodaji Aplikacije u biblioteci Moje aplikacije i igre Aplikacije @@ -139,12 +140,12 @@ Izbriši APK datoteke nakon instaliranja Preuzete APK datoteke će se izbrisati odmah nakon instalacije Filtriraj F-Droid aplikacije - Ne provjeravaj ažuriranja za aplikacije instalirane s F-Droida + Ne provjeravaj ažuriranja za aplikacije preuzete ili instalirane s F-Droida Dozvoli instaliranje aplikacija iz Aurora Store - Dozvola programa za instalaciju - Upravljač eksterne memorije + Dozvola za instalaciju + Upravljač vanjske memorije Za spremanje APK proširenih datoteka (OBB) za veće aplikacije i igre. - Pristup eksternoj memoriji + Pristup vanjskoj memoriji Kako si\? Dobro došao, dobro došla Dozvole @@ -169,7 +170,7 @@ Instalacija neuspjela Postavi Aurora usluge i najprije odobri sve dozvole. Instaliraj Aurora usluge 1.0.9 ili noviju verziju ili promijeni program za instalaciju. - Aurora usluge su dostupna i spremne za instalaciju. + Aplikacija „Aurora usluge” je dostupna i spremna za instalaciju. Nema administratorskog pristupa. Odobri ga ili promijeni instalaciju. Dvije Tri @@ -211,14 +212,15 @@ Čestitamo, traženi kod verzije je dostupan, preuzima se. Zatraženi kod verzije nije dostupan. Ručno preuzimanje + Prikaži slične i srodne skupove podataka na stranici detalja aplikacije Slične i srodne aplikacije - Prikaži „Stranice za tebe” na početnom ekranu - Stranice za tebe + Prikaži „Za tvoje stranice” na početnom ekranu + Za tvoje stranice Odaberi standardnu karticu Raspored Nema odgovarajuće aplikacije Dodatno - Paketirane (podijeljene) aplikacije ne možeš instalirati putem nativnog programa za insatliranje. Promijeni program za instaliranje u Sesija, Usluge ili Root. + Paketirane (podijeljene) aplikacije ne možeš instalirati putem nativnog programa za insatliranje. Promijeni instalatera u sesija, usluge ili administrator. Stranica pretraživanja nedostupna Neuspjelo generiranje AAS tokena Neuspjelo slanje ocjene @@ -279,20 +281,21 @@ Dodaj Zahtijeva da se „Aurora usluge” instalira kao aplikacija privilegiranog sustava Dozvoli da Aurora Store otvara podržane poveznice - Uvoz popisa blokiranih nije uspio! - Izvoz popisa blokiranih nije uspio! + Uvoz liste blokiranih nije uspio! + Izvoz liste blokiranih nije uspio! Prekinuto Završeno Preuzimanja u pozadini Dozvoli Aurora Storeu da preuzima i aktualizira aplikacije u pozadini + Možda ćeš morati ponovo pokrenuti aplikaciju kako bi se odrazilo odobrenje dozvole. Pregledaj i upravljaj dozatorima tokena za anonimne prijave Nema dozatora Neispravan URL Ukloni dozatora Uvoz omiljenih nije uspio! Omiljeni su uvezni! - Popis blokiranih je uvezen! - Popis blokiranih je izvezen! + Lista blokiranih je uvezena! + Lista blokiranih je izvezena! Pričekaj, tvoja se datoteka izvozi Paket aplikacije je uspješno izvezen Traži aktualiziranja @@ -312,22 +315,24 @@ Nema omiljenih aplikacija Saznaj kako Aurora Store koristi tvoje podatke Sigurnost podataka - Filtriraj aplikacije iz drugih izvora + Samo Aurora Store aplikacije Najprije moraš dodijeliti dozvolu za instaliranje Uspješno deinstalirano Dozvoli instaliranje aplikacija iz nepoznatih izvora - Želiš li ukloniti dozator „%1$s”? + Želiš li ukloniti dozator \\%1$s\"? Ukloni Izvoz omiljenih nije uspio! - Ne provjeravaj aktualiziranja za aplikacije koje su instalirane iz izvora izvan Aurora Store + Traži samo aktualiziranja za aplikacije koje su instalirane pomoću Aurora Store Omiljene aplikacije - Izvoz paketa aplikacije nije uspio + Pružatelj – bestappsales.com + Izvoz paket aplikacije nije uspio Odjaviti se? Stvarno se želiš odjaviti? URL dozatora Aplikacija nije dostupna za tvoj uređaj Odaberi sve Prakse privatnosti i sigurnosti podataka koje je proglasio programer + Možda ćeš morati ponovo odobriti dozvole zbog greške u Storage Access Frameworku Pronađi odgovore na često postavljana pitanja (ČPP), korake za rješavanje problema i više Ovo će opozvati dozvolu instalera sesije za instaliranje aplikacije u pozadini. Želiš li nastaviti s brisanjem vlasništva nad uređajem? Zadano (iz konfiguracije uređaja) @@ -344,16 +349,17 @@ Zahtijeva Shizuku ili Sui, mora se postaviti i odobriti dozvolu Izbriši gotove Obavijest o računu - Broj tvojih prijava je ograničen + Ups, učestalost tvojih prijava je ograničen Poveznice aplikacija Google Play, poznat i kao Google Play Store, a prije Android Market. + Proxy %1$s i %2$s Upiši ispravni proxy URL za prosljeđivanje svih podataka kroz proxy. Neispravan proxy URL. Provjeri format! Opcionalno Obavijesti o aktualiziranjima %1$d aktualiziranje dostupno - Konfiguriraj ponašanje automatskih aktualiziranja + Konfiguriraj automatska aktualiziranja Provjeri i instaliraj dostupna aktualiziranja automatski Interna greška! Pokušaj ponovo kasnije Provjeravanje nove sesije @@ -364,7 +370,7 @@ Saznaj što je unutra Dostupna je nova verzija za %1$s Dohvaćanje izvještaja o privatnosti nije uspjelo - Konfiguriraj vremenske intervale za automatska aktualiziranja, u satima. + Konfiguriraj intervale za automatska i ručna aktualiziranja, u satima. Korištenje API-ja sustava izravno s administratorskim pravima Izvorni kod Izrađeno sa %1$s u Indiji @@ -383,10 +389,12 @@ Politika privatnosti Obavijest o izvozu aplikacija Obavijest o instaliranjima + Dozvoli da sav promet aplikacije ide kroz proxy Obavijest o preuzimanjima - Prikaži aktualiziranja koja možda neće uspjeti + Aktiviraj proxy + Nekompatibilna aktualiziranja Prikaži aktualiziranja za nekompatibilne ili deaktivirane aplikacije koje se možda neće uspjeti instalirati - Automatka aktualiziranja + Automatko aktualiziranje aplikacija Preporučeno, ugrađeno i podržava sve Android verzije Google Play verzija Proxy URL @@ -414,54 +422,4 @@ Provjera kompatibilnosti … Ova aplikacija radi bez Googleove vlasničke biblioteke. Međutim, još uvijek može trebati druge biblioteke trećih strana da bi pravilno radila. Nema dostupnih aplikacija - Za jednostavniju prijavu autentificiraj se pomoću microG-a prilikom prijave na Google račune - Postavi - Deaktiviraj - Proxy je uspješno deaktiviran - Pogledaj i upravljaj konfiguracijom proxyja - Ograničenja za automatska aktualiziranja - Konfiguriraj ograničenja uređaja za automatska aktualiziranja - Kad je urađaj neaktivan - Kad razina baterije nije niska - Koristi microG za prijavu na račune - Samo na nemjerenim mrežama - Možda ćeš morati instalirati Googleovu vlasničku biblioteku ili FOSS -ovu implementaciju poput microG. - Podaci koje ova aplikacija može prikupljati - Programer tvrdi da ova aplikacija ne prikuplja korisničke podatke. - Podaci koje ova aplikacija može dijeliti - Programer tvrdi da ova aplikacija ne dijeli korisničke podatke s drugim tvrtkama ili organizacijama. - Ova verzija aplikacije može i dalje sadržavati više programa za prećenje koji još nisu prisutni u Exodus Privacy bazi podataka. - Preuzimanja - Zadnje aktualiziranje - Najmanja Android verzija - Cilj razine API-ja - Konpatibilnost aplikacije - Nedostaju ovisnosti - Pročitao/la sam i slažem se s uvjetima usluge i politici o privatnosti tvrtke microG - Nismo pronašli Google Play usluge na vašem uređaju. Nekoliko popularnih aplikacija ih sada zahtijeva za ispravan rad! - Pročitajte politiku privatnosti tvrtke microG - Pročitajte licencu i ugovor tvrtke microG - Posjetite web stranicu projekta microG - Kod verzije može sadržati samo znamenke - Nema opisa - %1$d dozvola - Više informacija - Ciljevi - Ime paketa - Dobna ocjena - Napredno - Izvor aplikacije - Neuspjela provjera preuzetih datoteka - Odaberite aplikaciju za više detalja - Bez oglasa - Bez usluga reprodukcije - Instaliraj microG paket - %1$d pronađena programa za praćenje u %2$s - microG je besplatna i otvorenog koda implementacija koja pruža sličnu funkcionalnost za pokretanje aplikacija koje ovise o Google Play uslugama na Android uređajima putem ponovne implementacije.\n\nmicroG omogućuje aplikacijama pristup Google API-jima, poboljšavajući kompatibilnost za korisnike uz dodatne prednosti po pitanju privatnosti.\n\nmicroG će se automatski pokrenuti u pozadini kada otvorite aplikacije koje ovise o Google mobilnim uslugama. - Priprema za instalaciju - - Potrebna dozvola - Potrebne dozvole - Potrebnih dozvola - diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 7d8df1ed7..aacadc9d3 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -5,12 +5,12 @@ Leírás Függőségek Hirdetéseket tartalmaz - Változáslista nincs megadva - Változáslista + Nincs megadva változásnapló + Változásnapló A jelentkezés eltarthat egy ideig, később ellenőrizheti az állapotot. Új funkciókkal és hibákkal találkozhat mindenki más előtt. Adjon visszajelzést a fejlesztőknek, hogy segítse őket a fejlesztésben. - Béta program - Csatlakozik a béta programhoz? + Bétaprogram + Csatlakozik a bétaprogramhoz? Ön bétatesztelő Engedélyezési lista Összes frissítése @@ -32,7 +32,7 @@ Csatlakozás Telepítés alatt Telepítés - Elutasítás + Mellőzés Megadva Megadás Alkalmazáscsomag mentése @@ -58,8 +58,8 @@ Bejelentkezés ezzel Google Anonim - Tekintse meg az Aurora Store XDA-fórumát megbeszélésekhez vagy javaslatokhoz. - XDA-fórum + Tekintse meg az Aurora Store XDA szálat a vitákért vagy javaslatokért. + XDA fórum Csatlakozzon az Aurora Támogatás csoporthoz beszélgetéshez és javaslatokért. Telegram PayPal adományozás @@ -82,28 +82,28 @@ Üdvözöljük Engedélyek Telepítő - Az Aurora Store-nak a következő engedélyek szükségesek + Az Aurora Store a következő engedélyeket igényli Új frissítés érhető el - Esetlegesen választhatja a natív telepítőt is, viszont így nem fog tudni kötegelt (osztott) APK-kat telepíteni, a választás az öné. + Választhatja a natív telepítőt is, viszont így nem fog tudni kötegelt (osztott) APK-kat telepíteni, a választás az öné. Tiltsa le a MIUI optimalizálást a telepítések engedélyezéséhez, vagy válassza a Root vagy Szolgáltatások telepítési módot. A munkemenet-alapú telepítő nem képes alkalmazásokat telepíteni a MIUI optimalizációi miatt. MIUI észlelve! Felhasználási feltételek Licenc - Közlemény + Jogi nyilatkozat Várakozás felhasználói megerősítésére Sikeresen telepítve - Nincs elég memória + Nincs elég tárhely Érvénytelen vagy sérült APK Nem kompatibilis alkalmazás Ütköző csomag található - Munkamenet létrehozása sikertelen - A telepítés le lett tiltva - Telepítés sikertelen - Először állítsa be az Aurora Szolgáltatásokat, és adjon meg minden engedélyt. - Telepítse az Aurora-szolgáltatások 1.0.9-es vagy magasabb verzióját, vagy változtasson a telepítőn. - Az Aurora-szolgáltatások elérhetőek és telepítésre készek. - Nincs root hozzáférés. Adjon hozzáférést vagy változtasson a telepítési módszeren. + Nem sikerült létrehozni a munkamenetet + A telepítés blokkolva lett + Sikertelen telepítés + Először állítsa be az Aurora szolgáltatásokat, és adjon meg minden engedélyt. + Telepítse az Aurora szolgáltatások 1.0.9-es vagy magasabb verzióját, vagy változtasson a telepítési módszeren. + Az Aurora szolgáltatások elérhetőek és telepítésre készek. + Nincs root hozzáférés. Adja meg a hozzáférést vagy változtasson a telepítési módszeren. Kettő Három Pozitív @@ -113,19 +113,19 @@ Kritikus Összes Jelentés megtekintése - ismert nyomkövető található a következőben + ismert nyomkövető található itt, Nyomkövetők keresése… - Exodus Privacy által működtetve + Működteti az Exodus Privacy Nincs ismert nyomkövető Becslés Összes folytatása - Várólistán + Besorolt Összes szüneteltetése Nincs letöltés Metaadatok beszerzése Összes kényszerített törlése Letöltés sikertelen - Kalkulálás + Számolás Letöltés befejezve Megszakítva Összes megszakítása @@ -135,23 +135,24 @@ Engedély Fizetős Nincs elérhető frissítés - Nincsenek engedélyek - Nincsenek függőségek + Nincs engedély + Nincs függőség Nincs hirdetés - További alkalmazásinformáció + További információ GSF szükséges Ingyenes - Weboldal + Honlap Fejlesztői profil - A fejlesztői beállítások megnyitásához engedélyezze azokat az eszköz beállításaiban. + Akciós alkalmazások + Az eszköze beállításaiban kapcsolja be a fejlesztői beállításokat, hogy megnyithassa őket. Munkamenet-alapú telepítő Az alkalmazásvásárlások nem érhetőek el a névtelen fiókok használata során. - Eszközálca alkalmazva. + Eszközálcázás sikeresen alkalmazva. Engedély megadva Vágólapra másolva - Engedélyezési listás - Tiltólistás - Nem elérhető anonim fiókoknál + Engedélyezési listán + Tiltólistán + Nem elérhető névtelen fiókoknál Frissítések Álcakezelő Beállítások @@ -177,172 +178,178 @@ Top bevétel Top ingyenes Toplisták - Ajánlott + Önnek Szerkesztők ajánlata Kategóriák A módosítások végrehajtásához jelentkezzen be és indítsa újra az alkalmazást. Az álca alkalmazásához jelentkezzen be újra A munkamenet lejárt, az új munkamenethez jelentkezzen be újra. - Fájlok lekérése sikertelen + Nem sikerült letölteni a fájlokat Az alkalmazás nem található Az alkalmazás nem támogatott Az alkalmazás nincs megvásárolva - Letöltés sikertelen + Sikertelen letöltés Testreszabás Hálózat Telepítési mód APK-fájlok telepítési módja - Aurora-szolgáltatások (elavult) + Aurora szolgáltatások (elavult) Root telepítő Natív telepítő (elavult) APK törlése telepítés után A letöltött APK-k a telepítés után azonnal törlődnek - F-Droid alkalmazások kiszűrése + F-Droid alkalmazások szűrése Ne keressen frissítéseket az F-Droidról letöltött vagy telepített alkalmazásokhoz Lehetővé teszi az Aurora Store-ból származó alkalmazások telepítését Telepítési engedély Külső tárhelykezelő - Nagy méretű alkalmazások és játékok APK-kiterjesztési fájljainak (OBB-k) mentéséhez. - Külső tárhelyhozzáférés + Az APK bővítőfájlok (OBB) mentése, nagy alkalmazásokhoz és játékokhoz. + Külső tárhely elérés Hogy van? Telepítések Tiltás Törlés + Hasonló és releváns csoportok megjelenítése a részletek lapon Hasonló és releváns alkalmazások - „Ajánlott” oldal megjelenítése a kezdőlapon - Ajánlott oldalak + „Önnek ajánlott” oldal megjelenítése a kezdőlapon + Önnek ajánlott Alapértelmezett lap kiválasztása Elrendezés Extrák Nem található alkalmazásegyezés - A kért verziókód elérhető, letöltés folyamatban. - A kért verziókód nem érhető el. + Gratulálunk, a kért verziókód elérhető, letöltése folyamatban van. + A kért verziókód nem elérhető. Kézi letöltés - Az AAS token generálása sikertelen + Az AAS token előállítása sikertelen Az értékelés elküldése sikertelen Értékelve, időbe telhet míg megjelenik A böngészőlap nem érhető el - A natív telepítő segítségével nem lehet telepíteni a kötegelt (osztott) alkalmazásokat. Változtassa a telepítőt Session, Services vagy Root-ra. - Eszközbeállítások exportálása sikertelen - Eszközbeállítások exportálva + A natív telepítő segítségével nem lehet telepíteni a kötegelt (osztott) alkalmazásokat. Változtassa a telepítőt Session, Services vagy root-ra. + Eszközkonfiguráció exportálása sikertelen + Eszközkonfiguráció sikeresen exportálva Lehetővé teszi a háttérben történő alkalmazásletöltést - Alkalmazásletöltés a háttérben + Háttérbeli alkalmazásletöltés Telepítse az App Managert vagy változtassa meg a telepítőt. AM telepítő Értesítések - Jelentkezzen be és érezze jól magát. - Eszközbeállítások importálása sikertelen + Jelentkezzen be és élvezze. + Az eszközkonfiguráció importálása sikertelen Importálás %1$d ó %2$d p %3$d mp van hátra %1$d p %2$d mp van hátra %1$d mp van hátra Szüneteltetve • %1$d / %2$d - A(z) %1$s új verziója érhető el + A(z) %1$s új verziója elérhető %1$s, %2$s és %3$s - Előkészítés… + Dolgok előkészítése… Munkamenet hitelesítése Google-munkamenet hitelesítése Keresési eredmények - Haladó - Eszközbeállítások importálva - frissítések érhetők el + Speciális + Eszközkonfiguráció importálva + Frissítések érhetők el Menü - %1$d frissítés érhető el + %1$d frissítések érhetők el %1$d frissítés érhető el %1$s és %2$s %1$s, %2$s, %3$s és %4$d további - Adatvédelmi jelentés lekérése sikertelen - Hozzáférés megtagadva! VPN-t vagy Tor-t használ? - Belső hiba! Próbálja újra később - Korlátozva lett + Nem sikerült lekérni az adatvédelmi jelentést + Hozzáférés megtagadva! VPN-t vagy Tort használ? + Belső hiba! Próbálja újra később. + Hoppá, korlátozásra került Bővebben Alkalmazások és játékok keresése %1$s • API %2$s - Szükséges engedélyek elutasítva. Adja meg őket a művelet folytatásához + A szükséges engedélyek meg lettek tagadva. Adja meg őket a művelet folytatásához. Új munkamenet kérése A kiszolgáló karbantartás miatt nem érhető el - Frissítések értesítései + Értesítések frissítésről A Shizuku nincs telepítve vagy megfelelően beállítva. Letöltés alatt • %1$d / %2$d%3$s - Google-fiókkal való bejelentkezés sikertelen - frissítés érhető el - Kiszolgáló nem érhető el + Nem sikerült bejelentkezni a Google-lal + Frissítés érhető el + A kiszolgáló nem érhető el Keresési javaslat - Hiba lépett fel! - További fájlok letöltése a következőhöz: %1$s - Munkamenet létrehozása sikertelen, hiba: %1$d + Hiba történt! + További fájlok letöltése ehhez: %1$s + Nem sikerült létrehozni a munkamenetet, hibakód: %1$d Értesítések küldése a telepítések állapotáról Shizuku telepítő - Minden rendben. + Azta! Minden rendben. Utolsó munkamenet törölve - Aurora Store által támogatott hivatkozások megnyitásának engedélyezése + Az Aurora Store által támogatott hivatkozások megnyitásának engedélyezése Ellenőrizze az internetkapcsolatot - Google Play, avagy Google Play Áruház, korábban Android Market. - Munkamenet létehozása sikertelen + Google Play, avagy Google Play Store, korábban Android Market. + Nem sikerült létrehozni a munkamenetet Új munkamenet ellenőrzése Alkalmazás nyelve Alkalmazáshivatkozások + Proxy engedélyezése Proxy webcíme - Automatikus frissítések intervallumának konfigurálása órákban mérve. - Egyéb forrásból származó alkalmazások szűrése + Automatikus frissítések intervallumának konfigurálása, órákban. + Csak Aurora Store alkalmazások + Proxy Érvénytelen proxy webcím, ellenőrizze a formátumot! - Ne keressen frissítéseket az Aurora Store-on kívüli forrásból telepített alkalmazásokhoz + Csak az Aurora Store által telepített alkalmazások frissítéseinek ellenőrzése Proxy sikeresen beállítva Alkalmazásbeállítások + Szolgáltató – bestappsales.com Automatikus frissítések gyakorisága Proxy beállítása sikertelen + Alkalmazás forgalmának átirányítása proxyn keresztül Az Android Market egy online áruház volt, amely szoftveralkalmazásokat kínált androidos eszközökhöz, és 2017-ben megszűnt. Alapértelmezett (eszközkonfiguráció) - Google Play-verzió - Értékelés címe + Google Play verzió + Értékelés Háttérbeli letöltések - Automatikus frissítések + Automatikus alkalmazásfrissítés Ellenőrizze, és értesítsen a rendelkezésre álló frissítésekről Ne frissítse automatikusan az alkalmazásokat - Engedélyezze az Aurora Store-nak az alkalmazások háttérben való letöltését és frissítését + Engedélyezze az Aurora Store számára az alkalmazások háttérben való letöltését és frissítését Automatikus frissítések viselkedésének beállítása Ellenőrizze, és automatikusan telepítse a rendelkezésre álló frissítéseket Új elemzés kérése - APK-k exportálása sikertelen + Az APK-k exportálása sikertelen Törlés befejezve - Sikertelen frissítések megjelenítése - Megjeleníti az inkompatibilis vagy letiltott alkalmazások frissítéseit, amelyek telepítése sikertelen lehet + Inkompatibilis frissítések + Inkompatibilis és letiltott alkalmazások frissítésének megjelenítése, a telepítés meghiúsulhat Főképernyőhöz adás Kérdései vannak? Itt találja a válaszokat Forráskód Tudja meg, mi van belül Adatvédelmi irányelvek - Ismerje meg, hogyan használja az Aurora Store az adatait + Ismerje meg, hogyan használja az Aurora Store az Ön adatait Munkamenet-alapú telepítő a kötegelt/felosztott APK-khoz - Ajánlott, beépített és támogatja az összes Android-verziót - Leginkább Android 4.4 alatti eszközökhöz ajánlott + Ajánlott, beépített és támogatja az összes Android verziót + Az Android 4.4-nél régebbi verziót futtató eszközökhöz a legmegfelelőbb Telepítő a háttérben történő telepítésekhez - Ehhez az Aurora-szolgáltatásokat privilegizált rendszeralkalmazásként kell telepíteni + Ehhez az Aurora szolgáltatásokat privilegizált rendszeralkalmazásként kell telepíteni Teljes funkcionalitású nyílt forráskódú csomagkezelő Rendszer API-k használata közvetlenül adb/root jogosultságokkal Shizuku vagy Sui szükséges, be kell állítani és engedélyt kell adni Írja be a letölteni kívánt verziókódot Elszámoltathatóság és felelősség - Shell-alapú telepítő root jogosultságokkal - Root/superuser jogosultságokat igényel, támogatja az összes Android-verziót. - Intent-alapú telepítő, minden eszközön elérhető + Shell alapú telepítő root jogosultságokkal + Root/superuser jogosultságokat igényel, támogatja az összes Android verziót. + Intent alapú telepítő, minden eszközön elérhető App Manager szükséges, adb/root mód szükséges a telepítéshez, ha a miui optimalizálás be van kapcsolva Wiki - Jelentkezzen be a Google Play-fiókjába + Jelentkezzen be a Google Play fiókjába Több Fiók kezelése Az Aurora Store névjegye - Eltávolítja az Aurora Store-t az eszköztulajdonosi rangból + Eltávolítja az Aurora Store-t eszköztulajdonos alkalmazásként Tudjon meg többet az Aurora Store-ról Találja meg válaszait a gyakran ismételt kérdések között (GYIK), hibaelhárítási lépések és egyebek - Az Aurora Store lehetővé teszi az alkalmazások keresését és letöltését a hivatalos Google Play Áruházból. Ellenőrizheti az alkalmazások leírását, képernyőképeit, frissítéseit, más felhasználók megjegyzéseit, és letöltheti az APK-t közvetlenül a Google Play-ről eszközére. Az Aurora Store használatához Google Play-fiókkal kell rendelkeznie, és az Aurora Store első megnyitásakor és konfigurálásakor be kell jelentkeznie a Google Play-fiókjába. \n \nA hagyományos alkalmazásboltokkal ellentétben az Aurora Store nem birtokol, nem licencel és nem terjeszt semmilyen alkalmazást. Az Aurora Store-ban található összes alkalmazás, alkalmazásleírás, képernyőkép és egyéb tartalom közvetlenül a Google Play-ből érhető el, tölthető le és/vagy jeleníthető meg. Az Aurora Store pontosan úgy működik, mint egy ajtó vagy egy böngésző, amely lehetővé teszi, hogy bejelentkezzen a Google Play-fiókjába, és megtalálja az alkalmazásokat a Google Play-ből. \n \nFelhívjuk figyelmét, hogy az Aurora Store nem rendelkezik a Google, a Google Play, az Aurora Store-on keresztül letöltött alkalmazások vagy bármely alkalmazásfejlesztő jóváhagyásával, szponzorálásával vagy engedélyével; az Aurora Store nem áll velük semmilyen együttműködésben vagy kapcsolatban. + Az Aurora Store lehetővé teszi az alkalmazások keresését és letöltését a hivatalos Google Play áruházból. Ellenőrizheti az alkalmazások leírását, képernyőképeit, frissítéseit, más felhasználók megjegyzéseit, és letöltheti az APK-t közvetlenül a Google Play-ből a készülékére. Az Aurora Store használatához Google Play fiókkal kell rendelkeznie, és az Aurora Store első megnyitásakor és konfigurálásakor be kell jelentkeznie a Google Play fiókjába. \n \nA hagyományos alkalmazásboltokkal ellentétben az Aurora Store nem birtokol, nem licencel és nem terjeszt semmilyen alkalmazást. Az Aurora Store-ban található összes alkalmazás, alkalmazásleírás, képernyőkép és egyéb tartalom közvetlenül a Google Play-ből érhető el, tölthető le és/vagy jeleníthető meg. Az Aurora Store pontosan úgy működik, mint egy ajtó vagy egy böngésző, amely lehetővé teszi, hogy bejelentkezzen a Google Play fiókjába, és megtalálja az alkalmazásokat a Google Play-ből. \n \nFelhívjuk figyelmét, hogy az Aurora Store nem rendelkezik a Google, a Google Play, az Aurora Store-on keresztül letöltött alkalmazások vagy bármely alkalmazásfejlesztő jóváhagyásával, szponzorálásával vagy engedélyével; az Aurora Store nem áll velük semmilyen együttműködésben vagy kapcsolatban. Kedvenc Nem található kedvenc alkalmazás - Eszköz tulajdonjogának törlése + Az eszköz tulajdonjogának törlése Adatbiztonság A fejlesztő által bejelentett adatvédelmi és biztonsági gyakorlatok Ismeretlen forrásból származó alkalmazások telepítésének engedélyezése Először adja meg a telepítési engedélyt + Előfordulhat, hogy a Storage Access Framework hibája miatt újra meg kell adnia az engedélyt Szükséges Sikeresen eltávolítva Ez visszavonja a munkamenet-alapú telepítő engedélyét az alkalmazás csendes telepítésére. Folytatja az eszköz tulajdonjogának törlését? @@ -351,124 +358,43 @@ Kedvenc alkalmazások Választható Kiosztott tokenek kezelése - Érvénytelen hivatkozás + Érvénytelen webcím Fájlexportáló - Várjon, a fájl exportálása folyamatban + Várjon, a fájl exportálása Aurora Store újraindítása Hozzáadás - Kiosztó hivatkozás - Kiosztó eltávolítása? + Kiosztó webcím + Kiosztó eltávolítása Szeretné eltávolítani a(z) „<xliff:g id=”url„>%1$s</xliff:g>” kiosztót? Eltávolítás Nincsenek elérhető kiosztók Kiosztó hozzáadása Kedvencek exportálva! - Kiosztótoken hozzáadása az Aurora Store-hoz. A kiosztótokenek hitelesítési adatokat biztosítanak az Aurora Store-hoz a névtelen bejelentkezéshez. - Kedvencek importálása sikertelen! - Kedvencek exportálása sikertelen! + Kiosztótoken hozzáadása az Aurora Store-hoz. A kiosztótokenek hitelesítési adatokat biztosítanak az Aurora Store számára a névtelen bejelentkezéshez. + A kedvencek importálása sikertelen! + A kedvencek exportálása sikertelen! Névtelen bejelentkezésekhez szükséges kiosztott tokenek megtekintése és kezelése Biztosan ki akar jelentkezni? Frissítések ellenőrzése Kedvencek importálva! Sikeresen exportált alkalmazáscsomag - Alkalmazáscsomag exportálása sikertelen + Nem sikerült az alkalmazáscsomag exportálása Kijelentkezik? Az Aurora Store-t újra kell indítani az újonnan módosított beállítások alkalmazásához - Alkalmazásexport értesítés - Telepítési értesítés - Letöltési értesítés + Értesítés alkalmazás exportálásáról + Értesítés telepítése + Letöltések értesítése Megszakítva - Befejezett + Elkészült Sorba állítva Letöltés - Nem elérhető + Nem érhető el Sikertelen Fiókkal kapcsolatos értesítés - Jelentkezzen be Google Play-fiókjába az alkalmazás archiválásának feloldásához! + Jelentkezzen be Google Play fiókjába az alkalmazás archiválásának feloldásához! Hitelesítés szükséges Frissítések ellenőrzése Szeretettel <xliff:g id=„heart_emoji”>%1$s</xliff:g> készült Indiában Alapértelmezett Elérhető - Tiltólista importálva! - Összes eltávolítása - Összes kijelölése - %1$d alkalmazás telepítve - Ellenőrzés - Az alkalmazás nem nyitható meg - Lehet, hogy telepítenie kell a Google zárt programkönyvtárát, vagy egy nyílt forráskódú újabb implementációt, például a microG-t. - Az alkalmazás működik a Google zárt programkönyvtára nélkül. Viszont lehet, hogy a helyes működéséhez más harmadik féltől származó programkönyvtárak szükségesek. - Tiltólista exportálva! - Google Play-szolgáltatások nélkül - Nincsenek elérhető alkalmazások - Tiltólista exportálása sikertelen! - Kompatibilitás ellenőrzése… - Google Play-szolgáltatásokra van szükség - Google Play-szolgáltatások nélkül is működik - A microG projekttel - Kompatibilis: Minden probléma nélkül működik - Korlátozott: Korlátozott funkciókkal működik - Nem támogatott: Nem működőképes - Ismeretlen: Még nem lett ellenőrizve - Plexus által működtetve - Tiltólista importálása sikertelen! - Legújabb - Archiválás visszavonása - Kompatibilitás - Beállítás - Használja a microG-t a fiókba való bejelentkezéshez - Letiltás - A letöltött fájlok ellenőrzése sikertelen - Proxy sikeresen kikapcsolva - Proxy konfiguráció megtekintése és kezelése - Automatikus frissítések korlátozásai - Eszközkorlátozások beállítása az automatikus frissítésekhez - Csak nem mért hálózatokon - Amikor az eszköz tétlen - Amikor a töltöttség nem alacsony - Google-fiókos bejelentkezés microG-vel az egyszerűbb hitelesítésért - %1$d engedélyek - Letöltések - Utoljára frissítve - Minimális Android-verzió - Cél API-szint - Speciális - Alkalmazás forrása - Telepítse a microG csomagot - Alkalmazáskompatibilitás - Hiányzó függőségek - Elolvastam és elfogadom a microG Általános Szerződési Feltételeit és Adatvédelmi Szabályzatát - Nem található Google Play-szolgáltatások az eszközén, több népszerű alkalmazásnak is szüksége van rá a megfelelő működéshez! - A microG egy ingyenes és nyílt forráskódú megvalósítás, amely újraimplementálással hasonló funkciókat biztosít a Google Play-szolgáltatásoktól függő alkalmazások futtatásához Android-eszközökön.\n\nA microG lehetővé teszi az alkalmazásoknak, hogy hozzáférjenek a Google API-khoz, javítva a kompatibilitást a felhasználók számára, miközben adatvédelmi előnyöket kínál.\n\nA microG automatikusan fut a háttérben, amikor a Google mobilszolgáltatásaitól függő alkalmazásokat nyit meg. - A microG adatvédelmi irányelveinek elolvasása - A microG licenc és felhasználási feltételeinek elolvasása - Látogasson el a microG weboldalára - Alkalmazás által gyűjtött adatok - A fejlesztő szerint ez az alkalmazás nem gyűjt felhasználói adatokat. - Alkalmazás által gyűjthető adatok - A fejlesztő szerint ez az alkalmazás nem oszt meg felhasználói adatokat más cégekkel vagy szervezetekkel. - Az alkalmazás ezen verziója még tartalmazhat olyan nyomkövetőket, amelyek egyelőre nem szerepelnek az Exodus Privacy adatbázisában. - %1$d ismert nyomkövető található a(z) %2$s verzióban - Nincs leírás - További információk - Célzott - Csomag neve - Tartalom besorolása - Válasszon egy alkalmazást a további részletekért - Nincsenek hirdetések - Nincsenek Google Play-szolgáltatások - A verziókód csak számokat tartalmazhat - Telepítés előkészítése - - Engedély szükséges - Engedélyek szükségesek - - A MicroG telepítő nem tudta telepíteni az alkalmazást, valószínűleg helytelen beállítás miatt. - MicroG telepítő - A microG kiegészítő alkalmazás telepítése szükséges - Segít megkerülni az App Integrity (csak telepítő) ellenőrzést - Betöltés folyamatban - Oldal %1$d - Kihagyás - Újraindítás a változtatások alkalmazásához? diff --git a/app/src/main/res/values-ia/strings.xml b/app/src/main/res/values-ia/strings.xml new file mode 100644 index 000000000..4a2a1948e --- /dev/null +++ b/app/src/main/res/values-ia/strings.xml @@ -0,0 +1,205 @@ + + + Clauder le session de Aurora + Cancellar + Finir + Permitter + Installar + Clauder session + Discarga le Aurora Store via F-Droid. + Initiar session con + Clauder + Discargas + Aperir + BHIM - UPI + GitLab + Actualisationes + Predefinite (ab le configuration de apparato) + Version pro Google Play + Resumer + Installationes + Adresse + Benvenite + Play Store + Compartir + Installator Shizuku + Licentia + Installator de session + Discargamentos + Application non supportate + Necun discargamentos + Applicationes in le bibliotheca + Profilo del disveloppator + Importar + Suggestiones de recerca + Avantiate + Toto + A proposito de + Permission del installator + Falleva le discargamento + De pagamento + Installate con successo + Plus apps e jocos + Copiate al area de transferentia + Reinitiar + Disinstallar + Bibliotheca + Tu es un usator beta + Salvar pacchetto del application + Contos + Installation + Actualisar toto + Parametros del application + Novitates + Installate + Apparato + Lingua + Information de application + Cercar + Occurreva un error! + Jocos + Falleva le discarga + Sequente + In cauda + OK + Parametros + Resumer toto + Applicationes + Exportar + Permissiones + Cancellar toto + Installator + Nove actualisation disponibile + Sito web + Actualisar + Disactivar + Application non trovate + Necun actualisationes disponibile + Falleva le installator + Rader + Liberapay + Toto + F-Droid + PayPal + Copiar ligamine + Permission + Installation in curso + Google + Telegram + Pausar toto + Copiar + Confidentialitate + E-mail + Facer un donation via Bitcoin Cash (BCH) + Ethereum + Sin dependentias + Facer un donation via PayPal + Sin avisos publicitari + Gratuite + Discargamento completate + Facer un donation via Ethereum (ETH) + Facer un donation via Bitcoin (BTC) + Ignorar + Dependentias + Facer un donation via UPI + Contine avisos publicitari + De pagamento + Bitcoin + Foros XDA + Miscellanea + Applicationes con publicitate + Bitcoin Cash + Sin permissiones + Description + Discargante files additional pro %1$s + Activar le proxy + Pro te + Verificar connexion a Internet + URL de proxy + Solmente applicationes de Aurora Store + Proxy + Un nove version de %1$s es disponibile + actualisation disponibile + Menu + Retes + Ligamines de application + actualisationes disponibile + Seliger scheda per predefinition + Frequentia de actualisationes automatic + %1$s, %2$s e %3$s + %1$d actualisationes disponibile + Lingua del application + %1$s e %2$s + Tendentias + %1$d actualisation disponibile + Cancellate + Shizuku non es installate o ben configurate. + Paginas pro te + Extras + Installator root + %1$s, %2$s, %3$s e %4$d plus + Categorias + Notificationes + Sortir + Non poteva importar le configuration del apparato + Pagina de navigation non disponibile + Actualisation automatic del applicationes + Installator AM + In pausa • %1$d / %2$d + Discarga manual + Configuration del apparato importate + Le installation esseva blocate + Resultatos del recerca + Notificationes de actualisationes + Discargante • %1$d / %2$d%3$s + Application non compatibile + + Le servicios de Aurora es disponibile e preste pro installar. + Installator de applicationes + Contacto del disveloppator + Gestor de immagazinage externe + Personalisation + Aurora Store require le sequente permissiones + Adder al lista nigre + Selige le modo de installation de APK + Lista nigre + Permitter le installation de applicationes ab Aurora Store + Plus super le application + Anonyme + Ignorar applicationes de F-Droid ab le Actualisationes e applicationes installate + Concedite + MIUI detegite! + Deler le APK depost le installation + Fornitor - bestappsales.com + Applicar + Filtros + Lista blanc + Novitates non fornite + Filtrar le applicationes de F-Droid + Verificante le session + Verificante le session de Google + Non disponibile in contos anonyme + Publicar + Installar Gestor de applicationes o cambiar le installator. + Non poteva crear le session + Acceso a immagazinage externe + Monstrar le paginas \"Pro te\" in le schermo de initio + Gestor de listas nigre + In le lista nigre + Non poteva initiar le session via Google + Discargamentos in secunde fundo + Permitter Aurora Store le discargas e actualisationes in secunde fundo + Verificante le nove session + Permission concedite + Falleva le exportation de APKs + Verificar e notificar le actualisationes disponibile + In le lista blanc + Vider reporto + Adder al schermo de initio + Actualisationes incompatibile + Verificar e installar actualisationes disponibile automaticamente + Wiki + Adder + Remover + Initia session con tu conto de Google Play + diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index e017da310..ded2a4604 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -5,30 +5,30 @@ Liberapay Dapatkan kode sumber Aurora Store dari laman Gitlab Aurora OSS. GitLab - Dapatkan Aurora Store melalui F-Droid. + Dapatkan Aurora Store lewat F-Droid. Donasi via UPI BHIM - UPI Situs web Surel Berbayar Lain-lain - Tergantung pada GSF + Bergantung dengan GSF Unduhan Saring Ekspor Nonaktifkan - Salin tautan + Salin Tautan Salin Tutup Hapus - Batalkan + Batal Tambahkan ke daftar blokir Daftar blokir Kembali - Gabung di grup Dukungan Aurora untuk diskusi atau saran. + Bergabunglah di grup dukungan Aurora untuk diskusi dan saran. Telegram Keluar - Tinggalkan + Keluar Nanti Gabung Memasang @@ -36,7 +36,7 @@ Pasang Abaikan Diizinkan - Simpan paket aplikasi + Simpan App bundle Selesai Penilaian Aplikasi dengan iklan @@ -51,8 +51,8 @@ Ethereum Donasi via Bitcoin (BTC) Bitcoin - Donasi via Bitcoin Tunai (BCH) - Bitcoin Tunai + Donasi via Bitcoin Cash (BCH) + Bitcoin Cash Masuk menggunakan Keluar dari Aurora Jadilah patron di Liberapay @@ -60,39 +60,40 @@ Daftar Putih Perbarui semua Perbarui - Info aplikasi + Info Aplikasi Copot Pemasangan - Bagikan + Berbagi Cari Lanjutkan Mulai ulang - Kirim + Pos Tertunda Buka Oke - Berikutnya + Lanjut Izinkan - Halaman jelajah tidak tersedia + Halaman telusur tidak tersedia Disalin ke papan klip Masuk daftar putih - Masuk daftar hitam + Dalam daftar hitam Tidak tersedia di akun anonim - Pengelola daftar hitam + Manajer daftar hitam + Aplikasi obral Aplikasi di perpustakaan - Aplikasi & permainan saya + Aplikasi & permainan Saya Aplikasi Akun Tentang Pembaruan - Pengelola pemalsuan + Manajer pemalsuan Pengaturan Riwayat pembelian Tidak ada jaringan Perpustakaan Bahasa - Pemasang aplikasi - Terpasang - Pemasangan + Penginstal Aplikasi + Terinstal + Instalasi Permainan Play Store Unduhan @@ -101,37 +102,37 @@ Aktifkan pengaturan pengembang dari pengaturan perangkat untuk membukanya. Dinilai, mungkin perlu beberapa saat untuk muncul Tidak dapat mengirimkan peringkat - Selamat, kode versi yang diminta tersedia, mengunduh sekarang. + Selamat, kode versi yang diminta tersedia, unduh sekarang. Kode versi yang Anda minta tidak tersedia. - Pembelian aplikasi tidak tersedia di akun anonim. + Pembelian aplikasi tidak tersedia di akun Anonim. Pemalsuan perangkat diterapkan. - Izin telah diberikan + Izin diberikan Tidak dapat membuat Token AAS Metode pemasangan - Saring aplikasi F-droid - Jangan periksa pembaruan untuk aplikasi yang terpasang dari F-Droid + Filter aplikasi F-droid + Jangan periksa pembaruan untuk aplikasi terunduh atau terpasang dari F-Droid Ekstra - Izinkan memasang aplikasi dari Aurora Store - Perizinan pemasang - Pengelola penyimpanan eksternal - Untuk menyimpan berkas ekspansi APK (OBB) untuk aplikasi & game berukuran besar. - Akses penyimpanan eksternal + Izinkan menginstal aplikasi dari Aurora Store + Izin Pemasang + Manajer Penyimpanan Eksternal + Untuk menyimpan file ekspansi APK (OBB) untuk aplikasi & game berukuran besar. + Akses Penyimpanan Eksternal Apa kabar\? Selamat Datang Perizinan - Pembaruan baru telah tersedia + Pembaruan tersedia MIUI terdeteksi! - Menunggu persetujuan pengguna + Menunggu konfirmasi pengguna Berhasil dipasang Ruang memori tidak cukup - APK tidak sah atau rusak - Aplikasi tidak cocok - Terdapat paket yang bemasalah + APK tidak valid atau rusak + Aplikasi tidak kompatibel + Ada paket yang berkonflik Tidak dapat membuat sesi Pemasangan diblokir - Pemasang gagal + Pemasangan gagal Layanan Aurora tersedia dan siap dipasang. - Tidak ada akses root. Berikan aksesnya atau ubah pemasang. + Tidak ada akses Root. Berikan aksesnya atau ubah pemasang. Ketentuan layanan Lisensi Penyanggahan @@ -141,7 +142,7 @@ Satu Empat Lima - Sangat penting + Kritis Semua Lihat laporan pelacak yang diketahui ditemukan di @@ -150,7 +151,7 @@ Tidak mengandung pelacak yang diketahui Memperkirakan Lanjutkan semua - Antrean + Antrian Jeda semua Tidak ada unduhan Mendapatkan metadata @@ -166,10 +167,10 @@ Perizinan Berbayar Tidak ada pembaruan yang tersedia - Tanpa perizinan - Tanpa ketergantungan + Tidak ada izin + Tanpa Dependensi Tidak ada aplikasi yang cocok - Tanpa iklan + Tidak ada iklan Selengkapnya tentang aplikasi Memerlukan GSF Gratis @@ -182,12 +183,12 @@ Daftar perubahan tidak disediakan Daftar perubahan Pendaftaran mungkin membutuhkan waktu, Anda dapat memeriksa statusnya nanti. - Anda akan melihat fitur-fitur baru dan kekurangan sebelum diketahui publik. Berikan umpan balik Anda kepada pengembang untuk membantu mereka meningkatkannya. - Bergabung ke program beta? + Anda akan melihat fitur baru dan bug sebelum dirilis ke publik, Berikan masukan Anda ke pengembang untuk bantu mereka meningkatkannya. + Bergabung dengan program beta? Anda adalah penguji beta Terlaris - Gratis Teratas - Tangga Teratas + Teratas gratis + Teratas Untuk Anda Pilihan Editor Kategori @@ -198,9 +199,10 @@ Aplikasi tidak ditemukan Aplikasi tidak didukung Aplikasi tidak dibeli + Tampilkan kluster serupa dan terkait di halaman rincian aplikasi Aplikasi serupa dan terkait - Tampilkan halaman Untuk Anda di layar beranda - Halaman Untuk Anda + Tampilan Halaman Anda di layar beranda + Untuk Anda Pilih tab bawaan Tata letak Kostumisasi @@ -209,49 +211,49 @@ Pemasang sesi Layanan Aurora (Tidak digunakan lagi) Pemasang root - Pemasang asli (Tidak digunakan lagi) + Pemasang native (Tidak digunakan lagi) Hapus APK setelah pemasangan - APK yang diunduh akan segera dihapus setelah pemasangan - Anda tidak dapat memasang aplikasi yang dipaketkan (terpisah) melalui pemasang Asli. Ubah pemasang Anda ke Sesi, Layanan, atau Root. - Pilihan lain Anda dapat memilih pemasang Asli, tapi Anda tidak dapat memasang paket APK (terpisah), jadi pilihan ada di tangan Anda. - Harap menonaktifkan optimasi MIUI untuk mengizinkan pemasangan, jika tidak, Anda dapat memilih pemasang Root atau Layanan. + APK yang diunduh akan segera dihapus setelah penginstalan + Anda tidak dapat memasang aplikasi bundled(split) melalui Native Installer. Ubah pemasang Anda ke Sesi, Layanan, atau Root. + Anda juga dapat memilih Pemasang asli, tetapi Anda tidak akan dapat menginstal APK yang dibundel (terpisah), jadi pilihan ada di tangan Anda. + Harap nonaktifkan optimisasi MIUI untuk mengizinkan pemasangan, jika tidak, Anda dapat memilih pemasang Root atau Layanan. Pemasang sesi tidak dapat memasang aplikasi karena Optimisasi MIUI. - Pasang Layanan Aurora 1.0.9 atau lebih baru, atau ubah pemasang. + Pasang layanan Aurora 1.0.9 atau lebih baru atau ubah pemasang. Sedang tren Berbayar teratas Pemasang - Aurora Store memerlukan perizinan sebagai berikut - Atur Layanan Aurora dan berikan seluruh perizinan terlebih dahulu. - Pengunduhan gagal + Aurora Store memerlukan izin sebagai berikut + Atur layanan Aurora dan berikan seluruh izin terlebih dahulu. + Pengunduhan Gagal Tidak dapat mengekspor konfigurasi perangkat Konfigurasi perangkat diekspor Aktifkan unduhan aplikasi di latar belakang Unduhan aplikasi di latar belakang Pemasang AM Pasang App Manager atau ubah pemasang. - Dijeda • %1$d / %2$d + Jeda • %1$d / %2$d %1$dm %2$dd tersisa - Pemberitahuan - Mengirim pemberitahuan mengenai status pemasangan + Notifikasi + Kirim notifikasi perihal status instalasi %1$s • API %2$s - Wah! Semuanya bagus. + Wow! Semuanya bagus. Terjadi kesalahan! - Izin yang diperlukan telah ditolak. Mohon berikan izin untuk melanjutkan tindakan + Izin yang diperlukan telah ditolak. Mohon berikan izin untuk melanjutkan Menu Memverifikasi sesi - Masuk dan bersenang-senanglah. - Cari aplikasi & permainan + Login dan nikmati. + Cari Aplikasi & Permainan %1$dj %2$dm %3$dd tersisa Pembaruan tersedia %1$dd tersisa Mengunduh • %1$d / %2$d%3$s Sesi terakhir dihapus - Tidak dapat masuk melalui Google - Menyiapkan segala sesuatu… + Gagal login melalui Google + Sedang mempersiapkan… Memverifikasi sesi Google Lanjutan Pembaruan tersedia - Perluas + Memperluas Pemasang Shizuku %1$d pembaruan tersedia %1$s dan %2$s @@ -264,115 +266,124 @@ Konfigurasi perangkat diimpor Tidak dapat mengimpor konfigurasi perangkat Notifikasi pembaruan - Server tidak berfungsi untuk pemeliharaan - Versi terbaru dari %1$s sudah tersedia + Server mati untuk pemeliharaan + Versi terbaru %1$s sudah tersedia %1$s, %2$s, %3$s dan %4$d lainnya Saran pencarian Hasil pencarian Akses ditolak! Apakah Anda menggunakan VPN atau Tor\? - Kesalahan internal! Silakan coba lagi setelah beberapa saat - Kuota Anda dibatasi + Internal error! Silakan coba lagi setelah beberapa saat + Ups, tarif Anda terbatas Gagal mengambil laporan privasi Server tidak dapat dijangkau - Gagal membuat sesi, kode kesalahan: %1$d + Gagal membuat sesi, kode error: %1$d Bawaan (dari konfigurasi perangkat) - Periksa sambungan internet + Aktifkan proksi + Periksa koneksi internet Versi Google Play - Tidak dapat membuat sesi + Tidak dapat menghasilkan sesi Judul ulasan URL Proksi - Atur rentang waktu untuk pembaruan otomatis, dalam jam. - Saring aplikasi dari sumber lain + Mengonfigurasi interval untuk pembaruan otomatis dan mandiri, dalam jam. + Hanya aplikasi Aurora Store + Proksi Izinkan Aurora Store untuk membuka tautan yang didukung - Unduhan latar belakang - URL proksi tidak sah, periksa format! - Jangan periksa pembaruan untuk aplikasi yang dipasang dari sumber di luar Aurora Store + Unduhan Latar Belakang + URL proksi invalid, periksa format! + Hanya periksa pembaruan untuk aplikasi yang terpasang oleh Aurora Store Proksi berhasil disetel - Tautan aplikasi + Tautan Aplikasi Google Play, juga dikenal sebagai Google Play Store dan sebelumnya Android Market. Memverifikasi sesi baru Izinkan Aurora Store untuk mengunduh dan memperbarui aplikasi di latar belakang - Pengaturan aplikasi + Pengaturan Aplikasi + Penyedia - bestappsales.com Frekuensi pembaruan otomatis Gagal menyetel proksi - Android Market adalah toko daring yang menyediakan aplikasi perangkat lunak yang dirancang untuk perangkat Android, dihentikan pada tahun 2017. - Bahasa aplikasi - Pembaruan otomatis - Atur perilaku pembaruan otomatis - Jangan perbarui otomatis aplikasi - Periksa & beri tahu apabila tersedia pembaruan - Periksa & pasang pembaruan yang tersedia secara otomatis - Selengkapnya + Izinkan semua lalu lintas dari aplikasi melewati proxy + Android Market adalah toko online yang menawarkan aplikasi perangkat lunak yang dirancang untuk perangkat Android, dihentikan pada tahun 2017. + Bahasa Aplikasi + Auto update aplikasi + Setel perilaku auto-update + Jangan auto-update aplikasi + Cek & beritau apabila update tersedia + Otomatis cek & install update tersedia + Lebih lanjut Temukan jawaban atas pertanyaan yang sering diajukan (FAQ), langkah-langkah pemecahan masalah, dan lainnya Wiki - Hapus yang sudah selesai - Membutuhkan hak akses root/superuser, mendukung semua versi Android. - Paling cocok untuk perangkat yang beroperasi di bawah Android 4.4 - Pemasang untuk pemasangan latar belakang + Hapus selesai + Membutuhkan hak akses root/pengguna super, mendukung semua versi Android. + Paling cocok untuk perangkat yang berjalan di bawah Android 4.4 + Penginstal untuk penginstalan latar belakang Menggunakan API sistem secara langsung dengan hak istimewa adb/root - Membutuhkan Shizuku atau SUI, perlu pengaturan dan izin yang diberikan - Kelola akun Anda - Lihat dan kelola dispenser token untuk login anonim - Ini akan mencabut izin pemasang sesi untuk memasang aplikasi secara diam-diam. Lanjutkan dengan menghapus kepemilikan perangkat? - Tambah dispenser token ke Aurora Store. Dispenser token memberikan kredensial akun ke Aurora Store untuk masuk secara anonim. - URL tidak sah + Membutuhkan Shizuku atau Sui, perlu pengaturan dan izin yang diberikan + Mengelola akun Anda + Melihat dan mengelola dispenser token untuk login anonim + Ini akan mencabut izin penginstal sesi untuk menginstal aplikasi secara diam-diam. Melanjutkan dengan menghapus kepemilikan perangkat? + Menambahkan dispenser token ke Aurora Store. Dispenser token memberikan kredensial akun ke Aurora Store untuk masuk secara anonim. + URL tidak valid Tambah - Tampilkan pembaruan untuk aplikasi yang tidak kompatibel atau dinonaktifkan yang mungkin gagal terpasang + Menampilkan pembaruan untuk aplikasi yang tidak kompatibel atau dinonaktifkan yang mungkin gagal diinstal Masukkan kode versi yang ingin Anda unduh Kode sumber Cari tahu apa yang ada di dalamnya Ada pertanyaan? Temukan jawabannya Kebijakan privasi - Pelajari bagaimana Aurora Store menggunakan data Anda + Ketahui bagaimana Aurora Store menggunakan data Anda Akuntabilitas dan tanggung jawab Silakan masuk ke akun Google Play Anda Tentang Aurora Store Pelajari lebih lanjut tentang Aurora Store - Tampilkan pembaruan yang mungkin gagal + Pembaruan tidak kompatibel Gagal mengekspor APK - Pemasang berbasis sesi untuk APK dipaketkan/terpisah + Penginstal berbasis sesi untuk APK gabungan/terpisah Direkomendasikan, sudah terpasang dan mendukung semua versi Android - Pemasang berbasis shell menggunakan izin root + Penginstal berbasis shell menggunakan izin root Minta analisis baru - Tambahkan ke layar beranda + Tambahkan ke layar Beranda Apakah Anda ingin menghapus dispenser \"%1$s\"? - Hapus - Pengelola paket sumber terbuka dengan fitur lengkap - Membutuhkan Aplikasi Manager, perlu mode adb/root untuk dipasang ketika optimasi MIUI aktif - Aurora Store memungkinkan Anda untuk mencari dan mengunduh aplikasi dari toko resmi Google Play. Anda dapat memeriksa deskripsi aplikasi, tangkapan layar, pembaruan, komentar pengguna lain, dan mengunduh APK langsung dari Google Play ke perangkat Anda. Untuk menggunakan Aurora Store, Anda harus memiliki akun Google Play, dan masuk ke akun Google Play saat pertama kali membuka dan mengatur Aurora Store. \n \nTidak seperti toko aplikasi tradisional, Aurora Store tidak memiliki, melisensikan, atau mendistribusikan aplikasi apa pun. Semua aplikasi, deskripsi aplikasi, tangkapan layar, dan konten lainnya di Aurora Store diakses, diunduh, dan/atau ditampilkan secara langsung dari Google Play. Aurora Store berfungsi persis seperti pintu atau peramban, memungkinkan Anda untuk masuk ke akun Google Play dan menemukan aplikasi dari Google Play. \n \nHarap diperhatikan bahwa Aurora Store tidak memiliki persetujuan, sponsor, atau otorisasi apa pun dari Google, Google Play, aplikasi apa pun yang diunduh melalui Aurora Store, atau pengembang aplikasi mana pun; Aurora Store juga tidak memiliki afiliasi, kerja sama, atau hubungan apa pun dengan mereka. + Menghapus + Manajer paket sumber terbuka dengan fitur lengkap + Membutuhkan Manajer Aplikasi, perlu mode adb / root untuk menginstal ketika pengoptimalan miui aktif + Aurora Store memungkinkan Anda untuk mencari dan mengunduh aplikasi dari toko resmi Google Play. Anda dapat memeriksa deskripsi aplikasi, tangkapan layar, pembaruan, komentar pengguna lain, dan mengunduh APK langsung dari Google Play ke perangkat Anda. Untuk menggunakan Aurora Store, Anda harus memiliki akun Google Play, dan masuk ke akun Google Play saat pertama kali membuka dan mengonfigurasi Aurora Store. +\n +\nTidak seperti toko aplikasi tradisional, Aurora Store tidak memiliki, melisensikan, atau mendistribusikan aplikasi apa pun. Semua aplikasi, deskripsi aplikasi, tangkapan layar, dan konten lainnya di Aurora Store diakses, diunduh, dan/atau ditampilkan secara langsung dari Google Play. Aurora Store berfungsi persis seperti pintu atau browser, memungkinkan Anda untuk masuk ke akun Google Play dan menemukan aplikasi dari Google Play. +\n +\nHarap diperhatikan bahwa Aurora Store tidak memiliki persetujuan, sponsor, atau otorisasi apa pun dari Google, Google Play, aplikasi apa pun yang diunduh melalui Aurora Store, atau pengembang aplikasi mana pun; Aurora Store juga tidak memiliki afiliasi, kerja sama, atau hubungan apa pun dengan mereka. Aplikasi tidak tersedia untuk perangkat Anda - Memerlukan Layanan Aurora yang dipasang sebagai aplikasi sistem dengan hak istimewa - Hapus dispenser? + Memerlukan Layanan Aurora untuk diinstal sebagai aplikasi sistem dengan hak istimewa + Hapus dispenser Kesukaan Tidak ada aplikasi kesukaan yang ditemukan - Aplikasi favorit + Aplikasi Kesukaan Hapus pemilik perangkat URL Dispenser Gagal mengimpor favorit! Gagal mengekspor favorit! Favorit diimpor! Favorit diekspor! - Pemasang berbasis intent, tersedia di semua perangkat - Hapus Aurora Store sebagai aplikasi pemilik perangkat - Berhasil mengekspor paket aplikasi - Gagal mengekspor paket aplikasi + Penginstal berbasis intent, tersedia di semua perangkat + Menghapus Aurora Store sebagai aplikasi pemilik perangkat + Paket aplikasi berhasil diekspor + Gagal mengekspor app bundle Tambah dispenser Kelola dispenser - Tidak ada dispenser yang tersedia - Berhasil dicopot - Masukkan proksi URL yang sah supaya data dapat dimuat melalui proksi. - Apakah Anda yakin ingin keluar? - Keluar? - Periksa pembaruan - Pengekspor berkas + Tidak ditemukan dispenser + Sukses dicopot + Masukkan proksi URL yang valid agar data dapat dimuat melalui proksi. + Anda yakin ingin keluar log? + Keluar log? + Periksa apakah ada pembaruan + Eksportir Berkas Tunggu sebentar, mengekspor berkas Anda - Memulai ulang Aurora Store + Memulai Ulang Aurora Store Keamanan data - Kebijakan privasi dan keamanan data yang disampaikan oleh pengembang + Praktik privasi dan keamanan data yang diumumkan oleh pengembang Mengizinkan memasang aplikasi dari sumber yang tidak dikenal - Anda perlu memberikan izin pemasangan terlebih dahulu + Anda perlu memberikan Izin Instalasi terlebih dahulu Dibutuhkan Opsional + Anda mungkin harus memberikan izin kembali karena adanya kesalahan dalam Kerangka Kerja Akses Penyimpanan Aurora Store perlu dimulai ulang untuk menerapkan pengaturan terbaru Pemberitahuan ekspor aplikasi Pemberitahuan pemasangan @@ -390,9 +401,10 @@ Dibuat dengan %1$s di India Bawaan Tersedia + Anda mungkin harus memulai ulang aplikasi untuk menyesuaikan dengan pemberian izin. Hapus semua Pilih semua - Terbaru + Terkini Gagal mengekspor daftar hitam! Daftar hitam diimpor! Daftar hitam diekspor! @@ -400,74 +412,19 @@ Memverifikasi Buka arsip Tidak dapat membuka aplikasi - Didukung oleh Plexus + Diberdayakan oleh Plexus Memeriksa kompatibilitas… Kompatibilitas Memerlukan Layanan Google Play Bekerja tanpa Layanan Google Play - Aplikasi ini bekerja tanpa pustaka milik Google. Namun, aplikasi ini mungkin masih memerlukan pustaka pihak ketiga lainnya untuk bekerja dengan baik. + Aplikasi ini bekerja tanpa pustaka Google bersumber tertutup. Namun, aplikasi ini mungkin masih memerlukan pustaka pihak ketiga lainnya untuk bekerja. Tanpa Layanan Google Play Kompatibel: Bekerja tanpa masalah Terbatas: Bekerja dengan fitur terbatas Tidak didukung: Tidak berfungsi Tidak diketahui: Belum diperiksa %1$d aplikasi terpasang - Anda mungkin perlu memasang pustaka milik Google atau implementasi ulang FOSS seperti microG. + Anda mungkin perlu memasang pustaka Google yang bersumber tertutup atau reimplementasi FOSS seperti microG. Dengan Proyek microG Tidak ada aplikasi yang tersedia - Gunakan microG untuk masuk ke akun - Autentikasi menggunakan microG saat masuk ke akun Google untuk proses masuk yang lebih sederhana - Atur - Nonaktifkan - Proksi berhasil dinonaktifkan - Lihat dan kelola konfigurasi proksi - Pembatasan pembaruan otomatis - Saat perangkat tidak digunakan - Konfigurasikan pembatasan perangkat untuk pembaruan otomatis - Hanya pada jaringan yang tidak terukur - Saat baterai tidak lemah - Gagal memverifikasi berkas terunduh - Unduhan - Terakhir diperbarui - Versi Android Minimum - Target Level API - Tingkat Lanjut - Sumber aplikasi - %1$d perizinan - Pasang Bundel microG - Kompatibilitas Aplikasi - Ketergantungan hilang - Saya telah membaca dan menyetujui Persyaratan Layanan dan Kebijakan Privasi - Kami tidak dapat menemukan Layanan Google Play di perangkat Anda, beberapa aplikasi populer sekarang memerlukannya untuk berfungsi! - Baca Kebijakan Privasi microG - Baca Lisensi dan Penyetujuan microG - Kunjungi Situs Web Proyek microG - microG adalah implementasi sumber terbuka dan terbuka yang menyediakan fungsionalitas serupa untuk menjalankan aplikasi yang bergantung pada layanan Google Play untuk perangkat Android melalui implementasi ulang.\n\nmicroG memungkinkan aplikasi untuk mengakses API Google tersebut, meningkatkan kompatibilitas bagi pengguna sambil menawarkan manfaat privasi. \n\nmicroG akan berjalan secara otomatis di latar belakang ketika Anda membuka aplikasi yang bergantung pada layanan seluler Google. - Data yang mungkin dikumpulkan oleh aplikasi ini - Pengembang menyatakan bahwa aplikasi ini tidak mengumpulkan data pengguna. - Data yang mungkin dibagikan oleh aplikasi ini - Pengembang menyatakan bahwa aplikasi ini tidak membagikan data pengguna dengan perusahaan atau organisasi lain. - Versi aplikasi ini mungkin masih mengandung pelacak yang belum terdaftar dalam basis data Exodus Privacy. - %1$d pelacak yang diketahui ditemukan di %2$s - Tidak ada deskripsi yang tersedia - Informasi lebih lanjut - Sasaran - Nama paket - Peringkat konten - Pilih aplikasi untuk detail lebih lanjut - Tidak ada iklan - Tidak ada layanan google play - Kode versi hanya dapat berisi angka - Mempersiapkan pemasangan - - Izin yang diperlukan - - Pemasang MicroG gagal memasang aplikasi, kemungkinan disebabkan oleh konfigurasi yang salah. - Pemasang MicroG - Membutuhkan aplikasi pendamping microG untuk dipasang - Membantu Anda melewati pemeriksaan Integritas Aplikasi (hanya untuk pemasang) - Pemuatan sedang berlangsung - Halaman %1$d - Lewat - Mulai ulang untuk menerapkan perubahan? diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 1d5a2594d..65c27c21b 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -10,7 +10,7 @@ Indirizzo E-mail Copiato negli appunti - Rimossa da lista nera + Rimossa dalla lista nera Messo in lista nera Aggiornamenti Impostazioni @@ -39,14 +39,15 @@ Annulla tutti Scaricamenti Installatore delle app + App in offerta App nella libreria Le mie app e i miei giochi App Applicazione non trovata Applicazione non supportata Applicazione non acquistata - Escludi le app provenienti da F-Droid - Non controllare gli aggiornamenti per le app installate da F-Droid + Filtra le app da F-Droid + Non controllare gli aggiornamenti per le app scaricate o installate da F-Droid Consenti l\'installazione di app da Aurora Store App incompatibile Cosa ne pensi di questa app? @@ -79,7 +80,7 @@ Partecipare al programma beta? Sei un beta tester Programma beta - Rimuovi da lista nera + Rimuovi dalla lista nera Aggiorna tutte Aggiorna Disinstalla @@ -112,7 +113,7 @@ Filtri Esporta Disabilita - Copia collegamento + Copia link Copia Chiudi Cancella @@ -138,7 +139,7 @@ Dona via Bitcoin (BTC) Bitcoin Dona via Bitcoin Cash (BCH) - Bitcoin Cash + Bitcoin Contanti Dona via UPI BHIM - UPI Contraffazione dispositivo applicata. @@ -174,7 +175,7 @@ Benvenuti Autorizzazioni Installatore - Aurora Store richiede le seguenti autorizzazioni + Aurora Store richiede le autorizzazioni seguenti Nuovo aggiornamento disponibile Facoltativamente puoi scegliere l\'installatore nativo, ma in tal caso non sarà possibile installare APK in bundle (divisi). Si prega di disattivare le ottimizzazioni MIUI per consentire le installazioni, altrimenti è possibile scegliere installatore Root o Services. @@ -208,6 +209,7 @@ Gli acquisti di app non sono disponibili sui profili anonimi. Assicurati di effettuare nuovamente l\'accesso e di riavviare l\'app per applicare le modifiche. Rete + Visualizza i gruppi di app simili e correlate nella pagina dei dettagli dell\'app App simili e correlate Visualizza le pagine «Per te» sulla schermata iniziale Pagine «Per te» @@ -230,7 +232,7 @@ Installatore AM Installa App Manager o cambia l\'installatore. Importa - Download in corso • %1$d / %2$d%3$s + Scaricamento • %1$d / %2$d%3$s Invia notifiche sullo stato delle installazioni Verifica della sessione Avanzato @@ -250,11 +252,11 @@ Si è verificato un errore! Menù Espandi - Le autorizzazioni richieste sono state negate. Si prega di concederle per continuare il processo + I permessi richiesti sono stati negati. Concedili per continuare l\'azione Cerca app e giochi - %1$d o %2$d m %3$d s rimanenti - %1$d m %2$d s rimanenti - %1$d s rimanenti + %1$d o %2$d min %3$d s rimasti + %1$d min %2$d s rimasti + %1$d s rimasti Accedi e divertiti. Wow! Tutto bene. Preparazione in corso… @@ -270,34 +272,38 @@ Suggerimenti di ricerca Risultati della ricerca Accesso negato! Stai usando VPN o Tor\? - La tua velocità è stata limitata + Oops, la tua velocità è stata limitata Server non raggiungibile Errore nel recupero del rapporto sulla privacy Errore interno! Riprova più tardi Errore nella generazione della sessione, codice: %1$d Controlla la tua connessione ad internet - Lingua dell\'app + Lingua app Consenti a Aurora Store di aprire i collegamenti supportati Impossibile generare la sessione Verifica della nuova sessione Collegamenti app Google Play, noto anche come Google Play Store e precedentemente Android Market. Titolo della recensione + Provider: bestappsales.com Android Market era un negozio online che offriva applicazioni software progettate per dispositivi Android, chiuso nel 2017. + Abilita proxy URL del proxy - Configura la frequenza degli aggiornamenti automatici (in ore). + Configura la frequenza degli aggiornamenti automatici (in ore) + Proxy Proxy impostato con successo Impostazioni app Frequenza degli aggiornamenti automatici È stato impossibile impostare il proxy Predefinito/a (dalla configurazione del dispositivo) Versione di Google Play - Escludi le app provenienti da altre fonti + Solo app da Aurora Store Scaricamenti in background URL proxy non valido, controlla il formato! - Non controllare gli aggiornamenti per app installate da altre fonti + Controlla gli aggiornamenti solo per le app installate da Aurora Store Consenti ad Aurora Store di scaricare e aggiornare le app in background - Aggiornamenti automatici + Permetti a tutti i dati di quest\'app di passare tramite proxy + Aggiorna le app automaticamente Controlla e segnala gli aggiornamenti disponibili Non aggiornare le app automaticamente Configura il comportamento degli aggiornamenti automatici @@ -305,7 +311,7 @@ Richiedi nuova analisi Esportazioni degli APK fallita Rimuovi completati - Mostra aggiornamenti che potrebbero fallire + Aggiornamenti incompatibili Mostra gli aggiornamenti per le app incompatibili o disabilitate che potrebbero non essere installabili Aggiungi alla pagina principale Inserisci il codice della versione che vuoi scaricare @@ -316,7 +322,7 @@ Scopri come Aurora Store utilizza i tuoi dati Responsabilità Consigliato, integrato e supporta tutte le versioni di Android - Installatore shell che usa permessi di root + Installatore shell che usa i permessi di root Richiede i permessi di root/superuser, supporta tutte le versioni di Android. Installatore basato sugli intent, disponibile su tutti i dispositivi Installatore basato sulla sessione per APK raggruppati/divisi @@ -331,7 +337,7 @@ Gestisci il tuo account Gestisci distributori Aggiungi distributore - Rimuovi distributore? + Rimuovi distributore Aggiungi Rimuovi Wiki @@ -355,6 +361,7 @@ Sicurezza dei dati Privacy e pratiche di sicurezza dei dati dichiarate dallo sviluppatore Consenti l\'installazione di app da fonti sconosciute + Potrebbe essere necessario ripristinare il permesso a causa di un errore nell\'infrastuttura che gestisce l\'accesso all\'archivizione È necessario concedere prima il permesso di installazione Obbligatorio Opzionale @@ -399,77 +406,4 @@ Annulla archiviazione Importazione della lista nera non riuscita! Lista nera importata! - Quando il dispositivo è inattivo - Quando il livello di carica della batteria non è basso - Nessuna applicazione disponibile - Con il progetto microG - Impossibile aprire l\'app - Compatibilità - Compatibile: Funziona senza alcun problema - Sconosciuto: Non ancora controllato - Proxy disattivato con successo - %1$d app installate - Usa microG per accedere agli account - Fornito da Plexus - Funziona senza Google Play Services - Imposta - Solo su reti non a consumo - Configura le restrizioni del dispositivo per gli aggiornamenti automatici - Visualizza e gestisci la configurazione del proxy - Potrebbe essere necessario installare la libreria proprietaria di Google o una reimplementazione libera come microG. - Restrizioni degli aggiornamenti automatici - Richiede Google Play Services - Questa applicazione funziona senza la libreria proprietaria di Google. Tuttavia, potrebbe richiedere altre librerie di terze parti per funzionare correttamente. - Controllo della compatibilità in corso… - Disabilita - Senza Google Play Services - Non supportato: incompatibile - Verifica dei file scaricati non riuscita - Effettua l\'autenticazione agli account Google usando microG per semplificare la procedura di accesso - Limitato: Funzionante ma con funzionalità limitate - Versione minima di Android - Ultimo aggiornamento - Download - Fonti delle app - Livello API target - %1$d autorizzazioni - Avanzate - Installa pacchetto microG - Compatibilità delle app - Componenti mancanti - Ho letto e accetto i Termini di servizio e l\'Informativa sulla privacy di microG - Non abbiamo trovare Google Play Services sul tuo dispositivo, molte applicazioni popolari lo richiedono per funzionare correttamente! - microG è un\'implementazione gratuita e open-source che fornisce funzionalità simili per l\'esecuzione di applicazioni che dipendono da Google Play Services per dispositivi Android attraverso una re-implementazione.\n\nmicroG consente alle app di accedere alle API di Google, migliorando la compatibilità per gli utenti e offrendo vantaggi in termini di privacy.\n\nmicroG viene eseguito automaticamente in background quando si aprono applicazioni che dipendono da Google Mobile Services. - Leggi l\'informativa sulla privacy di microG - Leggi la licenza e il l\'accordo di microG - Visita il sito web del progetto microG - Dati che questa app può raccogliere - Lo sviluppatore dice che questa app non raccoglie dati utente. - Dati che questa app può condividere - Lo sviluppatore afferma che questa app non condivide i dati utente con altre aziende o organizzazioni. - Questa versione dell\'app può contenere più tracker non ancora presenti nel database di Exodus Privacy. - %1$d tracker conosciuti in %2$s - L\'installatore MicroG non è riuscito a installare l\'app, probabilmente a causa di una configurazione errata. - Installatore MicroG - Salta - Richiede l\'installazione dell\'app microG companion - Aiuta a bypassare l\'integrità dell\'app (solo installatore) - Il codice di versione può contenere solo cifre - Riavviare per applicare le modifiche? - Nessuna descrizione disponibile - Più info - Compilato per - Nome pacchetto - Valutazione contenuti - Preparazione per l\'installazione - - Autorizzazione richiesta - Autorizzazioni richieste - Autorizzazioni richieste - - Seleziona un\'app per maggiori dettagli - Nessuna pubblicità - Senza Play Services - Caricamento in corso - Pagina %1$d diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 6108d2a83..379ef7bd0 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -52,12 +52,12 @@ Aurora Services 1.0.9以上をインストールするか、インストーラーを変更してください。 Aurora Services が使用可能でインストール準備ができました。 Root 権限がありません。権限を与えるかインストーラーを変更してください。 - 2つ星 - 3つ星 + 2つ星 + 3つ星 高評価 - 1つ星 - 4つ星 - 5つ星 + 1つ星 + 4つ星 + 5つ星 低評価 すべて レポートを見る @@ -172,6 +172,7 @@ Play ストア ダウンロード ブラックリストマネージャー + セール中アプリ ライブラリのアプリ カテゴリ エディターのおすすめ @@ -212,6 +213,7 @@ 要求したバージョン番号は利用できません。 おめでとう!要求したバージョンコードが利用できます。ダウンロード中。 手動ダウンロード + 類似のアプリをアプリ詳細ページに表示する 類似のアプリ ホーム画面におすすめページを表示する おすすめページ @@ -284,15 +286,19 @@ アプリの言語 アプリ設定 Android マーケットは、Android デバイス用にデザインされたソフトウェアアプリケーションを提供するオンラインストアでしたが、2017年に廃止されました。 + プロキシを有効化 評価タイトル プロキシ URL 自動/自己更新の間隔を時間単位で構成します。 Aurora Store アプリのみ + プロキシ プロキシ URL が無効です。形式を確認してください! Aurora Store でインストールしたアプリのみを更新とインストール済みアプリに表示 プロキシの設定に成功しました + 提供: bestappsales.com 自動更新周期 プロキシの設定に失敗しました + アプリからのすべてのトラフィックをプロキシに通す アプリの自動更新 バックグラウンドダウンロード 自動更新の動作を設定する @@ -340,7 +346,7 @@ トークンディスペンサーを Aurora Store に追加します。トークンディスペンサーは、匿名アカウントでログインするための認証情報を Aurora Store に提供します。 不正な URL です ディスペンサーの URL - ディスペンサーを削除しますか? + ディスペンサーを削除 ディスペンサー「%1$s」を削除しますか? 追加 削除 @@ -348,7 +354,11 @@ Google Play のアカウントにログインしてください Aurora Store について Aurora Store の詳細を知る - Aurora Store を使用すると、公式の Google Playストア からアプリの検索やダウンロードができます。アプリの詳細、スクリーンショット、更新、レビューを確認したり、Google Play からデバイスに直接 APK をダウンロードしたりできます。Aurora Store を使用するには、Google Play アカウントが必要であり、Aurora Store を初めて開いたときに Google アカウントでログインする必要があります。 \n \n従来のアプリ ストアとは異なり、Aurora Store はアプリを所有、ライセンス供与、配布しません。Aurora Store のすべてのアプリ、アプリの説明、スクリーンショット、その他のコンテンツは、Google Playストアから直接アクセス、ダウンロード、表示されます。Aurora Store は架け橋やブラウザのように機能し、Google Play アカウントにログインして Google Play からアプリを見つけることができます。 \n \nAurora Store は、Google、Playストア、Aurora Store を通じてダウンロードされたアプリは、アプリ開発者から承認、広告、または許可を受けておらず、また、Aurora Store はそれらと提携、協力、及び関係も一切ありませんのでご了承ください。 + Aurora Store を使用すると、公式の Google Playストア からアプリの検索やダウンロードができます。アプリの詳細、スクリーンショット、更新、レビューを確認したり、Google Play からデバイスに直接 APK をダウンロードしたりできます。Aurora Store を使用するには、Google Play アカウントが必要であり、Aurora Store を初めて開いたときに Google アカウントでログインする必要があります。 +\n +\n従来のアプリ ストアとは異なり、Aurora Store はアプリを所有、ライセンス供与、配布しません。Aurora Store のすべてのアプリ、アプリの説明、スクリーンショット、その他のコンテンツは、Google Play から直接アクセス、ダウンロード、表示されます。Aurora Store は架け橋やブラウザのように機能し、Google Play アカウントにログインして Google Play からアプリを見つけることができます。 +\n +\nAurora Store は、Google、Google Play、Aurora Store を通じてダウンロードされたアプリは、アプリ開発者から承認、広告、または許可を受けておらず、また、Aurora Store はそれらと提携、協力、及び関係も一切ありませんのでご了承ください。 このアプリはこの端末で使用できません 本当にログアウトしますか? 更新を確認 @@ -366,6 +376,7 @@ 開発者が宣言したデータのプライバシーと安全対策 不明なソースからのアプリのインストールを許可 まずインストーラーの権限を付与する必要があります + 権限要求のバグのため、権限を再度付与する必要がある可能性があります アンインストールに成功しました すべてのデータを Proxy 経由で渡すには、有効な Proxy の URL を入力します。 必須 @@ -383,91 +394,4 @@ アプリエクスポート通知 インストール通知 ダウンロード通知 - microG バンドルのインストール - すべて削除 - すべて選択 - このアプリが収集する可能性のあるデータ - 開発者は、このアプリがユーザーデータを収集しないと表明しています。 - このアプリが共有する可能性のあるデータ - デベロッパーによると、このアプリはユーザーデータを他の企業や組織と共有しません。 - このバージョンのアプリには、Exodus Privacyのデータベースにまだ存在しないトラッカーがまだ含まれている可能性があります。 - アカウントについての通知 - もっと - アプリ互換性 - アプリソース - Googleアカウントへのサインイン時にmicroGを使用した認証を行い、よりシンプルなサインインフローを実現します - 認証する必要があります - 自動更新の制限 - 利用可能 - ブラックリストをエクスポートしました! - ブラックリストをインポートしました! - 互換性をチェックしています… - 更新の確認 - 読み込み中 - インド製造%1$s - MicroG インストーラー - 最低限Androidバージョン - 依存関係が不足しています - もっとみる - %1$d 個のトラッカーが %2$s で見つかりました - 最新 - MicroG installer は誤った構成が原因でアプリのインストールに失敗しました。 - 利用可能なアプリはありません - ダウンロード - 最終更新 - ターゲット API レベル - スキップ - microGサービスの利用規約とプライバシーポリシーを読み、同意します - Google Play 開発者サービスがお使いのデバイス上で見つかりませんでした。現在、いくつかの人気アプリが正常に動作するには開発者サービスが必要です! - microG のプライバシーポリシーを読む - microG のライセンスと利用規約を読む - microG プロジェクトのウェブサイトを閲覧する - microG companion アプリがインストールされている必要があります - アプリの整合性チェック(インストーラ限定)のバイパスを補助します - バージョンコードは数字のみが利用できます - ブラックリストのインポートに失敗しました! - ブラックリストのエクスポートに失敗しました! - 変更を適用するために再起動しますか? - 検証中 - アプリのアーカイブを解除するためにはGoogle Play アカウントにログインしてください! - デフォルト - 説明が利用できません - %1$d 個の権限 - ターゲット - パッケージ名 - コンテンツの評価 - アーカイブ解除 - アプリを開けません - Plexus によるデータ - 互換性 - Google Play 開発者サービスが必要です - Google 独自のライブラリ、または microG などの FOSS 再実装をインストールする必要がある場合があります。 - Google Play 開発者サービスなしで動作します - このアプリはGoogle独自のライブラリがなくても動作します。ただし、正常に動作させるには他のサードパーティ製ライブラリが必要になる場合があります。 - microG プロジェクト - Google Play 開発者サービスなし - 互換性: 問題なく動作します - 限定的: 限定された機能で動作します - サポート対象外: 動作しません - 不明: まだチェックされていません - インストール準備中 - - 権限が必要です - - %1$d 個のアプリがインストールされています - アカウントのログインにmicroGを使用する - 設定 - 無効 - プロキシを無効にしました - プロキシ構成の表示と管理 - 自動アップデートのためにデバイス制限を設定する - 定額制ネットワークのみ - デバイスがアイドル時の場合のみ - バッテリー残量が少なくない場合 - ダウンロードしたファイルの検証に失敗しました - 詳細を確認するアプリを選択 - 広告なし - Google Play 開発者サービスなし - %1$d ページ - microGは、Androidデバイス向けにGoogle Play Servicesに依存するアプリを再実装によって動作させる、同様の機能を提供する無料のオープンソース実装です。\n\nmicroGはアプリがこれらのGoogle APIにアクセスすることを可能にし、ユーザーの互換性を高めつつプライバシー上の利点を提供します。\n\nGoogle Mobile Servicesに依存するアプリケーションを開くと、microGはバックグラウンドで自動的に動作します。 diff --git a/app/src/main/res/values-kab/strings.xml b/app/src/main/res/values-kab/strings.xml deleted file mode 100644 index dae6f5f3b..000000000 --- a/app/src/main/res/values-kab/strings.xml +++ /dev/null @@ -1,109 +0,0 @@ - - - Semmet - Sfeḍ - Mdel - Nɣel - Sifeḍ - Kter - Awiki - Bitcoin - Ethereum - F-Droid - GitLab - Liberapay - PayPal - Telegram - Udrig - Google - Tuɣalin - Imsizdigen - Akk - Snes - Ayen nniḍen - S lexlaṣ - Fakk - Anef-as - Sbedd - Isbeddiyen - Yesbedday - Ttekki - Ticki - Uḍfiṛ - Ih - Ldi - Yettraǧu - Ales asekker - Kemmel - Nadi - Bḍu - Kkes asbeddi - Mucceḍ - Aglam - Tansa - Imayl - Asmel Web - Baṭel - S lexlaṣ - Tasiregt - Tabaḍnit - Yettwasemmet - Asiḍen - Akk - Semmus - Ukkuẓ - Yiwen - Kraḍ - Sin - Turagt - Asagen - Taggayin - Ɣef - Imiḍanen - Isnasen - Ibenk - Uraren - Asbeddi - Yettwasbedd - Tutlayt - Iɣewwaren - Ileqman - Leqqayen - Umuɣ - D axetṛan - Taneɣruft - Zgel-it - Amesbedday - Tisirag - Ansuf - Ugar - Rnu - Kkes - Yecceḍ - Yettwasemmet - Immed - Asenqed - Amezwer - Bitcoin Cash - Nɣel aseɣwen - Senser tuqqna - Kkes-iten akk - Fren-iten akk - Leqqem-iten akk - Ahil n Biṭa - Deg-s adellel - Amaɣnu n uneflay - war adellel - Semmet-iten akk - Serǧu-ten akk - Yedda usbeddi akken iwata - Askar n usbeddi - I kečč·kem - Iɣewwaren n wesnas - Play Store - Amesbedday n yesnasen - Ulac aẓeṭṭa - Asumer n unadi - Igmaḍ n unadi - Asader s ufus - diff --git a/app/src/main/res/values-kmr/strings.xml b/app/src/main/res/values-kmr/strings.xml new file mode 100644 index 000000000..dec23477e --- /dev/null +++ b/app/src/main/res/values-kmr/strings.xml @@ -0,0 +1,230 @@ + + + Destûr tune + Ne Bawerî + Bê reklaman + Di derbarê sepanê de bêtir + GSF hewce dike + Belaş + Malper + Profîla Pêşdebir + E-name + Têkiliya pêşdebir + Navnîşan + Terîf + Bawerî + Reklamê Dihewîne + Guherînbar nehatiye peyda kirin + Guhertina guherînê + Tomarbûn dibe ku demek bigire, hûn dikarin paşê rewşa xwe kontrol bikin. + Hûn ê taybetmendî û çewtiyên nû berî raya giştî bibînin. Bersivên xwe bidin pêşdebiran da ku ji wan re baştir bibin. + Bernameya beta beşdarî bibin? + Hûn ceribandina betayê ne + Bernameya Beta + Lîsteya spî + Hemî nûve bikin + Nûve bikin + Agahdariya Sepanê + Rakirin + Parveke + Lê gerrîn + Dîsa vekirin + Dîsa dest pê bikin + Agah + Nexelas + Vekirî + Baş e + Piştî + Derkeve + Terikandin + Kirîna sepanan li ser hesabên Anonîm tune. + Derewa amûrê bi serfirazî hate sepandin. + Destûr hat dayîn + Vebijarkên pêşvebirinê venebû, pê ewle bine ku ew ji mîhengên amûrê hatî çalak kirin. + Li panelê hate kopî kirin + Li lîsteya spî zêde kirin + Di lîsteya reş de ye + Li ser hesabên bênav tune + Nûvekirin + Gerînendeyê hîlekirin + Mîhengên + Dîroka kirînê + Tor tune + Pirtûkxane + Ziman + Sazkerê Sepanê + Saz kirin + Lêkirinî + Lîstik + Dikana Play + Dakêşandin + Cîhaz + Gerînendeyê lîsteya reş + Sepanên firotanê + Sepanên li pirtûkxanê + Sepan û lîstikên min + Sepanên + Hesaban + Derheqê + Tiştên Trend + Pir didin + Kirîna herî mezin + Belaş herî populer + Rêzên jorîn + Ji were + Hilbijartina edîtorê + Kategorî + Piştrast bike ku hûn ji nû ve têkevin navnîşana xapîn + Danişîn xilas bû, ji nû ve têkevin navnîşana nû. + Pel nehatin girtin + Sepan nehat dîtin + Sepan nayê piştgirî kirin + Sepan ne kirî + Barkirin hilneweşe + Xwemalîkirin + Rêbaza sazkirinê + Modeya sazkirinê ya APK hilbijêrin + Sazkerê danişînê + Xizmetên Aurora + Sazkerê root + Sazkerê xwemalî + APK-ê piştî sazkirinê jê bibe + APK dê bi standard werin jêbirin + Fîlterkirin sepanên F-Droid + Sepanên F-Droid-ê ji navnîşên sepanan radike + Destûrê bidin sazkirina sepanan ji Aurora Store + Destûra Sazker + Gerînendeyê Stoka Derve + Ji bo barkirina dakêşanan (APK & OBBs), vesazkirin û vesazkirina amûrê li ser depoya derveyî. + Gihîştina depoya derveyî + Çawa ne\? + Bi xêr hatî + Destûrên + Sazker + Aurora Store destûrên jêrîn hewce dike + Nûvekirina nû heye + Bi vebijarkî hûn dikarin sazkarê Niştimanî hilbijêrin, lê hingê hûn nekarin APK-anên (dabeşkirî) saz bikin, ji ber vê yekê hilbijartin ya we ye. + Ji kerema xwe, optimîzasyonên MIUI-yê nehêlin ku destûrê bidin sazkirinê, nexwe hûn dikarin sazkerê Root an Xizmetan hilbijêrin. + Sazkerê danişînê ji ber Optîmîzasyonên MIUI nikare sepanan saz bike. + MIUI kifş kir! + Mercên karûbar + Lîsans + Destkêşname + Li benda pejirandina bikarhêner e + Bi serfirazî hate saz kirin + Cihê bîranînê têrê nake + APK-ya nederbasdar an xerakirî + Bernameya bêhevde + Pakêta nakokî heye + Nikare danişînê çêbike + Sazkirin hate asteng kirin + Sazker têk çû + Karûbarên Aurora nehatî mîheng kirin. Bawer bikin ku karûbarê çalak e & hemî destûr têne dayîn + Karûbarên Aurora ne sazkirî ye an guhertoyek çewt e (pêdivî ye >= 1.0.9), bi kerema xwe saz bikin an sazkerê biguherînin + Karûbarên Aurora hene û ji bo sazkirinê amade ne. + Root tune, destûra root destnîşan bikin an sazkerê biguherînin. + Du + + Pozîtîf + Yek + Çar + Pênc + Rexneyan + Hemû + Raporê bibînin + şopîner(ên) li dîtin + Kontrolkirina şopîneran… + Piştgirî te ji hêla Exodus + Şopîneran nagire + Texmîn kirin + Vejandina hemîyan + Rêzkirin + Hemiyan rawestînin + Dakêşandin tune + Metadata werdigire + Bi zorê hemî paqij bikin + Dakêşandin têk çû + Hesabkirin + Dakêşandî + Hat betalkirin + Hemî betal bikin + Hûn li ser vê sepanê çi difikirin\? + Paşan + Beşdarbûn + Damezirandin + Sazkirin + Lêkirin + Berçavnegirtin + Destûrdayîn + Pişgirî + Komek Sepanê hilînin + Qedandin + Nirxandin + Pere kirin + Newekhev + GSF girêdayî ye + Dakêşandin + Sepanên bi reklaman + Bikaranîn + Hemî + Parzûnan + Îxrac + Neçalak bike + Lînk Kopî Bikin + Kopî + Girtin + Zelal + Bişûndekirin + Zêdekirin nav Lîsteya Reş + Lîsteya reş + Paş + ji Aurora-yê derkeve + Bikaranîna têketinê + Google + Bênav + Ji bo nîqaş an pêşniyaran mijara Aurora Store XDA bibînin. + Mijara dêw + Ji bo nîqaş an pêşniyaran beşdarî koma Piştgiriya Aurora bibin. + Telegram + Bi PayPal bexş bike + Paypal + Li Liberapay bibin patron + Liberapay + Çavkaniya Aurora Store ji Aurora OSS li GitLab bistînin. + GitLab + Bi rêya F-Droid Firotgeha Aurora bistînin. + F-Droid + Bi Ethereum (ETH) bexş bike + Ethereum + Bi Bitcoin (BTC) bexş bike + Bitcoin + Bi Bitcoin Dirav (BCH) bexş bike + Bitcoin Dirav + Bi riya UPI-yê bexşê bike + BHIM - UPI + Nirxandin û nirxandinan + Taybetî + Destûr + Pere kirin + Nûvekirin tune + Rûpela tê lêgerîn neçalak e + Veavakirina mîhengê bi serneket + Veavakirina amûrê bi serkeftî hate şandin + Çêkirina AAS Token serneket + Nirxandin pêk nehat + Bi serkeftî hate nirxandin + Pîroz be, koda guhertoya ku tê xwestin heye, niha daxe. + Koda guhertoya ku tu dixwazî tune ye. + Bi destan daxe + Ji bo sepandina guhertinan zanibe be ku tu ji nû ve têketiye û sepanê ji nû ve daye destpêkirin. + Komên wekhev û têkildar li ser rûpela hûrgiliyên sepanê nîşan bide + Sepanên wekhev û têkildar + Rûpelên Bo Te li ser dîmendera malê rê bide + Rûpelên Bo Te + Hilpekîna jixweber hilbijêre + Pergal + Torandin + Zêde + Hûn nikarin bi navgîniya Sazkerê Xwecihî sepanên hevgirtî (parvekirî) saz bikin. Sazkerê xwe bi Danişîn, Xizmet an Rehê biguherînin. + Sepaneke lihevhatî nehat dîtin + diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 643756733..4944afa00 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -179,8 +179,11 @@ 세션 설치기 설치 방식 Google Play 버전 + 프록시 켜기 + 앱의 모든 트래픽이 프록시를 통과하도록 허용 프록시 URL 네트워킹 + 프록시 맞춤화 For You 페이지 기본값(장치 구성에서) @@ -196,6 +199,7 @@ 로그인하고 즐기십시오. 내 앱 & 게임 라이브러리의 앱 + 판매 중인 앱 기기 와우! 모두 좋습니다. 블랙리스트 관리자 @@ -207,10 +211,12 @@ 앱스 앱 설정 다운로드 실패됨 + 앱 세부 페이지에서 유사한 및 관련 클러스터 표시 새 분석 요청 홈 화면에 추가 완료건 지우기 구매하지 않은 앱 + 공급자 - bestappsales.com 네트워크 없음 자동 업데이트 작동주기 인기 무료 @@ -364,6 +370,7 @@ 익명 로그인을 위한 토큰 디스펜서를 보고 관리 블랙리스트를 가져올 실패! 대기 중 + 앱을 다시 시작해야 할 수도 있습니다. 권한 부여. 실패함 Google Play 계정으로 로그인하여 앱을 알리십시오! 잘못된 URL @@ -374,6 +381,7 @@ 사용불가 인증 필수 디스펜서 URL + 스토리지 액세스 프레임워크의 버그로 인해 권한을 다시 부여해야 할 수도 있습니다 Dispenser 제거 추가 Aurora Store에 대해 자세히 알아보기 diff --git a/app/src/main/res/values-kw/strings.xml b/app/src/main/res/values-kw/strings.xml deleted file mode 100644 index b945eb151..000000000 --- a/app/src/main/res/values-kw/strings.xml +++ /dev/null @@ -1,154 +0,0 @@ - - - Wiki - Kavos gorthebow rag govynnow govynys yn fenowgh (FAQ), danvonadow prevessa, ha moy - BHIM - UPI - Argevri dres UPI - Bitcoin Cash - Argevri dres Bitcoin Cash (BCH) - Bitcoin - Argevri dres Bitcoin (BTC) - Ethereum - Argevri dres Ethereum (ETH) - F-Droid - Kavos Aurora Store dres F-Droid. - GitLab - Kavos an kod Aurora Store a-dhia Aurora OSS war GitLab. - Liberapay - Bos unn tasek war Liberapay - PayPal - Argevri dres PayPal - Telegram - Omjunya an bagas Aurora Support rag omgussulyansow po profyansow. - XDA Forums - Gweles an neusen XDA Aurora Store rag omgussulyansow po profansyow. - Dihanow - Google - Omgelmi ow devnydhya - Omdhigelmi a-dhia Aurora - War Gamm - Rol-Du - Addya dhe rol-du - Hedhi - Dilea - Degea - Kopia - Kopia gorgevren - Ungallosegi - Esperthi - Ynperthi - Drudh - Sidhlow - Oll - Gweytha - Appys gans argemynnow - Iskargow - Omres dhe GSF - A Bub Sort - Pes - Finsya - Sawya gronn app - Grontya - Grontys - Skonya Aswon - Lea - Lea Gronn microG - Leyansow - Ow Lea - Omjunya - Diwettha - Diberth - Omdhigelmi - Nessa - Da lowr - Ygeri - Ow Gortos - Postya - Remova oll - Peji dielvennans nowydh - Dastalleth - Daskemeres - Hwilas - Dewis oll - Kevrenna - Dislea - Dislea yn sewen - Addya dhe skrin tre - Kedhlow app - Nowedhi - Nowedhi oll - Rol-Gwynn - Towlen beta - Os unn prover beta - Talvosow - Omjunya towlen arbrovel? - Ty a wra gweles nasyow nowydh ha kudynnow dherag an poblek. Dasliva rag gweres an awtours gwellhe. - Omjunyans a wra kemeres termyn meur martesen, ty a yll checkya studh diwettha. - Rol Chanjyow - Rol chanjyow na provys - Kontaynya argemynnow - Medhelweyth Serghek - Deskrifans - Trigva - Kestav awtour - Ebost - Profil awtour - Gwiasva - Heb Kost - Rekwirya GSF - Moy a-dro app - Argemynnow vyth - Par app kavosys vyth - Appys drudh kavosys vyth - Medhelweyth serghek vyth - Grontys vyth - Nowedhyansow kavadow vyth - Pes - Gront - Data may anapp ma kuntel martesen - An awtour leverel an app ma na kuntel data usyer. - Data may an app ma a yll kevrenna - An awtour leverel an app ma na kevrenna data usyer gans kompanis po kowethyansow aral. - Sawder data - Privetter data ha praktisyow sawder disklerys gans an awtour - Privetter - Talvosow ha breusyansow - Titel breusyans - Pyth tybi ty a-dro an app ma? - Hedhi oll - Hedhys - Dilea deu - Iskarg deu - Ow Kalkya - %1$de %2$dm %3$de remenant - %1$d m %2$de remenant - %1$de remenant - Iskarg fyllis - Hedhi oll yn krev - Ow kerghes metadata - Iskargow vyth - Powes oll - Lostys - Daskemeres oll - Ow Dysmygriva - Kontaynya aspioryon aswonys vyth - An versyon ma a\'n app kontaynya martesen moy aspioryon na y\'n sel dherivasow Exodus Privacy. - Ow checkya rag aspioryon… - aspioryon aswonys kavosys yn - Gweles derivas - Oll - Diwettha - Troboyntyel - Pymp - Peswar - Unn - Posedhek - Tri - Dew - Lea Dyghtyer App po chanjya an leyer. - Hedhas gwreythen vyth. Grontya yth po chanjya an leyer. - Shizuku na leys po selys yn da. - Gonisyow Aurora yw kavadow ha kysi rag leyans. - Lea Gonisyow Aurora 1.0.9 po moy, po chanjya an leyer. - Selya Gonisyow Aurora ha grontya oll grontys kynsa. - diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index cbec5c473..34ec402d4 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -151,6 +151,7 @@ Priverstinai išvalyti visus Pristabdyti visus „Jums“ puslapiai + Rodyti programėlės puslapyje panašių ir susijusių programėlių rinkinį Redaktoriaus pasirinkimas Jums Programėlės bibliotekoje @@ -208,6 +209,7 @@ Po įdiegimo ištrinti APK paketus Rodyti pradžios ekrane puslapius „Jums“ Išorinės saugyklos tvarkytuvė + Išparduodamos programėlės Pridėta į juodąjį sąrašą Pridėta į baltąjį sąrašą Naršomas puslapis neprieinamas @@ -215,10 +217,12 @@ Serveris nepasiekiamas %1$s, %2$s, %3$s ir dar %4$d Atsiunčiami papildomi failai, skirti %1$s + Įjungti įgaliotąjį serverį Tikrinti interneto jungiamumą Nepavyko sugeneruoti seanso, klaidos kodas: %1$d Nepavyko sugeneruoti seanso Įgaliotojo serverio URL + Įgaliotasis serveris Pranešimai Yra prieinama nauja %1$s versija Nepavyko importuoti įrenginio konfigūracijos @@ -234,6 +238,7 @@ Valio! Viskas gerai. Įrenginio konfigūracija importuota Programėlės nustatymai + Teikėjas – bestappsales.com Prisijunkite ir mėgaukitės. Įvyko klaida! %1$s, %2$s ir %3$s @@ -241,6 +246,7 @@ Paieškos rezultatai Pranešimai apie atnaujinimus Atsiunčiama • %1$d / %2$d%3$s + Leisti visam interneto duomenų srautui iš programėlės eiti per įgaliotąjį serverį Siųsti pranešimus apie įdiegimo būseną Prieiga negalima! Ar jūs naudojate VPN arba Tor\? Programėlės kalba diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml index 95b9cdbf7..5ddfd9041 100644 --- a/app/src/main/res/values-lv/strings.xml +++ b/app/src/main/res/values-lv/strings.xml @@ -1,6 +1,6 @@ - E-pasta adrese + E-pasts PayPal Liberapay GitLab @@ -19,18 +19,18 @@ Instalācijas Uzstādīt Neņemt vērā - Piešķirta - Piešķirt + Iedots + Dot Reitingi Lejupielādes Lietotnes ar reklāmām Lietot Visi Filtri - Izgūt - Atspējot - Ievietot saiti starpliktuvē - Ievietot starpliktuvē + Eskportēt + Izslēgt + Kopēt saiti + Kopēt Aizvērt Notīrīt Atcelt @@ -41,45 +41,45 @@ Pieteikties ar Google Anonīms - Pievienoties Aurora atbalsta kopai apspriedēm un ieteikumiem. + Pievienojaties Aurora Atbalsta grupai priekš diskusijām vai ieteikumiem. Ziedot ar PayPal - Kļūt par labvēli Liberapay + Kļūstiet par patronu uz Liberapay Iegūt Aurora Store pirmkodu no Aurora OSS GitLab. Tīmekļa vietne Ziedot ar Ethereum (ETH) Ethereum Telegram - Pievienoties beta programmai? + Pievienoties Beta programmai? Publicēt Restartēt Turpināt - Kopīgot + Dalīties Noņemt - Informācija par lietotni + Lietotnes informācija Atjaunināt Atjaunināt visas Beta lietotne Jūs esat Beta testētājs Licence - Maksas + Nopirkta Pabeigt Gaida - Izmaiņu žurnāls + Izmaiņas Satur reklāmas - Izstrādātāja saziņas informācija + Izstrādātāja kontakti Izstrādātāja profils Bezmaksas Vairāk par lietotni Nav reklāmu Nav atļauju Nav atjauninājumu - Maksas + Nopirkta Atļauja Privātums Vērtējumi un atsauksmes Pārtraukt visas Pārtraukts - Lejupielāde pabeigta + Lejupielādēte pabeigta Lejupielāde neizdevās Piespiest notīrīt visas Iegūst metadatus @@ -101,16 +101,17 @@ Nesaderīga lietotne Nederīgs vai bojāts APK Nepietiek atmiņas - Sekmīgi uzstādīta + Veiksmīgi uzstādīta Gaida lietotāja apstiprinājumu Pieejams jauns atjauninājums Uzstādītājs Atļaujas - Laipni lūdzam - Atlasīt noklusējuma cilni - Lapas \"Tev\" - Rādīt lapas \"Tev\" sākuma ekrānā + Laipni lūgti + Izvēlēties noklusējuma lapu + For You lapa + Rādīt For You lapu sākuma ekrānā Līdzīgas un saistītas lietotnes + Rādīt līdzīgas un saistītas lietotnes Lejupielāde neizdevās Top maksas Populāri @@ -129,6 +130,7 @@ Lietotnes Manas lietotnes un spēles Lietotnes bibliotēkā + Lietotnes izpārdošanā Ierīce Lejupielādes Spēles @@ -140,16 +142,16 @@ Nav interneta Pirkumu vēsture Ievietots starpliktuvē - Atļauja piešķirta - Iespējo lietotņu lejupielādi fonā - Lietotnes lejupielāde fonā + Atļauja nodrošināta + Ieslēdz fona lietotņu lejupielādi + Lietotne lejupielādēta fonā Aprēķina - Nākamais + Nākošais Atvērt Labi Aprēķina Ierindots - Nav izmaiņu žurnāla + Nav izmaiņu apraksta Apraksts Adrese Nav lejupielāžu @@ -160,8 +162,8 @@ Aurora Store ir nepieciešamas šādas atļaujas Izkārtojums Pielāgošana - Nevarēja iegūt datnes - Sesija ir beigusies, jāpiesakās no jauna, lai iegūtu jaunu sesiju. + Nevarēja iegūt failus + Sesija ir beigusies, izejiet no lietotnes, lai iegūtu jaunu sesiju. Lietotne nav atrasta Top sadaļas Top bezmaksas @@ -176,7 +178,7 @@ Tev Pievienota izņēmumiem Jānodrošina atkārtota pieteikšanās, lai pielietotu atdarināšanu - Nav superlietotāja piekļuves. Tā ir jāpiešķir vai jānomaina uzstādītājs. + Nav superlietotāja piekļuves. Tā ir jānodrošina vai jānomaina uzstādītājs. Atdarināšanas pārvaldnieks Nodrošina Exodus Privacy Jāuzstāda App Manager vai jānomaina uzstādītājs. @@ -184,14 +186,14 @@ Ir pieejama jauna %1$s versija Redaktora izvēle Neizdevās pieteikties ar Google - Piesakies un izbaudi. + Piesakies un izbaudi! Pārbauda sesiju Ievietots baltajā sarakstā Vā! Viss kārtībā. Tiek sagatavots nepieciešamais… Pēdējā sesija tika atmesta - Aplicina Google sesiju - Jānodrošina atkārtota pieteikšanās un lietotnes atkārtota palaišana, lai pielietotu izmaiņas. + Pārbauda Google sesiju + Jānodrošina atkārtota pieteikšanās un pārsāknēšana, lai pielietotu izmaiņas. Play veikals Papildu Nav pieejams anonīmiem kontiem @@ -200,12 +202,12 @@ Pieprasītā versija nav pieejama. Apsveicam! Pieprasītā versija ir pieejama, tā tagad tiek lejupielādēta. Shizuku nav uzstādīta vai pareizi iestatīta. - Skatīt XDA forums Aurora Store tēmas diskusijas un ieteikumus. + Skatīt apspriedes un ieteikumus Aurora Store XDA pavedienā. BHIM - UPI - XDA forums - Lūgums atspējot MIUI uzlabojumus, lai ļautu uzstādīšanu, pretējā gadījumā var izvēlēties superlietotāja vai pakalpojumu uzstādītāju. + XDA forumi + Lūgums atspējot MIUI uzlabojumus, lai ļaut uzstādīšanu, pretējā gadījumā var izvēlēties superlietotāja vai pakalpojumu uzstādītāju. Nav iespējams uzstādīt apvienotās (sastāvošas no vairākām daļām) lietotnes ar iebūvēto uzstādītāju. Tas ir jānomaina uz sesijas, pakalpojumu vai superlietotāja uzstādītāju. - Saglabāt lietotnes kopumu + Saglabāt lietotnes kopu Dažādi Atkarīgs no GSF Aurora pakalpojumi ir pieejami un gatavi uzstādīšanai. @@ -224,26 +226,26 @@ Atlasīt APK uzstādīšanas veidu Uzstādīšanas veids pieejams atjauninājums - atjauninājumi pieejami + pieejami atjauninājumi Pieejami %1$d atjauninājumi Pieejams %1$d atjauninājums - Ir iespējams izvēlēties arī iebūvēto uzstādītāju, bet tad nevarēs uzstādīt apvienotos (sastāvošus no vairākām daļām) APK, tā ka izvēle ir katra paša ziņā. + Ir iespējams izvēlēties arī iebūvēto uzstādītāju, bet tad nevarēs uzstādīt apvienotos (sastāvošus no vairākām daļām) APK, tā ka izvēle ir paša ziņā. Lejupielādē • %1$d/%2$d%3$s Lejupielādētie APK tiks izdzēsti uzreiz pēc uzstādīšanas Aurora pakalpojumi (novecojuši) Atkarības - Pieteikšanās var aizņemt kādu laiku, stāvokli var pārbaudīt vēlāk. - Nepārbaudīt atjauninājumus lietotnēm, kuras ir uzstādītas no F-Droid + Ievietošana sarakstā var aizņemt kādu laiku, vēlāk var pārbaudīt stāvokli. + Nepārbaudīt atjauninājumus lietotnēm, kuras ir lejupielādētas vai uzstādītas no F-Droid Apturēta • %1$d/%2$d - Būs pieejamas jaunas iespējas un nepilnības pirms laišanas klajā. Atgriezeniskās saites sniegšana izstrādātājiem palīdzēs viņiem veikt uzlabojumus. + Būs pieejamas jaunas iespējas un nepilnības pirms publicēšanas. Sniedzot atgriezenisko saiti izstrādātājiem tiks palīdzēts viņiem veikt uzlabojumus. Nepieciešams GSF Atlicis %1$dh %2$dm %3$ds Atlicis %1$dm %2$ds Atlikušas %1$ds - Vispirms jāuzstāda Aurora pakalpojumi un jāpiešķirt visas atļaujas. + Vispirms jāuzstāda Aurora pakalpojumi un jānodrošina visas atļaujas. Ierīces uzstādījumi ir izgūti Nav atkarību - Nav atrasta neviena atbilstoša lietotne + Atbilstība lietotnei netika atrasta Nebija iespējams izgūt ierīces uzstādījumus Serveris nav pieejams uzturēšanas darbu dēļ Atjauninājumu paziņojumi @@ -261,11 +263,11 @@ Nebija iespējams izveidot AAS piekļuves pilnvaru Ierīces uzstādījumi ir ievietoti Nebija iespējams ievietot ierīces uzstādījumus - Gadījās kļūda! + Gadījās kļūda. Izvēlne Izvērst %1$s • API %2$s - Nepieciešamās atļaujas tika noraidītas. Lūgums piešķirt tās, lai varētu turpināt darbību + Nepieciešamās atļaujas tika noraidītas. Lūgums tās nodrošināt, lai turpinātu darbību Meklēt lietotnes un spēles Piekļuve liegta. Vai tiek izmantots VPN vai Tor\? Meklēšanas iznākums @@ -273,31 +275,35 @@ Neizdevās izveidot sesiju. Kļūdas kods: %1$d Meklēšanas ieteikums Iekšēja kļūda. Lūgums pēc kāda laika mēģināt vēlreiz - Tev ir piemērots piekļuves ierobežojums + Ak vai, piemērots ierobežojums Serveris nav sasniedzams Pārbaudīt interneta savienojumu Lietotnes valoda Neizdevās izveidot sesiju Atļaut Aurora Store atvērt atbalstītās saites Lietotņu saites - Google Play, zināms arī kā Google Play veikals un iepriekš arī kā Android Market. + Google Play, zināms arī kā Google Play Store un agrāk Android Market. Pārbauda jauno sesiju - Android Market bija tiešsaistes veikals, kas piedāvāja lietotnes, kas ir paredzētas Android ierīcēm, tas pārstāja darboties 2017. gadā. + Android Market bija tiešsaistes veikals, kas piedāvāja lietotnes, kas ir paredzētas Android ierīcēm, pārstāja darboties 2017. gadā. Apskata nosaukums + Iespējot starpniekserveri Starpniekservera URL - Norādīt starplaiku stundās starp automātiskajiem atjauninājumiem. - Atsijāt lietotnes no citiem avotiem - Nederīgs starpniekservera URL, pārbaudiet URL struktūras formātu! - Nepārbaudīt atjauninājumus lietotnēm, kuras ir uzstādītas no avotiem ārpus Aurora Store - Starpniekserveris sekmīgi iestatīts + Norādīt starpposmu stundās automātiskajiem un pašatjauninājumiem. + Tikai Aurora Store lietotnes + Starpniekserveris + Nederīgs starpniekservera URL, jāpārbauda pieraksts. + Pārbaudīt atjauninājumus tikai lietotnēm, kuras ir uzstādītas ar Aurora Store + Starpniekserveris veiksmīgi iestatīts Lietotnes iestatījumi + Nodrošinātājs - bestappsales.com Automātisko atjauninājumu biežums Neizdevās iestatīt starpniekserveri + Atļaut visu lietotnes datplūsmu sūtīt caur starpniekserveri Pieprasīt jaunu izvērtējumu Fona lejupielādes Ļaut Aurora Store lejupielādēt un atjaunināt lietotnes fonā Google Play versija - Automātiski atjauninājumi + Automātiski atjaunināt lietotnes Neatjaunināt lietotnes automātiski Pārbaudīt un automātiski uzstādīt pieejamos atjauninājumus Pārbaudīt un ziņot par pieejamajiem atjauninājumiem @@ -305,7 +311,7 @@ Noklusējuma (no ierīces konfigurācijas) Rādīt atjauninājumus nesaderīgām vai atspējotām lietotnēm, kuru uzstādīšana var neizdoties Neizdevās izgūt APK - Jāievada lejupielādējamās versijas kods + Jāievada versijas, kuru vēlies lejupielādēt, kods Ir jautājumi? Atrodi atbildes Pirmkods Atklāj, kas ir iekšā @@ -317,20 +323,20 @@ Nepieciešams uzstādīt Aurora pakalpojumus kā neierobežotu sistēmas lietotni Pilnu iespēju atvērtā pirmkoda pakotņu pārvaldnieks Izmantojot sistēmas API ar adb/superlietotāja tiesībām - Nepieciešams Shizuku vai Sui, jābūt iestatītai un piešķirtai atļaujai + Nepieciešams Shizuku vai Sui, jābūt iestatītai un nodrošinātai atļaujai Pievienot sākuma ekrānam Notīrīt pabeigtās - Rādīt atjauninājumus, kuri var neizdoties + Nesaderīgi atjauninājumi Sesijā balstīts uzstādītājs apkopotiem/sadalītiem APK Nepieciešamas superlietotāja tiesības, atbalsta visas Android versijas. Nolūkā balstīts uzstādītājs, pieejams visās ierīcēs Vispiemērotākais ierīcēm, kurās darbojas par Android 4.4 vecāka versija Nepieciešams Lietotņu pārvaldnieks, jāizmanto adb/saknes stāvoklis, lai uzstādītu, kad ir ieslēgta miui optimizācija - Privātuma pamatnostādnes + Privātuma nosacījumi Vairāk Pārvaldīt savu kontu Viki vietne - Atrast atbildes uz biežāk uzdotajiem jautājumiem (BUJ), sarežģījumu novēršanas soļiem un vēl + Atrodi atbildes uz biežāk uzdotajiem jautājumiem (BUJ), sarežģījumu novēršanas soļiem un vēl Noņem Aurora Store kā ierīces īpašnieka lietotni Pārvaldīt izkliedētājus Notīrīt ierīces īpašnieku @@ -342,60 +348,66 @@ Pievienot pilnvaru izkliedētāju Aurora Store. Pilnvaru izkliedētāji nodrošina Aurora Store ar konta pieteikšanās informāciju, lai pieteiktos anonīmi. Nederīgs URL Izkliedētāja URL - Noņemt izkliedētāju? + Noņemt izkliedētāju Uzzināt vairāk par Aurora Store Noņemt - Aurora Store ļauj meklēt un lejupielādēt lietotnes no Google Play veikala. Ir pieejams lietotņu apraksts, ekrānuzņēmumi, atjauninājumi, citu lietotāju piebildes, kā arī var lejupielādēt ierīcē APK tieši no Google Play. Lai izmantotu Aurora Store, ir nepieciešams Google Play konts, un tajā ir jāpiesakās, kad Aurora Store tiek pirmo reizi atvērta un konfigurēta. \n \nAtšķirībā no ierasta lietotņu veikala, Aurora Store nepieder, nelicencē un neizplata lietotnes. Visas lietotnes un to aprakstam, ekrānuzņēmumiem un citam Aurora Store pieejamajam saturam tiek tieši piekļūts, lejupielādēts un/vai attēlots no Google Play. Aurora Store darbojas kā durvis vai pārlūks, ļaujot pieteikties savā Google Play kontā un atrast Google Play lietotnes. \n \nLūgums ņemt vērā, ka Aurora Store nav nekādas piekrišanas, pabalstītājdarbības vai autorizācijas no Google, Google Play, jebkuras ar Aurora Store starpniecību lejupielādētas lietotnes vai lietotņu izstrādātājiem; tāpat Aurora Store nav nekādas piederības, sadarbības vai sasaistes ar tiem. + Aurora Store ļauj meklēt un lejupielādēt lietotnes no Google Play veikala. Ir pieejams lietotņu apraksts, ekrānuzņēmumi, atjauninājumi, citu lietotāju piebildes, kā arī var lejupielādēt ierīcē APK tieši no Google Play. Lai izmantotu Aurora Store, ir nepieciešams Google Play konts, un tajā ir jāpiesakās, kad Aurora Store tiek pirmo reizi atvērta un konfigurēta. +\n +\nAtšķirībā no ierasta lietotņu veikala, Aurora Store nepieder, nelicencē un neizplata lietotnes. Visas lietotnes un to aprakstam, ekrānuzņēmumiem un citam Aurora Store pieejamajam saturam tiek tieši piekļūts, lejupielādēts un/vai attēlots no Google Play. Aurora Store darbojas kā durvis vai pārlūks, ļaujot pieteikties savā Google Play kontā un atrast Google Play lietotnes. +\n +\nLūgums ņemt vērā, ka Aurora Store nav nekādas piekrišanas, pabalstītājdarbības vai autorizācijas no Google, Google Play, jebkuras ar Aurora Store starpniecību lejupielādētas lietotnes vai lietotņu izstrādātājiem; tāpat Aurora Store nav nekādas piederības, sadarbības vai sasaistes ar tiem. Par Aurora Store - Tas atsauks sesijas uzstādītāja atļauju nemanāmi uzstādīt lietotnes. Turpināt ar ierīces īpašumtiesību notīrīšanu? + Tas atsauks sesijas uzstādītāja atļauju klusām uzstādīt lietotnes. Turpināt ar ierīces īpašumtiesību notīrīšanu? Pievienot Neizdevās izgūt izlasi. Izlase izgūta. Datņu izguvējs Pacietību, izgūst datni - Neizdevās izgūt lietotnes kopumu + Neizdevās izgūt lietotnes kopu Pārbaudīt atjauninājumus Pārsāknēt Aurora Store Nav izlasē pievienotu lietotņu Datu drošība Atļaut lietotņu uzstādīšanu no nezināmiem avotiem Lietotne nav pieejama šajā ierīcē - Vispirms ir nepieciešams piešķirt uzstādīšanas atļauju + Vispirms jānodrošina uzstādīšanas atļauja Nepieciešams Izvēles Neizdevās ievietot izlasi. - Lietotnes kopums sekmīgi izgūts + Lietotnes kopa veiksmīgi izgūta Vai tiešām atteikties? Atteikties? - Sekmīgi noņemta + Veiksmīgi noņemta Lietotņu izlase Izlase ievietota. Aurora Store ir jāpārsāknē, lai pielietotu tikko mainītos iestatījumus Izlasē Izstrādātāja noteikta datu privātuma un drošības prakse + Var būt nepieciešams atkārtoti nodrošināt atļauju krātuves piekļuves ietvara nepilnības dēļ Jāievada derīgs starpniekservera URL, lai sūtītu visus datus caur to. Neizdevās Nepieejams Lejupielādē Atcelts - Pabeigta + Pabeigts Ierindots Lietotnes izgūšanas paziņojums Uzstādīšanas paziņojums Lejupielāžu paziņojums Ar kontu saistīts paziņojums Nepieciešama autentificēšanās - Lūdzu, ieiet savā Google Play kontā, lai atpakotu lietotni! + Lūgums pieteikties savā Google Play kontā, lai atceltu lietotnes arhivēšanu. Pārbauda atjauninājumus Ar %1$s radīta Indijā Noklusējums Pieejams + Var būt nepieciešams pārsāknēt lietotni, lai atspoguļotu nodrošināto atļauju. Noņemt visu Jaunākās - Neizdevās ievietot izņēmumus! + Neizdevās ievietot izņēmumus. Izņēmumi ievietoti. - Izņēmumu saraksts izgūts. - Neizdevās izgūt izņēmumu sarakstu! + Izņēmumi izgūts. + Neizdevās izgūt izņēmumus. Atlasīt visu Apliecina Atcelt arhivēšanu @@ -405,71 +417,14 @@ Saderība Nepieciešami Google Play pakalpojumi Darbojas bez Google Play pakalpojumiem - Šī lietotne darbojas bez Google īpašnieciskās bibliotēkas. Tomēr var būt nepieciešamas citas trešo pušu bibliotēkas, lai tā pienācīgi darbotos. + Šī lietotne darbojas bez Google īpašnieciskās bibliotēkas. Tomēr, var būt nepieciešamas citas trešo pušu bibliotēkas, lai tā pienācīgi darbotos. Ar microG projektu Saderīga: darbojas bez sarežgījumiem Ierobežota: darbojas ar ierobežotām iespējām Neatbalstīta: nedarbojas - Nezināms: vēl nav pārbaudīta + Nezināma: vēl nav pārbaudīta %1$d uzstādītu lietotņu Bez Google Play pakalpojumiem - Var būt nepieciešams uzstādīt Google īpašniecisko bibliotēku vai tās FOSS atveidojumu, piemēram, microG. + Var būt nepieciešams uzstādīt Google īpašnieciskā bibliotēka vai tās FOSS atdarinājums, piemēram, microG. Nav pieejama neviena lietotne - Izmantot microG, lai pieteiktos kontos - Autentificēt ar microG, kad piesakās Google kontos, vienkāršākai pieteikšanās plūsmai - Atspējot - Starpniekserveris sekmīgi atspējots - Apskatīt un pārvaldīt starpniekservera konfigurāciju - Iestatīt - Automātisko atjauninājumu ierobežojumi - Konfigurēt ierīces ierobežojumus automatizētiem atjauninājumiem - Tikai neuzskaitāmos tīklos - Kad ierīce ir dīkstāvē - Kad akumulators nav tukšs - Neizdevās lejupielādēto datņu apliecināšana - Papildu - Lietotnes avots - Mazākā nepieciešamā Android versija - Mērķa API līmenis - Pēdējoreiz atjaunināta - Lejupielādes - %1$d atļaujas - Uzstādīt microG lietotņu kopumu - Lietotņu saderība - Trūkstošas atkarības - Es izlasīju un piekrītu migroG pakalpojumu izmantošanas noteikumiem un privātuma pamatnostādnēm - Mēs ierīcē nevarējām atrast Google Play pakalpojumus, atsevišķas izplatītas lietotnes tagad pieprasa to, lai pienācīgi darbotos. - microG ir brīvs un atvērta pirmkoda īstenojums, kas sniedz līdzīgas iespējas, lai palaistu lietotnes, kas ir atkarīgas no Google Play pakalpojumiem, Android ierīcēm ar atkārtotu ieviešanu.\n\nmicroG sniedz iespēju lietotnēm piekļūt Google API, uzlabojot lietotājiem saderību, vienlaikus sniedzot privātuma ieguvumus. \n\nmicroG tiks fonā palaista automātiski, kad tiks atvērtas lietotnes, kas ir atkarīgas no Google mobilajiem pakalpojumiem. - Lasīt microG privātuma pamatnostādnes - Lasīt microG licenci un vienošanos - Apmeklēt microG projekta tīmekļvietni - Dati, ko šī lietotne var ievākt - Izstrādātājs apgalvo, ka šī lietotne neievāc lietotāju datus. - Dati, ko šī lietotne var kopīgot - Izstrādātājs apgalvo, ka šī lietotne nekopīgo lietotāju datus ar citiem uzņēmumiem vai apvienībām. - Šī lietotnes versija joprojām var saturēt vairāk izsekotāju, kuri vēl nav Exodus Privacy datubāzē. - Atrasts/i %1$d zināms/i izsekotājs/i %2$s - Versijas kods var saturēt tikai ciparus - Nav pieejams apraksts - Vairāk informācijas - Mērķi - Pakotnes nosaukums - Satura novērtējums - Jāatlasa lietotne, lai iegūtu vairāk informācijas - Nav reklāmu - Nav Play pakalpojumu - Gatavojas uzstādīt - - Nepieciešamas atļaujas - Nepieciešama atļauja - Nepieciešamas atļaujas - - MicroG uzstādītājam neizdevās uzstādīt lietotni, visdrīzāk nepareizas konfigurācijas dēļ. - MicroG uzstādītājs - Nepieciešams uzstādīt microG pavadošo lietotni - Palīdz apiet lietotņu veseluma (tikai uzstādītājs) pārbaudi - Notiek ielādēšana - Lapa %1$d - Izlaist - Palaist no jauna, lai pielietotu izmaiņas? diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml new file mode 100644 index 000000000..ded5d25f5 --- /dev/null +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -0,0 +1,260 @@ + + + Gratis + Nettsted + Utviklerprofil + E-post + Utviklerkontakt + Adresse + Kopiert til utklippstavle + Hvitlistet + Svartelistet + Innstillinger + Bibliotek + Språk + Installert + Installasjon + Spill + Nedlastinger + Enhet + Programmer i bibliotek + Mine programmer og spill + Programmer + Kontoer + Om + Kategorier + Aurora-tjenester + Velkommen + Tilganger + Tjenestevilkår + Lisens + Ansvarsfraskrivelse + Ugyldig eller skadet APK + Inkompatibelt program + Kunne ikke starte økt + To + Tre + Positivt + En + Fire + Fem + Kritiske + Alle + Vis rapport + kjente sporer(e) funnet i + Ser etter sporere … + Inneholder ingen kjente sporere + Gjenoppta alt + I kø + Sett alt på pause + Ingen nedlastinger + Henter metadata + Nedlasting mislyktes + Regner ut + Nedlasting fullført + Avbrutt + Avbryt alle + Hva synes du om dette programmet\? + Vurdering og anmeldelser + Personvern + Tilgang + Betalt + Ingen tilganger + Ingen avhengigheter + Ingen reklame + Mer om programmet + Beskrivelse + Avhengigheter + Inneholder reklame + Endringslogg + Du er en betatester + Betaprogram + Hviteliste + Oppgrader + Oppgrader alle + Programinfo + Avinstaller + Del + Søk + Fortsett + Start på ny + Post + Venter + Åpne + OK + Neste + Forlat + Senere + Ta del + Installerer … + Installasjoner + Installer + Ignorer + Innvilget + Innvilg + Fullfør + Vurderinger + Betalt + Ymse + Nedlastinger + Programmer med reklame + Bruk + Alle + Filter + Eksporter + Kopier lenke + Kopier + Lukk + Tøm + Avbryt + Legg til i svartelisten + Svartelist + Tilbake + Logg inn med + Google + Anonym + Utviklingstråd + Telegram + Doner via PayPal + PayPal + Liberapay + GitLab + F-Droid + Doner via Ethereum (ETH) + Ethereum + Doner via Bitcoin (BTC) + Bitcoin + Doner via Bitcoin Cash (BCH) + Bitcoin Cash + Doner via UPI + BHIM - UPI + Gratulerer, ønsket versjonskode er tilgjengelig, lastes ned nå. + Versjonskoden du ber om, er ikke tilgjengelig. + Appkjøp er ikke tilgjengelig på anonyme kontoer. + Tillatelse gitt + Ikke tilgjengelig på anonyme kontoer + Manuell nedlasting + Oppdateringer + Kjøpshistorikk + Ingen nettverk + Apper på salg + Trender + Topp betalt + Bestselgende + Topp gratis + Topplister + For deg + Redaktørens valg + Økten er utløpt, logg inn på nytt for å få en ny økt. + Appen ble ikke funnet + App støttes ikke + Appen er ikke kjøpt + Nedlasting mislyktes + Lignende og relaterte apper + For deg Sider + Nettverk + Installasjonsmetode + Velg modus for APK-installasjon + APK-er blir slettet som standard + Tillat å installere apper fra Aurora Store + Hvordan går det\? + Aurora Store krever følgende tillatelser + Ny oppdatering tilgjengelig + MIUI oppdaget! + Venter på brukerbekreftelse + Installert + Motstridende pakke eksisterer + Installasjonen ble blokkert + Aurora-tjenester er tilgjengelige og klare til å installeres. + Drevet av Exodus + Estimering + Påmelding kan ta litt tid, du kan sjekke status senere. + Du vil se nye funksjoner og feil før offentligheten gjør det. Gi tilbakemelding til utviklere for å hjelpe dem med å forbedre seg. + Bli med i beta-programmet ? + Logg ut + GSF avhengig + Deaktiver + Logg ut fra Aurora + Se Aurora Store-tråden på XDA for diskusjoner eller forslag. + Bli med i Aurora Support-gruppen for diskusjoner eller forslag. + Få kildekoden til Aurora Store fra Aurora OSS på GitLab. + Få Aurora Store via F-Droid. + Ingen oppdateringer tilgjengelig + Ingen app-samsvar funnet + Krever GSF + Endringslogg ikke inkludert + Bli patron på Liberapay + Installer Aurora Services 1.0.9 eller nyere, eller endre installasjonsprogrammet. + Skru på utviklingsinnstillingene fra enhetsinnstillingene for å åpne dem. + Utforskningssiden er utilgjengelig + Enhetslureri i bruk. + Vis lignende og relaterte klynger på appdetaljsiden + Vis For You-sider på startskjermen + Sett opp Aurora-tjenester og innvilg alle tilganger først. + Lureri-håndterer + Logg inn igjen og start programmet igjen for å bruke endringene. + Logg inn igjen for å anvende lureriet + Slett APK etter installering + Installereren mislyktes + Ingen rot-tilgang. Innvilg det eller endre installasjonsmetode. + Tving fjern alt + Kunne ikke eksportere enhetsoppsett + Enhetsoppsett eksportert + Kunne ikke generere AAS-symbol + Kunne ikke sende vurdering + Vurdert + Program-installerer + Svarteliste-håndterer + Kunne ikke hente filer + Fjerner F-Droid-programmer fra programlistene + Ekstra + Håndterer for eksternlagring + Eksporter enhetsoppsett til og fra eksternlagring for å lagre nedlastinger (APK-er og OBB-er). + Play-butikk + Velg forvalgt fane + Oppsett + Tilpasning + Systemspesifikk installerer + Økt-installerer + Rot-installerer + Filtrer F-Droid-programmer + Tilgang for installerer + Tilgang til eksternlagring + Installerer + Du kan ikke installere medfølgende (delte) apper via Native Installer. Endre installasjonsprogrammet til Session, Services eller Root. + Eventuelt kan du velge Native installasjonsprogram, men da kan du ikke installere medfølgende (delte) APK-er, så valget er ditt. + Vennligst deaktiver MIUI-optimaliseringer for å tillate installasjoner, ellers kan du velge Root- eller Services-installasjonsprogram. + Session Installer kan ikke installere apper på grunn av MIUI-optimaliseringer. + Utilstrekkelig minneplass + Lagre programknippe + Last ned bakgrunnsapp + Aktiverer bakgrunnsappnedlasting + AM installatør. + Installer App Manager eller endre installasjonsprogrammet. + Shizuku er enten ikke installert eller satt opp på riktig vis. + %1$s • API %2$s + Bekrefter økt … + Merknader + Kunne ikke importere enhetsoppsett + %1$ds igjen + Tillat Aurora Store å åpne støttede lenker + Forespør ny økt … + Importer + Søkeforslag + Avansert + Meny + %1$dm %2$ds igjen + Programlenker + Bekrefter ny økt … + %1$dt %2$dm %3$ds igjen + Klargjør … + Bekrefter Google-økt … + Utvid + Søkeresultater + Send merknader om installasjonsstatus. + Programspråk + Pause • %1$d / %2$d + Be om nye analyser + Legg til på startskjermem + Laste ned • %1$d / %2$d%3$s + diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 39f5d16d0..3b8f2d9f9 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -16,45 +16,46 @@ Doneer met Bitcoin Cash (BCH) Doneer met Bitcoin (BTC) Doneer met UPI - Geen root-toegang. Sta toe of verander de installatiemethode. + Geen root toegang. Geef het of verander de installateur. Verkrijg de Aurora Store broncode van Aurora OSS op GitLab. Haal de Aurora Store op F-Droid. Top hitlijsten Zoek Overig - Applicatiebundel opslaan - Schakelt achergrondinstallatie in - Achtergrondinstallatie + Applicatie bundel opslaan + Schakelt achergrond app download in + Achtergrond app download Kon aparaatconfiguratie niet exporteren Apparaat configuratie geëxporteerd Kon geen AAS Token genereren Kon beoordeling niet versturen Blader pagina niet beschikbaar - Gefeliciteerd, de aangevraagde versie code is beschikbaar, nu aan het installeren. - De versiecode die je verzoekt is niet beschikbaar. - App aankopen niet beschikbaar op anonieme accounts. - Apparaatvervalsing toegepast. + Gefeliciteerd, de aangevraagde versie code is beschikbaar, nu aan het downloaden. + De versie code die u verzoekt is niet beschikbaar. + App aankopen niet beschikbaar op Anonieme accounts. + Apparaat vervalsing toegepast. Recht toegestaan Schakel ontwikkelaar instellingen in via de apparaatinstellingen om ze te openen. Gekopieerd naar klembord Op witte lijst Niet beschikbaar op anonieme accounts - Vervalsing beheren + Vervals beheerder Instellingen Aankoop geschiedenis Geen netwerk Bibliotheek Taal - App-installatiemethode + App Installateur Geïnstalleerd Installatie Spelletjes Play Store Downloads Apparaat - Zwarte lijst beheren + Zwarte lijst beheerder + Apps op korting Apps in bibliotheek - Mijn apps & spellen + Mijn apps & games Viraal Top betaald Top verdienende @@ -62,62 +63,63 @@ Voor jou Bewerkers keuze Categorieën - Wees zeker dat je opnieuw bent ingelogd en herstart de app om wijzigingen toe te passen. + Wees zeker dat u opnieuw bent ingelogd en herstart app om wijzigingen toe te passen. Wees zeker dat je opnieuw bent ingelogd om de vervalsing toe te passen Sessue verlopen, log opnieuw in om een nieuwe sessie te verkrijgen. Kon bestanden niet ontvangen App niet gevonden App niet ondersteund App niet aangeschaft - Installatie mislukt + Download Mislukt + Toon vergelijkbare en gerelarteerde clusters op app details pagina Vergelijkbare en gerelateerde apps - Pagina met aanbevelingen op thuisscherm tonen - Voor jou pagina\'s - Standaard tabblad selecteren + Toon Voor Jou Pagina\'s op thuisscherm + Voor Jou Pagina\'s + Selecteer standaard tabblad Lay-out Aanpassing Netwerken - Installatiemethode - Modus van APK-installatie selecteren + Installatie methode + Selecteer modus van APK installatie Session installateur - Aurora Diensten (Verouderd) + Aurora Diensten Root installateur - Oorspronkelijke installatie (Verouderd) + Native installateur Verwijder APK na installatie - Gedownloade APK\'s zullen onmiddellijk worden verwijderd na installatie - F-Droid-apps filteren - Niet op updates controleren voor apps geïnstalleerd van F-Droid + APKs worden standaard verwijderd + Filter F-Droid apps + Negeer F-Droid-apps van Updates en Geïnstalleerde apps Extra\'s - Sta installeren van apps met Aurora Store toe - Installatierecht - Beheerder externe opslag - Voor het opslaan van APK-extensiebestanden (OBB\'s) voor grote apps en spellen - Toegang externe opslag - Hoe gaat het met je? + Sta installeren van apps van Aurora Store toe + Installateur Recht + Externe Opslag Beheerder + Voor het opslaan van APK-extensiebestanden (OBB\'s) voor grote apps en games. + Externe Opslag Toegang + Hoe gaat het met u\? Welkom Toestemmingen - Installatiemethode + Installateur Aurora Store vereist de volgende toestemmingen - Je kunt geen gebundelde (gesplitste) applicaties installeren met oorspronkelijke installatiemethode. Verander de installatiemethode naar Sessie, Service of Root. + U kan geen gebundelde(split) applicaties installeren met Native Installer. Verander uw installatiemethode naar Session, Service of Root. Nieuwe update beschikbaar - Optioneel kun je kiezen voor de oorspronkelijke installatiemethode maar dan kun je geen gebundelde (gesplitste) APK\'s installeren. - Schakel alsjeblieft MIUI optimalisatie uit voor het accepteren van installaties, kies anders Root of Service-installatie. - Sessie-installatiemethode kan geen apps installeren door MIUI optimalisaties. + Optioneel kan u kiezen voor de Native installateur, maar dan kan u geen gebundelde (gesplitste) APKs installeren, de keuze is aan u. + Schakel alstublieft MIUI optimalisatie uit voor het accepteren van installaties, kies anders Root of Service installatie. + Session installateur kan geen apps installeren door MIUI Optimalisaties. MIUI gedetecteerd! Servicevoorwaarden Licentie Waarschuwing - Wachten op gebruikersbevestiging + Wachten voor gebruikersbevestiging Succesvol geïnstalleerd - Onvoldoende opslagruimte + Onvoldoende geheugen ruimte Ongeldig of beschadigde APK Incompatibele app Conflicterend packet bestaat Kon geen sessie aanmaken Installatie was geblokkeerd - Installatiemethode mislukt + Installateur gefaald Stel Aurora diensten in en geef als eerst alle toestemmingen. - Installeer Aurora diensten 1.0.9. of hoger, of verander de installatiemethode. + Installeer Aurora diensten 1.0.9. of hoger, of verander de installateur. Aurora diensten zijn beschikbaar en klaar om te installeren. Twee Drie @@ -133,42 +135,42 @@ Mogelijk gemaakt door Exodus Privacy Bevat geen bekende trackers Geschatte - Alles voortzetten + Alle voortzetten In de wachtrij Pauzeer alle Geen installaties Metadata verkrijgen - Alles geforceerd wissen + Forceer verwijder alle Installatie mislukt Aan het berekenen - Geïnstalleerd + Download voltooid Afgebroken Annuleer alle - Wat vind je van deze app? + Wat vind u van deze app\? Beoordeling en beoordelingen Privacy Toestemming Betaald Geen updates beschikbaar Geen toestemmingen - Geen afhankelijkheden + Geen Afhankelijkheden Geen app overeenkomst gevonden Geen advertenties Meer over app Vereist GSF Afhankelijkheden - Bevat advertenties + Bevat Advertenties Niet voorzien van wijzigingslog Wijzigingslog - Inschrijving kan even duren, je kunt de status later bekijken. - Je zal nieuwe functies en fouten zien voordat het publiek het ziet. Geef commentaar aan ontwikkelaars om hen helpen te verbeteren. + Inschrijving kan even duren, u kunt de status later bekijken. + U zal nieuwe functies en fouten zien voordat het publiek het ziet. Geef uw commentaar aan ontwikkelaars om hen helpen te verbeteren. Aanmelden bij bèta-programma? Je bent een bèta tester Bèta-programma Witte lijst Werk alle bij Werk bij - App-informatie + App Informatie Deïnstalleren Deel Hervat @@ -198,7 +200,7 @@ Filters Verzenden Schakel uit - Link kopiëren + Kopieër de link Kopieër Sluit Wis @@ -209,7 +211,7 @@ Google Anoniem Bekijk de Aurora Store XDA pagina voor discussies of suggesties. - Ontwikkelaarsforum + Ontwikkelaarsblad Neem deel aan de Aurora Support groep voor discussies of suggesties. Telegram Doneer met PayPal @@ -224,11 +226,11 @@ Bitcoin Cash BHIM - UPI Verlenen - Beoordeeld, het kan even duren voordat het zichtbaar is + Beoordeeld Handmatige installatie Updates Installeer App Manager of verander de installatiewijze. - AM-installatieprogramma + AM-installatieprogramma. Importeren nog %1$dm %2$ds nog %1$dh %2$dm %3$ds @@ -238,7 +240,7 @@ Sessie verifiëren Google-sessie verifiëren Server buiten gebruik voor werkzaamheden - Aan het installeren • %1$d / %2$d%3$s + Aan het downloaden • %1$d / %2$d%3$s Shizuku is niet geïnstalleerd of niet goed ingesteld. Meldingen Aanmelden via Google mislukt @@ -250,7 +252,7 @@ %1$s, %2$s, %3$s en %4$d more %1$s, %2$s en %3$s %1$s • API %2$s - Meldingen over de status van installaties verzenden + Meldingen voor de status van installaties verzenden Shizuku installatieprogramma Aanmelden en genieten. Wow! Alles goed. @@ -260,215 +262,32 @@ Menu Uitbreiden Vereiste rechten zijn geweigerd. Verleen deze alstublieft om verder te gaan met de actie - Zoeken naar apps & spellen + Zoeken naar Apps & Spellen Nieuwe sessie aanvragen - Extra bestanden installeren voor %1$s + Extra bestanden downloaden voor %1$s Meldingen voor updates %1$d updates beschikbaar Een nieuwere versie van %1$s is beschikbaar %1$s en %2$s Controleer internetconnectiviteit - App-taal + App Taal Aurora Store toestaan om ondersteunde links te openen Zoeksuggestie Zoekresultaten Mislukt bij het ophalen van privacyrapport Server onbereikbaar Sessie genereren mislukt, foutcode: %1$d - Je hebt een limiettarief + Oeps, je bent in snelheid beperkt Toegang geweigerd! Gebruik je een VPN of Tor\? Interne fout! Probeer het opnieuw na enige tijd Sessie kan niet worden gegenereerd Nieuwe sessie verifiëren - App-koppelingen + App koppelingen Google Play, ook bekend als de Google Play Store en voorheen Android Market. Nieuwe analyse aanvragen - Achtergrondinstallaties - Sta Aurora Store toe om apps te installeren en te updaten in de achtergrond + Downloads in achtergrond + Sta Aurora Store toe om apps te downloaden en updaten in de achtergrond Toevoegen aan startpagina Titels beoordelen Verwijder voltooid - Wiki - Gebruikt systeem API\'s direct met adb/root-privileges - Toon updates voor incompatibele of uitgezette apps die mogelijk niet kunnen worden geïnstalleerd - Alles selecteren - Alles verwijderen - Laatste - Account-gerelateerde melding - Wacht even, bestand exporteren - Meld je aan bij je Google Play-account om de app uit het archief te halen! - Intent-gebaseerde installatiemethode, beschikbaar op alle apparaten - Vereist Shizuku of Sui, moet worden ingesteld en toestemming moet worden verleend - Weet je zeker dat je bent afgemeld? - Mogelijk moet je de eigen bibliotheek van Google of een FOSS-herimplementatie zoals microG installeren. - Sta installeren van apps vanuit onbekende bronnen - App niet beschikbaar voor jouw apparaat - Je moet eerst het installatierecht toestaan - Sessie-gebaseerde installatiemethode voor gebundelde/gesplitste APK\'s - Installatiemethode voor achtergrondinstallaties - Volledig uitgeruste open bron pakketbeheerder - Vind antwoorden op veelgestelde vragen (FAQ), stappen voor probleemoplossing en meer - Voer versiecode in die je wilt installeren - Wil je de distributeur verwijderen \"%1$s\"? - Favoriet - Meld je aan bij je Google Play-account - Meest geschikt voor apparaten met Android lager dan 4.4 - Vereist root/superuser privileges, ondersteund alle Androidversies - Beheer je account - Dit zal de toestemming van de sessie-installatiemethode intrekken om stilletjes de app te installeren. Doorgaan met het vrijmaken van eigendomsrecht? - Shell-gebaseerde installatiemethode, gebruikt root-toegang - Vereist Aurora Diensten om geïnstaleerd te worden als vertrouwelijke systeemapp - Succesvol geïnstalleerd - Geen favoriete apps gevonden - Niet op updates controleren voor de apps geïnstalleerd van bronnen buiten Aurora Store - Leer hoe Aurora Store je gegevens gebruikt - Aanbevolen, ingebouwd en ondersteund alle Androidversies - Vereist App Manager, gebruikt adb/root modus om te installeren als miui-optimalisatie aan staat - Installatiemelding - Gegevensveiligheid - Privacy van gegevens en veiligheidstoepassingen verklaard door de ontwikkelaar - Controleer & installeer beschikbare updates automatisch - Incompatibele updates tonen - Proxy-URL - Proxy succesvol ingesteld - Google Play-versie - App-export melding - Installeren - App-instellingen - Standaard (van apparaatconfiguraties) - Voer een geldige proxy-URL in om alle gegevens via de proxy te sturen. - Favoriete apps - Ongeldige proxy-URL, controleer indeling! - Melding met downloads - Apps van andere bronnen filteren - APK\'s exporteren mislukt - Broncode - Over Aurora Store - Geen distributeurs beschikbaar - Ondek wat erin zit - Optioneel - Geen apps beschikbaar - Leer meer over Aurora Store - Distributeur toevoegen - Controleer & stuur melding voor beschikbare updates - Stel het tijdsinterval voor automatische updates in, in uren - Apps niet automatisch updaten - Gemaakt met %1$s in India - Vereist - Android Market was een online winkel die softwareapplicaties voor Android-apparaten aanbood. Deze winkel is sinds 2017 niet meer beschikbaar. - Proxy instellen mislukt - Apparaateigenaar wissen - Automatische updates - Configureer gedrag van automatische updates - Frequentie van automatische updates - Vragen? Ontdek de antwoorden - Meer - Distributeurs beheren - Privacybeleid - Verantwoording - Verwijderd Aurora Store als de appparaateigenaar-app - Distributeur-URL - Distributeur verwijderen? - Ongeldige URL - Distributeurs voor anonieme aanmeldingen bekijken en beheren - Uit archief halen - Mislukt - Deze app werkt zonder Google\'s eigen bibliotheek. Echter kan het nog steeds andere bibliotheken van derden nodig hebben om goed te werken. - Zwarte lijst geëxporteerd! - Bestands-exporteerder - Appbundel succesvol geëxporteerd - Aurora Store opnieuw opstarten - Aurora Store moet opnieuw worden opgestart om de instellingen toe te passen - Authenticatie vereist - Verwijderen - Favorieten exporteren mislukt! - Favorieten geïmporteerd! - Favorieten geëxporteerd! - Zwarte lijst importeren mislukt! - Zwarte lijst exporteren mislukt! - Zwarte lijst geïmporteerd! - Afmelden? - Controleren op updates - Geannuleerd - Voltooid - Onbeschikbaar - Verifiëren - Standaard - Beschikbaar - Kan app niet openen - Met microG project - Zonder Google Play Services - Compatibel: Werkt zonder problemen - Beperkt: Werkt met beperkte functies - %1$d apps geïnstalleerd - Aangedreven door Plexus - Compatibiliteit controleren… - Compatibiliteit - Vereist Google Play Services - Werkt zonder Google Play Services - Niet ondersteund: Niet functioneel - Onbekend: Nog niet gecontroleerd - Favorieten importeren mislukt! - Op updates controleren - In de wachtrij - Gebruik microG om accounts aan te melden - Authenticeer met microG tijdens het aanmelden van Google-accounts voor een vloeiendere inlogervaring - Appbundel exporteren mislukt - Toevoegen - Voeg een distributeur toe aan Aurora Store. Distributeurs bieden accountgegevens aan om anoniem aan te melden. - Proxy succesvol uitgeschakeld - Beperkingen automatische updates - Instellen - Configureer apparaatbeperkingen voor automatische updates - Alleen op ongelimiteerde netwerken - Uitschakelen - Bekijk en beheer proxyconfiguratie - Als het apparaat inactief is - Als de batterij niet laag is - Gedownloade bestanden verifiëren mislukt - Met Aurora Store kunt u apps zoeken en downloaden uit de officiële Google Play Store. U kunt app-beschrijvingen, screenshots, updates en reacties van andere gebruikers bekijken en de APK rechtstreeks vanuit Google Play naar uw apparaat downloaden. Om Aurora Store te gebruiken moet u een Google Play-account hebben en inloggen op uw Google Play-account wanneer u Aurora Store voor het eerst opent en configureert.\n\nIn tegenstelling tot een traditionele app store bezit, licentieert of distribueert Aurora Store geen apps. Alle apps, app-beschrijvingen, screenshots en andere content in Aurora Store worden rechtstreeks geopend, gedownload en/of weergegeven via Google Play. Aurora Store werkt precies zoals een deur of een browser, waarmee u kunt inloggen op uw Google Play-account en de apps vanuit Google Play kunt vinden.\n\nHoud er rekening mee dat Aurora Store geen goedkeuring, sponsoring of autorisatie heeft van Google, Google Play, apps die via Aurora Store zijn gedownload of app-ontwikkelaars; Aurora Store heeft ook geen enkele band, samenwerking of connectie met hen. - Geavanceerd - App-bron - Downloads - Beoogd API-niveau - Laatst bijgewerkt - Minimale Androidversie - %1$d rechten - microG-pakket installeren - App-compatibiliteit - Ontbrekende afhankelijkheden - Ik heb de microG-servicevoorwaarden en het privacybeleid gelezen en ga hiermee akkoord - We konden Google Play Services niet op je apparaat vinden. Verscheidende populaire apps hebben het tegenwoordig nodig om goed te kunnen functioneren! - microG is een gratis en open-source-implementatie die vergelijkbare functionaliteit biedt voor het uitvoeren van apps die afhankelijk zijn van Google Play Services voor Android-apparaten via herimplementatie.\n\nMicroG stelt apps in staat toegang te krijgen tot die Google API\'s, wat de compatibiliteit voor gebruikers verbetert en tegelijkertijd privacyvoordelen biedt.\n\nMicroG wordt automatisch op de achtergrond uitgevoerd wanneer je apps opent die afhankelijk zijn van Google Mobile Services. - Privacybeleid van microG lezen - Licentieovereenkomst van microG lezen - microG-projectwebsite bezoeken - Gegevens die deze app kan verzamelen - De ontwikkelaar zegt dat deze app geen gebruikersgegevens verzamelt. - Gegevens die deze app mogelijk deelt - De ontwikkelaar zegt dat deze app geen gebruikersgegevens deelt met andere bedrijven of organisaties. - Deze versie van de app kan meer trackers bevatten die nog niet in de databank van Exodus Privacy aanwezig zijn. - %1$d bekende tracker(s) gevonden in %2$s - Geen beschrijving beschikbaar - Meer informatie - Doel-API - Pakketnaam - Inhoudsbeoordeling - Selecteer een app om meer details te bekijken - Geen advertenties - Geen play services - Versiecode mag alleen cijfers bevatten - Voorbereiden om te installeren - - Recht vereist - Rechten vereist - - Page %1$d - MicroG-installateur kon de app niet installeren, waarschijnlijk vanwege een verkeerde configuratie. - MicroG-installateur - Overslaan - Vereist installatie van microG Companion app - Hiermee kun je de app-integriteitscontrole omzeilen (alleen voor installatieprogramma\'s) - Bezig met laden - Herstarten om wijzigingen toe te passen? diff --git a/app/src/main/res/values-pa/strings.xml b/app/src/main/res/values-pa/strings.xml index 60b78b5b6..ba768d85e 100644 --- a/app/src/main/res/values-pa/strings.xml +++ b/app/src/main/res/values-pa/strings.xml @@ -35,6 +35,7 @@ ਡਾਊਨਲੋਡਸ ਡਿਵਾਈਸ ਬਲੈਕ ਲਿਸਟ ਮੈਨੇਜਰ + ਸੇਲ ਵਾਲੇ ਐਪਸ ਦੀ ਸੂਚੀ ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚ ਐਪਸ ਮੇਰੇ ਐਪਸ ਤੇ ਗੇਮਜ਼ ਐਪਸ @@ -55,6 +56,7 @@ ਐਪ ਸਪੋਰਟਡ ਨਹੀਂ ਇਹ ਐਪ ਅਜੇ ਤੁਹਾਡੇ ਵਲੋਂ ਖਰੀਦਿਆ ਨਹੀਂ ਗਿਆ ਡਾਊਨਲੋਡ ਫੇਲ੍ਹ + ਐਪ ਜਾਣਕਾਰੀ ਵਾਲੇ ਪੇਜ ਤੇ ਇਸੇ ਸ਼੍ਰੇਣੀ ਦੇ ਕੁੱਝ ਹੋਰ ਐਪਸ ਵਾਲਾ ਖ਼ਾਨਾ ਵਿਖਾਓ ਇਸੇ ਸ਼੍ਰੇਣੀ ਦੇ ਕੁੱਝ ਹੋਰ ਐਪਸ ਖਾਸ ਤੁਹਾਡੇ ਲਈ ਚੁਣੇ ਹੋਏ ਐਪਸ ਵਾਲਾ ਪੰਨਾ ਵਿਖਾਓ ਤੁਹਾਡੇ ਲਈ ਚੁਣੇ ਹੋਏ ਐਪਸ @@ -288,11 +290,15 @@ ਸਿਰਫ਼ ਔਰੋਰਾ ਸਟੋਰ ਐਪਸ ਅੱਪਡੇਟਸ ਅਤੇ ਇੰਸਟਾਲ ਐਪ ਟੈਬ ਵਿੱਚ ਸਿਰਫ਼ ਔਰੋਰਾ ਸਟੋਰ ਇੰਸਟਾਲ ਐਪਾਂ ਵਿਖਾਓ ਐਪ ਸੈਟਿੰਗਾਂ + ਪ੍ਰੋਵਾਈਡਰ - bestappsales.com ਆਟੋਮੈਟਿਕ ਅੱਪਡੇਟ ਆਵ੍ਰਿਤੀ + ਪ੍ਰੌਕਸੀ ਚਾਲੂ ਕਰੋ ਪ੍ਰੌਕਸੀ URL + ਪ੍ਰੌਕਸੀ ਅਵੈਧ ਪ੍ਰੌਕਸੀ URL, ਫਾਰਮੈਟ ਦੀ ਜਾਂਚ ਕਰੋ! ਪ੍ਰੌਕਸੀ ਸਫਲਤਾਪੂਰਵਕ ਸੈੱਟ ਕੀਤੀ ਗਈ ਪ੍ਰੌਕਸੀ ਸੈੱਟ ਕਰਨ ਵਿੱਚ ਅਸਫਲ + ਐਪ ਤੋਂ ਸਾਰੇ ਟ੍ਰੈਫਿਕ ਨੂੰ ਪ੍ਰੌਕਸੀ ਰਾਹੀਂ ਜਾਣ ਦਿਓ ਪੂਰਵ-ਨਿਰਧਾਰਤ (ਡਿਵਾਈਸ ਸੰਰਚਨਾ ਤੋਂ) ਗੂਗਲ ਪਲੇ ਸੰਸਕਰਣ ਬੈਕਗ੍ਰਾਊਂਡ ਡਾਊਨਲੋਡ @@ -338,7 +344,11 @@ ਕਿਰਪਾ ਕਰਕੇ ਆਪਣੇ Google Play ਖਾਤੇ ਵਿੱਚ ਲੌਗ ਇਨ ਕਰੋ ਐਪ ਤੁਹਾਡੇ ਡਿਵਾਈਸ ਲਈ ਉਪਲਬਧ ਨਹੀਂ ਹੈ ਔਰੋਰਾ ਸਟੋਰ ਬਾਰੇ ਹੋਰ ਜਾਣੋ - ਔਰੋਰਾ ਸਟੋਰ ਤੁਹਾਨੂੰ ਅਧਿਕਾਰਤ ਗੂਗਲ ਪਲੇਅ ਸਟੋਰ ਤੋਂ ਐਪਸ ਨੂੰ ਖੋਜਣ ਅਤੇ ਡਾਊਨਲੋਡ ਕਰਨ ਦੇ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ। ਤੁਸੀਂ ਐਪ ਦੇ ਵਰਣਨ, ਸਕਰੀਨਸ਼ਾਟਸ, ਅੱਪਡੇਟਾਂ, ਹੋਰ ਉਪਭੋਗਤਾਵਾਂ ਦੀਆਂ ਟਿੱਪਣੀਆਂ ਦੀ ਜਾਂਚ ਕਰ ਸਕਦੇ ਹੋ, ਅਤੇ ਏਪੀਕੇ ਨੂੰ ਸਿੱਧੇ Google Play ਤੋਂ ਆਪਣੀ ਡਿਵਾਈਸ \'ਤੇ ਡਾਊਨਲੋਡ ਕਰ ਸਕਦੇ ਹੋ। Aurora ਸਟੋਰ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ, ਤੁਹਾਡੇ ਕੋਲ ਇੱਕ Google Play ਖਾਤਾ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ, ਅਤੇ ਜਦੋਂ ਤੁਸੀਂ ਪਹਿਲੀ ਵਾਰ Aurora ਸਟੋਰ ਖੋਲ੍ਹਦੇ ਅਤੇ ਸੰਰਚਿਤ ਕਰਦੇ ਹੋ ਤਾਂ ਆਪਣੇ Google Play ਖਾਤੇ ਵਿੱਚ ਲੌਗ ਇਨ ਕਰੋ। \n \nਪਰੰਪਰਾਗਤ ਐਪ ਸਟੋਰ ਦੇ ਉਲਟ, Aurora ਸਟੋਰ ਕਿਸੇ ਵੀ ਐਪ ਦਾ ਮਾਲਕ ਨਹੀਂ, ਲਾਇਸੰਸ ਜਾਂ ਐਪਾਂ ਵੰਡਦਾ ਨਹੀਂ ਹੈ। Aurora ਸਟੋਰ ਵਿੱਚ ਸਾਰੀਆਂ ਐਪਾਂ, ਐਪ ਵਰਣਨ, ਸਕ੍ਰੀਨਸ਼ਾਟ ਅਤੇ ਹੋਰ ਸਮੱਗਰੀ ਸਿੱਧੇ ਤੌਰ \'ਤੇ Google Play ਤੋਂ ਐਕਸੈਸ ਕੀਤੀ ਜਾਂਦੀ ਹੈ, ਡਾਊਨਲੋਡ ਕੀਤੀ ਜਾਂਦੀ ਹੈ ਅਤੇ/ਜਾਂ ਪ੍ਰਦਰਸ਼ਿਤ ਹੁੰਦੀ ਹੈ। Aurora Store ਬਿਲਕੁਲ ਦਰਵਾਜ਼ੇ ਜਾਂ ਬ੍ਰਾਊਜ਼ਰ ਵਾਂਗ ਕੰਮ ਕਰਦਾ ਹੈ, ਜਿਸ ਨਾਲ ਤੁਸੀਂ ਆਪਣੇ Google Play ਖਾਤੇ ਵਿੱਚ ਲੌਗਇਨ ਕਰ ਸਕਦੇ ਹੋ ਅਤੇ Google Play ਤੋਂ ਐਪਸ ਲੱਭ ਸਕਦੇ ਹੋ। \n \nਕਿਰਪਾ ਕਰਕੇ ਨੋਟ ਕਰੋ ਕਿ Aurora Store ਕੋਲ Google, Google Play, Aurora Store ਜਾਂ ਕਿਸੇ ਵੀ ਐਪ ਡਿਵੈਲਪਰ ਦੁਆਰਾ ਡਾਊਨਲੋਡ ਕੀਤੇ ਗਏ ਕਿਸੇ ਵੀ ਐਪ ਤੋਂ ਕੋਈ ਪ੍ਰਵਾਨਗੀ, ਸਪਾਂਸਰਸ਼ਿਪ ਜਾਂ ਅਧਿਕਾਰ ਨਹੀਂ ਹੈ; ਨਾ ਹੀ Aurora ਸਟੋਰ ਦੀ ਉਹਨਾਂ ਨਾਲ ਕੋਈ ਮਾਨਤਾ, ਸਹਿਯੋਗ ਜਾਂ ਸਬੰਧ ਹੈ। + ਔਰੋਰਾ ਸਟੋਰ ਤੁਹਾਨੂੰ ਅਧਿਕਾਰਤ ਗੂਗਲ ਪਲੇਅ ਸਟੋਰ ਤੋਂ ਐਪਸ ਨੂੰ ਖੋਜਣ ਅਤੇ ਡਾਊਨਲੋਡ ਕਰਨ ਦੇ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ। ਤੁਸੀਂ ਐਪ ਦੇ ਵਰਣਨ, ਸਕਰੀਨਸ਼ਾਟਸ, ਅੱਪਡੇਟਾਂ, ਹੋਰ ਉਪਭੋਗਤਾਵਾਂ ਦੀਆਂ ਟਿੱਪਣੀਆਂ ਦੀ ਜਾਂਚ ਕਰ ਸਕਦੇ ਹੋ, ਅਤੇ ਏਪੀਕੇ ਨੂੰ ਸਿੱਧੇ Google Play ਤੋਂ ਆਪਣੀ ਡਿਵਾਈਸ \'ਤੇ ਡਾਊਨਲੋਡ ਕਰ ਸਕਦੇ ਹੋ। Aurora ਸਟੋਰ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ, ਤੁਹਾਡੇ ਕੋਲ ਇੱਕ Google Play ਖਾਤਾ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ, ਅਤੇ ਜਦੋਂ ਤੁਸੀਂ ਪਹਿਲੀ ਵਾਰ Aurora ਸਟੋਰ ਖੋਲ੍ਹਦੇ ਅਤੇ ਸੰਰਚਿਤ ਕਰਦੇ ਹੋ ਤਾਂ ਆਪਣੇ Google Play ਖਾਤੇ ਵਿੱਚ ਲੌਗ ਇਨ ਕਰੋ। +\n +\nਪਰੰਪਰਾਗਤ ਐਪ ਸਟੋਰ ਦੇ ਉਲਟ, Aurora ਸਟੋਰ ਕਿਸੇ ਵੀ ਐਪ ਦਾ ਮਾਲਕ ਨਹੀਂ, ਲਾਇਸੰਸ ਜਾਂ ਐਪਾਂ ਵੰਡਦਾ ਨਹੀਂ ਹੈ। Aurora ਸਟੋਰ ਵਿੱਚ ਸਾਰੀਆਂ ਐਪਾਂ, ਐਪ ਵਰਣਨ, ਸਕ੍ਰੀਨਸ਼ਾਟ ਅਤੇ ਹੋਰ ਸਮੱਗਰੀ ਸਿੱਧੇ ਤੌਰ \'ਤੇ Google Play ਤੋਂ ਐਕਸੈਸ ਕੀਤੀ ਜਾਂਦੀ ਹੈ, ਡਾਊਨਲੋਡ ਕੀਤੀ ਜਾਂਦੀ ਹੈ ਅਤੇ/ਜਾਂ ਪ੍ਰਦਰਸ਼ਿਤ ਹੁੰਦੀ ਹੈ। Aurora Store ਬਿਲਕੁਲ ਦਰਵਾਜ਼ੇ ਜਾਂ ਬ੍ਰਾਊਜ਼ਰ ਵਾਂਗ ਕੰਮ ਕਰਦਾ ਹੈ, ਜਿਸ ਨਾਲ ਤੁਸੀਂ ਆਪਣੇ Google Play ਖਾਤੇ ਵਿੱਚ ਲੌਗਇਨ ਕਰ ਸਕਦੇ ਹੋ ਅਤੇ Google Play ਤੋਂ ਐਪਸ ਲੱਭ ਸਕਦੇ ਹੋ। +\n +\nਕਿਰਪਾ ਕਰਕੇ ਨੋਟ ਕਰੋ ਕਿ Aurora Store ਕੋਲ Google, Google Play, Aurora Store ਜਾਂ ਕਿਸੇ ਵੀ ਐਪ ਡਿਵੈਲਪਰ ਦੁਆਰਾ ਡਾਊਨਲੋਡ ਕੀਤੇ ਗਏ ਕਿਸੇ ਵੀ ਐਪ ਤੋਂ ਕੋਈ ਪ੍ਰਵਾਨਗੀ, ਸਪਾਂਸਰਸ਼ਿਪ ਜਾਂ ਅਧਿਕਾਰ ਨਹੀਂ ਹੈ; ਨਾ ਹੀ Aurora ਸਟੋਰ ਦੀ ਉਹਨਾਂ ਨਾਲ ਕੋਈ ਮਾਨਤਾ, ਸਹਿਯੋਗ ਜਾਂ ਸਬੰਧ ਹੈ। ਕੀ ਤੁਸੀਂ ਡਿਸਪੈਂਸਰ \"%1$s\" ਨੂੰ ਹਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ? ਅਗਿਆਤ ਲੌਗਿਨ ਲਈ ਟੋਕਨ ਡਿਸਪੈਂਸਰ ਵੇਖੋ ਅਤੇ ਪ੍ਰਬੰਧਿਤ ਕਰੋ ਕੋਈ ਡਿਸਪੈਂਸਰ ਉਪਲਬਧ ਨਹੀਂ ਹੈ @@ -371,6 +381,7 @@ ਡਾਟਾ ਸੁਰੱਖਿਆ ਡਿਵੈਲਪਰ ਦੁਆਰਾ ਘੋਸ਼ਿਤ ਡਾਟਾ ਗੋਪਨੀਯਤਾ ਅਤੇ ਸੁਰੱਖਿਆ ਅਮਲ ਅਗਿਆਤ ਸਰੋਤਾਂ ਤੋਂ ਐਪਸ ਇੰਸਟਾਲ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ + ਸਟੋਰੇਜ਼ ਐਕਸੈਸ ਫਰੇਮਵਰਕ ਵਿੱਚ ਬੱਗ ਦੇ ਕਾਰਨ ਤੁਹਾਨੂੰ ਅਨੁਮਤੀ ਨੂੰ ਦੁਬਾਰਾ ਦੇਣਾ ਪੈ ਸਕਦਾ ਹੈ ਵਿਕਲਪਿਕ ਲੋੜੀਂਦੀ ਅੱਪਡੇਟ ਲਈ ਚੈੱਕ ਕਰੋ diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 74cbe3bca..cf1ecec85 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -24,7 +24,7 @@ Biała lista Aktualizuj wszystkie Aktualizuj - Informacje o aplikacji + O aplikacji Odinstaluj Udostępnij Szukaj @@ -112,6 +112,7 @@ Pobrane Urządzenie Menedżer czarnej listy + Aplikacje na wyprzedaży Aplikacje w bibliotece Moje gry i aplikacje Aplikacje @@ -140,14 +141,14 @@ Usuń APK po zainstalowaniu Pobrany plik APKs zostanie usunięty zaraz po zakończonej instalacji Filtruj aplikacje F-Droid - Nie sprawdzaj aktualizacji dla aplikacji zainstalowanych z F-Droid + Nie sprawdzaj aktualizacji dla aplikacji pobranych lub zainstalowanych z F-Droid Instalacja Metoda instalacji Dostosowywanie Zezwól na instalowanie aplikacji z Aurora Store Uprawnienia instalatora Menedżer pamięci zewnętrznej - Do zapisu rozszerzeń APK (plików OBB) dla dużych gier i aplikacji + Do zapisu rozszerzeń APK (plików OBB) dla dużych gier i aplikacji. Dostęp do pamięci zewnętrznej Uprawnienia Aurora Store wymaga następujących uprawnień @@ -157,7 +158,7 @@ Dostępna jest nowa aktualizacja Instalator sesji nie może zainstalować aplikacji z powodu Optymalizacji MIUI. Wykryto MIUI! - Warunki świadczenia usługi + Warunki korzystania z usługi Licencja Zrzeczenie się odpowiedzialności Czekam na potwierdzenie użytkownika @@ -169,8 +170,8 @@ Nie można utworzyć sesji Instalacja zablokowana Instalacja nieudana - Skonfiguruj Usługi Aurora i przyznaj wszystkie uprawnienia. - Zainstaluj Usługi Aurora w wersji 1.0.9 lub wyższej albo zmień instalator. + Skonfiguruj usługi Aurora i przyznaj wszystkie uprawnienia. + Zainstaluj usługi Aurora w wersji 1.0.9 lub wyższej albo zmień instalator. Usługi Aurora są dostępne i gotowe do instalacji. Brak dostępu do roota. Przyznaj go lub zmień instalator. Zainstalowane @@ -211,6 +212,7 @@ Dodatkowe Strony dla Ciebie Wyświetl strony Dla Ciebie na ekranie głównym + Wyświetl grupy podobnych i powiązanych na stronie szczegółów aplikacji Aplikacje podobne i powiązane Wybierz domyślną kartę Układ @@ -270,7 +272,7 @@ Podpowiedzi wyszukiwania Odmowa dostępu! Czy używasz VPN lub Tor\? Błąd wewnętrzny! Spróbuj ponownie później - Masz ograniczoną liczbę żądań + Ups, masz ograniczoną liczbę żądań Serwer jest niedostępny Nie udało się wygenerować sesji, kod błędu: %1$d Wyniki wyszukiwania @@ -284,28 +286,32 @@ Weryfikowanie nowej sesji Android Market był sklepem internetowym oferującym aplikacje przeznaczone na urządzenia z systemem Android, wycofanym w 2017 roku. Tytuł recenzji - Skonfiguruj częstotliwość automatycznych aktualizacji (w godzinach) - Filtruj aplikacje z innych źródeł + Dostawca - bestappsales.com + Skonfiguruj częstotliwość samoaktualizacji oraz automatycznych aktualizacji (w godzinach) + Tylko aplikacje Aurora Store Ustawienia aplikacji Częstotliwość automatycznych aktualizacji + Włącz proxy Adres URL serwera proxy + Proxy Nieprawidłowy adres URL serwera proxy, sprawdź format! Ustawiono serwer proxy Nie udało się ustawić serwera proxy - Nie sprawdzaj aktualizacji dla aplikacji zainstalowanych ze źródeł innych niż Aurora Store + Zezwól, aby cały ruch z aplikacji przechodził przez serwer proxy + Sprawdzaj aktualizacje tylko dla aplikacji zainstalowanych przez Aurora Store Domyślna (z konfiguracji urządzenia) Wersja Google Play Pobieranie w tle Zezwól Aurora Store na pobieranie i aktualizowanie aplikacji w tle - Automatyczne aktualizacje + Automatyczna aktualizacja aplikacji Sprawdź i powiadom o dostępnych aktualizacjach Nie aktualizuj automatycznie aplikacji Skonfiguruj zachowanie automatycznych aktualizacji Sprawdź i automatycznie zainstaluj dostępne aktualizacje Poproś o nową analizę Nie udało się wyeksportować pliku APKs - Pokaż aktualizacje, które mogą zakończyć się niepowodzeniem - Wyświetl aktualizacje dla niekompatybilnych lub wyłączonych aplikacji, których instalacja może zakończyć się niepowodzeniem + Niekompatybilne aktualizacje + Pokaż aktualizacje dla niekompatybilnych lub wyłączonych aplikacji, których instalacja może się nie udać Wyczyść zakończone Dodaj do ekranu głównego Masz pytania? Znajdź odpowiedzi @@ -323,7 +329,7 @@ Instalator oparty na powłoce z uprawnieniami roota Wymaga uprawnień roota/superużytkownika, obsługuje wszystkie wersje Androida. Bezpośrednie korzystanie z systemowych interfejsów API z uprawnieniami adb/root - Wymaga Shizuku lub Sui, musi zostać skonfigurowana i uzyskać uprawnienie + Wymaga Shizuku lub Sui, musi zostać skonfigurowana i uzyskać pozwolenie Instalator oparty na intencjach, dostępny na wszystkich urządzeniach Wymaga zainstalowania Aurora Services jako uprzywilejowanej aplikacji systemowej Wymaga Menedżera aplikacji, wymaga trybu adb/root do instalacji, gdy włączona jest optymalizacja miui @@ -336,14 +342,14 @@ Dodaj dostawcę Adres URL dostawcy Dodaj - Czy chcesz usunąć dostawcę \"%1$s\"? + Czy chcesz usunąć dostawcę %1$s\? Usuń Wiki Nieprawidłowy adres URL Znajdź odpowiedzi na często zadawane pytania (FAQ), kroki rozwiązywania problemów i nie tylko Wyświetl i zarządzaj dostawcami tokenów do anonimowego logowania Brak dostępnych dostawców - Usunąć dostawcę? + Usuń dostawcę Dodaj dostawcę tokenów do Aurora Store. Dostawcy tokenów udostępniają dane logowania do konta Aurora Store umożliwiając anonimowe logowanie. Zaloguj się na swoje konto Google Play O aplikacji Aurora Store @@ -363,13 +369,14 @@ Wyeksportowano pakiet aplikacji Nie udało się wyeksportować pakietu aplikacji Sprawdź aktualizacje - Zezwól na instalowanie aplikacji z nieznanych źródeł + Zezwalaj na instalowanie aplikacji z nieznanych źródeł Wymagane Opcjonalne Aurora Store umożliwia wyszukiwanie i pobieranie aplikacji z oficjalnego sklepu Google Play. Możesz przeglądać opisy aplikacji, zrzuty ekranu, aktualizacje, komentarze innych użytkowników oraz pobierać pliki APK bezpośrednio z Google Play na swoje urządzenie. Aby korzystać z Aurora Store, musisz posiadać konto Google Play i zalogować się na nie przy pierwszym otwarciu i konfiguracji Aurora Store.\n\nW przeciwieństwie do tradycyjnego sklepu z aplikacjami, Aurora Store nie jest właścicielem, nie licencjonuje ani nie dystrybuuje żadnych aplikacji. Wszystkie aplikacje, ich opisy, zrzuty ekranu oraz inna zawartość w Aurora Store są dostępne, pobierane i/lub wyświetlane bezpośrednio z Google Play. Aurora Store działa jak drzwi lub przeglądarka, umożliwiając zalogowanie się do konta Google Play i znalezienie aplikacji w Google Play.\n\nNależy pamiętać, że Aurora Store nie jest zatwierdzony, sponsorowany ani autoryzowany przez Google, Google Play, aplikacje pobrane za pośrednictwem Aurora Store ani żadnych twórców aplikacji. Aurora Store nie ma z nimi żadnego związku, współpracy ani powiązania. Bezpieczeństwo danych Najpierw musisz przyznać uprawnienia instalatorowi Praktyki dotyczące prywatności i bezpieczeństwa danych zadeklarowane przez dewelopera + Może być konieczne ponowne przyznanie uprawnień z powodu błędu w Storage Access Framework Uruchom ponownie Aurora Store Aby zastosować nowe ustawienia, należy uruchomić ponownie Aurora Store Poczekaj, eksportuję plik @@ -390,6 +397,7 @@ Stworzono z %1$s w Indiach Domyślny Dostępny + Może być konieczne ponowne uruchomienie aplikacji, aby uwzględnić przyznane uprawnienia. Usuń wszystkie Wybierz wszystkie Nie udało się zaimportować czarnej listy! @@ -415,62 +423,4 @@ Ta aplikacja działa bez zastrzeżonej biblioteki Google. Do prawidłowego działania może jednak wymagać bibliotek innych firm. %1$d zainstalowanych aplikacji Brak dostępnych aplikacji - Użyj microG do logowania się na konto - Serwer proxy został wyłączony - Wyłącz - Ustaw - Ograniczenia automatycznych aktualizacji - Wyświetl i zarządzaj konfiguracją serwera proxy - Skonfiguruj ograniczenia dla automatycznych aktualizacji - Tylko w sieciach bez limitu - Gdy urządzenie jest bezczynne - Gdy poziom baterii jest wysoki - Nie udało się zweryfikować pobranych plików - Uwierzytelnij się za pomocą microG podczas logowania do kont Google, aby uprościć proces logowania - Zaawansowane - Źródło aplikacji - Pobrane - Ostatnia aktualizacja - Minimalna wersja systemu Android - Docelowy poziom API - %1$d uprawnień - Zainstaluj pakiet microG - Zgodność aplikacji - Brakujące zależności - Przeczytaj politykę prywatności microG - Przeczytaj licencję i umowę microG - Odwiedź stronę internetową projektu microG - Przeczytałem i akceptuję warunki świadczenia usług oraz politykę prywatności microG - Nie znaleźliśmy usług Google Play na twoim urządzeniu. Niektóre popularne aplikacje wymagają tej usługi do prawidłowego działania! - microG to darmowa otwartoźródłowa implementacja zastrzeżonych bibliotek Google o otwartym kodzie źródłowym, która zastępuje usługi Google Play w systemie operacyjnym Android.\n\nmicroG umożliwia aplikacjom dostęp do interfejsów Google API, zwiększając kompatybilność i oferując korzyści związane z prywatnością.\n\nmicroG będzie działać automatycznie w tle gdy otworzysz aplikacje zależne od usług mobilnych Google. - Wybierz aplikację, aby uzyskać więcej informacji - Nazwa pakietu - Ocena treści - Docelowy poziom interfejsu - Więcej informacji - %1$d znane elementy śledzące w %2$s - Brak opisu - Dane, które może zbierać ta aplikacja - Dane, które może udostępniać ta aplikacja - Deweloper twierdzi, że ta aplikacja nie gromadzi danych użytkownika. - Deweloper twierdzi, że ta aplikacja nie udostępnia danych użytkownika innym firmom lub organizacjom. - Ta wersja aplikacji może zawierać więcej elementów śledzących, których nie ma jeszcze w bazie danych Exodus Privacy. - Bez reklam - Bez usług Google Play - Kod wersji może zawierać tylko cyfry - Przygotowywanie do instalacji - - Wymagane uprawnienie - Wymagane uprawnienia - Wymagane uprawnienia - Wymagane uprawnienia - - Strona %1$d - Instalator MicroG nie mógł zainstalować aplikacji, prawdopodobnie z powodu nieprawidłowej konfiguracji. - Instalator MicroG - Trwa ładowanie - Pomaga ominąć kontrolę integralności aplikacji (tylko instalator) - Wymaga zainstalowania aplikacji microG Companion - Pomiń - Uruchomić ponownie, aby zastosować zmiany? diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 1c0e83a08..27b24bb82 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -6,14 +6,14 @@ Endereço E-mail Descrição - Simulação - Desbloquear atualizações - Atualizações bloqueadas + Gerenciar simulação + Lista branca + Gerenciar lista negra Play Store Downloads Apps - Aurora Services (Depreciado) - Downloads + Serviços Aurora (Depreciado) + Download Telegram PayPal GitLab @@ -25,19 +25,19 @@ OK Apps com anúncios Exportar - Bloquear atualizações - Desconectar da Aurora - Conectar-se usando + Adicionar à lista negra + Sair da Aurora + Entrar usando Google Fóruns XDA Liberapay - A compra de apps não está disponível em contas anônimas. + As compras de apps não estão disponíveis em contas anônimas. Simulação de dispositivo aplicada. Permissão concedida Ative as configurações do desenvolvedor a partir das configurações do dispositivo para abri-las. Copiado para a área de transferência - As atualizações foram desbloqueadas - As atualizações estão bloqueadas + Na lista branca + Na lista negra Não está disponível em contas anônimas Atualizações Configurações @@ -45,60 +45,60 @@ Sem rede Biblioteca Idioma - Instalador de apps + Instalador de Apps Instalados Instalação Jogos - Permita a instalação de apps pela Aurora Store - Permissão de instalação - Gerenciador de armazenamento externo - Para salvar arquivos de expansão de APK (OBBs) para apps e jogos grandes. - Acesso ao armazenamento externo + Permita a instalação de apps da Aurora Store + Permissão de Instalação + Gerenciador de Armazenamento Externo + Para salvar arquivos de expansão (OBBs) para apps e jogos grandes. + Acesso ao Armazenamento Externo Como você está\? - Boas-vindas + Bem vindo Permissões Instalador A Aurora Store requer as seguintes permissões Nova atualização disponível Opcionalmente, você pode escolher o instalador nativo, mas não poderá instalar pacotes APKs (divididos), a escolha é sua. Desative as Otimizações MIUI para permitir instalações, caso contrário, você pode escolher o instalador Root ou Serviços. - O instalador de sessão não pode instalar apps devido às otimizações da MIUI. + O instalador de sessão não pode instalar apps devido à Otimizações MIUI. MIUI detectada! - Termos de serviço + Termos de Serviço Licença - Isenção de responsabilidade + Isenção de Responsabilidade Aguardando confirmação do usuário Instalado com sucesso Espaço de armazenamento insuficiente APK inválido ou corrompido App incompatível - Existe um pacote conflitante + Um pacote conflitante existe Não foi possível criar a sessão A instalação foi bloqueada O instalador falhou - Primeiro, configure o Aurora Services e permita todas as permissões. - Instale o Aurora Services 1.0.9 ou superior, ou altere o instalador. - O Aurora Services está disponível e pronto para instalação. - Sem acesso root. Permita-o ou altere o instalador. - Duas + Primeiro, configure os serviços Aurora e conceda todas as permissões. + Instale os serviços Aurora 1.0.9 ou superior, ou mude de instalador. + Os serviços Aurora estão disponíveis e prontos para instalação. + Sem acesso root. Conceda-o ou mude de instalador. + Dois Três - Positivas - Uma + Positivo + Um Quatro Cinco Críticas Todas Visualizar relatório rastreador(es) conhecido(s) encontrado(s) em - Conferindo se há rastreadores… - Disponibilizado pelo Exodus Privacy + Verificando por rastreadores… + Disponibilizado por Exodus Privacy Não contém rastreadores conhecidos Estimando - Retomar tudo + Retomar todos Em fila - Pausar tudo - Não há downloads - Buscando metadados + Pausar todos + Nenhum download + Obtendo metadados Limpar tudo Falha no download Calculando @@ -110,38 +110,38 @@ Privacidade Permissões Pago - Não há atualizações disponíveis - Não há permissões - Não há dependências + Nenhuma atualização disponível + Nenhuma permissão + Nenhuma Dependência Sem anúncios Mais sobre o app - Requer o GSF + Usa o GSF Gratuito Dependências - Contém anúncios - Registro de alterações indisponível - Registro de alterações - A inscrição pode levar algum tempo, você pode conferir o estado dela mais tarde. + Contém Anúncios + Registro de alterações não fornecido + Mudanças + A inscrição pode levar algum tempo, você pode verificar o status mais tarde. Você verá novos recursos e bugs antes dos outros. Dê seu feedback aos desenvolvedores para ajudá-los a melhorar. Participar do programa beta? Você é um testador beta Programa beta - Atualizar tudo + Atualizar todos Atualizar - Informações do app + Informações do App Desinstalar Compartilhar - Buscar + Pesquisar Retomar Reiniciar Publicar Pendente Abrir - Avançar - Desconectar + Próximo + Sair Sair - Mais tarde - Juntar-se + Depois + Junte-se Instalando Instalações Instalar @@ -158,25 +158,26 @@ Qualquer Filtros Desativar - Copiar link + Copiar Link Copiar Fechar Limpar Cancelar - Bloquear atualizações + Lista negra Voltar Anônimo - Veja a publicação da Aurora Store no XDA para discussões ou sugestões. + Veja o tópico da Aurora Store no XDA para discussões ou sugestões. Junte-se ao grupo de suporte da Aurora para discussões ou sugestões. Doar via PayPal Torne-se um patrono no Liberapay - Baixe o código-fonte da Aurora Store do Aurora OSS no GitLab. - Instale a Aurora Store pelo F-Droid. + Obtenha o código-fonte de Aurora Store no Aurora OSS no GitLab. + Obtenha a Aurora Store no F-Droid. Doar via Ethereum (ETH) Doar via Bitcoin (BTC) Doar via Bitcoin Cash (BCH) Doar via UPI Dispositivo + Apps em promoção Apps na biblioteca Meus apps e jogos Contas @@ -185,50 +186,51 @@ Principais apps pagos Mais rentáveis Principais apps gratuitos - Em alta - Para você + Em Alta + Recomendações Escolha dos editores Categorias - Certifique-se de conectar sua conta novamente para aplicar a simulação - Sessão expirada, conecte-se à sua conta novamente para obter uma nova sessão. - Não foi possível obter os arquivos + Certifique-se de iniciar sessão novamente para aplicar a simulação + Sessão expirada, faça login novamente para obter uma nova sessão. + Não foi possível obter arquivos App não encontrado App não suportado - O app não foi comprado - Download falhou - Personalização + App não foi comprado + Download Falhou + Customização Método de instalação - Selecione o modo de instalação de APKs - Instalador de sessão + Selecione o modo de instalação para APKs + Instalador de Sessão Instalador root - Instalador nativo (Depreciado) - Apagar APK após a instalação - Os APKs baixados serão apagados após a instalação + Instalador Nativo (Depreciado) + Excluir APK após a instalação + APKs baixados serão excluídos após a instalação Filtrar apps do F-Droid - Não verificar se há atualizações de apps instalados pelo F-Droid - Conecte-se à sua conta novamente e reinicie o app para aplicar as mudanças. - Páginas de recomendação + Não buscar por atualizações de apps baixados ou instalados do F-Droid + Tenha certeza que você se reconectou e reinicie o app para aplicar as mudanças. + Páginas de Recomendações O código da versão solicitada está disponível, baixando agora. O código de versão que você solicitou não está disponível. - Baixar manualmente - Exibir páginas de recomendação na tela inicial + Download manual + Exibir apps semelhantes e relacionados na página de detalhes do app + Exibir páginas de recomendações na tela inicial Rede - Não há apps correspondentes + Nenhum app correspondente encontrado Apps relacionados ou semelhantes - Alterar aba padrão - Organização + Aba padrão + Layout Extras Você não pode instalar apps em pacote (divididos) por meio do Instalador nativo. Mude seu instalador para Sessão, Serviços ou Root. - Não foi possível gerar o token AAS - Não foi possível enviar a avaliação + Não foi possível gerar Token AAS + Não foi possível enviar a classificação Limitado, pode levar um tempo para aparecer Página indisponível Não foi possível exportar a configuração de dispositivo - Configuração de dispositivo exportada - Permite o download de apps em segundo plano + Configuração de dispositivo exportado + Ativa o download de apps em segundo plano Download de app em segundo plano Instalador AM - Instale o App Manager ou altere o instalador. + Instale o App Manager ou mude de instalador. Notificações Deixando tudo certo… Pausado • %1$d / %2$d @@ -237,239 +239,192 @@ %1$dm %2$ds restando %1$ds restando Aê! Tudo certo. - Não foi possível se conectar pelo Google - Verificando a sessão - A ultima sessão foi descartada + Não foi possível iniciar sessão via Google + Verificando sessão + Última sessão foi descartada atualizações disponíveis - Permissões necessárias foram negadas. As permita para continuar a ação + Permissões necessárias foram negadas. Conceda-as para continuar a ação %1$d atualizações disponíveis - %1$s, %2$s, %3$s e mais %4$d + %1$s, %2$s, %3$s e %4$d mais %1$s e %2$s %1$s, %2$s e %3$s Baixando • %1$d / %2$d%3$s O Shizuku não está instalado ou configurado corretamente. - Enviar notificações a respeito do estado das instalações + Enviar notificações a respeito dos status das instalações Instalador Shizuku - Conecte-se à sua conta e aproveite. - Verificando a sessão do Google + Faça login e aproveite. + Verificando Sessão Google Avançado Não foi possível importar as configurações de dispositivo Configurações de dispositivo importadas - Solicitando uma sessão nova - O servidor está fora do ar para manutenção + Solicitando nova sessão + Servidor fora do ar para manutenção Ocorreu um erro! atualização disponível - Buscar por apps & jogos + Pesquisar por Apps & Jogos Expandir Notificações de atualização %1$d atualização disponível - Há uma nova versão de %1$s disponível + Uma nova versão de %1$s está disponível Baixando arquivos adicionais para %1$s Menu %1$s • API %2$s - Sugestão de busca - Resultados da busca - Falha ao obter o relatório de privacidade - Acesso negado! Você está usando uma VPN ou o Tor? - Erro interno! Tente de novo mais tarde - Você foi limitado + Sugestão de pesquisa + Resultados da pesquisa + Falhou em obter o relatório de privacidade + Acesso negado! Está usando uma VPN ou Tor? + Erro interno! Tente novamente mais tarde + Oops, você foi limitado Servidor inacessível - Falha ao gerar a sessão, código de erro: %1$d - Idioma do app - Conferir a conexão à internet - Verificando a sessão nova - Links do app - Permita que a Aurora Store abra os links suportados - O Google Play, também conhecido como a Google Play Store e anteriormente Android Market. - Não foi possível gerar uma sessão - Android Market foi uma loja on-line que oferecia apps feitos para dispositivos Android, fechada em 2017. + Falhou em gerar sessão, código de erro: %1$d + Idioma do App + Verificar a conexão à internet + Verificando nova sessão + Links de App + Permitir que a Aurora Store abra links suportados + Google Play, também conhecido como a Google Play Store e anteriormente Android Market. + Não foi possível gerar a sessão + Android Market foi uma loja on-line que oferecia apps de software feitos para dispositivos Android, fechada em 2017. Título da análise - Configure o intervalo das atualizações automáticas, em horas. - Filtrar apps de outras fontes - Não verificar se há atualizações de apps não instalados pela Aurora Store - Configurações do app + Provedor - bestappsales.com + Configurar os intervalos das atualizações automáticas, em horas. + Apenas apps da Aurora Store + Buscar atualizações somente para apps instalados pela Aurora Store + Configurações do App Frequência das atualizações automáticas + Ativar proxy URL da proxy + Proxy URL de proxy inválida, verifique o formato! - Proxy configurada com sucesso - Falha ao configurar a proxy + Proxy definido com sucesso + Falhou em definir proxy + Permitir que todo o tráfego do app passe pela proxy Padrão (da configuração do dispositivo) Versão do Google Play - Downloads em segundo plano + Downloads em Segundo Plano Permita que a Aurora Store baixe e atualize apps em segundo plano - Atualizações automáticas - Verificar se há atualizações disponíveis e enviar notificações - Não atualizar os apps automaticamente - Configure o comportamento das atualizações automáticas - Verificar se há atualizações disponíveis e instalá-las automaticamente - Solicitar uma nova análise + Atualizar apps automaticamente + Buscar atualizações e enviar notificações + Não atualizar apps automaticamente + Configurar comportamento das atualizações automáticas + Buscar e instalar atualizações disponíveis automaticamente + Solicitar nova análise Falha ao exportar APKs - Mostrar atualizações que podem falhar - Exibir atualizações de apps incompatíveis ou desativados que podem falhar ao instalar - Limpar concluídos - Adicionar à tela inicial + Atualizações incompatíveis + Mostrar atualizações para apps incompatíveis ou desativados que podem falhar ao instalar + Limpar finalizados + Adicionar à Tela inicial Instalador baseado em shell usando permissões root Precisa de privilégios root, suporta todas as versões do Android. Instalador baseado em intent, disponível em todos os dispositivos Melhor para dispositivos rodando versões anteriores ao Android 4.4 Instalador para instalações em segundo plano - Requer que o Aurora Services seja instalado como um app do sistema privilegiado - Requer o Shizuku ou Sui, precisa ser configurado e ter a permissão concedida + Precisa que os Serviços Aurora estejam instalados como um app do sistema privilegiado + Precisa do Shizuku ou Sui, precisa ser configurado e que a permissão seja concedida Gerenciador de pacotes completo de código aberto - Requer o App Manager, precisa do modo adb/root para instalar quando a otimização da MIUI estiver ativada - Utilizando APIs do sistema diretamente com privilégios de adb/root - Instalador baseado em sessão para APKs em pacote/divididos + Precisa do App Manager, precisa do modo adb/root para instalar quando a otimização da MIUI está ligada + Usando APIs do sistema diretamente com privilégios de adb/root + Instalador baseado em sessão para APKs bundled/split Recomendado, é integrado e suporta todas as versões do Android - Tem dúvidas? Encontre as respostas + Tem perguntas? Encontre as respostas Código-fonte Descubra o que há por dentro Política de privacidade Responsabilização - Saiba mais sobre como a Aurora Store usa seus dados - Digite o código da versão que deseja baixar + Descubra como a Aurora Store usa seus dados + Insira o código da versão que deseja baixar Mais - Gerenciar sua conta + Gerencie sua conta Limpar proprietário do dispositivo Remove a Aurora Store como o app proprietário do dispositivo Isso irá revogar a permissão do instalador da sessão de silenciosamente instalar apps. Prosseguir com a limpeza da propriedade do dispositivo? Wiki Adicionar distribuidor - Gerenciar os distribuidores + Gerenciar distribuidores URL inválida - Remover distribuidor? + Remover distribuidor Remover - Encontre respostas para perguntas frequentes (FAQ), soluções para problemas comuns e mais - Visualize e gerencie os distribuidores de tokens de contas anônimas - Não há distribuidores disponíveis - Adicione um distribuidor de tokens à Aurora Store. Distribuidores de tokens fornecem credenciais de conta para entrar na Aurora Store de forma anônima. + Encontre respostas para perguntas frequentes (FAQ), passos para diagnosticar problemas e mais + Veja e gerencie distribuidores de token para logins anônimos + Nenhum distribuidor disponível + Adicione um distribuidor de token à Aurora Store. Distribuidores de token providenciam credenciais de conta para a Aurora Store para entrar anonimamente. URL do distribuidor Deseja remover o distribuidor \"%1$s\"? Adicionar - Conecte-se à sua conta do Google Play + Por favor entre em sua conta Google Play Sobre a Aurora Store Saiba mais sobre a Aurora Store - A Aurora Store permite que você busque e instale apps da Google Play Store oficial. Você pode ver as descrições dos apps, capturas de tela, atualizações, os comentários dos usuários e baixar o APK diretamente da Google Play no seu dispositivo. Para usar a Aurora Store, você precisa ter uma conta do Google Play e conectar a conta ao abrir e configurar a Aurora Store pela primeira vez.\n\nDiferentemente de uma loja de apps tradicional, a Aurora Store não tem propriedade, licencia ou distribui nenhum app. Todos os apps, as descrições dos apps, capturas de tela e outros conteúdos da Aurora Store são acessados, baixados e/ou exibidos do Google Play. A Aurora Store funciona exatamente como uma porta ou navegador, permitindo que você entre na sua conta do Google Play e encontre os apps do Google Play.\n\nObserva que a Aurora Store não possui qualquer aprovação, patrocínio ou autorização do Google, Google Play, apps baixados pela Aurora Store ou qualquer desenvolvedor dos apps, nem possui qualquer afiliação, cooperação ou conexão com eles. + A Aurora Store permite que você pesquise e instale apps da loja Google Play. Você pode ver as descrições dos apps, capturas de tela, atualizações, os comentários dos usuários e baixar o APK diretamente da Google Play para o seu dispositivo. Para usar a Aurora Store, você deve ter uma conta Google Play e entrar na conta quando abrir e configurar a Aurora Store. +\n +\nDiferentemente de uma loja de apps tradicional, a Aurora Store não possui, licencia ou distribui nenhum app. Todos os apps, as descrições dos apps, capturas de tela e outros conteúdos da Aurora Store são acessados, baixados e/ou exibidos da Google Play. A Aurora Store funciona exatamente como uma porta ou navegador, permitindo que você entre em sua conta Google Play e encontre os apps da Google Play. +\n +\nPor favor note que a Aurora Store não possui qualquer aprovação, patrocínio ou autorização do Google, Google Play, apps baixados pela Aurora Store ou qualquer desenvolvedor de app, nem possui qualquer afiliação, cooperação ou conexão com eles. App não disponível para seu dispositivo - Falha ao importar os curtidos! - Não há apps curtidos - Apps curtidos - Curtir + Falhou em importar favoritos! + Nenhum app favorito encontrado + Apps Favoritos + Favoritar Favoritos exportados! - Falha ao exportar os favoritos! - Curtidos importados! - Pacote de aplicativo exportado com sucesso - Falha ao exportar o pacote de app + Falhou ao exportar favoritos! + Favoritos importados! + Pacote de app exportado com sucesso + Falha ao exportar pacote de app Desinstalado com sucesso - Digite uma URL de proxy válida para passar todo o tráfego pela proxy. - Desconectar-se? + Insira uma URL de proxy válida para passar todos os dados pela proxy. + Sair? Tem certeza que deseja sair? - Verificar se há atualizações - Segurança dos dados + Buscar atualizações + Segurança de dados + Você pode ter que conceder a permissão novamente devido a um bug no \"Storage Access Framework\" Necessário - Práticas declaradas pelo desenvolvedor da segurança e privacidade dos dados - Permita a instalação de apps de fontes desconhecidas + Práticas de segurança e privacidade de dados declaradas pelo desenvolvedor + Permitir a instalação de apps de fontes desconhecidas Você precisa conceder a permissão de instalador primeiro Opcional Reiniciar a Aurora Store - A Aurora Store precisa ser reiniciada para aplicar as configurações novas - Exportador de arquivo - Aguarde, seu arquivo está sendo exportado - Notificação de exportação de apps + A Aurora Store precisa ser reiniciada para aplicar as novas configurações + Exportador de Arquivos + Aguarde, exportando seu arquivo + Notificação de exportação de app Notificação de instalação Notificação de downloads - Falha + Falhado Concluído Na fila Indisponível Baixando Cancelado Notificação relacionada à conta - Conecte-se à sua conta do Google Play para desarquivar o app! + Por favor, faça login em sua conta do Google Play para desarquivar o app! Autenticação necessária - Verificando se há atualizações + Checando atualizações Feito com %1$s na Índia Padrão - Disponíveis - Remover tudo - Selecionar tudo - Mais recentes - Falha ao importar a lista de aplicativos com atualizações bloqueadas! - Falha ao exportar a lista de apps com atualizações bloqueadas! - A lista de apps com atualizações bloqueadasrfoi importada! - A lista de aplicativos com atualizações bloqueadas foi exportada! + Disponível + Você pode ter que reiniciar o app para refletir o concedimento da permissão. + Remover todos + Selecionar todos + Últimas + Falha ao importar lista negra! + Falha ao exportar lista negra! + Lista negra importada! + Lista negra exportada! Desarquivar Verificando Não é possível abrir o app - Disponibilizado pelo Plexus + Fornecido pelo Plexus Compatibilidade Esse app funciona sem a biblioteca proprietária do Google. Porém, ele pode ainda precisar de outras bibliotecas de terceiros para funcionar corretamente. - Desconhecido: Não foi conferido ainda - Conferindo a compatibilidade… + Desconhecido: Não foi verificado ainda + Verificando compatibilidade… Compatível: Funciona sem problemas Requer o Google Play Services Você pode precisar instalar a biblioteca proprietária do Google, ou uma reimplementação FOSS como o microG. Com o projeto microG Funciona sem o Google Play Services - Limitado: Funciona mas com os recursos limitados + Limitado: Funciona com funcionalidade limitada Sem Google Play Services - Não suportado: Não funciona + Não suportado: Não funcional %1$d apps instalados - Não há apps disponíveis - Utilizar o microG para conectar-se às contas - Autentique-se usando o microG ao se conectar às contas do Google para um fluxo de login mais simples - Configurar - Desativar - Proxy desativada com sucesso - Visualize e gerencie a configuração de proxy - Restrições das atualizações automáticas - Configure as restrições do dispositivo para as atualizações automáticas - Somente em redes ilimitadas - Apenas quando o dispositivo estiver em repouso - Quando a bateria não estiver baixa - Falha ao verificar os arquivos baixados - Fonte do aplicativo - Avançado - Última atualização - Nível alvo da API - Downloads - Versão do Android mínima - %1$d permissões - Instalar o conjunto do microG - Compatibilidade de apps - Dependências ausentes - Eu li e concordo com os termos de serviço e a política de privacidade do microG - Não foi possível encontrar o Google Play Services no seu dispositivo, muitos apps populares requerem ele para funcionar corretamente! - O microG é uma implementação de código aberto e livre que fornece funcionalidade similar para a execução de apps que dependem no Google Play Services em dispositivos Android, através da reimplementação.\n\nO microG permite que apps acessem essas APIs do Google, melhorando a compatibilidade para os usuários enquanto melhora oferece benefícios à privacidade.\n\nO microG é executado automaticamente em segundo plano ao abrir aplicativos que dependem do Google Mobile Services. - Ler a política de privacidade do microG - Ler a licença do microG - Visitar o site do projeto do microG - Dados que este app pode coletar - O desenvolvedor diz que este app não coleta dados do usuário. - Dados que este app pode compartilhar - O desenvolvedor diz que este app não compartilha dados do usuário com outras empresas ou organizações. - Esta versão do app ainda pode conter mais rastreadores não presentes ainda no banco de dados do Exodus Privacy. - %1$d rastreador(es) conhecidos encontrados na %2$s - Nenhuma descrição disponível - Mais informações - Alvos - Nome do pacote - Classificação do conteúdo - Selecione um aplicativo para mais informações - Sem anúncios - Sem play services - O código de versão pode conter apenas dígitos - Preparando para instalar - - Permissão necessária - Permissões necessárias - Permissões necessárias - - O instalador do microG falhou ao instalar o app, provavelmente devido a má configuração. - Instalador do microG - Requer que o app companheiro do microG esteja instalado - Ajuda a burlar a checagem da Integridade do App (apenas o instalador) - Carregando - %1$dª página - Pular - Reiniciar para aplicar mudanças? + Nenhum app disponível diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 77376cfb7..047946f52 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -1,7 +1,7 @@ - Sítio eletrónico - Endereço de correio eletrónico + Site + E-mail Google Anónimo Visite o tópico Aurora Store no XDA para participar em discussões e sugestões. @@ -27,9 +27,10 @@ Descrição BHIM - UPI Play Store + Aplicações à venda Aplicações na biblioteca Permitir instalação de aplicações a partir da Aurora Store - Não pode instalar conjuntos de aplicações (dividir) através do instalador nativo. Altere o seu instalador para Sessão, Serviços ou Raiz. + Não é possível instalar conjuntos de aplicações via instalador nativo. Altere para o instalador de sessão, serviços ou root. O instalador de sessão não pode instalar aplicações devido às otimizações MIUI. Paga Aplicações com anúncios @@ -40,7 +41,7 @@ Página de navegação indisponível Parabéns, o código da versão solicitada está disponível. A descarregar neste momento. O código da versão solicitada não está disponível. - A compra de apps não está disponível em contas anônimas. + A compra de aplicações não está disponível em contas anónimas. Disfarce do dispositivo aplicado. Permissão concedida Ative as definições de programador nas definições do dispositivo para as abrir. @@ -56,7 +57,7 @@ Sem rede Biblioteca Idioma - Instalador de apps + Instalador de aplicações Instaladas Instalação Jogos @@ -82,10 +83,11 @@ Aplicação não encontrada Aplicação não suportada Aplicação não comprada - Descarga falhou + Falha ao descarregar + Mostrar grupos de aplicações semelhantes e relacionadas na página de detalhes das aplicações Aplicações semelhantes e relacionadas - Exibir páginas de recomendação no ecrã inicial - Páginas de recomendação + Mostrar sugestões no ecrã inicial + Sugestões para si Selecione o separador padrão Apresentação Personalização @@ -97,13 +99,13 @@ Instalador nativo (descontinuado) Eliminar o APK após a instalação Os APKs descarregados serão eliminados imediatamente após a instalação - Não procurar por atualizações para as aplicações instaladas do F-Droid + Não verifique atualizações de aplicativos baixados ou instalados do F-Droid Filtrar aplicações F-Droid Extras - Permissão de instalação + Permissão do instalador Gestor de armazenamento externo Para guardar ficheiros de expansão APK (OBBs) para aplicações e jogos de grande dimensão. - Acesso ao armazenamento externo + Acesso a armazenamento externo Como está\? Bem-vindo Permissões @@ -125,9 +127,9 @@ Não foi possível criar a sessão Instalação bloqueada Instalador falhou - Primeiro, configure o Aurora Services e permita todas as permissões. - Instale o Aurora Services 1.0.9 ou superior, ou altere o instalador. - O Aurora Services está disponível e pronto para instalação. + Configure os serviços Aurora e conceda todas as permissões primeiro. + Instale Aurora Services 1.0.9+ ou escolha outro instalador. + Aurora Services está disponível e pronto para instalar. Sem acesso root. Conceda-o ou escolha outro instalador. 2 3 @@ -166,7 +168,7 @@ Contém anúncios Alterações não disponibilizadas Nenhuma permissão - Nenhuma dependência + Sem dependências Nenhuma aplicação encontrada Sem anúncios Requer GSF @@ -176,13 +178,13 @@ Novidades A adesão poderá levar algum tempo. Pode verificar o estado mais tarde. Verá novas funcionalidades e erros antes do público. Dê a sua opinião aos programadores para os ajudar a melhorar. - Participar do programa beta? + Aderir ao programa beta? É um beta tester Programa beta Lista branca Atualizar tudo Atualizar - Informações da app + Informações da aplicação Desinstalar Partilhar Pesquisar @@ -203,7 +205,7 @@ Ignorar Permitido Permitir - Gravar pacote da app + Guardar pacote de aplicações Terminar Outro Depende de GSF @@ -218,7 +220,7 @@ Fechar Limpar Cancelar - Adicionar à lista de bloqueio + Adicionar à lista negra Lista negra Recuar Terminar sessão @@ -256,71 +258,75 @@ Falha ao iniciar sessão via Google Última sessão perdida A verificar sessão - A verificar a sessão do Google + A verificar sessão Goggle Não foi possível importar a configuração do dispositivo atualização disponível atualizações disponíveis - As permissões necessárias foram recusadas. Tem que as permitir para poder continuar - Pesquisar por apps & jogos + As permissões necessárias foram recusadas. Tem que as conceder para poder continuar. + Pesquisar por aplicações e jogos A solicitar nova sessão Servidor em manutenção - Notificações de atualização + Notificação sobre atualizações %1$d atualizações disponíveis Está disponível uma nova versão de %1$s Permitir abertura de ligações através de Aurora Não foi possível obter o relatório de privacidade Acesso recusado. Está a usar uma VPN ou Tor\? - Erro interno! Tente de novo mais tarde - Você está sujeito a um limite de taxa de transferência. + Erro interno. Tente mais tarde. + A sua conta tem limite de utilizações Servidor inacessível Falha ao gerar a sessão. Código de erro: %1$d Verificar ligação - Idioma da app + Idioma Sugestão de pesquisa Resultados da pesquisa Não foi possível gerar a sessão A verificar a nova sessão - Ligações da app + Ligações Google Play, também conhecida como Google Play Store e, anteriormente, Android Market. O Android Market foi uma loja online que oferecia aplicações para dispositivos Android, descontinuada em 2017. + Ativar proxy Título da avaliação URL do proxy - Configure o intervalo das atualizações automáticas, em horas. - Filtrar aplicações de outras fontes + Configurar tempo de intervalo para procurar atualizações (em horas). + Apenas aplicações Aurora Store + Proxy URL inválido. Verifique o formato! - Não procurar por atualizações para as aplicações instaladas de fontes fora da Loja Aurora + Verifique apenas atualizações de aplicativos instalados pela Aurora Store Proxy definido com sucesso - Configurações da app + Definições + Fornecedor - bestappsales.com Frequência das atualizações automáticas Falha ao definir o proxy + Permitir que todo o tráfego da aplicação passe pelo proxy Padrão (configuração do dispositivo) - Versão do Google Play + Versão Google Play Descargas em segundo plano Permitir que a Aurora Store descarregue e atualize aplicações em segundo plano - Atualizações automáticas - Configure o comportamento das atualizações automáticas + Atualizar aplicações automaticamente + Configurar comportamento da atualização automática Verificar e notificar sobre atualizações disponíveis Verificar e instalar atualizações disponíveis automaticamente Não atualizar automaticamente as aplicações Requisitar nova análise Falha ao exportar APK - Mostrar atualizações que possam falhar + Atualizações incompatíveis Adicionar ao ecrã inicial Limpeza efetuada - Exibir as atualizações para as aplicações incompatíveis ou desativadas que possam falhar a instalação - Insira o código da versão que pretende transferir + Mostrar atualizações para aplicações incompatíveis ou desativadas + Introduza o código da versão que pretende descarregar Tem perguntas? Encontre as respostas - Código fonte + Código-fonte Descubra o que está no interior Política de privacidade - Saiba como a Loja Aurora utiliza os seus dados - Responsabilidade e Prestação de Contas - Requer que os Serviços Aurora estejam instalados como uma aplicação do sistema privilegiada + Saiba como a Aurora Store utiliza os seus dados + Responsabilidade e obrigação de prestar contas + Requer que os serviços Aurora sejam instalados como uma aplicação de sistema privilegiado Mais adequado para dispositivos com versões inferiores ao Android 4.4 Instalador para instalações em segundo plano - Utilizar as APIs do sistema diretamente com privilégios adb/raiz + Utilizar as APIs do sistema diretamente com privilégios adb / root Requer Shizuku ou Sui, precisa de ser configurado e de ter permissão concedida - Instalador baseado em sessão para APKs agrupados/divididos + Instalador baseado em sessão para APKs agrupados / divididos Recomendado, incorporado e compatível com todas as versões do Android Instalador baseado em shell usando permissões de root Requer privilégios de root / superutilizador, suporta todas as versões do Android. @@ -330,15 +336,15 @@ Limpar o proprietário do dispositivo Remove a Aurora Store como a aplicação do proprietário do dispositivo Isto irá revogar a permissão do instalador da sessão para instalar silenciosamente a aplicação. Continuar com a limpeza da propriedade do dispositivo? - Gestor de pacotes de código aberto completo - Requer o \'Gestor de Aplicações\', precisa do modo adb/raiz para instalar quando a otimização de miui está ativada + Gestor de pacotes de código aberto com todas as funcionalidades + Requer o App Manager, precisa do modo adb / root para instalar quando a otimização do MIUI está ativada Wiki Gerir os distribuidores Ver e gerir distribuidores de token para inícios de sessão anónimos Não existem distribuidores disponíveis Adicionar distribuidor URL do distribuidor - Remover o dispensador? + Remover distribuidor Encontre respostas a perguntas frequentes (F.A.Q.), passos de resolução de problemas e muito mais Adicionar um distribuidor de tokens ao Aurora Store. Os distribuidores de tokens fornecem credenciais de conta à Aurora Store para iniciar sessão anonimamente. URL inválido @@ -352,29 +358,34 @@ Segurança de dados Práticas de privacidade e segurança dos dados declaradas pelo programador Introduza um URL de proxy válido para passar todos os dados através do proxy. - Apps curtidos + Aplicações favoritas + Poderá ter de voltar a conceder a permissão devido a um erro no Storage Access Framework Obrigatório Opcional Terminar sessão? Favoritos exportados! Pacote de aplicações exportado com êxito - Não foi possível exportar o pacote de aplicações + Falha ao exportar o pacote de aplicações Desinstalado com sucesso Não foram encontradas aplicações favoritas - Sobre a Loja Aurora - Saiba mais sobre a Loja Aurora + Sobre a Aurora Store + Saiba mais sobre a Aurora Store Falha na importação dos favoritos! Falha na exportação dos favoritos! Favoritos importados! - Precisa conceder a permissão de instalador primeiro - Exportador de ficheiro + É necessário conceder primeiro a permissão do instalador + Exportador de ficheiros Aguarde. A exportar o seu ficheiro Quer mesmo terminar a sessão? Verificar se há atualizações Permitir a instalação de aplicações de fontes desconhecidas Aplicação não disponível para o seu dispositivo - A Aurora Store permite que pesquise e instale apps da Google Play Store oficial. Pode ver as descrições dos apps, capturas de ecrã, atualizações, os comentários dos utilizadores e descarregar o APK diretamente da Google Play no seu dispositivo. Para usar a Aurora Store, precisa ter uma conta do Google Play e entrar na conta quando abrir e configurar a Aurora Store pela primeira vez.\n\nDiferentemente de uma loja de apps tradicional, a Aurora Store não tem propriedade, licencia ou distribui nenhum app. Todos os apps, as descrições dos apps, capturas de ecrã e outros conteúdos da Aurora Store são acedidos, descarregados e/ou exibidos do Google Play. A Aurora Store funciona exatamente como uma porta ou navegador, permitindo que entre na sua conta Google Play e encontre os apps do Google Play.\n\nObserva que a Aurora Store não possui qualquer aprovação, patrocínio ou autorização do Google, Google Play, apps descarregados pela Aurora Store ou qualquer programador dos apps, nem possui qualquer afiliação, cooperação ou conexão com eles. - Desenvolvido com %1$s na Índia + A Aurora Store permite-lhe pesquisar e transferir aplicações da loja oficial do Google Play. Pode verificar as descrições das aplicações, capturas de ecrã, atualizações, comentários de outros utilizadores e descarregar o APK diretamente do Google Play para o seu dispositivo. Para utilizar a Aurora Store, é necessário ter uma conta Google Play e iniciar sessão na sua conta Google Play quando abrir e configurar a Aurora Store pela primeira vez. +\n +\nAo contrário de uma loja de aplicações tradicional, a Aurora Store não detém, licencia ou distribui quaisquer aplicações. Todas as aplicações, descrições de aplicações, capturas de ecrã e outros conteúdos na Aurora Store são acedidos, descarregados e/ou apresentados diretamente a partir do Google Play. A Aurora Store funciona exatamente como uma porta ou um navegador, permitindo-lhe iniciar sessão na sua conta Google Play e encontrar as aplicações do Google Play. +\n +\nTenha em atenção que a Aurora Store não tem qualquer aprovação, patrocínio ou autorização do Google, do Google Play, de quaisquer aplicações descarregadas através da Aurora Store ou de quaisquer programadores de aplicações. A Aurora Store também não tem qualquer afiliação, cooperação ou ligação com os mesmos. + Feito com %1$s na Índia Notificação relacionada à conta Notificação de exportação de aplicativo Notificação de instalação @@ -399,77 +410,4 @@ Não é possível abrir a app Selecionar todos A verificar - Nenhum app disponível - Usar microG para iniciar a sessão nas contas - Definir - Quando a pilha não está baixa - Mais recentes - Pode precisar instalar a biblioteca proprietária do Google, ou uma reimplementação FOSS como o microG. - Com o projeto microG - Sem Google Play Services - Compatível: Funciona sem problemas - Desconhecido: Ainda não foi verificado - Autenticar usando o microG quando iniciar a sessão nas contas Google para um fluxo de autenticação mais simples - Desativar - Proxy desativada com sucesso - Veja e gira a configuração de proxy - Restrições das atualizações automáticas - Configure as restrições do dispositivo para atualizações automáticas - Somente em redes ilimitadas - Quando o dispositivo estiver parado - Falha ao verificar os ficheiros descarregados - %1$d apps instalados - Fornecido pelo Plexus - Funciona sem o Google Play Services - Este app funciona sem a biblioteca proprietária do Google. Porém, ele pode ainda precisar de outras bibliotecas de terceiros para funcionar corretamente. - Limitado: Funciona mas com os recursos limitados - Não suportado: Não funciona - A verificar a compatibilidade… - Compatibilidade - Requer o Google Play Services - Instalar Conjunto microG - Transferências - Última atualização - Versão Mínima de Android - Nível de API de Destino - Compatibilidade da Aplicação - Dependências em falta - Eu li e concordo com os \'Termos do Serviço\' e \'Política de Privacidade\' de microG - Não foi possível encontrar os Serviços do Google Play no seu dispositivo, vários aplicações populares agora exigem-no para funcionarem corretamente! - Ler \'Política de Privacidade\' de microG - Ler \'Licença e Acordo\' de microG - Visitar o \'\'site\'\' da Web do Projeto microG - Avançado - Fonte da app - micro G é uma implementação gratuita e de código aberto que fornece funcionalidade semelhante para executar apps dependentes do Google Play Services para dispositivos com Android através da re-implementação.\n\nmicro O G permite que as apps acedam essas APIs do Google, melhorando a compatibilidade para os utilizadores ao oferecer benefícios de privacidade.\n\nmicro G será executado automaticamente em segundo plano quando abre aplicações dependentes do Google Mobile Services. - %1$d permissões - Página %1$d - Carregamento em progresso - Dados que este aplicativo pode coletar - O desenvolvedor afirma que este aplicativo não coleta dados do usuário. - Dados que este aplicativo pode compartilhar - O desenvolvedor afirma que este aplicativo não compartilha dados do usuário com outras empresas ou organizações. - Esta versão do aplicativo ainda pode conter rastreadores que não estão presentes no banco de dados do Exodus Privacy. - %1$d rastreadores conhecidos encontrados em %2$s - O instalador MicroG não conseguiu instalar o aplicativo, provavelmente devido a uma configuração incorreta. - Instalador MicroG - Pular - Requer a instalação do aplicativo complementar microG - Ajuda você a ignorar a verificação de integridade do aplicativo (somente instalador) - O código da versão só pode conter dígitos - Reiniciar para aplicar mudanças? - Nenhuma descrição disponível - Mais informações - Alvos - Nome do pacote - Classificação de conteúdo - Preparando para instalar - - Permissão requerida - Permissões requeridas - Permissãos requeridas - - Selecione um aplicativo para obter mais detalhes - Sem anúncios - Sem serviços de reprodução diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 4e76230f6..f1f8782e7 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -4,7 +4,7 @@ Devino patron pe Liberapay Donează prin Bitcoin (BTC) Donează prin UPI - Numerar Bitcoin + Bitcoin Cash Obține Aurora Store prin intermediul F-Droid. BHIM - UPI Donează prin Bitcoin Cash (BCH) @@ -14,7 +14,7 @@ Consultă forumul XDA Aurora Store pentru discuții sau sugestii. Anonim Forumuri XDA - Salvează pachetul de aplicații + Se salvează pachetul aplicației Jurnalul modificărilor Susținut de Exodus Privacy Dezactivează @@ -56,7 +56,7 @@ Ce mai faci\? Acces la stocare Manager de stocare externă - Copiază link-ul + Copiază legătură Adaugă la lista neagră Acordă Exportă @@ -163,7 +163,7 @@ PayPal Telegram Google - Nu se verifică actualizările pentru aplicațiile instalate de pe F-Droid + Nu se verifică actualizările pentru aplicațiile descărcate sau instalate de pe F-Droid Filtrează aplicațiile F-Droid APK-urile descărcate vor fi șterse imediat după instalare Șterge fișierul APK după instalare @@ -190,12 +190,13 @@ Aplicații Aplicațiile și jocurile mele Aplicații în bibliotecă + Aplicații cu reducere Managerul listei negre Dispozitiv Activează setările pentru dezvoltatori în setările dispozitivului pentru a le deschide. Permisiune acordată S-a aplicat o falsificare a dispozitivului. - Achiziții de aplicații nu sunt disponibile în conturile anonime. + Achizițiile de aplicații nu sunt disponibile în conturile anonime. Codul de versiune pe care îl soliciți nu este disponibil. Felicitări, codul versiunii solicitate este disponibil, se descarcă acum. Pagina de navigare nu este disponibilă @@ -207,6 +208,7 @@ Copiat în clipboard Instalator sesiune Metoda de instalare + Afișare grupuri similare și asociate pe pagina de detalii a aplicației Rețea Vai! Toate bune. Istoricul achizițiilor @@ -274,28 +276,32 @@ Nu s-a reușit preluarea raportului de confidențialitate Acces refuzat! Utilizezi VPN sau Tor\? Eroare internă! Încearcă din nou mai târziu - Ești limitat + Hopa, ești limitat Server inaccesibil Nu s-a reușit generarea sesiunii, cod de eroare: %1$d Implicit (din configurația dispozitivului) + Activează proxy-ul Versiunea Google Play Nu s-a putut genera sesiunea Titlul recenziei Adresa URL proxy Configurează intervale pentru actualizări, în ore. - Filtrează aplicațiile din alte surse + Numai aplicațiile Aurora Store + Proxy Permite magazinului Aurora să deschidă linkuri acceptate Adresa URL proxy nevalidă, verifică formatul! - Nu se verifică actualizările pentru aplicațiile instalate din surse din afara magazinului Aurora + Se verifică doar actualizările pentru aplicațiile instalate de Aurora Store Proxy setat cu succes - Link-urile aplicațiilor + Link-uri la aplicații Google Play, cunoscut și ca Google Play Store și anterior Android Market. Se verifică noua sesiune Setările aplicației + Furnizor - bestappsales.com Frecvența actualizărilor automate Nu s-a putut seta proxy + Permite întregului trafic din aplicație să treacă prin proxy Android Market a fost un magazin online care oferea aplicații software concepute pentru dispozitive Android, retras în 2017. - Actualizări automate + Actualizări automate ale aplicațiilor Verifică și notifică despre actualizările disponibile Verifică și instalează automat actualizările disponibile Nu se actualizează automat aplicațiile @@ -306,8 +312,8 @@ Fișierele APK nu au putut fi exportate Curățare finalizată Adaugă la ecranul de pornire - Afișează actualizările ce pot eșua - Afișează actualizări pentru aplicațiile incompatibile sau dezactivate pentru care ar putea eșua instalarea + Actualizări incompatibile + Afișează actualizări pentru aplicațiile incompatibile sau dezactivate care nu pot fi instalate Ai întrebări? Află răspunsurile Cod sursă Află ce se află înăuntru @@ -343,16 +349,20 @@ Adaugă Elimină Despre Aurora Store - Aurora Store permite căutarea și să descărcarea aplicațiilor din magazinul oficial Google Play. Poți verifica descrierile aplicațiilor, capturile de ecran, actualizările, comentariile altor utilizatori și poți descărca APK-ul direct de pe Google Play pe dispozitiv. Pentru a utiliza Aurora Store, trebuie să ai un cont Google Play și să te conectezi la contul Google Play atunci când deschizi și configurezi pentru prima dată Aurora Store. \n \nSpre deosebire de un magazin de aplicații tradițional, Aurora Store nu deține, nu licențiază și nu distribuie nicio aplicație. Toate aplicațiile, descrierile aplicațiilor, capturile de ecran și alt conținut din Aurora Store sunt accesate direct, descărcate și/sau afișate de pe Google Play. Aurora Store funcționează exact ca o ușă sau un browser, permițând conectarea la contul Google Play și găsirea aplicațiilor din Google Play. \n \nReține că Magazinul Aurora nu are nicio aprobare, sponsorizare sau autorizare de la Google, Google Play, nicio aplicație descărcată prin Magazin Aurora sau orice dezvoltator de aplicații; Aurora Store nu are nicio afiliere, cooperare sau legătură cu aceștia. + Aurora Store permite căutarea și să descărcarea aplicațiilor din magazinul oficial Google Play. Poți verifica descrierile aplicațiilor, capturile de ecran, actualizările, comentariile altor utilizatori și poți descărca APK-ul direct de pe Google Play pe dispozitiv. Pentru a utiliza Aurora Store, trebuie să ai un cont Google Play și să te conectezi la contul Google Play atunci când deschizi și configurezi pentru prima dată Aurora Store. +\n +\nSpre deosebire de un magazin de aplicații tradițional, Aurora Store nu deține, nu licențiază și nu distribuie nicio aplicație. Toate aplicațiile, descrierile aplicațiilor, capturile de ecran și alt conținut din Aurora Store sunt accesate direct, descărcate și/sau afișate de pe Google Play. Aurora Store funcționează exact ca o ușă sau un browser, permițând conectarea la contul Google Play și găsirea aplicațiilor din Google Play. +\n +\nReține că Magazinul Aurora nu are nicio aprobare, sponsorizare sau autorizare de la Google, Google Play, nicio aplicație descărcată prin Magazin Aurora sau orice dezvoltator de aplicații; Aurora Store nu are nicio afiliere, cooperare sau legătură cu aceștia. Adaugă un distribuitor de jetoane la Aurora Store. Distribuitoarele de jetoane furnizează acreditările contului Magazinului Aurora pentru a se conecta anonim. URL nevalid Nu există distribuitoare disponibile Adaugă distribuitor - Elimini distribuitorul? - Aplicația nu este disponibilă pentru acest dispozitiv + Elimină distribuitorul + Aplicația nu este disponibila pentru dispozitivul dvs. Favorit Nu s-a găsit nici-o aplicație favorită - Aplicații favorite + Aplicații Favorite Exportul favoritelor a eșuat! Favoritele au fost importate! Favoritele au fost exportate! @@ -365,10 +375,11 @@ Sunteți sigur(ă) că vreți să vă deconectați? Verifică actualizări Siguranța datelor - Mai întâi trebuie să acorzi permisiunea instalatorului + Mai întâi trebuie să acordați permisiunea instalatorului Necesar Opțional Practici privind confidențialitatea și securitatea datelor declarate de producător + Este posibil să trebuiască să acordați din nou permisiunea din cauza unei erori în cadrul de acces la stocare Permite instalarea aplicațiilor din surse necunoscute Repornește Aurora Store Aurora Store trebuie să fie repornită pentru ca noile schimbări să intre în efect @@ -391,6 +402,7 @@ Lista neagră importată! Lista neagră a fost exportată! Notificare legată de cont + Poate fi necesar să repornești aplicația pentru a reflecta acordarea permisiunii. Implicit Se verifică Disponibil @@ -399,77 +411,4 @@ Este necesară autentificarea Conectează-te la contul Google Play pentru a dezarhiva aplicația! Selectează tot - Nu există aplicații disponibile - Compatibilitate - Necesită Servicii Google Play - Cu proiectul microG - Funcționează fără serviciile Google Play - Această aplicație funcționează fără biblioteca proprietară de la a Google. Cu toate acestea, este posibil să solicite în continuare alte biblioteci terțe să funcționeze corect. - Este posibil să fie nevoie să instalezi biblioteca proprietară de la Google sau o reimplementare FOSS, cum ar fi Microg. - Fără serviciile Google Play - Compatibil: funcționează fără probleme - Limitat: funcționează cu caracteristici limitate - Neacceptat: nu funcționează - Necunoscut: nu este verificat încă - Imposibil de deschis aplicația - Alimentat de Plex - Verificarea compatibilității… - %1$d aplicații instalate - Dezactivează - Vizualizează și gestionează configurația proxy - Configurează restricțiile dispozitivului pentru actualizările automate - Numai pe rețelele nelimitate - Nu a reușit verificarea fișierelor descărcate - Când bateria nu este descărcată - Restricții actualizări automate - Proxy dezactivat cu succes - Când dispozitivul este inactiv - Autentifică-te folosind microG atunci când te conectezi la conturile Google, pentru un proces simplificat de conectare - Utilizează microG pentru a te conecta la conturi - Setează - Avansat - Sursa aplicației - Descărcări - Versiune Android minimă - Nivelul API țintă - Ultima actualizare - %1$d permisiuni - Instalează pachetul microG - Compatibilitatea aplicațiilor - Dependențe lipsă - Am citit și sunt de acord cu Termenii și Politica de confidențialitate microG - Nu am putut găsi serviciile Google Play pe dispozitiv, mai multe aplicații populare necesită prezența lor ca să funcționeze corect! - microG este o implementare gratuită și open-source, care oferă funcționalitate similară pentru a rula aplicații dependente de serviciile Google Play pentru dispozitivele Android prin reimplementare.\n\nmicroG permite aplicațiilor să acceseze acele API-uri Google, îmbunătățind compatibilitatea pentru utilizatori, oferind în același timp beneficii de confidențialitate.\n\nmicroG va rula automat în fundal atunci când deschizi aplicații dependente de Serviciile Google Mobile. - Citește Politica de confidențialitate microG - Citește Licența și Acordul microG - Accesează pagina web a proiectului microG - Date pe care această aplicație le poate colecta - Dezvoltatorul spune că această aplicație nu colectează datele utilizatorilor. - Date pe care această aplicație le poate partaja - Dezvoltatorul spune că această aplicație nu partajează datele utilizatorilor altor companii sau organizații. - Această versiune a aplicației poate conține mai mulți urmăritori care nu sunt încă prezenți în baza de date a confidențialității Exodus. - %1$d urmăritori cunoscuți găsiți în %2$s - Fără descriere - Mai multe informații - Obiective - Numele pachetului - Evaluare conținut - Selectează o aplicație pentru mai multe detalii - Fără publicitate - Fără serviciile Play - Codul versiunii poate conține doar cifre - Se pregătește instalarea - - Permisiune necesară - Permisiuni necesare - Permisiuni necesare - - Programul de instalare microG nu a reușit să instaleze aplicația, probabil din cauza unei configurări greșite. - Instalator microG - Necesită instalarea aplicației companion microG - Ajută la ocolirea verificării integrității aplicației (numai instalator) - Încărcare în curs - Pagina %1$d - Omite - Repornești pentru a aplica modificările? diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 8681d17f1..d0a47adcd 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -22,7 +22,7 @@ Рейтинги Платное Зависит от GSF - Скачивания + Загрузки Приложения с рекламой Все Фильтры @@ -55,14 +55,14 @@ Пожертвовать через PayPal Стать спонсором на Liberapay Исходный код Aurora Store в Aurora OSS на GitLab. - Скачать Aurora Store из репозитория F-Droid. + Загрузить Aurora Store из репозитория F-Droid. Пожертвовать через Ethereum (ETH) Пожертвовать через Bitcoin (BTC) Пожертвовать через Bitcoin Cash (BCH) Пожертвовать через UPI Установка заблокирована - Сначала установите Сервисы Aurora и предоставьте все разрешения. - Установите Сервисы Aurora 1.0.9 или новее, либо смените установщик. + Сначала установите сервисы Aurora и предоставьте все разрешения. + Установите сервисы Aurora 1.0.9 или новее, либо смените установщик. Сервисы Aurora доступны и готовы к установке. Нет root-доступа. Предоставьте его или смените программу-установщик. Две @@ -121,20 +121,20 @@ Информация о приложении Удалить Менеджер подмены - Убедитесь, что перезашли в профиль для применения подмены устройства + Убедитесь, что перезашли в аккаунт для применения подмены устройства Установка с помощью сессии (Android 5+) Условия предоставления услуг Положительный Отрицательный Отправить - Сохранить пакет приложения + Сохранить APK приложения Применена подмена устройства. Разрешение выдано Не удалось открыть настройки разработчика, убедитесь, что он включен в настройках устройства. Скопировано в буфер обмена Добавлен в белый список Добавлен в черный список - Недоступно когда анонимно + Недоступно на анонимных аккаунтах Обновления Настройки История покупок @@ -145,9 +145,10 @@ Установка Игры Play Маркет - Скачивания + Загрузки Устройство - Управление черным списком + Менеджер черного списка + Приложения со скидкой Приложения в библиотеке Мои приложения и игры Приложения @@ -161,12 +162,12 @@ Бестселлеры Выбор редакции Категории - Срок действия сеанса истек, повторно войдите в профиль для возобновления сеанса. + Срок действия сеанса истек, повторно войдите в аккаунт для возобновления сеанса. Не удалось получить файлы Приложение не найдено Приложение не поддерживается Приложение не куплено - Скачивание не удалось + Ошибка загрузки Внешний вид Способ установки Выберите режим установки APK @@ -176,12 +177,12 @@ Удалить APK-файлы после установки Загруженные APK-файлы будут удаляться сразу после установки Фильтр приложений F-Droid - Не проверять обновления для приложений установленных из F-Droid + Не проверять обновления для приложений, загруженных или установленных с F-Droid Разрешить установку приложений из Aurora Store Разрешения установщика - Менеджер внешнего хранилища + Менеджер памяти Для сохранения файлов с расширением APK (OBB) для больших приложений и игр. - Доступ к внешнему хранилищу + Доступ к памяти Как дела\? Добро пожаловать Разрешения @@ -205,10 +206,11 @@ Ошибка установки Разное Применить - Покупка приложений недоступна когда анонимно. + Покупка приложений недоступна для анонимных аккаунтов. Убедитесь, что выполнили новый вход и перезапустили приложение для применения изменений. Сеть - Показать страницу рекомендаций на главном экране + Показать секции похожих и связанных на странице приложения + Показать страницу рекомендаций на основном экране Вкладка по умолчанию Вкладки Дополнительно @@ -218,7 +220,7 @@ Поздравляем, запрошенный код версии доступен. Начинаем загрузку. Запрошенный вами код версии недоступен. Ручная загрузка - Пакетные приложения (разделенные, сплит) невозможно установить системным установщиком. Измените метод установки на Сессионный, Сервисы Aurora или Root. + Пакетные (сплит-) приложения через системный установщик установить невозможно. Измените метод установки на Сессионный, Сервисы Aurora или Root. Не удалось сгенерировать AAS-токен Не удалось поставить оценку Оценка принята, ее отображение может занять некоторое время @@ -230,7 +232,7 @@ Установите Менеджер Приложений или смените установщик. AppManager Приостановлено • %1$d / %2$d - Скачивание • %1$d / %2$d%3$s + Загрузка • %1$d / %2$d%3$s Последний сеанс отменен Проверка сеанса Проверка сеанса Google @@ -250,18 +252,18 @@ обновления(-ий) Произошла ошибка! Необходимые разрешения были отклонены. Пожалуйста, предоставьте их, чтобы продолжить действие - Поиск приложений и игр + Поиск в Приложениях и Играх %1$s • API %2$s Запрос новой сессии Сервер отключен на техобслуживание Импортировать Профиль устройства импортирован Не удалось импортировать профиль устройства - Скачивание дополнительных файлов для %1$s + Загрузка дополнительных файлов для %1$s %1$d доступно обновление - Доступна новая версия %1$s - Уведомления об обновлении - Доступно %1$d обновления + Новая версия %1$s доступна + Уведомления об обновлениях + %1$d обновления доступно %1$s и %2$s %1$s, %2$s и %3$s Shizuku не установлено или не настроено правильно. @@ -270,7 +272,7 @@ Поисковое предложение Результаты поиска Внутренняя ошибка! Пожалуйста, повторите попытку через некоторое время - Слишком много попыток входа + Сожалеем, слишком много попыток входа Сервер недоступен Не удалось создать сессию, код ошибки: %1$d Не удалось получить отчет о конфиденциальности @@ -284,20 +286,24 @@ Google Play, также известный как Google Play Store, а ранее - Android Market. Android Market - магазин приложений для устройств под управлением ОС Android, закрытый в 2017 году. Заголовок отзыва + Включить прокси URL прокси - Настроить интервал автоматических обновлений, в часах. + Настроить интервал автоматического и самостоятельного обновления в часах. + Прокси Неверный URL прокси, проверьте формат! - Не проверять обновления для приложений, установленных из других источников вне Aurora Store + Проверять обновления для приложений, установленных только с Aurora Store Прокси успешно настроен Настройки приложения + Провайдер - bestappsales.com Частота автоматических обновлений Не удалось настроить прокси - Фильтровать приложения из других источников + Только приложения из Aurora Store + Разрешить трафику приложения проходить через прокси По умолчанию (с конфигурации устройства) - Google Play версия + Версия Google Play Фоновые загрузки Разрешить Aurora Store загружать и обновлять приложения в фоне - Автоматические обновления + Автообновление приложений Проверять доступные обновления и уведомлять о них Не обновлять приложения автоматически Настройка поведения автоматических обновлений @@ -305,16 +311,16 @@ Запросить новый анализ Не удалось экспортировать APK-файлы Очистить завершенные - Показывать обновления которые могут не сработать + Несовместимые обновления Показывать обновления для несовместимых или отключенных приложений, которые могут не установиться - Добавить на главный экран + Добавить на Главный экран У вас есть вопросы? Узнайте ответы Исходный код Политика конфиденциальности Подотчетность и ответственность Сеансовый установщик для разделенных/пакетных файлов APK Рекомендованный, встроенный и поддерживает все версии Android - Установщик основанный на Shell, использующий Root права суперпользователя + Установщик основанный на Shell, использующий Root права Требует права Root/суперпользователя, поддерживает все версии Android. Лучше всего подходит для устройств, работающих под управлением Android 4.4 Установщик для фоновых установок @@ -328,27 +334,31 @@ Требуется App Manager, необходим adb/root режим, чтобы произвести установку при включенной MIUI оптимизации Использует API системы напрямую с adb/root привилегиями Еще - Управление профилем + Управление аккаунтом Удалить запись о владельце устройства Удаляет Aurora Store как приложение владельца устройства Это удалит разрешение у session installer на автоматическую установку приложений. Продолжить? Wiki Просмотр и управление распределителями токенов для анонимной авторизации Добавить - Пожалуйста, войдите в свой профиль Google Play + Пожалуйста, войдите в свой аккаунт Google Play О Aurora Store Узнайте больше о Aurora Store Удалить Управление распределителями Нет доступных распределителей Добавить распределитель - Некорректный URL-адрес - URL-адрес распределителя - Удалить распределитель? + Некорректный URL + URL рапределителя + Удалить распределитель Вы хотите удалить распределитель \"%1$s\"? - Найдите ответы на часто задаваемые вопросы (ЧаВо), шаги по устранению неполадок и многое другое - Aurora Store позволяет искать и загружать приложения из официального магазина Google Play. Вы можете ознакомиться с описанием приложений, скриншотами, обновлениями, комментариями других пользователей и загрузить APK непосредственно из Google Play на свое устройство. Чтобы использовать Aurora Store, необходимо иметь профиль Google Play и войти в него при первом открытии и настройке Aurora Store. \n \nВ отличие от традиционного магазина приложений, Aurora Store не владеет, не лицензирует и не распространяет приложения. Все приложения, описания приложений, скриншоты и прочий контент в Aurora Store напрямую доступны, загружаются и/или отображаются из Google Play. Aurora Store работает точно так же, как дверь или браузер, позволяя вам войти в свой профиль Google Play и найти приложения из Google Play. \n \nОбратите внимание, что Aurora Store не имеет никакого соглашения, спонсорства или разрешения от Google, Google Play, любых приложений, загружаемых через Aurora Store, или разработчиков приложений; Aurora Store также не имеет с ними никакого родства, сотрудничества или связи. - Добавьте распределитель токенов в Aurora Store. Распределители токенов обеспечивают Aurora Store профилями для анонимной авторизации. + Найдите ответы на часто задаваемые вопросы (F.A.Q.), шаги по устранению неполадок и многое другое + Aurora Store позволяет искать и загружать приложения из официального магазина Google Play. Вы можете ознакомиться с описанием приложений, скриншотами, обновлениями, комментариями других пользователей и загрузить APK непосредственно из Google Play на свое устройство. Чтобы использовать Aurora Store, необходимо иметь аккаунт Google Play и войти в него при первом открытии и настройке Aurora Store. +\n +\nВ отличие от традиционного магазина приложений, Aurora Store не владеет, не лицензирует и не распространяет приложения. Все приложения, описания приложений, скриншоты и прочий контент в Aurora Store напрямую доступны, загружаются и/или отображаются из Google Play. Aurora Store работает точно так же, как дверь или браузер, позволяя вам войти в свой аккаунт Google Play и найти приложения из Google Play. +\n +\nОбратите внимание, что Aurora Store не имеет никакого соглашения, спонсорства или разрешения от Google, Google Play, любых приложений, загружаемых через Aurora Store, или разработчиков приложений; Aurora Store также не имеет с ними никакого родства, сотрудничества или связи. + Добавьте распределитель токенов в Aurora Store. Распределители токенов обеспечивают Aurora Store аккаунтами для анонимной авторизации. Введите действительный URL прокси для передачи всех данных через него. Избранное Избранные приложения не найдены @@ -359,7 +369,7 @@ Избранное импортировано! Избранное экспортировано! Пакетное приложение успешно экспортировано - Не удалось экспортировать набор приложений + Не удалось экспортировать пакетное приложение Успешно удалено Выйти? Вы действительно хотите выйти? @@ -369,19 +379,20 @@ Перезапустить Aurora Store Разрешать установку приложений из неизвестных источников Сначала вам необходимо предоставить разрешение установщику + Возможно, вам придется повторно предоставить разрешение из-за ошибки в Storage Access Framework Обязательно Не обязательно Безопасность данных Практика конфиденциальности и безопасности данных, заявленная разработчиком Необходимо перезапустить Aurora Store для применения новых настроек Сделано с %1$s в Индии - Уведомление, связанное с профилем - Скачивание + Уведомление, связанное с аккаунтом + Загрузка Недоступно Завершено В очереди Необходима аутентификация - Пожалуйста, войдите в ваш профиль Google Play, чтобы разархивировать приложение! + Пожалуйста, войдите в ваш аккаунт Google Play, чтобы разархивировать приложение! Проверка обновлений Не удалось Отменено @@ -395,6 +406,7 @@ Черный список экспортирован! По умолчанию Выбрать все + Вам может потребоваться перезагрузить приложение, чтобы применить выданное разрешение. Не удалось экспортировать черный список! Доступно Проверка @@ -404,9 +416,9 @@ Проверка совместимости… Совместимость Требует Сервисы Google Play - Вам может потребоваться установить библиотеку от Google или свободную реализацию, такую как microG. + Вам может потребоваться установить проприетарную библиотеку Google или FOSS реализацию, такую как microG. Работает без Сервисов Google Play - Данное приложение работает без библиотеки от Google. Тем не менее оно все еще может требовать другие сторонние библиотеки для правильной работы. + Данное приложение работает без проприетарной библиотеки Google. Тем не менее, оно все еще может требовать другие сторонние библиотеки для правильной работы. Совместимо: Работает без каких-либо проблем Ограничено: Работает только с ограниченным функционалом Не поддерживается: Неработоспособно @@ -415,62 +427,4 @@ С Проектом microG Без Сервисов Google Play Нет доступных приложений - Использовать microG для входа в профили - Аутентифицировать через microG при входе в профиль Google для упрощенного процесса входа - Настроить - Отключить - Прокси отключен успешно - Просмотр и управление конфигурацией прокси - Ограничения автоматического обновления - Только в сетях без ограничения трафика - Когда устройство не используется - Настроить ограничения устройства для автоматических обновлений - Когда батарея не разряжена - Не удалось проверить загруженные файлы - Минимальная версия Android - Источник приложения - %1$d разрешений - Целевая версия API - Загрузки - Последнее обновление - Расширенные - Совместимость приложений - Отсутствующие зависимости - Я прочитал и согласен с условиями предоставления услуг и политикой конфиденциальности microG - Мы не смогли найти сервисы Google Play на вашем устройстве. Некоторые популярные приложения требуют его для корректной работы! - microG - это свободная разработка с открытым исходным кодом, которая обеспечивает нужную функциональность для работы приложений, зависящих от Google Play Services, на устройствах Android.\n\nmicroG обеспечивает доступ приложений к API Google, повышая совместимость и обеспечивая конфиденциальность.\n\nmicroG будет запускаться автоматически в фоновом режиме при открытии приложений, зависящих от Google Mobile Services. - Прочитать политику конфиденциальности microG - Прочитать Лицензию и Соглашение microG - Посетите сайт проекта microG - Установите пакет microG - Данные, которые может собирать это приложение - Разработчик утверждает, что это приложение не собирает данные пользователей. - Данные, которые может передавать это приложение - Разработчик утверждает, что это приложение не передает данные пользователей другим компаниям или организациям. - Эта версия приложения может содержать дополнительные трекеры, которые еще не внесены в базу данных Exodus Privacy. - Известных трекеров, найденных в %2$s: %1$d - Описание отсутствует - Дополнительная информация - Цели - Название пакета - Рейтинг контента - Выберите приложение для получения более подробной информации - Без рекламы - Без сервисов Google Play - Код версии может содержать только цифры - Подготовка к установке - - Требуется разрешение - Требуются разрешения - Требуются разрешения - Требуются разрешения - - Загрузка в прогрессе - Страница %1$d - Установщик MicroG не смог установить приложение, вероятнее всего, из-за проблем с конфигурацией. - Установщик MicroG - Пропустить - Требует установки дополнительного приложения microG - Помогает пропустить проверку целостности приложения (только для установщика) - Перезапустить чтобы применить изменения? diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml new file mode 100644 index 000000000..4d33316a2 --- /dev/null +++ b/app/src/main/res/values-sc/strings.xml @@ -0,0 +1,234 @@ + + + Liberapay + Diveni unu sustenidore in Liberapay + PayPal + Intra impreende + Essi dae Aurora + In segus + Annanghe a sa lista niedda + Còpia + Acabba + Sarva su pachete de aplicatziones + Fruni + Frunidu + Ignora + AB + In suspesu + Pùblica + Chirca + Programma Beta + Pigare parte a su programma beta? + As a bìdere sas funtzionalidades e sas faddinas noas in antis de su pùblicu. Dae s\'opinione tua a sos isvilupadores pro los agiudare a megiorare. + S\'iscritzione diat pòdere pigare unu pagu de tempus. Torra a verificare s\'istadu prus a tardu. + Registru de sas modìficas + Registru de sas modìficas non frunidu + Cuntenet publitzidade + Dipendèntzias + Descritzione + Profilu de s\'isvilupadore + Tenet bisòngiu de GSF + Àteras informatziones subra de s\'aplicatzione + Peruna aplicatzione currispondente agatada + Peruna dipendèntzia + Perunu permissu + A pagamentu + Riservadesa + Votos e retzensiones + Ite nde pensas de custa aplicatzione\? + Annulladu + Carculende + Iscarrigamentu fallidu + Stima in cursu + Chirchende arrastadores… + arrastadore(s) agatadu(os) in + Crìticas + Chimbe + Bator + Unu + Tres + Duos + Installa su gestore de aplicatzione o muda s\'installadore. + Chene atzessu de raighina. Fruni·lu o muda s\'installadore. + Sos servìtzios de Aurora sunt a disponimentu e prontos pro s\'installatzione. + Installa sos servìtzios Aurora 1.0.9 o prus noos, o muda s\'installadore. + A primu imposta sos servìtzios de Aurora e fruni totu sos permissos. + Installatzione fallida + Creatzione de sa sessione fallida + Esistit unu pachete in cunflitu + Tretu in memòria chi non bastat + MIUI agatadu! + S\'installadore de sessione non podet installare aplicatziones pro neghe de sas otimizatziones de MIUI. + Inabìlita sas otimizatziones pro permìtere s\'installatzione, si nono podet isseberare s\'installadore de raighina o de sos servìtzios. + Si cheres podes isseberare s\'installadore nativu, ma tando no as a pòdere installare sos APK agrupados (partzidos). + Non podes installare sas aplicatziones agrupadas (partzidas) cun s\'installadore nativu. Muda s\'installadore tuo a su de sessione, servìtzios o raighina. + Aurora Store tenet bisòngiu de sos permissos chi sighint + Installadore + Comente andat\? + Atzessu a sa memòria esterna + Pro sarvare sos iscarrigamentos (APK e OBB), esportare e importare sas configuratziones de su dispositivu a e dae sa memòria esterna. + Gestore de sa memòria esterna + Permissu de s\'installadore + Permite s\'installatzione de aplicatziones dae s\'Aurora Store + Extras + Sos APK s\'ant a iscantzellare comente impostatzione predefinida + Installadore AM. + Installadore nativu + Installadore de raighina + Installadore de sessione + Retze + Personalizatzione + Dispositzione + Pàginas pro tene + Ammustra sas pàginas pro tene in s\'ischermada printzipale + Aplicatziones simigiantes e ligadas + Iscarrigamentu fallidu + Aplicatzione non comporada + Aplicatzione non suportada + No est istadu possìbile otènnere sos archìvios + Sessione iscadida, torra a intrare pro nde otènnere una noa. + Assegura·ti de torrare a intrare pro aplicare sa simulatzione + Assegura·ti de torrare a intrare e de torrare a allùghere s\'aplicatzione pro aplicare sas modìficas. + Seletzione de sos editores + Pro tene + Classìficas + Prus bèndidas + Aplicatziones + Aplicatziones e giogos meos + Aplicatziones in sa biblioteca + Aplicatziones in oferta + Gestore de sa lista niedda + Dispositivu + Giogos + Peruna connessione + Iscarrigamentu manuale + No a disponimentu in sos contos anònimos + Copiadu in punta de billete + Allughe sas impostatziones de isvilupu dae sas impostatziones de su dispositivu pro las abèrrere. + Simulatzione de su dispositivu aplicada. + Sas còmporas de aplicatziones non sunt a disponimentu in sos contos anònimos. + Su còdighe de sa versione chi ses pedende no est a disponimentu. + Bene meda, su còdighe de sa versione est a disponimentu. Iscarrigamentu in cursu. + Valutadu + Imbiu de sa valutatzione fallidu + Generatzione de su getone AAS fallidu + Anònimu + Abìlita s\'iscarrigamentu de sas aplicatziones in s\'isfundu + Contu de Google + Lista niedda + Annulla + Isbòida + Còpia ligàmene + Disabìlita + Esporta + Filtros + Totu + Àplica + Aplicatziones cun publitzidade + Iscarrigamentos + Vàrias + A pagamentu + Valutatziones + Installatziones + Prus a tardu + Essi + Imbeniente + Torra a allùghere + Sighi + Disinstalla + Lista bianca + De badas + De badas prus populares + Prus redditìtzias + De tendèntzia + Installa + Installende + Peruna publitzidade + Aberi + Cumpartzi + Agiorna + Annulla totu + Iscarrigamentu acabadu + Fortza Iscantzella totu + Pone totu in pàusa + In isetu + Sighi cun totu + Aplicatzione no agatada + Non cuntenet arrastadores + Alimentadu dae Exodus + Abbàida su raportu + Dipendente dae GSF + Perunu agiornamentu disponìbile + Installadas + Agiorna totu + Avisu + Contos + Iscarrigamentos + Litzèntzia + Impostatziones + Tèrmines de impreu + Bogat sas aplicatziones de F-Droid dae sa lista de sas aplicatziones + Filtra sas aplicatziones de F-Droid + Iscantzella sos apk a pustis de s\'installatzione + Ischerta sa manera de installatzione de sos APK + Manera de installatzione + Auni·ti + Abbandona + Ses unu proadore beta + Permissos + Bene bènnidu + In sa lista niedda + In sa lista bianca + Limba + Faghe·mi una donatzione in Paypal + F-Droid + GitLab + Otene su còdighe mitza de Aurora Store dae Aurora OSS in GitLab. + Telegram + Auni·ti a su grupu de suportu de Aurora Store pro arresonos e impòsitos. + Discussione Isvilupadores + Pòmpia·ti sa discussione de Aurora Store in XDA pro arresonos o impòsitos. + Serra + Ischerta s\'ischeda prefefinida + Perunu iscarrigamentu + Permissu + Play Store + Apl. non cumpatìbile + Informatziones apl. + S\'installatzione est istada blocada + APK non vàlidu o corrùmpidu + Installatzione resèssida + Isetende pro sa cunfirma de s\'impreadore + Totus + B\'at un\'agiornamentu nou disponìbile + Cuntatos de s\'isvilupadore + Posta eletrònica + Indiritzu + Situ web + Categorias + Positiva + Bitcoin + Dona pro mèdiu de Bitcoin (BTC) + Bitcoin Cash + Dona pro mèdiu de Bitcoin Cash (BCH) + Ethereum + Dona pro mèdiu de Ethereum (ETH) + BHIM - UPI + Dona pro mèdiu de UPI + Retzende meta-datos + Ammustra sos grupos de aplicatziones simigiantes e ligados in sa pàgina de sos detàllios de s\'aplicatzione + Otene Aurora Store pro mèdiu de F-Droid. + Servìtzios de Aurora + Installatzione + Biblioteca + Cronologia de sas còmporas + Gestore de simulatzione + Installadore de aplicatziones + Agiornamentos + Iscarrigamentu de sas aplicatziones in s\'isfundu + Permissu frunidu + Pàgina de navigatzione no a disponimentu + Configuratzione de su dispositivu esportada + Esportatzione de sa configuratzione de su dispositivu fallida + Informatziones + diff --git a/app/src/main/res/values-si/strings.xml b/app/src/main/res/values-si/strings.xml index c93f8d082..0920ce005 100644 --- a/app/src/main/res/values-si/strings.xml +++ b/app/src/main/res/values-si/strings.xml @@ -99,6 +99,7 @@ ප්ලේ ස්ටෝර් බාගැනීම් උපාංගය + විකිණීමට ඇති යෙදුම් යෙදුම් ගිණුම් පිළිබඳව @@ -234,6 +235,7 @@ වි. %1$d ත. %2$d ක් ඉතිරිය ත. %1$d ක් ඉතිරිය දැනුම්දීම් + යෙදුමේ විස්තර පිටුවේ සමාන හා ආශ්‍රිත පර්ෂද පෙන්වන්න ඔක්කොම හරි! ඇතුළු වී අත්විඳින්න. සූදානම් කෙරෙමින්… @@ -307,6 +309,8 @@ අසමත් විය යාවත්කාල සොයමින් නොතිබේ + ප්‍රතියුක්තය + ප්‍රතියුක්තය සබල කරන්න ප්‍රියතම දත්ත ආරක්‍ෂාව යාවත්කාල බලන්න diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 4990b1706..7b9b6f917 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -49,7 +49,7 @@ Rozpoznané MIUI! Inštalátor relácie nemôže nainštalovať aplikácie kvôli optimalizácii MIUI. Prostredníctvom natívneho inštalátora nemôžete nainštalovať pribalené (rozdelené) aplikácie. Zmeňte inštalačný program na Reláciu, Služby alebo Root. - Nekontrolovať F-Droid aplikácie z nainštalovaných aplikácií + Nekontrolovať F-Droid aplikácie z aktualizácií a nainštalovaných aplikácií AM inštalátor Google obchod verzia Zobraziť stránky pre vás na domovskej obrazovke @@ -118,6 +118,7 @@ Viac o aplikácií Nenašla sa žiadna zhoda aplikácie Sieť + Proxy Sťahovanie aplikácie na pozadí Umožňuje sťahovanie aplikácie na pozadí Zásady ochrany osobných údajov @@ -140,6 +141,9 @@ Shizuku inštalátor Inštalátor relácie Predvolené (z konfigurácie zariadenia) + Povoliť proxy + Povoliť všetku sieťovú prevádzku aplikácie cez server proxy + Zobraziť podobné a súvisiace skupiny na stránke podrobností aplikácie Nekompatibilné aktualizácie Zobraziť aktualizácie pre nekompatibilné alebo zakázané aplikácie, ktoré môžu zlyhať pri nštalovaní Iba aplikácie Aurora obchod @@ -151,7 +155,7 @@ Požiadať o novú reláciu Sťahovanie dodatočných súborov pre %1$s %1$d dostupná aktualizácia - Nakonfigurovať správanie automatických aktualizácií + Nakonfigurujte správanie automatických aktualizácií Frekvencia automatických aktualizácií Server je nedostupný Nepodarilo sa vygenerovať reláciu, kód chyby: %1$d @@ -202,9 +206,12 @@ Pre vás Najlepšie zdarma Aplikácie v knižnici + Aplikácie v zľave Inštalačný program aplikácie Najprv musíte udeliť povolenie inštalátorovi + Možno budete musieť znova udeliť povolenie kvôli chybe v prístupe úložiska Požadované + Poskytovateľ - bestappsales.com Voliteľné Server je mimo prevádzky z dôvodu údržby Hry @@ -216,7 +223,7 @@ Skontrolovať dostupné aktualizácie a informovať o nich %1$s, %2$s, %3$s a %4$d viac Neaktualizovať aplikácie automaticky - Nastaviť interval pre vlastné automatické aktualizácie v hodinách. + Nastaviť intervaly pre automatické a vlastné aktualizácie v hodinách. Ups, váš účet je obmedzený Nepodarilo sa vygenerovať reláciu Overuje sa nová relácia @@ -227,7 +234,11 @@ Inštalátor balíkov/rozdelených súborov APK založený na relácii Odporúčané, vstavané a podporuje všetky verzie systému Android Inštalátor založený, dostupný na všetkých zariadeniach - Aurora vám umožňuje vyhľadávať a sťahovať aplikácie z oficiálneho obchodu Google Play. Môžete skontrolovať popisy aplikácií, snímky obrazovky, aktualizácie, komentáre ostatných používateľov a stiahnuť si súbor APK priamo zo služby Google Play do svojho zariadenia. Ak chcete používať Aurora Store, musíte mať účet Google Play a prihlásiť sa do svojho účtu Google Play pri prvom otvorení a konfigurácii obchodu Aurora. \n \nNa rozdiel od tradičného obchodu s aplikáciami Aurora Store nevlastní, nelicencuje ani nedistribuuje žiadne aplikácie. Všetky aplikácie, popisy aplikácií, snímky obrazovky a ďalší obsah v obchode Aurora sú priamo prístupné, stiahnuté a/alebo zobrazené z Google Play. Aurora Store funguje presne ako dvere alebo prehliadač, vďaka čomu sa môžete prihlásiť do svojho účtu Google Play a nájsť aplikácie zo služby Google Play. \n \nUpozorňujeme, že Aurora nemá žiadne schválenie, sponzorstvo ani autorizáciu od spoločnosti Google, Google Play, žiadnych aplikácií stiahnutých cez Aurora ani žiadnych vývojárov aplikácií; ani Aurora Store s nimi nemá žiadne spojenie, spoluprácu alebo spojenie. + Aurora vám umožňuje vyhľadávať a sťahovať aplikácie z oficiálneho obchodu Google Play. Môžete skontrolovať popisy aplikácií, snímky obrazovky, aktualizácie, komentáre ostatných používateľov a stiahnuť si súbor APK priamo zo služby Google Play do svojho zariadenia. Ak chcete používať Aurora Store, musíte mať účet Google Play a prihlásiť sa do svojho účtu Google Play pri prvom otvorení a konfigurácii obchodu Aurora. +\n +\nNa rozdiel od tradičného obchodu s aplikáciami Aurora Store nevlastní, nelicencuje ani nedistribuuje žiadne aplikácie. Všetky aplikácie, popisy aplikácií, snímky obrazovky a ďalší obsah v obchode Aurora sú priamo prístupné, stiahnuté a/alebo zobrazené z Google Play. Aurora Store funguje presne ako dvere alebo prehliadač, vďaka čomu sa môžete prihlásiť do svojho účtu Google Play a nájsť aplikácie zo služby Google Play. +\n +\nUpozorňujeme, že Aurora nemá žiadne schválenie, sponzorstvo ani autorizáciu od spoločnosti Google, Google Play, žiadnych aplikácií stiahnutých cez Aurora ani žiadnych vývojárov aplikácií; ani Aurora Store s nimi nemá žiadne spojenie, spoluprácu alebo spojenie. Balík aplikácie bol úspešne exportovaný Nenašli sa žiadne obľúbené aplikácie Žiadne závislosti @@ -257,12 +268,12 @@ Zistite viac o obchode Aurora Pridať Adresa URL dávkovača - Odstrániť dávkovač? + Odstrániť dávkovač Odstrániť Nepodarilo sa importovať obľúbené položky! Chcete odstrániť dávkovač \"%1$s\"? Wau! Všetko funguje. - Automatické aktualizácie + Automaticky aktualizovať aplikácie Zadajte kód verzie, ktorú chcete stiahnuť Ignorovať Inštalovať @@ -390,6 +401,7 @@ Vyrobené s %1$s v Indii Predvolené K dispozícií + Možno budete musieť reštartovať aplikáciu, aby odrážal grant. Najnovšia Nepodarilo sa importovať čiernu listinu! Overujem @@ -415,62 +427,4 @@ Kontrolujem kompatibilitu… Nie sú k dispozícii žiadne aplikácie %1$d nainštalované aplikácie - Na prihlásenie do účtov použite microG - Pri prihlasovaní do účtov Google sa overte pomocou microG, čím si zjednodušíte prihlasovací proces - Zakázať - Proxy bol úspešne deaktivovaný - Zobrazenie a správa konfigurácie servera proxy - Len v nemeraných sieťach - Keď je zariadenie nečinné - Nakonfigurovať obmedzenia zariadenia pre automatické aktualizácie - Nastaviť - Obmedzenia automatických aktualizácií - Keď batéria nie je vybitá - Overenie stiahnutých súborov zlyhalo - Stiahnuté - Naposledy aktualizované - Minimálne Android verzia - Cieľová úroveň rozhrania API - Rozšírené - Zdroj aplikácie - Inštalovať balík microG - Údaje, ktoré môže táto aplikácia zhromažďovať - Vývojár tvrdí, že táto aplikácia nezhromažďuje údaje používateľa. - Údaje, ktoré môže táto aplikácia zdieľať - Vývojár tvrdí, že táto aplikácia nezdieľa údaje používateľov s inými spoločnosťami alebo organizáciami. - Táto verzia aplikácie môže stále obsahovať ďalšie sledovacie zariadenia, ktoré ešte nie sú v databáze Exodus Privacy. - Prečítajte si licenciu a zmluvu microG - Prečítajte si zásady ochrany osobných údajov spoločnosti microG - Navštívte webovú stránku projektu microG - Fragment s podrobnosťami o aplikácii - %1$d oprávnení - Viac informácií - Ciele - Názov balíka - Hodnotenie obsahu - Vyberte aplikáciu pre viac informácií - Žiadne reklamy - Žiadne Play služby - Kompatibilita aplikácie - Chýbajúce závislosti - Prečítal som si a súhlasím s podmienkami používania služby microG a so zásadami ochrany osobných údajov - Vo vašom zariadení sme nenašli službu Google Play, viaceré populárne aplikácie ju teraz vyžadujú na správne fungovanie! - %1$d známy/e sledovač/e nájdené v %2$s - microG je bezplatná implementácia s otvoreným zdrojovým kódom, ktorá poskytuje podobné funkcie na spúšťanie aplikácií závislých od služieb Google Play pre zariadenia so systémom Android prostredníctvom reimplementácie.\n\nmicroG umožňuje aplikáciám prístup k týmto rozhraniam API spoločnosti Google, čím zvyšuje kompatibilitu pre používateľov a zároveň ponúka výhody v oblasti ochrany osobných údajov. \n\nmicroG sa automaticky spustí na pozadí pri otvorení aplikácií závislých od mobilných služieb Google. - Kód verzie môže obsahovať iba číslice - Príprava na inštaláciu - - Potrebné povolenie - Potrebných povolení - Potrebné povolenia - Potrebné povolenia - - MIcroG inštalátor zlyhal pri inštalácií aplikácie, pravdepodobne z dôvodu miskonfigurácie. - MicroG inštalátor - Vyžaduje doplnkovú MicroG aplikáciu na správne fungovanie - Pomáha obísť kontrolu App Integrity (iba inštalátor) - Prebieha načítanie - Strana %1$d - Reštartovať pre uplatnenie zmien? - Preskočiť diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index b714fc636..5a35a1128 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -144,7 +144,7 @@ Namestitev je bila blokirana Čakam na potrditev uporabnika Prosimo, izključite optimizacije MIUI, da omogočite nameščanje ali uporabite nameščanje s servisom ali korensko nameščanje. - Zaustavljeno • %1$d / %2$d + Zaustavljeno •%1$d / %2$d Shizuku namestitveni program AM namestitveni program Prenešeni APK-ji bodo izbrisani takoj po namestitvi @@ -169,13 +169,14 @@ še %1$dh %2$dm %3$ds še %1$dm %2$ds še %1$ds - Prenašanje • %1$d / %2$d%3$s + Prenašanje •%1$d / %2$d%3$s Sejni namestitveni program Izberite način namestitve APK Omreženje Najboljše dobičkonosne Najboljše plačane Aplikacije v knjižnici + Aplikacije v prodaji Upravitelj črnega seznama Konfiguracija naprave je uvožena Ni bilo mogoče uvoziti konfiguracije naprave @@ -272,6 +273,7 @@ Filtrirajte F-Droid aplikacije Prilagajanje Strani za vas + Prikaži podobne in sorodne gruče na strani s podrobnostmi o aplikaciji Meni Wiki Poiščite odgovore na pogosto zastavljena vprašanja (F.A.Q.), korake za odpravljanje težav in več @@ -285,15 +287,16 @@ Neveljaven URL posrednika, preverite obliko! Dovoli Aurora Store odpiranje podprtih povezav Oceni naslov + Dovoli ves promet iz aplikacije skozi posrednika Pokaži posodobitve za nezdružljive ali onemogočene aplikacije, katerih namestitev lahko spodleti - Samodejne posodobitve + Samodejno posodobi aplikacije Google Play, znan tudi kot Google Play Store in prej znan kot Android Market. Izvoz APKjev ni uspel Priljubljene aplikacije Nastavitve aplikacije Posrednik uspešno nastavljen Nastavitev posrednika ni uspela - Nastavi obnašanje samodejnih posodobitev + Nastavi obnašanje samodejnega posodabljanja Zahtevano Obvestilo v povezavi z računom Prenosi v ozadju @@ -302,6 +305,7 @@ Najprej morate odobriti dovoljenje za nameščanje Preveri in namesti razpoložljive posodobitve samodejno Vnesite veljaven URL posrednika za prenos vseh podatkov skozi posrednika. + Ponudnik - bestappsales.com Ne posodobi aplikacij samodejno Jezik aplikacije Povezave aplikacij @@ -312,9 +316,12 @@ Samo Aurora Store aplikacije Preveri in obvesti za razpoložljivimi posodobitvami Pogostost samodejnih posodobitev + Posrednik Dovoli namestitev aplikacij iz neznanih virov + Omogoči posrednika Nezdružljive posodobitve Dovoli Aurora Store prenose in posodobitve aplikacij v ozadju + Morda boste morali ponovno odobriti dovoljenje zaradi hrošča v Storage Access Framework-u Izberite privzeti zavihek Izbirno Počisti končane @@ -331,7 +338,7 @@ Vnovično zaženi Aurora Store Dodaj dozirnik žetona v Aurora Store. Dozirnik žetona priskrbi podatke računa v Aurora Store, za anonimno prijavljanje. Ali želite odstraniti dozirnik \"%1$s\"? - Nastavite časovni interval za samodejne posodobitve, v uri. + Nastavite intervale za samodejne posodobitve, v uri. Vnesite kodo različice, ki jo želite prenesti Izvorna koda Odkrijte, kaj se skriva znotraj @@ -390,6 +397,7 @@ Na voljo ni dozirnikov Na voljo Privzeto + Morda boste morali vnovično zagnati aplikacijo za uveljavitev odobrenega dovoljenja. Odstrani vse Izberi vse Zadnje @@ -401,29 +409,4 @@ Preverjanje Ni mogoče odpreti aplikacije %1$d aplikacij nameščenih - Ta aplikacija deluje brez Googlove lastniške knjižnice. Kakor koli, morda bo še vedno zahtevala knjižnice tretje osebe za pravilno delovanje. - Brez storitev Google Play - Združljiva: Deluje brez težav - Omejena: Deluje z omejenimi funkcijami - Združljivost - Poganja Plexus - Preverjanje združljivosti… - Nepodprta: Ni delujoča - Neznano: Še ni preverjena - Uporabi microG za vpis v račune - Overite z uporabo microG, ko se vpisujete v račune Google za preprostejši tok vpisa. - Zahteva storitve Google Play - Na voljo ni nobena aplikacija - Morda boste morali namestiti Googlovo lastniško knjižnico ali FOSS izvedbo, kot je microG. - Deluje brez storitev Google Play - S projektom microG - Nastavi - Onemogoči - Posrednik uspešno onemogočen - Preglej in upravljaj nastavitev posrednika - Omejitve samodejnih posodobitev - Nastavi omejitve naprave za samodejne posodobitve. - Samo na nemerjenih omrežjih - Ko je naprava v pripravljenosti - Ko napolnjenost baterije ni nizka diff --git a/app/src/main/res/values-so/strings.xml b/app/src/main/res/values-so/strings.xml new file mode 100644 index 000000000..42c407e62 --- /dev/null +++ b/app/src/main/res/values-so/strings.xml @@ -0,0 +1,234 @@ + + + Ugu deeq - UPI + BHIM - UPI + Ugu deeq - Bitcoin Cash (BCH) + GitLab + Kasoo dagso Aurora Store F-Droid. + F-Droid + Ugu deeq - Ethereum (ETH) + Ethereum + Ugu deeq Bitcoin (BTC) + Bitcoin + Kaashka Bitkooyn + Appska + Geemam + Appska & Gemaamka + Saar + Kushubaya + Kushubida + Kushub + Ka hel koodhka Aurora Store barta GitLab ee Aurora OSS. + Kusaabsan dukaanka + Kasoo fur fadhiyada curiyaasha xaga fadhiga aallada si aad ufurto. + Fadhiga + Xaqiiji inaad dib usoo gasho akoonka si uu iska-dhigdhigidu u hirgalo + Iska-dhigida aalada waa la hirgaliyay. + Maamulaha iska-dhigaha + Liberapay + Laxanibay + Maamulaha xannibaada + Kudar Xannibaada + Xannibaada + Apps xaraash ah + Dhammaan wada nadiifi + Dhamaan siiwad + Siiwad + Wada haki + Majiraan wax lasoo dajiyay + Noocyada + Kuwa sare + Adiga + Cusboonaysiin + Kujira + Dhaliilaha + Wuxuu ogolaadaa in appka dajintiisa xaga dambe laga wado + Dajinta appka xaga dambe + Bogga joogtada ah + Shaandhaynta + Lama gudbin karo fadhiga aallada + Fadhiga aallada waa lagudbiyay + Lama abuuri karo Matalaha AAS + Lama gudbin karo qiimaynta + Laqiimeeyay + Bogga Dhexmushaax lama heli karo + Hambalyo, lambarka tirsiga waa laheli karaa waana la dajinayaa. + Lambarka tirsiga aad codsanayso lama helikaro. + Iibsashada appska looma heli karo akoonada garanwaaga ah. + Codsiga waa la ogolaaday + Dhakada ayaa lagu qabtay + Lagu daray La ogolaaday + Looma heli karo akoonada garanwaaga ah + Dajin gacanta ah + Kaydka iibsiga + Khad majiro + Maktabada + Luuqada + Kushubaha appka + Kushubida + Play Store + Soodajinta + Aallada + Appska maktabada kujira + Akoonada + Shiddan + Kuwa lacagta sare + Iibsiga sare + Bilaashka sare + Dookha tafatiraha + Hubso inaad dib-u-gasho oo aad dib usoo bilowdo appka si aad u hirgaliso wax-kabadalka. + Xidhiidhkii wuu dhacay, dib-u-gal si aad xidhiidh cusub usamayso. + Lama heli karo faylasha + Appka lama helin + Appka lama taageerin + Appka lama iibsanin + Dajintii maguulaysan + Soodhig appska lamidka ah iyo kuwa laxidhiidha bogga faahfaahinta appka + Lamid ah & laxidhiidha + Boggaga Adiga shaashada hore soodhig + Boggaga Adiga + Qaabka + Habaynta + Khadka + Habka kushibida + Dooro habka kushubida APK-ga + Kushubaha Xidhiidhka + Adeega Aurora + Kushubaha Root + Kushubaha aallada + Saar marka lagushubo + APK-ga waa lasaari (waa hadaada fadhiga badalin) + Shaandee appska F-Droid + Wuxuu liistada kasaaraa appska F-Droid + Dheeraad + Ogolow in Dukaanka Aurora appska lagaga sooshubo + Fasaxa Kushubaha + Maamulaha Kayka Dibada + Si aad ukaydiso soodajinta (APK-yada & OBB-yada), ugudbiso ood uga soogaliso fadhiga aallada kaydka dibada. + Ogolaansha Kaydka Dibada + Seetahay\? + Soodhawoow + Ogolaanshaha + Kushubaha + Dukaanka Aurora wuxuu ubaahan yahay inaad u oglaato kuwan + Kuma shubi kartid appska xidhmada (lakala jajabiyay) adoo isticmaalaya kushubaha barnaamijka aallada. Ubadal kushubahaaga Xidhiidka, Adeega ama Root. + Cusboonaysiin ayaa jirta + Sidoo kale waxaad dooran kartaa kushubaha barnaamijka aallada, markaasna APK-yada nooca xidhmada (kala qaybqaybsan) iskugu jira kuma shubi kartid. Sidaa darteed mid uun doorro. + Fadlan xidh MIUI Optimizations si kushubidu ushaqayso, hadiikale waxaad dooran kartaa Root ama Adeega kushubaha. + Kushubuhan kuma shubi karo wax app ah ayadooy ugu wacantahay MIUI Optimizations. + Waxaad isticmaalaysaa MIUI! + Shuruudaha adeega + Laysan + Afeef + Suggaya inaad xaqiijiso + Waa lagu shubay + Kaydka kuma fila + APK khalad ah ama cilladaysan + App aan kushaqaynaynin + Waxaa jirta xidhmo khilaafaysa + Lama abuuri karo xidhiidka + Kushubidii waa laxanibay + Kushibiihii maguulaysan + Marka hore fadhiisi adeega Aurora oo u ogolow codsiyadiisoo dhan. + Kushub adeega Aurora 1.0.9 ama mid kasareeya, ama badal kushubaha. + Adeega Aurora waa laheli karaa waana diyaar in lagu shubo. + Looma ogolaan root-ka. U ogolow ama badal kushubaha. + Labo + Sadex + Wanaagsan + Hal + Afar + Shan + Dhammaan + Fiiri warka + Dabgale(yaal) ayaa lahelay + Hubinaya dabagaleyaal… + Kushaqeeya Exodus + Malaha wax dabagale ah + Qiyaasaya + Lahoray + Helaya xogta dheeraadka ah + Dajintii maguulaysan + Xisaabinaya + Ladajiyay + Laga noqday + Kawada noqo + Appkan maxaad ka qabtaa\? + Qiimaynta iyo faallada + Sirdhawrka + Ogolaansho + Lacag + Majiraan wax cusboonaysiin ah + Ogolaansho majiraan + Majiraan Kutiirsanaan + Wax app ah oo udhigma lama helin + Bilaa xayisiis + Faahfaahin dheeraada + Ubaahan GSF + Bilaash + Emailka + Websiteka + Barta hormariyaha + Xidhiidhka hormariyaha + Ciwaan + Faahfaahin + Ku tiirsan + Xayisiis Leh + Waxa isbadalay lama soogudbinin + Waxa isbadalay + Isdiwaangalintu waxay qaadan kartaa wakhti, hadhow ayaad fiirin kartaa meeshay wax marayaan. + Waxaad la kulmi doontaa waxyaabo cusub iyo sidoo kale cillado intaysa bulshowaynta kale arag. Warcelintaada sii hormariyaasha (sameeyaasha appka) si aad oga caawiso inay hormariyaan adeega. + Ku biir barnaamijka tijaabada? + Waxaad tahay tijaabiye + Barnaamija tijaabada + La ogolyahay + Wada cusboonaysii + Cusboonaysii + Faahfaahinta Appka + La wadaag + Raadi + Dib usoobilow + Bandhig + Suggaya + Fur + Hagaag + Xiga + Ka bax + Ka bax + Hadhow + Ku biir + Iskadhaaf + Loo ogolaaday + U ogolow + Kaydi xidhmada Appka + Dhamee + Qiimaynta + Lacag ah + Iskujir + Kutiirsan GSF + Soodajinta + Kuwa xayisiika leh + Fulli + Dhammaan + Gudbi + Xidh + Koobiyee Tixraaca + Koobiyee + Xidh + Nadiifi + Kanoqo + Kanoqo + Kabax Aurora + Gal adoo isticmaalaya + Google + Garanwaa + Fiiri Aurora Store qormadooda xaga XDA si aad doodaha ama soojeedinada oga qayb qaadato. + Qoraalada Hormariyaha + Ku biir qolka Aurora Support si aad oga qayb qaadato doodaha iyo soojeedinada. + Telegram + Ugu deeq xaga PayPal + PayPal + Noqo taageere xaga Liberapay + wiki + Ka hel jawaabaha su\'aalaha inta badan la is weydiiyo (F.A.Q.), tallaabooyinka xallinta khaladdadka iyo waxyaabo kale. + diff --git a/app/src/main/res/values-sq/strings.xml b/app/src/main/res/values-sq/strings.xml index 70c1e81c7..58039d68c 100644 --- a/app/src/main/res/values-sq/strings.xml +++ b/app/src/main/res/values-sq/strings.xml @@ -25,7 +25,7 @@ Profil zhvilluesi BHIM - UPI Për diskutime dhe sugjerime, shihni rrjedhën Aurora Store XDA. - Të merret pjesë te programi beta? + Të merret pjesë te programi Beta? Për ju Anonim Google @@ -33,12 +33,12 @@ Dil nga Aurora Mbprasht Listë bllokimesh - Shtoje në listë bllokimesh + Shtoje në Listë Bllokimesh Anoloje Spastroje Mbylle Kopjoje - Kopjoji lidhjen + Kopjoji Lidhjen Çaktivizoje Eksportoje Filtra @@ -51,7 +51,7 @@ Me pagesë Vlerësime Përfundoje - Ruaj paketë aplikacioni + Ruaj paketë Aplikacioni Akordoja U akordua Shpërfille @@ -63,7 +63,7 @@ Ikni Dilni Pasuesi - Ne rregull + OK Hape Pezull Postoje @@ -72,7 +72,7 @@ Kërko Ndajeni Çinstaloje - Hollësi aplikacioni + Hollësi Aplikacioni Përditësoje Përditësoji krejt Listë lejimesh @@ -82,7 +82,7 @@ Përgatitja mund të dojë ca kohë, gjendjen mund ta kontrolloni më vonë. Regjistër ndryshimesh S’u dha regjistër ndryshimesh - Përmban reklama + Përmban Reklama Varësi Kontakte zhvilluesi E lirë @@ -90,7 +90,7 @@ Më tepër mbi aplikacionin Pa reklama S’u gjet aplikacion me përputhje - Pa varësi + Pa Varësi S’ka leje S’ka përditësime gati Me pagesë @@ -100,7 +100,7 @@ Si ju duket ky aplikacion\? Anuloji krejt Anuluar - Shkarkimi u plotësua + Shkarkim i plotësuar Po llogaritet Shkarkimi dështoi Spastroji krejt me detyrim @@ -108,7 +108,7 @@ S’ka shkarkime Ndali krejt Në Radhë - Vazhdoi krejt + Rimerri krejt Afërsisht S’përmban gjurmues të ditur Bazuar në Exodus Privacy @@ -125,8 +125,8 @@ Dy S’ka hyrje si rrënjë. Akordojeni, ose ndryshoni intaluesin. Shërbimet Aurora janë të passhme dhe për t’i instaluar. - Instaloni Shërbimet Aurora 1.0.9 ose më sipër, ose ndryshoni instaluesin. - Së pari ujdisni Shërbime Aurora dhe akordoni krejt lejet. + Instaloni shërbimet Aurora 1.0.9 ose më sipër, ose ndryshoni instaluesin. + Së pari ujdisni shërbime Aurora dhe akordoni krejt lejet. Instaluesi dështoi Instalimi u bllokua S’u krijua sesion @@ -150,13 +150,13 @@ Leje Mirë se vini Si ia çoni\? - Hyrje në depozitë të jashtme + Hyrje Në Depozitë të Jashtme Për ruajtje kartelash zgjerimi APK (OBBs) për aplikacione & lojëra të mëdha. - Përgjegjës depozitash të jashtme - Leje instaluesi + Përgjegjësi Depozitash të Jashtme + Leje Instaluesi Lejo instalim aplikacionesh prej Shitores Aurora Ekstra - Mos kontrollo për përditësime për aplikacione të instaluar nga F-Droid + Mos kërko përditësime për shkarkues aplikacionesh, ose të instaluar nga F-Droid Filtro aplikacione F-Droid APK-të e shkarkuara do të fshihen menjëherë pas instalimit Fshije APK-në pas instalimit @@ -170,10 +170,11 @@ Përshtatje Skemë Përzgjidhni skedën parazgjedhje - Faqe “Për ju” - Shfaq te skena e kreut faqe “Për ju” + Faqe “Për Ju” + Shfaq te skena e kreut Faqe “Për Ju” Aplikacione të ngjashme dhe të afërta - Shkarkimi dështoi + Shfaq te faqja e hollësive të aplikacionit grumbuj të ngjashëm dhe të afërt + Shkarkimi Dështoi Aplikacion jo i blerë Aplikacioni nuk mbulohet S’u gjet aplikacion @@ -193,6 +194,7 @@ Aplikacione Apllikacionet & lojërat e mia Aplikacione në bibliotekë + Aplikacione me ulje çmimi Përgjegjës liste bllokimesh Pajisje Shkarkime @@ -200,7 +202,7 @@ Lojëra Instalim U instalua - Instalues aplikacionesh + Instalues Aplikacionesh Gjuhë Bibliotekë Pa rrjet @@ -235,20 +237,20 @@ Njoftime Parazgjedhje (nga formësim pajisjeje) URL ndërmjetësi - Shfaq përditësime që mund të dështojnë - Filtro aplikacione nga burime të tjera + Përditësime jo të përputhshme + Vetëm aplikacione Shitoreje Aurora Bëni hyrjen dhe shijojeni. S’u importua dot formësim pajisjeje Po shkarkohen kartela shtesë për %1$s Formësoni sjellje vetë-përditësimesh Shpeshti përditësimesh të vetvetishme - Lidhje aplikacionesh + Lidhje Aplikacionesh Android Market qe një shitore internetore aplikacionesh software e ngritur për pajisje Android, mbyllur më 2017. Importoji Po kërkohet sesion i ri Edhe %1$dh %2$dm %3$ds Formësimi i pajisjes u importua - Shkarkime në prapaskenë + Shkarkime Në Prapaskenë Lejojeni Shitoren Aurora të shkarkojë dhe përditësojë aplikacione në prapaskenë Version Google Play Po bëhet gjërat gati… @@ -263,43 +265,47 @@ %1$s • API %2$s U mohuan leje të domosdoshme. Ju lutemi, që të mund të vazhdohet veprimi, akordojini Ka gati një version të ri të %1$s - Formësoni intervale kohorë për përditësime të automatizuara, në orë. + Formësoni intervale për përditësime të automatizuara dhe të vetvetishme, në orë. %1$s, %2$s, %3$s dhe %4$d të tjerë Hyrje e mohuar! Po përdorni VPN, ose Tor? Google Play, e njohur dhe si Google Play Store dhe ish-Android Market. Mos i vetë-përditëso aplikacionet Kontrollo & instalo vetvetiu përditësime të gatshme Po verifikohet sesioni - Kërkoni për aplikacione & lojëra + Kërkoni për Aplikacione & Lojëra %1$s dhe %2$s %1$d përditësim gati Instalues Shizuku Shërbyesi jashtë funksionimi, për mirëmbajtje Njoftime përditësimesh - Rregullime aplikacioni + Rregullime Aplikacioni + Furnizues - bestappsales.com Të mëtejshme - Për ju ka kufizime + Oh, për ju ka kufizime Shërbyes i pakapshëm Kontrolloni lidhjen në rrjet - Gjuhë aplikacioni + Gjuhë Aplikacioni Kërkoni analizë të re Ndalur • %1$d / %2$d Shizuku s’është instaluar, ose s’është ujdisur si duhet. - Shtoje te skena e kreut - Spastro te përfunduarat + Shtoje te Skena e Kreut + Spastrimi përfundoi Edhe %1$dm %2$ds Edhe %1$ds Dërgo njoftime lidhur me gjendje instalimesh + Ndërmjetës + Aktivizo ndërmjetës + Lejo që krejt trafiku prej aplikacionesh të kalojë përmes ndërmjetësit Shfaq përditësime për aplikacione të papërputhshëm, ose të çaktivizuar, për të cilët mund të dështojë instalimi - Mos kontrollo për përditësime për aplikacione të instaluar nga burime jashtë Shitores Aurora + Kërko për përditësime vetëm për aplikacione të instaluar me Shitoren Aurora Hyaaa! Gjithçka në rregull. - Po verifikohet sesion Google + Po verifikohet Sesion Google Sugjerim kërkimi Përfundime kërkimi ka përditësime %1$d përditësime gati %1$s, %2$s dhe %3$s - Përditësime të automatizuara + Vetë-përditësoji aplikacionet Kontrollo & njofto për përditësime të gatshme Gabim i brendshëm! Ju lutemi, riprovoni pas ca kohe S’u prodhua dot sesion @@ -332,9 +338,9 @@ Shtoje Hiqe Wiki - Gjeni përgjigje për pyetje të bëra shpesh, hapa diagnostikimi dhe më shumë + Merrni përgjigje për pyetje të bëra rëndom (PBR), hapa diagnostikimi, etj S’u gjetën aplikacione të parapëlqyer - Aplikacione të parapëlqyer + Aplikacione të Parapëlqyer Aplikacion jo gati për pajisjen tuaj Mbi Aurora Store-in Mësoni më tepër mbi Aurora Store-in @@ -346,7 +352,11 @@ Të parapëlqyerit u eksportuan! Ju lutemi, bëni hyrjen te llogaria juaj Google Play E preferuara - Aurora Store ju mundëson të kërkoni dhe shkarkoni aplikacione nga Shitorja zyrtare Google Play. Mund të shihni përshkrimet e aplikacioneve, foto ekrani, përditësime, komente përdoruesish të tjerë dhe të shkarkoni APK-në drejtpërdrejt nga Google Play në pajisjen tuaj. Që të përdorni Aurora Store, duhet të keni një llogari në Google Play dhe të bëni hyrjen në të, kur të hapni për herë të parë dhe formësoni Aurora Store.\n \nNdryshe nga një shitore tradicionale aplikacionesh, Aurora Store nuk zotëron, licencon ose shpërndan ndonjë aplikacion. Krejt aplikacionet, përshkrimet e tyre, fotot e ekranit dhe lëndë tjetër në Aurora Store shihen, shkarkohen dhe/ose shfaqen drejtpërdrejt nga Google Play. Aurora Store funksionon mu si një derë, ose një shfletues, duke ju lejuar të bëni hyrjen në llogarinë tuaj Google Play dhe t’i gjeni aplikacionet nga Google Play. \n \nJu lutemi, kini parasysh se Aurora Store nuk ka ndonjë miratim, sponsorizim apo autorizim nga Google, Google Play, nga çfarëdo aplikacionesh të shkarkuar përmes Aurora Store apo nga çfarëdo zhvilluesish aplikacionesh; as ka Aurora Store ndonjë përshoqërim, bashkëpunim apo lidhje me ta. + Aurora Store ju mundëson të kërkoni dhe shkarkoni aplikacione nga shitorja zyrtare Google Play. Mund të shihni përshkrimet e aplikacioneve, foto ekrani, përditësime, komente përdoruesish të tjerë dhe të shkarkoni APK-në drejtpërdrejt nga Google Play në pajisjen tuaj. Që të përdorni Aurora Store, duhet të keni një llogari në Google Play dhe të bëni hyrjen në të, kur të hapni për herë të parë dhe formësoni Aurora Store. +\n +\nNdryshe nga një shitore tradicionale aplikacionesh, Aurora Store nuk zotëron, licencon ose shpërndan ndonjë aplikacion. Krejt aplikacionet, përshkrimet e tyre, fotot e ekranit dhe lëndë tjetër në Aurora Store shihen, shkarkohen dhe/ose shfaqen drejtpërdrejt nga Google Play. Aurora Store funksionon mu si një derë, ose një shfletues, duke ju lejuar të bëni hyrjen në llogarinë tuaj Google Play dhe t’i gjeni aplikacionet nga Google Play. +\n +\nJu lutemi, kini parasysh se Aurora Store nuk ka ndonjë miratim, sponsorizim apo autorizim nga Google, Google Play, nga çfarëdo aplikacionesh të shkarkuar përmes Aurora Store apo nga çfarëdo zhvilluesish aplikacionesh; as ka Aurora Store ndonjë përshoqërim, bashkëpunim apo lidhje me ta. U çinstalua me sukses Jepni një URL ndërmjetësi të vlefshme për të kaluar krejt të dhënat përmes ndërmjetësit. Kontrollo për përditësime @@ -362,7 +372,8 @@ Privatësi të dhënash dhe praktika sigurie të deklaruara nga zhvilluesi Siguri të dhënash Lejo instalim aplikacionesh nga burime të panjohura - Së pari lypset të akordoni leje instaluesi + Mund t’ju duhet të riakordoni lejen, për shkak të mete te Platformë Hyrjeje Në Depozitë + Së pari lypset të akordoni Leje Instaluesi E domosdoshme Opsionale S’u arrit të eksportohej paketë aplikacioni @@ -371,7 +382,7 @@ Shënim rreth eksportimi aplikacionesh Shënim instalimi Shënim rreth shkarkimesh - Eksportues kartelash + Eksportues Kartelash Që të çarkivoni aplikacionin, ju lutemi, bëni hyrjen në llogarinë tuaj Google Play! Njoftim lidhur me llogari Lyp mirëfilltësim @@ -384,7 +395,9 @@ Krijuar me %1$s në Indi Shtoni distributor Shtoni te Aurora Store një distributor token-ësh. Distributorët e token-ëve i furnizojnë Aurora Store-it kredenciale llogarie për hyrje anonime. + Hiqe distributorin Parazgjedhje + Mund t’ju duhet të rinisni aplikacionin, që të pasqyrohet akordimi i lejeve. S’u arrit të eksportohej listë ndalimesh! Lista e ndalimeve u eksportua! S’u arrit të importohej listë ndalimesh! @@ -407,65 +420,4 @@ I kufizuar: Funksionon me kufizime veçorish Po shihet përputhshmëria… Mund t’ju duhet të instaloni bibliotekë pronësore të Google-it, ose një risendërtim FOSS, fjala vjen, microG. - Përdor microG për të bërë hyrje në llogari - Bëni mirëfilltësimin duke përdorur microG, kur bëhet hyrje në llogari Google, për një rrjedhë më të thjeshtë pune me hyrjen - Dhënie llogarie dhe përgjegjësi - S’ka aplikacione - Ndërmjetësi u çaktivizua me sukses - Çaktivizoje - Shihni dhe administroni formësim ndërmjetësi - Kufizime përditësimesh të automatizuara - Formësoni kufizime pajisjeje për përditësime të automatizuara - Vetëm në rrjete me trafik të pakufizuar - Kur bateria s’është e pakët - Kur pajisja është e plogësht - S’u arrit të verifikohen kartelat e shkarkuara - Version Android Minimum - Nivel API i synuar - Përditësuar së fundi më - Shkarkime - Të mëtejshme - Burim aplikacioni - - Lyp leje - Lyp leje - - Ujdiseni - Të riniset, që të aplikohen ndryshimet? - Instalo Paketën microG - Të dhëna që mund të grumbullojë ky aplikacion - Zhvilluesi thotë se ky aplikacion s’grumbullon të dhëna përdoruesi. - Të dhëna që ky aplikacion mund t’u japë të tjerëve - Zhvilluesi thotë se ky aplikacion s’jep të dhëna përdoruesi për shoqëri dhe ente të tjerë. - Ky version i aplikacioni mund të përmbajë ende gjurmues të tjerë jo të pranishëm në bazën e të dhënave të Exodus Privacy-së. - Te %2$s u gjet(ën) %1$d gjurmues i(të) njohur - Instaluesi MicroG s’arriti të instalojë aplikacionin, me gjasa për shkak formësimi të gabuar. - Instalues MicroG - Anashkaloje - Përputhje Aplikacioni - Ka varësi të paplotësuara - I kam lexuar dhe pajtohem me Kushtet e Shërbimit dhe Rregullat e Privatësisë së microG-së - S’gjetëm dot Google Play Services në pajisjen tuaj, një numër aplikacionesh të njohur tanimë e kanë të domosdoshëm, që të funksionojnë si duhet! - microG është një sendërtim i lirë dhe me burim të hapët, që ofron funksione të ngjashme për xhirim aplikacionesh që varen nga Google Play Services për pajisje Android, përmes risendërimti.\n\nmicroG u bën të mundur aplikacioneve të përdorin këto API Google, duke zgjeruar për përdoruesit shkallë përputhjeje, teksa ofron përfitime në pikëpamje të privatësisë. \n\nmicroG do të funksionojë automatikisht në prapaskenë, kur hapni aplikacione që varen nga Google Mobile Services. - Lexoni Rregulla Privatësie të microG-së - Lexoni Licencë dhe Marrëveshje për microG - Vizitoni Sajtin e Projektit microG - Që të instalohet, lyp aplikacionin shoqërues microG - Ju ndihmon të anashkaloni kontroll Integriteti Aplikacioni (vetëm për instaluesin) - Kodi i versionit mund të përmbajë vetëm shifra - Po verifikohet - S’ka përshkrim - %1$d leje - Më tepër informacion - Emër pakete - Vlerësim lënde - Po bëhet gati për instalim - Për më tepër hollësi, përzgjidhni një aplikacion - Pa reklama - Pa shërbime luajtjesh - Ngarkim në kryerje e sipër - Faqja %1$d - Nuk është gati - Gati - Synimi diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 06ab1aa40..9f5b710e2 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -25,6 +25,7 @@ Преузимања Уређај Менаџер црне листе + Апликације на распродаји Апликације у збирци Моје апликације и игре Апликације @@ -55,7 +56,7 @@ Избриши APK након инсталације Преузети APK-ови ће бити избрисани одмах након инсталације Филтрирај F-Droid апликације - Не проверавајте ажурирања за апликације инсталиране у F-Droid-у + Не проверавајте ажурирања за апликације преузете или инсталиране у F-Droid-у Дозволите инсталирање апликација из Aurora Store-а Дозвола програма за инсталацију Менаџер спољне меморије @@ -215,6 +216,7 @@ Кôд верзије који тражите није доступан. Ручно преузимање Обавезно се поново пријавите и поново покрените апликацију да бисте применили промене. + Прикажите сличне и сродне скупове на страници с детаљима о апликацији Сличне и сродне апликације Прикажите странице за вас на почетном екрану Странице за вас @@ -225,14 +227,14 @@ Није пронађена ниједна одговарајућа апликација Није могуће извести конфигурацију уређаја Конфигурација уређаја је извезена - Паузирано • %1$d / %2$d + Паузирано • \u0020 %1$d / %2$d Припремање ствари… Није могуће пријавити се преко Google-а Верификација Google сесије Предлог за претрагу Резултати претраге Интерна грешка! Покушајте поново касније - Ваш налог је ограничен + Упс, ваш налог је ограничен Језик апликације Захтевање нове сесије Увези @@ -289,7 +291,7 @@ Сервер недоступан Генерисање сесије није успело, кôд грешке: \n \n%1$d Проверите интернет везу - Преузимање • %1$d / %2$d %3$s + Преузимање • \u0020 %1$d / %2$d %3$s Преузимање додатних фајлова за \n \n%1$s @@ -308,20 +310,24 @@ Линкови апликација Android Market је била онлајн продавница која је нудила софтверске апликације дизајниране за Android уређаје, пензионисана 2017. године. Прегледај наслов - Конфигуришите временски интервал за аутоматска ажурирања, у сатима. - Филтрирај апликације из других извора - Не проверавајте ажурирања за апликације инсталиране из извора ван Aurora Store + Пружалац - bestappsales.com + Конфигуришите интервале за аутоматска ажурирања, у сатима. + Само Aurora Store апликације + Проверавајте ажурирања само за апликације инсталиране помоћу Aurora Store Подешавања апликације Учесталост аутоматског ажурирања + Омогући прокси URL адреса проксија + Прокси Неважећи URL проксија, проверите формат! Прокси је успешно подешен Подешавање проксија није успело + Дозволите да сав саобраћај из апликације пролази кроз прокси Подразумевано (из конфигурације уређаја) Верзија Google Play-а Преузимања у позадини Дозволите Aurora Store-у да преузима и ажурира апликације у позадини - Аутоматска ажурирања + Аутоматско ажурирање апликација Провера и обавештење о доступним ажурирањима Без аутоматског ажурирања апликација Конфигуришите понашање аутоматских ажурирања @@ -329,7 +335,7 @@ Затражи нову анализу Извоз APK-ова није успео Очисти завршено - Прикажи ажурирања која можда неће успети + Некомпатибилна ажурирања Прикажите ажурирања за некомпатибилне или онемогућене апликације које можда неће бити успешно инсталиране Додај на почетни екран Имате питања? Сазнајте одговоре @@ -371,7 +377,11 @@ Уклањање дозатора Prijavite se na vaš Google Play nalog Saznajte više o Aurora Store - Aurora Store вам омогућава да претражујете и преузимате апликације из званичне Google Play продавнице. Можете да проверите описе апликација, снимке екрана, ажурирања, коментаре других корисника и преузмете APK директно са Google Play-а на свој уређај. Да бисте користили Aurora Store, морате да имате Google Play налог и да се пријавите на свој Google Play налог када први пут отворите и конфигуришете Aurora Store. \n \nЗа разлику од традиционалне продавнице апликација, Aurora Store не поседује, не лиценцира нити дистрибуира ниједну апликацију. Свим апликацијама, описима апликација, снимцима екрана и другом садржају у Аурора продавници се директно приступа, преузима се и/или приказује са Google Play-а. Aurora Store функционише баш као врата или претраживач, омогућавајући вам да се пријавите на свој Google Play налог и пронађете апликације са Google Play-а. \n \nИмајте на уму да Aurora Store нема одобрење, спонзорство или овлашћење од Google-а, Google Play-а, било које апликације преузете преко Aurora Store-а или било ког програмера апликација; нити Aurora Store има некакву повезаност, сарадњу или везу са њима. + Aurora Store вам омогућава да претражујете и преузимате апликације из званичне Google Play продавнице. Можете да проверите описе апликација, снимке екрана, ажурирања, коментаре других корисника и преузмете APK директно са Google Play-а на свој уређај. Да бисте користили Aurora Store, морате да имате Google Play налог и да се пријавите на свој Google Play налог када први пут отворите и конфигуришете Aurora Store. +\n +\nЗа разлику од традиционалне продавнице апликација, Aurora Store не поседује, не лиценцира нити дистрибуира ниједну апликацију. Свим апликацијама, описима апликација, снимцима екрана и другом садржају у Аурора продавници се директно приступа, преузима се и/или приказује са Google Play-а. Aurora Store функционише баш као врата или претраживач, омогућавајући вам да се пријавите на свој Google Play налог и пронађете апликације са Google Play-а. +\n +\nИмајте на уму да Aurora Store нема одобрење, спонзорство или овлашћење од Google-а, Google Play-а, било које апликације преузете преко Aurora Store-а или било ког програмера апликација; нити Aurora Store има некакву повезаност, сарадњу или везу са њима. O Aurora Store Апликација није доступна за ваш уређај Омиљено @@ -391,6 +401,7 @@ Безбедност података Приватност података и безбедносне праксе које је објавио програмер Прво морате да дате дозволу програму за инсталацију + Можда ћете морати поново да дате дозволу због грешке у радном простору за приступ меморији Опционално Дозволите инсталацију апликација из непознатих извора Неопходно @@ -414,6 +425,7 @@ Направљено од %1$s у Индији Подразумевана Доступна + Можда ћете морати да рестартујете апликацију да бисте приказали дату дозволу. Црна листа је увезена! Верификовање Деархивирај @@ -439,55 +451,4 @@ Можда ћете морати да инсталирате Google-ову власничку библиотеку или заменску имплементацију FOSS-а као што је microG. %1$d апликација инсталирано Нема доступних апликација - Користи microG за пријављивање на налоге - Аутентификација коришћењем microG при пријављивању на Google налоге за једноставнији ток пријављивања - Постави - Онемогући - Прокси је успешно онемогућен - Прегледајте и управљајте конфигурацијом проксија - Конфигуришите ограничења уређаја за аутоматска ажурирања. - Само на мрежама са ограничењем - Када је уређај у стању мировања - Када батерија није празна - Ограничења аутоматских ажурирања - Верификација преузетих фајлова није успела - Напредно - Извор апликације - Преузимања - Последње ажурирање - Циљни ниво API-ја - Минимална верзија Android-а - %1$d дозвола - Инсталирај microG пакет - Компатибилност апликације - Недостајуће зависности - Прочитао/ла сам и сагласан/на сам са Условима коришћења услуга и Политиком приватности microG-а - Нисмо могли да пронађемо Google Play услуге на вашем уређају, неколико популарних апликација их сада захтева да би правилно функционисале! - microG је бесплатна имплементација отвореног кода која пружа сличну функционалност за покретање апликација зависних од Google Play услуга за Android уређаје кроз поновну имплементацију.\n\nmicroG омогућава апликацијама приступ тим Google API-јима, побољшавајући компатибилност за кориснике и нудећи предности приватности.\n\nmicroG ће се аутоматски покренути у позадини када отворите апликације које зависе од Google мобилних услуга. - Прочитај Политику приватности microG-а - Прочитај microG лиценцу и уговор - Посети веб-сајт пројекта microG - Подаци које ова апликација може прикупљати - Програмер каже да ова апликација не прикупља корисничке податке. - Подаци које ова апликација може да дели - Програмер каже да ова апликација не дели корисничке податке са другим компанијама или организацијама. - Ова верзија апликације може и даље да садржи више пратилаца који још нису присутни у бази података Exodus Privacy-а. - %1$d познатих пратилаца пронађено у %2$s - Код верзије може да садржи само цифре - Нема доступног описа - Више информација - Циљеви - Назив пакета - Оцена садржаја - Изаберите апликацију за више детаља - Без реклама - Нема Play услуга - MicroG програм за инсталацију није успео да инсталира апликацију, највероватније због неисправне конфигурације. - MicroG Програм за инсталацију - Прескочи - MicroG Companion је неопходан за инсталацију ове апликације - Помаже Вам да заобиђете проверу App Integrity (само у програму за инсталацију) - Поновно покренути ради примењивања нових подешавања? - Припрема се за инсталацију - Учитавање у току diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 2fbeb3605..eeb0c9773 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -4,7 +4,7 @@ Logga in med Forum på XDA Gå med i Aurora\'s hjälp-grupp för diskussioner eller förslag. - Bli en patron i Liberapay + Bli en gynnare i Liberapay Hämta Aurora-butiken\'s källkod från Aurora OSS i GitLab. Betygsattes, det kan ta ett tag innan det visas Bläddringssidan otillgänglig @@ -27,6 +27,7 @@ Play-butiken Hämtningar Enhet + Rea-appar Appar i biblioteket Mina appar & spel Appar @@ -57,7 +58,7 @@ Hämtade APK:er kommer att tas bort efter installation Filtrera F-Droid-appar Tillåt att installera appar från Aurora-butiken - För att spara APK expansionspaket (OBB:er) för stora appar & spel. + För att kunna spara expansionsfiler för APK (OBB:er) till stora appar & spel. Hur går det för dig? Välkommen Behörigheter @@ -89,7 +90,7 @@ Visa rapport kända spårare hittades i Söker efter spårare… - Drivs av Exodus Privacy + Drivs av Exodus Innehåller inga kända spårare Uppskattar Återuppta alla @@ -111,7 +112,7 @@ Mer om appen Kräver GSF Gratis - Webbplats + Hemsida E-post Adress Beskrivning @@ -120,8 +121,8 @@ Ändringsloggen tillhandahålls inte Ändringslogg Registreringen kan ta lite tid, du kan kontrollera status senare. - Du kommer att få se nya funktioner och buggar före allmänheten gör det. Ge din återkoppling till utvecklarna för att hjälpa dem att förbättra. - Gå med i betaprogrammet? + Du kommer att få se nya funktioner och buggar före allmänheten gör det. Ge din återgivning till utvecklarna för att hjälpa dem att förbättra. + Gå med i beta-programmet ? Du är en beta-testare Beta-program Vitlista @@ -162,7 +163,7 @@ Stäng Rensa Avbryt - Lägg till i svartlista + Lägg till i Svartlista Svartlista Bakåt Logga ut från Aurora @@ -191,7 +192,7 @@ Till dig Visa Sidor för dig på hemskärmen Sidor för dig - Kontrollera inte uppdateringar för appar installerade från F-Droid + Ignorera appar från F-Droid i Uppdateringar och Installerade appar Behörighet för installationsprogrammet Åtkomst till externt lagringsutrymme Installationen lyckades @@ -202,35 +203,36 @@ Kunde inte exportera enhetens konfiguration Enhetens konfiguration exporterades Svartlistad + Visa liknande och relaterade klustrar på appens detaljsida Hanterare av externt lagringsutrymme Inga behörigheter Avvaktande Ingen matchande app hittades Påtvinga rensning av allt Ansvarsfriskrivning - Installationsprogrammet för sessionen kan inte installera appar på grund av MIUI-optimeringar. + Installationsprogrammet för sessionen kan inte installera appar på grund av MIUI-optimiseringar. Skicka in Alternativt kan du välja Inbyggt installationsprogram, men då kan du inte installera buntade (uppdelade) APK-filer, så valet är ditt. Ställ in Aurora-tjänster och godkänn alla behörigheter först. Snälla, inaktivera MIUI-optimeringar för att tillåta installationer, annars kan du välja installationsprogrammet för Root eller Tjänster. Installera app-hanteraren eller ändra på installationsprogrammet. - Spara appaket + Spara app-sortiment Extra - Installationsprogrammet AM + AM-installatör Inbyggt installationsprogram (Föråldrat) - Installationsprogram för appen + Installationsprogram för app Du kan inte installera medföljande (uppdelade) appar via det inbyggda installationsprogrammet. Ändra installationsprogrammet till Session, Tjänster eller Root. Säkerställ att du loggar in igen för att verkställa imitationen Hanterare av svartlista Hämta appen i bakgrunden Behörigheten godkändes Kunde inte generera AAS-symbol - Hanterare av spoofing + Hanterare av imitering Aktivera utvecklingsinställningarna från enhetens inställningar för att öppna dem. Enhetsförfalskning tillämpades. Aktiverar app-hämtningar i bakgrunden Shizuku är inte installerat eller är inte korrekt inställt. - Du är hastighetsbegränsad + Hoppsan, du är hastighetsbegränsad %1$s • API %2$s Servern kunde inte nås %1$s, %2$s, %3$s och %4$d mer @@ -246,7 +248,7 @@ Begär ny session Internt fel! Vänligen försök igen efter ett tag uppdatering tillgänglig - Sök efter appar och spel + Sök efter Appar & Spel Importera Sökförslag Avancerat @@ -279,20 +281,24 @@ Kolla anslutbarheten mot internet App-länkar Enhetskonfigurationen importerades - Uppdateringsaviseringar + Aviseringar om uppdateringar Behörigheter som krävs nekades. Vänligen godkänn dessa för att fortsätta åtgärden Installationsprogrammet Shizuku Android Market var en nätbaserad butik som erbjöd mjukvaru-applikationer gjorda för Android-enheter, gick i pension 2017. Recensera titel + Leverantör - bestappsales.com + Aktivera proxy Proxyn\'s URL - Konfigurera intervall för automatiska självuppdateringar, i timmar. - Filtrera appar från andra källor + Konfigurera intervall för automatiska själv-uppdateringar, i timmar. + Enbart appar från Aurora-butiken + Proxy Ogiltig URL för proxy, kontrollera formatet! - Kontrollera inte efter uppdateringar för appar installerade från källor utanför Aurora Store + Visa endast installerade appar från Aurora-butiken i Uppdateringar och Installerade appar Inställningen av proxy lyckades - Inställningar för appen + Inställningar för app Automatisk uppdateringsfrekvens Inställningen av proxy\'n misslyckades + Tillåt all trafik från appen att gå genom proxyn Standard (från enhetskonfiguration) Google Play-version Hämtningar i bakgrunden @@ -300,19 +306,19 @@ Konfigurera beteende för automatiska uppdateringar Kontrollera & meddela om tillgängliga uppdateringar Kontrollera & installera tillgängliga uppdateringar automatiskt - Automatiska uppdateringar + Uppdatera appar automatiskt Uppdatera inte alla appar automatiskt Begär ny analys Misslyckades med att exportera APKs - Rensning slutförd - Visa uppdateringar som kan misslyckas + Rensningen slutfördes + Ej kompatibla uppdateringar Wiki Hitta svar till frekvent ställda frågor (F.A.Q), steg för felsökning och mer Favorit Lägg till på hemskärmen Avinstallationen lyckades Inga favorit-appar hittades - Visa uppdateringar för inkompatibla eller inaktiverade appar som kan misslyckas med att installera + Visa uppdateringar för ej kompatibla eller inaktiverade appar vars installation kan misslyckas Kräver privilegier för root/superanvändare, har stöd för alla Android-versioner. Använder systemets API:er direkt med privilegier för adb/root Hantera ditt konto @@ -334,7 +340,7 @@ Datasäkerhet Dataskydd och säkerhetsrutiner som har deklarerats av utvecklaren Tillåt installation av appar från okända källor - Ange en giltig URL för proxyn för att skicka vidare all data genom proxyn. + Ange en giltig URL för proxy\'n för att skicka vidare all data genom proxy\'n. Rekommenderas, inbyggd och har stöd för alla Android-versioner Avsiktsbaserat installationsprogram, tillgängligt på alla enheter Källkod @@ -360,115 +366,7 @@ Lär dig hur Aurora Store använder din data Appen är inte tillgänglig för din enhet Du behöver godkänna behörighet för installationsprogrammet först + Du kan behöva godkänna behörigheten igen till följd av en bugg i ramverket för åtkomst till lagringsutrymmet Krävs Valfritt - Ställ in - Konto-relaterad avisering - Senaste - Kompabilitet - Standard - Tillgänglig - Inaktivera - Bekräftar - Installera microG-paket - Ta bort allt - Välj allt - Data som denna app kan samla - Utvecklarna säger att denna app inte samlar användardata. - Data som denna app kan dela - Utvecklaren säger att denna app inte delar användardata med andra företag eller organisationer. - Den här versionen av appen kan fortfarande innehålla fler trackers som ännu inte finns i Exodus Privacys databas. - %1$d kända trackers funna i %2$s - MicroG-installationen misslyckades, sannolikt på grund av felkonfiguration. - MicroG-installerare - Inga appar tillgängliga - Nedladdningar - Senast uppdaterad - Äldsta Androidversion - Målets API-nivå - Hoppa över - Appkompatibilitet - Saknade beroenden - Jag har läst och gått med på mikroG användarvillkor och sekretesspolicy - Vi kunde inte hitta Google Play-tjänster på din enhet, flera populära appar kräver nu att den fungerar korrekt! - mikroG är en fri och öppen källkodsimplementering som ger liknande funktionalitet för att köra appar beroende av Google Play Services för Androidenheter genom omdirigering.\n\nmikroG gör det möjligt för appar att komma åt dessa Google API:er, förbättra kompatibiliteten för användare samtidigt som de erbjuder sekretessfördelar.\n\nmikroG körs automatiskt i bakgrunden när du öppnar program beroende av Google Mobile Services. - Läs MicroG:s sekretesspolicy - Läs mikroG:s licens och avtal - Besök microG-projektets webbplats - Sessionbaserad installationsmjukvara för packade/splittade APK:er - Bäst lämpad för enheter som kör Android under version 4.4 - Kräver Auroratjänster som ska installeras som en privilegierad systemapp - Kräver mikroG följeslagarapp som ska installeras - Hjälper dig att kringgå Appintegritetskontroll (endast installera) - Fullfjädrad pakethanterare med öppen källkod - Kräver App Manager, behöver adb/rootläge för att installera när miui optimering är på - Kräver Shizuku eller Sui, måste ställas in och beviljas tillstånd - Versionskod kan endast innehålla siffror - Tillverkad med %1$s i Indien - Om Aurora Store - Aurora Store gör att du kan söka och ladda ner appar från den officiella Google Play Store. Du kan kontrollera appbeskrivningar, skärmdumpar, uppdateringar, andra användares kommentarer och ladda ner APK-filen direkt från Google Play till din enhet. För att använda Aurora Store måste du ha ett Google Play-konto och logga in på ditt Google Play-konto när du första gången öppnar och konfigurerar Aurora Store.\n\nTill skillnad från en traditionell appbutik äger Aurora Store inte, licensierar eller distribuerar några appar. Alla appar, appbeskrivningar, skärmdumpar och annat innehåll i Aurora Store är direkt hämtade, nedladdade och/eller visas från Google Play. Aurora Store fungerar precis som en dörr eller en webbläsare, så att du kan logga in på ditt Google Play-konto och hitta apparna från Google Play.\n\nObservera att Aurora Store har inget godkännande, sponsring eller tillstånd från Google, Google Play, några appar som laddats ner via Aurora Store eller någon apputvecklare; inte heller har Aurora Store någon anslutning, samarbete eller koppling till dem. - Rensa enhetsägare - Detta kommer att återkalla sessionsinstallerarens tillstånd att tyst installera appar. Fortsätt med rensa enhet ägande? - Hantera fördelare - Visa och hantera tokenutdelare för anonyma inloggningar - Inga utdelare tillgängliga - Lägg till utdelare - Lägg till en tokenutdelare till Aurora Store. Tokenutdelare ger kontouppgifter till Aurora Store för anonym inloggning. - Utdelaradress - Ta bort utdelare? - Vill du ta bort utdelaren \"%1$s\"? - Misslyckades med att importera svartlista! - Misslyckades med att exportera svartlista! - Svartlista importerad! - Svartlista exporterad! - Framgångsrikt exporterad appbunt - Misslyckades att exportera appbunt - Söker efter uppdateringar - Starta om att tillämpa ändringar? - Aurora Store måste startas om för att tillämpa de nyligen ändrade inställningarna - Autentisering krävs - Logga in på ditt Google Play-konto för att packa upp appen! - Ingen beskrivning tillgänglig - %1$d behörigheter - Mer info - Mål - Paketnamn - Innehållsbetyg - Packa upp - Kan inte öppna app - Drivs av Plexus - Kontrollera kompatibilitet… - Kräver Google Play Services - Du kan behöva installera Googles egenutvecklade bibliotek eller en FOSS-reimplementering som microG. - Fungerar utan Google Play Services - Den här appen fungerar utan Googles egna bibliotek. Det kan dock fortfarande kräva att andra tredjepartsbibliotek för att fungera korrekt. - Med mikroG-projekt - Utan Google Play-tjänster - Kompatibel: Fungerar utan problem - Begränsad: Fungerar med begränsade funktioner - Stöds ej: Ej fungerande - Okänt: Inte kontrollerad ännu - Förbereder för att installera - - Tillstånd krävs - Tillstånd krävs - - %1$d appar installerade - Använd microG för att logga in på konton - Autentisera med mikroG när du loggar in på Google konton för ett enklare inloggningsflöde - Proxy inaktiverad framgångsrikt - Visa och hantera proxykonfiguration - Avancerat - Automatiska uppdateringsbegränsningar - Konfigurera enhetsbegränsningar för automatiserade uppdateringar - Endast på obevakade nätverk - När enheten är inaktiv - När batteriet inte är lågt - Appkälla - Misslyckades med att verifiera nedladdade filer - Välj en app för mer detaljer - Ingen reklam - Inga speltjänster - Nedladdning pågår - Sida%1$d diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml index a5eec028c..c183948a7 100644 --- a/app/src/main/res/values-ta/strings.xml +++ b/app/src/main/res/values-ta/strings.xml @@ -12,7 +12,7 @@ நிறுவல்கள் நிறுவு புறக்கணி - பயன்பாட்டு மூட்டைச் சேமி + பயன்பாட்டு மூட்டை சேமிக்கவும் முடிந்தது மதிப்பீடுகள் கட்டணம் @@ -28,7 +28,7 @@ மூடுக நீக்கு ரத்துசெய் - தடுப்புப்பட்டியலில் சேர் + தடுப்புப்பட்டியலில் சேர்க்கவும் தடுப்புப்பட்டியல் எஃப்-டிரயோடு யுபிஐ வழியாக கொடையளி @@ -97,6 +97,7 @@ தளவமைப்பு இயல்புநிலை தாவலைத் தேர்ந்தெடுக்கவும் ஒத்த மற்றும் தொடர்புடைய பயன்பாடுகள் + செயலி விவரங்கள் பக்கத்தில் ஒத்த மற்றும் தொடர்புடைய கொத்துகளைக் காண்பி பயன்பாடு கிடைக்கவில்லை சாதனம் நிறவப்பட்டவை @@ -117,7 +118,7 @@ வழங்கப்பட்டது இடுகையிடு பயன்பாட்டுத் தகவல் - புதுப்பி + புதுப்பிப்புகள் நீங்கள் பீட்டா சோதனையாளர் பீட்டா திட்டத்தில் சேரவா? மாற்றப்பதிவு @@ -153,8 +154,8 @@ ஐந்து நான்கு நேர்மறை - அரோரா சேவைகள் கிடைக்கின்றன மற்றும் நிறுவத் தயாராக உள்ளன. - அரோரா சேவைகளை 1.0.9 அல்லது அதற்கு மேல் நிறுவவும் அல்லது நிறுவியை மாற்று. + அரோரா சேவைகள் கிடைக்கின்றன மற்றும் நிறுவ தயாராக உள்ளன. + அரோரா சேவைகளை 1.0.9 அல்லது அதற்கு மேல் நிறுவவும் அல்லது நிறுவியை மாற்றவும். அரோரா சேவைகளை அமைத்து, முதலில் அனைத்து அனுமதிகளையும் வழங்கவும். நிறுவல் தோல்வியடைந்தது அமர்வை படைக்க முடியவில்லை @@ -187,7 +188,7 @@ நிறுவல் பயன்முறை பிணையமாக்கம் உங்களுக்கான பக்கங்கள் - முகப்புத் திரையில் உங்களுக்கான பக்கங்களைக் காட்டு + முகப்புத் திரையில் உங்களுக்கான பக்கங்களைக் காட்டவும் பதிவிறக்கம் தோல்வியடைந்தது பயன்பாடு வாங்கப்படவில்லை மாற்றங்களைப் பயன்படுத்த, நீங்கள் மீண்டும் உள்நுழைந்து பயன்பாட்டை மறுதொடக்கம் செய்வதை உறுதிசெய்து கொள்ளவும். @@ -201,6 +202,7 @@ பயன்பாடுகள் எனது பயன்பாடுகள் & விளையாட்டுகள் நூலகத்தில் உள்ள பயன்பாடுகள் + பயன்பாடுகள் விற்பனையில் உள்ளன பதிவிறக்கங்கள் ப்ளே ஸ்டோர் விளையாட்டுகள் @@ -216,7 +218,7 @@ அவற்றைத் திறக்க, சாதன அமைப்புகளில் இருந்து டெவலப்பர் அமைப்புகளை இயக்கவும். அனுமதி வழங்கப்பட்டது சாதன ஸ்பூஃப் பயன்படுத்தப்பட்டது. - பெயரிலி கணக்குகளில் பயன்பாடுகள் வாங்குதல்கள் கிடைக்காது. + அநாமதேய கணக்குகளில் ஆப்ஸ் வாங்குதல்கள் கிடைக்காது. வாழ்த்துகள், கோரப்பட்ட பதிப்புக் குறியீடு உள்ளது, இப்போது பதிவிறக்குகிறது. உலாவல் பக்கம் கிடைக்கவில்லை AAS கிள்ளாக்குகளைப் உருவாக்க முடியவில்லை @@ -234,7 +236,7 @@ சாதன உரிமையாளரை அழிக்கவும் ரத்து செய்யப்பட்டது பட்டியல் - கூகிள் இயக்கு பதிப்பு + கூகிள் பிளே பதிப்பு விரிவாக்கு %1$ds இடது அடிக்கடி கேட்கப்படும் கேள்விகள் (F.A.Q.), சரிசெய்தல் படிகள் மற்றும் பலவற்றிற்கான பதில்களைக் கண்டறியவும் @@ -242,6 +244,8 @@ மதிப்பாய்வு தலைப்பு பயன்பாடுகளை பின்னணியில் பதிவிறக்கம் செய்து புதுப்பிக்க அரோரா கடையை அனுமதிக்கவும் சிசுகு உறுப்பினர்கள் கோ + ப்ராக்சியை இயக்கவும் + பயன்பாட்டிலிருந்து அனைத்து போக்குவரத்தையும் பதிலாள் வழியாக செல்ல அனுமதிக்கவும் நிறுவத் தவறிய பொருந்தாத அல்லது முடக்கப்பட்ட பயன்பாடுகளுக்கான புதுப்பிப்புகளைக் காட்டு அரோரா கடை பயன்பாடுகள் மட்டுமே அரோரா கடை நிறுவிய பயன்பாடுகளுக்கான புதுப்பிப்புகளை மட்டுமே சரிபார்க்கவும் @@ -249,18 +253,20 @@ பற்றி பிடித்த பயன்பாடுகள் உங்கள் சாதனத்திற்கு பயன்பாடு கிடைக்கவில்லை + சேமிப்பக அணுகல் கட்டமைப்பில் பிழை காரணமாக நீங்கள் அனுமதியை மீண்டும் வழங்க வேண்டியிருக்கும் + இசைவு மானியத்தை பிரதிபலிக்க நீங்கள் பயன்பாட்டை மறுதொடக்கம் செய்ய வேண்டியிருக்கும். தவறான பதிலாள் முகவரி, வடிவத்தை சரிபார்க்கவும்! பதிலாள் வெற்றிகரமாக அமைக்கப்படுகிறது விரும்பினால் தேவையான அனுமதிகள் மறுக்கப்பட்டன. நடவடிக்கையைத் தொடர தயவுசெய்து அவற்றை வழங்கவும் <xliff: g ஐடி = \"app_one_name\">%1$s </xliff: g> மற்றும் <xliff: g ஐடி = \"app_two_name\">%2$s </xliff: g> - %1$s, %2$s மற்றும் %3$s + <xliff: g ஐடி = \"app_one_name\">%1$s </xliff: g>, <xliff: g ஐடி = \"app_two_name\" \">%3$s </xliff: g> <Xliff: g ஐடி = \"app\">%1$s </xliff: g> க்கான கூடுதல் கோப்புகளைப் பதிவிறக்குகிறது <xliff: g ஐடி = \"apps_count\">%1$d </xliff: g> புதுப்பிப்பு கிடைக்கிறது <Xliff: g ஐடி = \"app_one_name\">%1$s </xliff: g> இன் புதிய பதிப்பு கிடைக்கிறது கிடைக்கக்கூடிய புதுப்பிப்புகளுக்கு சரிபார்த்து அறிவிக்கவும் - தானி மற்றும் தன்வய புதுப்பிப்புகளுக்கான இடைவெளிகளை மணிநேரத்தில் உள்ளமை. - தானி புதுப்பிப்புகளின் நடத்தை உள்ளமை + ஆட்டோ மற்றும் தன்வய புதுப்பிப்புகளுக்கான இடைவெளிகளை மணிநேரத்தில் உள்ளமைக்கவும். + ஆட்டோ புதுப்பிப்புகளின் நடத்தை உள்ளமைக்கவும் தனியுரிமை அறிக்கையைப் பெறுவதில் தோல்வி அச்சச்சோ, நீங்கள் விகிதம் வரையறுக்கப்பட்டவர் அமர்வை உருவாக்க முடியவில்லை @@ -288,7 +294,7 @@ கிடைக்கவில்லை ஏற்பு தேவை கிடைக்கிறது - அதிகாரப்பூர்வ கூகிள் பிளே ச்டோரிலிருந்து பயன்பாடுகளைத் தேடவும் பதிவிறக்கவும் அரோரா கடை உங்களுக்கு உதவுகிறது. பயன்பாட்டு விளக்கங்கள், திரை சாட்கள், புதுப்பிப்புகள், பிற பயனர்களின் கருத்துகளை நீங்கள் சரிபார்க்கலாம் மற்றும் Google Play இலிருந்து உங்கள் சாதனத்திற்கு நேரடியாக APK ஐ பதிவிறக்கம் செய்யலாம். அரோரா ச்டோரைப் பயன்படுத்த, நீங்கள் ஒரு Google Play கணக்கை வைத்திருக்க வேண்டும், மேலும் நீங்கள் முதலில் அரோரா கடையைத் திறந்து உள்ளமைக்கும்போது உங்கள் Google Play கணக்கில் உள்நுழைக. \n\nபாரம்பரிய ஆப் ச்டோரைப் போலன்றி, அரோரா கடை எந்த பயன்பாடுகளையும் சொந்தமாகவோ, உரிமம் பெறவோ அல்லது விநியோகிக்கவோ இல்லை. அரோரா கடையில் உள்ள அனைத்து பயன்பாடுகள், பயன்பாட்டு விளக்கங்கள், திரை சாட்கள் மற்றும் பிற உள்ளடக்கங்கள் நேரடியாக அணுகப்படுகின்றன, பதிவிறக்கம் செய்யப்படுகின்றன மற்றும்/அல்லது கூகிள் பிளேயில் இருந்து காட்டப்படுகின்றன. அரோரா கடை ஒரு கதவு அல்லது உலாவி போன்றது, உங்கள் Google Play கணக்கில் உள்நுழைந்து Google Play இலிருந்து பயன்பாடுகளைக் கண்டறிய உங்களை அனுமதிக்கிறது. \n\nஅரோரா ச்டோருக்கு கூகிள், கூகிள் பிளே, அரோரா கடை அல்லது எந்த பயன்பாட்டு உருவாக்குபவர்கள் மூலம் பதிவிறக்கம் செய்யப்பட்ட எந்த பயன்பாடுகளும் ஒப்புதல், ச்பான்சர்சிப் அல்லது ஏற்பு இல்லை என்பதை நினைவில் கொள்க; அரோரா கடைக்கு அவர்களுடன் எந்த தொடர்பும், ஒத்துழைப்பும் அல்லது தொடர்பும் இல்லை. + அதிகாரப்பூர்வ கூகிள் பிளே ச்டோரிலிருந்து பயன்பாடுகளைத் தேடவும் பதிவிறக்கவும் அரோரா கடை உங்களுக்கு உதவுகிறது. பயன்பாட்டு விளக்கங்கள், திரை சாட்கள், புதுப்பிப்புகள், பிற பயனர்களின் கருத்துகளை நீங்கள் சரிபார்க்கலாம் மற்றும் Google Play இலிருந்து உங்கள் சாதனத்திற்கு நேரடியாக APK ஐ பதிவிறக்கம் செய்யலாம். அரோரா ச்டோரைப் பயன்படுத்த, நீங்கள் ஒரு Google Play கணக்கை வைத்திருக்க வேண்டும், மேலும் நீங்கள் முதலில் அரோரா கடையைத் திறந்து உள்ளமைக்கும்போது உங்கள் Google Play கணக்கில் உள்நுழைக.\n\n பாரம்பரிய ஆப் ச்டோரைப் போலன்றி, அரோரா கடை எந்த பயன்பாடுகளையும் சொந்தமாகவோ, உரிமம் பெறவோ அல்லது விநியோகிக்கவோ இல்லை. அரோரா கடையில் உள்ள அனைத்து பயன்பாடுகள், பயன்பாட்டு விளக்கங்கள், திரை சாட்கள் மற்றும் பிற உள்ளடக்கங்கள் நேரடியாக அணுகப்படுகின்றன, பதிவிறக்கம் செய்யப்படுகின்றன மற்றும்/அல்லது கூகிள் பிளேயில் இருந்து காட்டப்படுகின்றன. அரோரா கடை ஒரு கதவு அல்லது உலாவி போன்றது, உங்கள் Google Play கணக்கில் உள்நுழைந்து Google Play இலிருந்து பயன்பாடுகளைக் கண்டறிய உங்களை அனுமதிக்கிறது.\n\n அரோரா ச்டோருக்கு கூகிள், கூகிள் பிளே, அரோரா கடை அல்லது எந்த பயன்பாட்டு உருவாக்குபவர்கள் மூலம் பதிவிறக்கம் செய்யப்பட்ட எந்த பயன்பாடுகளும் ஒப்புதல், ச்பான்சர்சிப் அல்லது ஏற்பு இல்லை என்பதை நினைவில் கொள்க; அரோரா கடைக்கு அவர்களுடன் எந்த தொடர்பும், ஒத்துழைப்பும் அல்லது தொடர்பும் இல்லை. மேலும் பயன்பாட்டை அமைதியாக நிறுவ அமர்வு நிறுவியின் அனுமதியை இது ரத்து செய்யும். சாதன உரிமையை அழிக்க வேண்டுமா? விநியோகிப்பாளர்களை நிர்வகிக்கவும் @@ -307,7 +313,7 @@ பிழை ஏற்பட்டது! புதிய அமர்வைக் கோருகிறது தெளிவாக முடிந்தது - பதிவிறக்கம் • %1$d / %2$d%3$s + பதிவிறக்கம் • <xliff: g ஐடி = \"நிறைவு செய்யப்பட்ட_டவுண்ட் லோடுகள்\">%1$d </xliff: g>/<xliff: g ஐடி = \"all_downloads\">%2$d </xliff: g> • <xliff: g ஐடி = \"வேகம்\">%3$s </xliff: g> நீங்கள் பதிவிறக்க விரும்பும் பதிப்பு குறியீட்டை உள்ளிடவும் கணக்கு தொடர்பான அறிவிப்பு அறியப்படாத மூலங்களிலிருந்து பயன்பாடுகளை நிறுவ அனுமதிக்கவும் @@ -315,7 +321,7 @@ விசயங்களை ஆயத்தம் செய்வது… பயன்பாட்டு அமைப்புகள் பராமரிப்புக்காக சேவையகம் கீழே - %1$s, %2$s, %3$s and %4$d மேலும் + <xliff: g ஐடி = \"app_one_name\">%1$s </xliff: g>, <xliff: g ஐடி = \"app_two_name\" \">%3$s</xliff:g> and <xliff:g id=\"apps_count\">%4$d</xliff:g> more அணுகல் மறுக்கப்பட்டது! நீங்கள் VPN அல்லது TOR ஐப் பயன்படுத்துகிறீர்களா? சேவையகம் அணுக முடியாதது ரூட்/சூப்பர் யூசர் சலுகைகள் தேவை, அனைத்து ஆண்ட்ராய்டு பதிப்புகளையும் ஆதரிக்கிறது. @@ -329,11 +335,11 @@ பதிலாள் முகவரி ஓ! எல்லாம் நல்லது. அமர்வு சரிபார்க்கிறது - கூகிள் அமர்வைச் சரிபார்க்கிறது + Google அமர்வை சரிபார்க்கிறது தேடல் முடிவுகள் மேம்பட்ட தானியங்கி புதுப்பிப்புகள் அதிர்வெண் - தானியங்கு புதுப்பிப்புகள் + தானியங்கு புதுப்பிப்பு பயன்பாடுகள் கிடைக்கக்கூடிய புதுப்பிப்புகளை சரிபார்த்து நிறுவவும் அமர்வை உருவாக்குவதில் தோல்வி, பிழைக் குறியீடு: <xliff: g ஐடி = \"status_code\">%1$d </xliff: g> பதிவிறக்குகிறது @@ -349,7 +355,7 @@ இயல்புநிலை உதவி இணைப்புகளைத் திறக்க அரோரா கடையை அனுமதிக்கவும் பிடித்த - பயன்பாடுகள் மற்றும் விளையாட்டுகளைத் தேடு + பயன்பாடுகள் மற்றும் விளையாட்டுகளைத் தேடுங்கள் <xliff: g ஐடி = \"உற்பத்தியாளர்\">%1$s </xliff: g> • பநிஇ <xliff: g ஐடி = \"api\">%2$s </xliff: g> பயன்பாடுகளை தானாக புதுப்பிக்க வேண்டாம் அரோரா கடை பற்றி @@ -357,7 +363,7 @@ சாதன கட்டமைப்பை இறக்குமதி செய்ய முடியவில்லை புதுப்பிப்பு கிடைக்கிறது புதுப்பிப்புகள் கிடைக்கின்றன - அறிவிப்புகளைப் புதுப்பி + அறிவிப்புகளைப் புதுப்பிக்கிறது <xliff: g ஐடி = \"apps_count\">%1$d </xliff: g> புதுப்பிப்புகள் கிடைக்கின்றன ரூட் அனுமதிகளைப் பயன்படுத்தி செல் அடிப்படையிலான நிறுவி ஆண்ட்ராய்டு 4.4 க்கு கீழே இயங்கும் சாதனங்களுக்கு மிகவும் பொருத்தமானது @@ -372,17 +378,19 @@ உள் பிழை! சிறிது நேரம் கழித்து மீண்டும் முயற்சிக்கவும் பயன்பாட்டு மூட்டை வெற்றிகரமாக ஏற்றுமதி செய்தது வெற்றிகரமாக நிறுவல் நீக்கப்பட்டது + பதிலாள் அரோரா கடை பற்றி மேலும் அறிக - முகப்புத் திரையில் சேர் + முகப்புத் திரையில் சேர்க்கவும் அகற்று நோக்கம் அடிப்படையிலான நிறுவி, எல்லா சாதனங்களிலும் கிடைக்கிறது இறக்குமதி பிடித்த பயன்பாடுகள் எதுவும் கிடைக்கவில்லை %1$dh %2$dm %3$ds மீதமுள்ளது %1$dm %2$ds மீதமுள்ளது - இடைநிறுத்தப்பட்டது • %1$d / %2$d + இடைநிறுத்தப்பட்டது • <xliff: g ஐடி = \"நிறைவு செய்யப்பட்ட_டவுண்ட் லோடுகள்\">%1$d </xliff: g>/<xliff: g ஐடி = \"all_downloads\">%2$d </xliff: g> சிசுகு நிறுவப்படவில்லை அல்லது சரியாக அமைக்கப்படவில்லை. உள்நுழைந்து மகிழுங்கள். + வழங்குநர் - bestappsales.com சாதன கட்டமைப்பு இறக்குமதி செய்யப்பட்டது ப்ராக்சியை அமைப்பதில் தோல்வி பிடித்தவை ஏற்றுமதி! @@ -390,41 +398,4 @@ பயன்பாட்டு ஏற்றுமதி அறிவிப்பு அறிவிப்பை நிறுவவும் பதிவிறக்க அறிவிப்பு - கணக்குகளில் உள்நுழைய மைக்ரோகைப் பயன்படுத்தவும் - அளவிடப்படாத நெட்வொர்க்குகளில் மட்டுமே - அனைத்தையும் அகற்று - அனைத்தையும் தேர்ந்தெடு - தடுப்புப்பட்டியலை ஏற்றுமதி செய்வதில் தோல்வி! - பிளாக்லிச்ட் இறக்குமதி செய்யப்பட்டது! - பதிவிறக்கம் செய்யப்பட்ட கோப்புகளை சரிபார்க்கத் தவறிவிட்டது - பயன்பாடுகள் எதுவும் கிடைக்கவில்லை - சரிபார்க்கும் - அன்கான் - பயன்பாட்டைத் திறக்க முடியவில்லை - பொருந்தக்கூடிய தன்மையைச் சரிபார்க்கிறது… - பொருந்தக்கூடிய தன்மை - Google Play சேவைகள் தேவை - கூகிள் பிளே சேவைகள் இல்லாமல் - இணக்கமானது: எந்த சிக்கலும் இல்லாமல் செயல்படுகிறது - ஆதரிக்கப்படாதது: செயல்படவில்லை - அண்மைக் கால - பிளெக்சசால் இயக்கப்படுகிறது - மைக்ரோக் திட்டத்துடன் - நீங்கள் Google இன் தனியுரிம நூலகம் அல்லது மைக்ரோக் போன்ற FOSS மறுசீரமைப்பை நிறுவ வேண்டியிருக்கலாம். - லிமிடெட்: வரையறுக்கப்பட்ட அம்சங்களுடன் செயல்படுகிறது - தடுப்புப்பட்டியலை இறக்குமதி செய்வதில் தோல்வி! - பிளாக்லிச்ட் ஏற்றுமதி! - கூகிள் பிளே சேவைகள் இல்லாமல் வேலை செய்கிறது - இந்த பயன்பாடு கூகிளின் தனியுரிம நூலகம் இல்லாமல் செயல்படுகிறது. இருப்பினும், மற்ற மூன்றாம் தரப்பு நூலகங்கள் சரியாக வேலை செய்ய வேண்டும். - தெரியவில்லை: இன்னும் சரிபார்க்கப்படவில்லை - எளிமையான உள்நுழைவு ஓட்டத்திற்கு Google கணக்குகளில் கையொப்பமிடும்போது மைக்ரோகைப் பயன்படுத்தி அங்கீகரிக்கவும். - கணம் - முடக்கு - பதிலாள் வெற்றிகரமாக முடக்கப்பட்டது - பதிலாள் உள்ளமைவைக் காணவும் நிர்வகிக்கவும் - <xliff: g அடையாளம் = \"install_apps_size\">%1$d </xliff: g> பயன்பாடுகள் நிறுவப்பட்டுள்ளன - தானியங்கி புதுப்பிப்புகள் கட்டுப்பாடுகள் - தானியங்கு புதுப்பிப்புகளுக்கான சாதன கட்டுப்பாடுகளை உள்ளமைக்கவும். - சாதனம் சும்மா இருக்கும்போது - பேட்டரி குறைவாக இல்லாதபோது diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 98fd353c2..d3bf560b4 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -7,7 +7,7 @@ XDA Forumları Temizle İptal et - Kara liste + Kara Liste Kara listeye ekle Geri Aurora\'dan çıkış yap @@ -49,7 +49,7 @@ İnternet yok Kütüphane Dil - Uygulama kurucu + Uygulama Kurucu Kuruldu Kurulum Oyunlar @@ -57,6 +57,7 @@ İndirilenler Cihaz Kara liste yöneticisi + Satıştaki uygulamalar Kütüphanedeki uygulamalar Uygulamalarım ve oyunlarım Uygulamalar @@ -77,10 +78,11 @@ Uygulama bulunamadı Uygulama desteklenmiyor Uygulama satın alınmadı - İndirme başarısız + İndirme Başarısız + Uygulama ayrıntıları sayfasında benzer ve ilgili kümeleri görüntüle Benzer ve ilgili uygulamalar - Ana ekranda Sana özel sayfaları göster - Sana özel sayfalar + Ana ekranda Sana Özel Sayfalar\'ı göster + Sana Özel Sayfalar Varsayılan sekmeyi seç Yerleşim Özelleştirme @@ -94,13 +96,13 @@ Kurduktan sonra APK\'yi sil İndirilen APK\'lar kurulumdan hemen sonra silinecek F-Droid uygulamalarını süz - F-Droid\'den kurulan uygulamaların güncellemelerini denetleme + F-Droid\'den indirilen ya da kurulan uygulamaların güncellemelerini denetleme Ekler Aurora Store\'dan uygulama kurmaya izin ver - Kurucu izni - Dış depolama yöneticisi + Kurucu İzni + Harici Depolama Yöneticisi Büyük uygulamalar ve oyunlar için APK genişletme dosyalarını (OBB\'ler) kaydetmek için. - Dış depolama erişimi + Harici Depolama Erişimi Neler yapıyorsun\? Hoş geldiniz İzinler @@ -123,9 +125,9 @@ Oturum oluşturulamadı Kurulum engellendi Kurucu başarısız oldu - Önce Aurora Hizmetlerini kurun ve tüm izinleri verin. - Aurora Hizmetleri 1.0.9 veya üstünü kurun ya da kurucuyu değiştirin. - Aurora Hizmetleri uygun ve kuruluma hazır. + Önce Aurora hizmetlerini kurun ve tüm izinleri verin. + Aurora hizmetleri 1.0.9 veya üstünü kurun ya da kurucuyu değiştirin. + Aurora hizmetleri var ve kuruluma hazır. Kök erişimi yok. İzin verin veya kurucuyu değiştirin. İki Üç @@ -136,7 +138,7 @@ Kritik Tümü Raporu görüntüle - bilinen izleyici bulundu + bilinen izleyici(ler) bulundu İzleyiciler denetleniyor… Exodus Privacy Tarafından Destekleniyor Bilinen izleyici içermiyor @@ -159,10 +161,10 @@ Ücretli Güncelleme yok İzin yok - Bağımlılık yok + Bağımlılık Yok Eşleşen uygulama bulunamadı Reklam yok - Uygulamayla ilgili daha çoğu + Uygulama hakkında daha fazla GSF Gerekir Ücretsiz Geliştirici profili @@ -170,18 +172,18 @@ Adres Açıklama Bağımlılıklar - Reklam içerir + Reklam İçerir Değişiklik günlüğü sunulmadı Değişiklik günlüğü Kayıt işlemi biraz zaman alabilir, burayı sonra gözden geçirebilirsiniz. Resmî olarak yayınlanmadan önce yeni özellikleri ve hataları görebileceksin. Geri bildirim yaparak geliştiricilere destek olabilirsin. - Ön izleme programına katılınsın mı? + Ön izleme programına katılmak ister misin\? Artık ön izleme sürümü kullanıyorsunuz Ön izleme programı Beyaz liste Tümünü güncelle Güncelle - Uygulama bilgisi + Uygulama Bilgisi Kaldır Paylaş Ara @@ -229,7 +231,7 @@ Arka planda uygulama indirme App Manager kurun veya kurucuyu değiştirin. AM kurucu - Duraklatıldı • %1$d / %2$d + Duraklatıldı •%1$d / %2$d Son oturum iptal edildi Oturum doğrulanıyor Google oturumu doğrulanıyor @@ -243,11 +245,11 @@ %1$ddak %2$dsn kaldı Bildirimler Kurulum durumuyla ilgili bildirimler gönder - İndiriliyor • %1$d / %2$d%3$s + İndiriliyor •%1$d / %2$d%3$s Vay canına! Her şey yolunda. Google aracılığıyla oturum açılamadı Hazırlanıyor… - Uygulama ve oyun Ara + Uygulama ve Oyun Ara güncelleme var Genişlet %1$s • API %2$s @@ -275,29 +277,33 @@ Gizlilik raporu alınamadı Erişim reddedildi! VPN veya Tor kullanıyor musunuz\? İç hata! Lütfen bir süre sonra yeniden deneyin - Uygulama dili + Uygulama Dili İnternet bağlantısını denetle Oturum oluşturulamadı Aurora Store\'un desteklenen bağlantıları açmasına izin ver Yeni oturum doğrulanıyor - Uygulama bağlantıları + Uygulama Bağlantıları Google Play, Google Play Store ve eski adıyla Android Market olarak da bilinir. Android Market, Android aygıtlar için tasarlanan yazılım uygulamaları sunan çevrim içi mağazaydı ve 2017 yılında yayın yaşamını sonlandırdı. İnceleme başlığı Kendiliğinden güncellemeler için saat türünde aralığı yapılandır. - Diğer kaynaktan uygulamaları süz - Aurora Store dışındaki kaynaklardan kurulan uygulamaların güncellemelerini denetleme - Uygulama ayarları + Yalnızca Aurora Store uygulamaları + Yalnızca Aurora Store tarafından kurulan uygulamaları denetle + Uygulama Ayarları + Sağlayıcı - bestappsales.com Kendiliğinden güncelleme sıklığı + Vekili etkinleştir Vekil URL\'si + Vekil Geçersiz vekil URL\'si, biçimi denetle! Vekil belirleme başarılı Vekil belirlenemedi + Uygulamadan tüm trafiğin vekilden gitmesini sağla Varsayılan (cihaz yapılandırmasından) - Google Play sürümü - Arka plan indirmeleri + Google Play Sürümü + Arka Plan İndirmeleri Aurora Store\'un arka planda uygulamaları indirmesine ve güncellemesine izin ver - Otomatik güncellemeler + Uygulamaları kendiliğinden güncelle Kullanılabilir güncellemeleri denetle ve bildir Uygulamalar kendiliğinden güncellenmesin Kendiliğinden güncelleme davranışını yapılandır @@ -305,19 +311,19 @@ Yeni değerlendirme iste APK\'lar dışa aktarılamadı Temizlendi - Başarısız olabilecek güncellemeleri göster - Kurulamayabilecek uyumsuz veya devre dışı uygulamalar için güncellemeleri görüntüle + Uyumsuz güncellemeler + Kurulamayabilecek uyumsuz veya devre dışı uygulamalar için güncellemeleri göster Ana ekrana ekle Arka planda kurulumlar için kurucu Aurora Hizmetlerinin ayrıcalıklı sistem uygulaması olarak kurulmasını gerektirir Tam özellikli açık kaynaklı paket yöneticisi - App Manager gerektirir, MIUI iyileştirmesi açıkken kurmak için adb/kök kipi gerekir - Sistem API\'lerini doğrudan adb/kök ayrıcalıklarıyla kullan + App Manager gerektirir, MIUI iyileştirmesi açıkken kurmak için adb/root kipine ihtiyaç duyar + Sistem API\'lerini doğrudan adb/root ayrıcalıklarıyla kullan Shizuku veya Sui gerektirir, ayarlanması ve izin verilmesi gerekir Paketlenmiş/bölünmüş APK\'lar için oturum tabanlı kurucu Tavsiye edilir, yerleşiktir ve tüm Android sürümlerini destekler - Kök izinlerini kullanan kabuk tabanlı kurucu - Kök/yetkili kullanıcı ayrıcalıkları gerektirir, tüm Android sürümlerini destekler. + Root izinlerini kullanan kabuk tabanlı kurucu + Root/yetkili kullanıcı ayrıcalıkları gerektirir, tüm Android sürümlerini destekler. Intent tabanlı kurucu, tüm aygıtlarda kullanılabilir Android 4.4 sürümünden önceki aygıtlar için en uygun Sorularınız mı var? Yanıtlarını öğrenin @@ -327,17 +333,17 @@ İndirmek istediğiniz sürüm kodunu girin Gizlilik politikası Aurora Store\'un verilerinizi nasıl kullandığını öğrenin - Daha Çoğu + Daha Fazla Hesabınızı yönetin Aygıt sahibini temizle Aurora Store\'un aygıt sahibi uygulaması olmasını kaldırır Bu, oturum kurucunun uygulamayı sessizce kurma iznini iptal edecektir. Aygıt sahipliğini temizlemeye devam edilsin mi? Dağıtıcıları yönet Anonim oturum açmak için belirteç dağıtıcılarını görüntüleyin ve yönetin - Dağıtıcı kaldırılsın mı? + Dağıtıcıyı kaldır Kaldır Wiki - Sık sorulan soruların (S.S.S.) yanıtlarını, sorun giderme adımlarını ve daha çoğunu bulun + Sık sorulan soruların (SSS) yanıtlarını, sorun giderme adımlarını ve daha fazlasını bulun Kullanılabilir dağıtıcı yok \"%1$s\" dağıtıcısını kaldırmak istiyor musunuz? Ekle @@ -346,17 +352,21 @@ Geçersiz URL Dağıtıcı URL\'si Aurora Store Hakkında - Aurora Store ile ilgili daha çok bilgi edinin - Aurora Store, resmi Google Play Mağazasından uygulama aramanızı ve indirmenizi sağlar. Uygulama açıklamalarını, ekran görüntülerini, güncellemeleri, diğer kullanıcıların yorumlarını görebilir ve APK\'yı doğrudan Google Play\'den aygıtınıza indirebilirsiniz. Aurora Store\'u kullanmak için bir Google Play hesabınızın olması ve Aurora Store\'u ilk açtığınızda ve yapılandırdığınızda Google Play hesabınızda oturum açmanız gerekir. \n \nGeleneksel bir uygulama mağazasının tersine, Aurora Store herhangi bir uygulamayı sahiplenmez, lisanslamaz veya dağıtmaz. Aurora Store\'daki tüm uygulamalara, uygulama açıklamalarına, ekran görüntülerine ve diğer içeriğe doğrudan Google Play\'den erişilir, indirilir ve/veya görüntülenir. Aurora Store, tıpkı bir kapı veya tarayıcı gibi çalışarak Google Play hesabınızda oturum açmanıza ve Google Play\'deki uygulamaları bulmanızı sağlar.\n \nAurora Store\'un Google, Google Play, Aurora Store üzerinden indirilen herhangi bir uygulama veya herhangi bir uygulama geliştiricisinden herhangi bir onay, sponsorluk veya yetkilendirme almadığını ve Aurora Store\'un bunlarla herhangi bir ilişkisi, işbirliği veya bağlantısı olmadığını lütfen unutmayın. + Aurora Store hakkında daha fazla bilgi edinin + Aurora Store, resmi Google Play mağazasından uygulama aramanızı ve indirmenizi sağlar. Uygulama açıklamalarını, ekran görüntülerini, güncellemeleri, diğer kullanıcıların yorumlarını görebilir ve APK\'yı doğrudan Google Play\'den aygıtınıza indirebilirsiniz. Aurora Store\'u kullanmak için bir Google Play hesabınızın olması ve Aurora Store\'u ilk açtığınızda ve yapılandırdığınızda Google Play hesabınızda oturum açmanız gerekir. +\n +\nGeleneksel bir uygulama mağazasının aksine, Aurora Store herhangi bir uygulamaya sahip değildir, lisanslamaz veya dağıtmaz. Aurora Store\'daki tüm uygulamalara, uygulama açıklamalarına, ekran görüntülerine ve diğer içeriğe doğrudan Google Play\'den erişilir, indirilir ve/veya görüntülenir. Aurora Store, tıpkı bir kapı veya tarayıcı gibi çalışarak Google Play hesabınızda oturum açmanıza ve Google Play\'deki uygulamaları bulmanıza olanak tanır. +\n +\nAurora Store\'un Google, Google Play, Aurora Store üzerinden indirilen herhangi bir uygulama veya herhangi bir uygulama geliştiricisinden herhangi bir onay, sponsorluk veya yetkilendirme almadığını ve Aurora Store\'un bunlarla herhangi bir ilişkisi, işbirliği veya bağlantısı olmadığını lütfen unutmayın. Lütfen Google Play hesabınızda oturum açın Uygulama aygıtınız için kullanılabilir değil - Gözdeler dışa aktarılamadı! - Gözdeler içe aktarıldı! - Gözdeler dışa aktarıldı! - Gözde uygulamalar - Gözdelere ekle - Gözde uygulama bulunamadı - Gözdeler içe aktarılamadı! + Sık kullanılanlar dışa aktarılamadı! + Sık kullanılanlar içe aktarıldı! + Sık kullanılanlar dışa aktarıldı! + Sık Kullanılan Uygulamalar + Sık kullanılanlara ekle + Sık kullanılan uygulama bulunamadı + Sık kullanılanlar içe aktarılamadı! Uygulama paketi başarıyla dışa aktarıldı Uygulama paketi dışa aktarılamadı Başarıyla kaldırıldı @@ -366,13 +376,14 @@ Güncellemeleri denetle Bilinmeyen kaynaklardan uygulamaların kurulmasına izin ver Veri güvenliği - Geliştiricice açıklanan veri gizliliği ve güvenliği uygulamaları + Geliştirici tarafından açıklanan veri gizliliği ve güvenliği uygulamaları Önce kurucu izni vermeniz gerekir + Depolama Erişim Çerçevesindeki bir hata nedeniyle izni yeniden vermeniz gerekebilir Gerekli İsteğe bağlı Aurora Store\'u yeniden başlat Aurora Store\'un yeni değiştirilen ayarları uygulamak için yeniden başlatılması gerekir - Dosya dışa aktarıcı + Dosya Dışa Aktarıcı Bekleyin, dosyanız dışa aktarılıyor Uygulama dışa aktarma bildirimi Kurulum bildirimi @@ -396,6 +407,7 @@ Kara liste içe aktarılamadı! Kara liste dışa aktarıldı! Kara liste dışa aktarılamadı! + Verilen iznin etkinleşmesi için uygulamayı yeniden başlatmanız gerekebilir. Öntanımlı Kara liste içe aktarıldı! Arşivden kaldır @@ -414,61 +426,4 @@ Desteklenmiyor: İşlevsiz Bilinmiyor: Henüz denetlenmedi %1$d uygulama kuruldu - Uygulama yok - Hesaplara giriş yapmak için microG kullan - Daha basit bir giriş akışı için Google hesaplarına giriş yaparken microG ile kimliği doğrula - Ayarla - Devre Dışı Bırak - Vekil başarıyla devre dışı bırakıldı - İndirilen dosyalar doğrulanamadı - Yalnızca ölçülmeyen ağlarda - Aygıt boştayken - Pil gücü düşük değilken - Vekil yapılandırmasını göster ve yönet - Kendiliğinden güncelleme kısıtları - Kendiliğinden güncellemeler için aygıt kısıtlarını yapılandır - Gelişmiş - Uygulama kaynağı - İndirme - En Düşük Android Sürümü - Son güncelleme - Hedef API Düzeyi - %1$d izin - microG Paketini Kur - Uygulama Uyumluluğu - Eksik bağımlılıklar - microG Hizmet Koşullarını ve Gizlilik İlkelerini okudum ve kabul ediyorum - Aygıtınızda Google Play Hizmetleri\'ni bulamadık, birçok gözde uygulama düzgün çalışabilmek için ona gereksiniyor! - microG, Android İçin Google Play Hizmetleri\'ne bağımlı uygulamaları çalıştırmak için yeniden uyarlama yoluyla benzer işlevselliği sağlayan; özgür ve açık kaynaklı bir uyarlamadır.\n\nmicroG, uygulamaların Google API\'lerine erişmesini sağlar, kullanıcılara gizlilik yararları sunarken için uyumluluğu artırır.\n\nmicroG, Google Mobil Hizmetleri\'ne bağımlı uygulamaları açtığınızda kendiliğinden arka planda çalışacak. - microG Gizlilik İlkesini Oku - microG Lisans ve Anlaşmasını Oku - microG Projesi Web Sitesine Git - Bu uygulamanın toplayabileceği veriler - Geliştirici bu uygulamanın kullanıcı verileri toplamadığını söylüyor. - Bu uygulamanın paylaşabileceği veriler - Geliştirici bu uygulamanın kullanıcı verilerini diğer şirketler ve kurumlarla paylaşmayacağını söylüyor. - Uygulamanın bu sürümü henüz Exodus Privacy\'nin veri merkezinde bulunmayan takipçiler bulundurabilir. - Daha çok bilgi - Hedefler - Paket adı - Daha çok ayrıntı için uygulama şeçin - %2$s içinde bilinen %1$d izleyici bulundu - Açıklama yok - İçerik derecelendirme - Sürüm kodu yalnızca rakam içerebilir - Reklam yok - Play hizmetleri yok - Kuruluma hazırlanıyor - - İzin gerekli - İzinler gerekli - - MicroG kurucu, büyük olasılıkla yanlış yapılandırma nedeniyle uygulamayı kuramadı. - MicroG kurucu - microG yardımcı uygulamasının kurulmasını gerektirir - Uygulama Tümlüğü (yalnızca kurucu) denetimini atlamanıza yardımcı olur - Yükleme devam ediyor - Sayfa %1$d - Atla - Değişiklikleri uygulamak için yeniden başlatılsın mı? diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index d43440ddc..501874c14 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -1,22 +1,22 @@ Вебсайт - Ел. пошта - Усі + Електронна пошта + Все Переглянути звіт - відомих відстежувачів виявлено в - Перевірка на наявність відстежувачів… - На основі Exodus Privacy - Не містить відомих відстежувачів - Оцінювання - Відновити всі - У черзі + відомих трекерів знайдено в + Перевірка наявності елементів стеження… + За підтримки Exodus Privacy + Не містить відомих трекерів + Оцінюється + Продовжити все + В черзі Призупинити все Немає завантажень Отримання метаданих - Примусово очистити всі - Не вдалося завантажити - Обчислення + Примусово очистити все + Помилка завантаження + Обчислюється Завантаження завершено Скасувати всі Скасовано @@ -25,27 +25,27 @@ Платний Приватність Дозволи - Немає доступних оновлень + Немає оновлень Без дозволів - Без залежностей + Немає залежностей Застосунок не знайдено - Без реклами + Без оголошень Докладніше про застосунок Потребує GSF - Безплатний + Безплатно Профіль розробника - Зв\'язок із розробником + Зв\'язок з розробником Адреса Опис Залежності - Містить рекламу - Перелік змін не надано - Перелік змін - Реєстрація може зайняти трохи часу, стан можна перевірити пізніше. - Ви побачите нові функції та помилки раніше за інших. Надсилайте свій відгук розробникам, щоби допомогти їм удосконалити застосунок. - Приєднатися до бета-тестування? - Ви – бета-тестувальник - Бета-тестування + Містить оголошення + Список змін не наданий + Список змін + Реєстрація може тривати трохи часу, стан можна перевірити пізніше. + Ви побачите нові функції та помилки перед тим, як це стане загальнодоступним. Надішліть свій відгук розробникам, щоб допомогти їм вдосконалити застосунок. + Приєднатися до бета тестування? + Ви бета тестувальник + Бета тестування Білий список Оновити все Оновити @@ -64,27 +64,27 @@ Залишити Пізніше Приєднатися - Установлення - Установлення - Установити + Встановлення + Установки + Встановити Знехтувати Надати Надано - Зберегти набір застосунків + Зберегти APK застосунку Завершити Оцінки Платні Різне - Залежні від GSF + Потребує GSF Завантаження - Застосуноки з рекламою + Застосунок з рекламою Застосувати - Усі + Всі Фільтри - Експорт + Експортувати Вимкнути - Скопіювати покликання - Скопіювати + Копіювати посилання + Копіювати Закрити Очистити Скасувати @@ -105,7 +105,7 @@ Liberapay Початковий код Aurora Store в репозиторії Aurora OSS на GitLab. GitLab - Завантажити Aurora Store з F-Droid. + Завантажити Aurora Store з репозиторію F-Droid. F-Droid Допомогти через Ethereum (ETH) Ethereum @@ -115,17 +115,17 @@ Bitcoin Cash Допомогти через UPI BHIM - UPI - Вітаємо, запитаний код версії доступний, наразі завантажується. + Вітаємо, запитаний код версії доступний, завантажується зараз. Запитуваний код версії недоступний. - Придбання застосунків недоступне для знеособлених облікових записів. + Покупки застосунків недоступні у знеособлених облікових записах. Підміну пристрою застосовано. Дозвіл надано - Увімкніть налаштування розробника в налаштуваннях пристрою, щоб відкрити їх. + Не вдалося відкрити налаштування розробника, переконайтеся, що ви ввімкнули їх в налаштуваннях пристрою. Скопійовано до буфера обміну У білому списку - У чорному списку + В чорному списку Недоступно для знеособлених облікових записів - Ручне завантаження + Власноручне завантаження Оновлення Менеджер підміни Налаштування @@ -133,14 +133,15 @@ Немає мережі Бібліотека Мова - Установлювач застосунків - Установлені + Встановлювач застосунків + Встановлені Встановлення Ігри Play Маркет Завантаження Пристрій Менеджер чорного списку + Розпродаж застосунків Застосунки в бібліотеці Мої застосунки та ігри Застосунки @@ -148,67 +149,68 @@ Про застосунок Популярні Найкращі платні - Найприбутковіші - Найкращі безплатні + Найпродаваніші + Найкращі безкоштовні Найпопулярніші Для вас Вибір редакції Категорії Переконайтеся, що ви повторно увійшли та перезапустили застосунок, щоб застосувати зміни. - Переконайтеся, що ви повторно увійшли, щоби застосувати підміну - Сеанс завершився. Увійдіть знову, щоби розпочати новий сеанс. - Не вдалось отримати файли + Переконайтеся, що ви повторно увійшли, щоб застосувати підміну + Сеанс минув, повторно увійдіть, щоб розпочати новий сеанс. + Не вдалося отримати файли Застосунок не знайдено Застосунок не підтримується Застосунок не придбано - Не вдалося завантажити + Збій завантаження + Показ подібних і пов\'язаних кластерів на сторінці відомостей про застосунок Подібні та пов’язані застосунки - Показувати сторінки для вас на головному екрані - Персоналізовані сторінки - Оберіть типову вкладку + Показувати сторінки на головному екрані + Сторінки для вас + Виберіть типову вкладку Макет Зовнішній вигляд Мережа - Спосіб установлення - Оберіть режим установлення APK - Установлювач Android - Сервіси Aurora (застарілі) - Root-установлювач - Власний установлювач (застарілий) - Видаляти APK після встановлення - Завантажені APK видалятимуться одразу після встановлення + Спосіб встановлення + Виберіть режим встановлення APK + Установник Android + Служби Aurora (Застарілі) + Кореневий встановлювач + Власний встановлювач (Застарілий) + Видалити APK після встановлення + Завантажені APK будуть видалені одразу після встановлення Дозволити встановлення застосунків з Aurora Store - Дозвіл установлювача + Дозвіл встановлювача Менеджер зовнішнього сховища - Щоби зберігати файли розширення APK (OBB) для великих застосунків та ігор. + Щоб зберігати файли розширення APK (OBB) для великих програм та ігор. Доступ до зовнішнього сховища Як справи\? Вітаємо Дозволи - Установлювач - Aurora Store потребує таких дозволів - Ви не можете встановлювати пакетні (розділені) застосунки за допомогою нативного встановлювача. Змініть встановлювач на сеансовий, сервісний або Root. + Встановлювач + Aurora Store використовує такі дозволи + Неможливо встановити пакети застосунків (split) через системний встановлювач Android. Змініть встановлювач на Session, служби Aurora або Root. Доступне нове оновлення - Ви також можете вибрати власний установлювач, але тоді ви не зможете встановлювати розділені (split) APK, тому вибір за вами. - Вимкніть оптимізації MIUI, щоби дозволити встановлення, інакше ви можете вибрати встановлювач Root або сервіси Aurora. - Установлювач Android не може встановлювати застосунки через оптимізації MIUI. + За бажанням ви можете вибрати власний встановлювач, але тоді ви не можете встановлювати розділені (split) APK, тому вибір за вами. + Вимкніть оптимізацію MIUI, щоб дозволити встановлення, інакше ви можете вибрати встановлювач Root або Services. + Встановлювач Android не може встановлювати застосунки через оптимізацію MIUI. Виявлено MIUI! - Умови використання + Умови надання послуг Ліцензія - Застереження + Дисклеймер Очікується підтвердження Успішно встановлено - Недостатньо вільної пам\'яті + Недостатньо пам\'яті Недійсний або пошкоджений APK Несумісний застосунок - Є конфліктний пакунок + Існує конфліктний пакунок Не вдалося створити сеанс - Установлення було заблоковано + Встановлення було заблоковано Помилка встановлювача - Спочатку налаштуйте сервіси Aurora та надайте всі дозволи. - Установіть сервіси Aurora версії 1.0.9 або новіше або змініть установлювач. - Сервіси Aurora доступні та готові до встановлення. - Немає root-доступу. Надайте його або змініть установлювач. + Налаштуйте служби Aurora, найперше надавши всі дозволи. + Встановіть служби Aurora 1.0.9 чи новішу версію або змініть встановлювач. + Служби Aurora доступні та готові до встановлення. + Немає root доступу, надайте його або змініть встановлювач. Два Три Позитивні @@ -216,19 +218,19 @@ Чотири П’ять Критичні - Фільтрувати F-Droid застосунки - Не перевіряти оновлення для застосунків, встановлених з F-Droid + Фільтрувати застосунки F-Droid + Не перевіряти оновлення для застосунків, завантажених або встановлених з F-Droid Додаткові Не вдалося створити токен AAS Не вдалося надіслати оцінку - Оцінено, може знадобитися деякий час для показу + Оцінено, оцінка може з\'явитися не одразу Сторінка огляду недоступна - Не вдалось експортувати налаштування пристрою - Налаштування пристрою експортовано + Не вдалося експортувати конфігурацію пристрою + Конфігурацію пристрою експортовано Вмикає фонове завантаження застосунків - Фонове завантаження застосунків - Установлювач менеджера застосунків - Установіть Менеджер застосунків або змініть установлювач. + Фонове завантаження застосунку + Інсталятор менеджера застосунків + Встановити Менеджер застосунків або змінити встановлювач. Залишилося %1$dхв %2$dс Приготування… Не вдалось увійти через Google @@ -237,25 +239,25 @@ Перевірка сеансу Google Сталася помилка! Меню - Пошук застосунків та ігор + Пошук застосунків та іграх Сповіщення Залишилося %1$dс Призупинено • %1$d / %2$d Залишилося %1$dгод %2$dхв %3$dс Завантаження • %1$d / %2$d%3$s - Надсилати сповіщення про стан установлення - Ого! Усе добре. + Надсилати сповіщення про стан встановлення + Вау! Усе добре. доступне оновлення - Увійдіть та насолоджуйтесь. + Увійдіть і насолоджуйтесь. Розширені доступні оновлення Розгорнути %1$s • API %2$s - Необхідні дозволи відхилено. Надайте їх, щоби продовжити дію + У наданні необхідних дозволів відмовлено. Надайте їх, щоб продовжити дію Сервер вимкнено для технічного обслуговування Запит нового сеансу - Налаштування пристрою імпортовано - Не вдалось імпортувати налаштування пристрою + Імпортовано конфігурацію пристрою + Не вдалося імпортувати конфігурацію пристрою Завантаження додаткових файлів для %1$s Імпорт Доступне %1$d оновлення @@ -266,114 +268,123 @@ %1$s, %2$s та %3$s %1$s, %2$s, %3$s та ще %4$d Shizuku не встановлено або не налаштовано належним чином. - Установлювач Shizuku + Інсталятор Shizuku Пошукова пропозиція Результати пошуку - Не вдалось отримати звіт про приватність + Не вдалося отримати звіт про приватність У доступі відмовлено! Ви використовуєте VPN або Tor\? - Ви обмежені тарифом - Не вдалося створити сеанс, код помилки: %1$d - Внутрішня помилка! Повторіть спробу згодом + Халепа, забагато спроб входу + Не вдалося згенерувати сеанс, код помилки: %1$d + Внутрішня помилка! Повторіть спробу трохи згодом Сервер недоступний - Перевірте з\'єднання з інтернетом + Перевірте інтернет-з\'єднання Мова застосунку - Не вдалося створити сеанс - Дозволити Aurora Store відкривати підтримувані покликання + Не вдалося згенерувати сеанс + Дозволити Aurora Store відкривати підтримувані посилання Підтвердження нового сеансу - Покликання застосунків - Google Play, також відомий як Google Play Маркет, а раніше – Android Market. - Android Маркет — інтернет-крамниця, що пропонувала програмне забезпечення для пристроїв Android, припинив свою діяльність у 2017 році. - Заголовок відгуку - Налаштувати часовий проміжок для автоматичних оновлень, у годинах. - Фільтрувати застосунки з інших джерел - Не перевіряти наявність оновлень для застосунків, встановлених з джерел поза Aurora Store + Посилання на застосунки + Google Play, також відомий як Google Play Маркет, а раніше - Android Market. + Android Маркет — інтернет-магазин, що пропонував програмне забезпечення для Android-пристроїв, припинив свою діяльність у 2017 році. + Назва відгуку + Налаштуйте інтервали для автоматичних і самооновлень, у годинах. + Тільки застосунки Aurora Store + Перевіряйте оновлення лише для застосунків, встановлених з Aurora Store Налаштування застосунку + Провайдер - bestappsales.com Частота автоматичних оновлень - URL-адреса проксі - Недійсна URL-адреса проксі, перевірте формат! + Увімкнути проксі + URL проксі + Проксі + Неправильна URL-адреса проксі, перевірте формат! Проксі успішно налаштовано Не вдалося налаштувати проксі - Типова (з налаштувань пристрою) + Дозволити всьому трафіку із застосунку проходити через проксі + Типово (з конфігурації пристрою) Версія Google Play - Фонове завантаження + Завантаження у фоні Дозволити Aurora Store завантажувати й оновлювати застосунки у фоновому режимі - Автоматичні оновлення - Перевіряти та сповіщати про доступні оновлення + Автооновлення застосунків + Перевіряти та повідомляти про доступні оновлення Не оновлювати застосунки автоматично - Налаштувати поведінку автоматичних оновлень - Перевіряти та встановлювати доступні оновлення автоматично + Налаштувати поведінку автооновлень + Автоматична перевірка та встановлення доступних оновлень Запросити новий аналіз - Не вдалось експортувати APK + Не вдалося експортувати APK-файли Очистити завершені - Показувати оновлення, які можуть не вдатися - Показувати оновлення для несумісних або вимкнених застосунків, встановлення яких може не вдатися - Додати на головний екран - Потрібує прав root/суперкористувача, підтримуються всі версії Android. - Установлювач Android для розділених/пакетних файлів APK - Використання системних API безпосередньо з привілеями adb/root - Потребує Shizuku або Sui, потрібно налаштувати та надати дозвіл + Несумісні оновлення + Показувати оновлення для несумісних або вимкнених застосунків, які можуть не встановитися + Додати на домашній екран + Потрібні права root/суперкористувача, підтримуються всі версії Android. + Сеансовий встановлювач для розділених/пакетних файлів APK + Використовує прямі системні API з правами adb/root + Потрібен Shizuku або Sui, потрібно налаштувати та надати дозвіл Рекомендовано, вбудовано та підтримує всі версії Android - Установлювач на основі оболонки з використанням root-дозволів - Установлювач на основі Intents, доступний на всіх пристроях - Найкраще підходить для пристроїв, що працюють на версії Android нижче 4.4 - Установлювач для фонових установлень - Потрібує встановлення Aurora Services як привілейованого системного застосуноку - Повнофункціональний менеджер пакунків із відкритим початковим кодом - Потребує Менеджера застосунків, для встановлення якого потрібен режим adb/root, якщо увімкнено оптимізації MIUI - Уведіть код версії, яку хочете завантажити - Маєте питання? Знайдіть відповіді - Дізнатися, що всередині - Підзвітність та відповідальність - Початковий код + Сеансовий встановлювач, використовує root-права + Класичний встановлювач, доступний на всіх пристроях + Найкраще підходить для пристроїв, що працюють на Android 4.4 та нижче + Встановлювач для фонових встановлень + Потрібно, щоб Aurora Services було встановлено як привілейований системний застосунок + Повнофункціональний менеджер пакунків з відкритим кодом + Потрібен App Manager, потрібен режим adb/root для встановлення при ввімкненій оптимізації miui + Введіть код версії, яку потрібно завантажити + Є питання? Знайдіть відповіді + Дізнайтеся, що всередині + Підзвітність і відповідальність + Вихідний код Політика приватності - Дізнатися, як Aurora Store використовує ваші дані + Дізнайтеся, як Aurora Store використовує ваші дані Докладніше Керувати обліковим записом Видалити власника пристрою - Вилучає Aurora Store зі списку власників пристроїв - Ця дія відкличе дозвіл установлювача Android на встановлення застосунків у фоні. Впевнені, що хочете продовжити? + Видаляє застосунок Aurora Store зі списку власників пристроїв + Ця дія відкличе дозвіл встановлювача на встановлення застосунків у фоні. Впевнені, що хочете продовжити? Додати розподільник - Керувати розподільниками - Перегляд і керування розподільниками токенів для знеособленого входу + Керування розподільниками + Перегляд розподільників токенів для анонімного входу та керування ними Немає доступних розподільників - Вилучити розподільник? - Додайте розподільник токенів до Aurora Store. Розподільники токенів надають облікові дані Aurora Store для знеособленого входу. - URL-адреса розподільника - Недійсна URL-адреса - Вилучити розподільник \"%1$s\"? + Видалити розподільник + Додайте розподільник токенів до Aurora Store. Розподільники токенів надають облікові дані Aurora Store для анонімного входу. + URL розподільника + Недійсний URL + Видалити розподільник \"%1$s\"? Додати - Вилучити + Видалити Вікі - Знайти відповіді на поширені запитання (F.A.Q.), кроки для усунення несправностей та багато іншого + Знайти відповіді на поширені запитання (F.A.Q.), кроки з усунення несправностей та багато іншого Про Aurora Store Дізнатися більше про Aurora Store Увійдіть у свій обліковий запис Google Play - Aurora Store дає змогу шукати та завантажувати застосунки з офіційного Google Play Маркету. Ви можете переглядати описи застосунків, знімки екрана, оновлення, коментарі інших користувачів, а також завантажувати APK безпосередньо з Google Play на свій пристрій. Щоби користуватися Aurora Store, вам потрібно мати обліковий запис Google Play та ввійти до нього під час першого відкриття та налаштування Aurora Store.\n\nНа відміну від традиційних крамниць застосунків, Aurora Store не володіє, не ліцензує та не розповсюджує застосунки. Усі застосунки, їхні описи, знімки екрана та інший зміст в Aurora Store безпосередньо отримуються, завантажуються та/або показуються з Google Play. Aurora Store працює як двері або браузер, дозволяючи вам увійти до свого облікового запису Google Play та знаходити застосунки з Google Play.\n\nЗауважте, що Aurora Store не має жодного схвалення, спонсорства чи дозволу від Google, Google Play, будь-яких застосунків, завантажених через Aurora Store або будь-яких розробників застосунків; Aurora Store також не має з ними жодного зв\'язку, співпраці чи відносин. + Aurora Store дає змогу шукати та завантажувати застосунки з офіційної крамниці Google Play. Ви можете переглядати описи застосунків, знімки екрана, оновлення, коментарі інших користувачів і завантажувати APK безпосередньо з Google Play на свій пристрій. Щоб використовувати Aurora Store, вам потрібно мати обліковий запис Google Play та увійти до нього, коли ви вперше відкриваєте та налаштовуєте Aurora Store. +\n +\nНа відміну від традиційного магазину застосунків, Aurora Store не володіє, не ліцензує та не розповсюджує жодні застосунки. Усі вони, їхні описи, знімки екрана та інший вміст в Aurora Store доступні, завантажуються та/або показуються безпосередньо з Google Play. Aurora Store працює як двері або браузер, дозволяючи вам увійти у свій обліковий запис Google Play і знайти застосунки з Google Play. +\n +\nЗауважте, що Aurora Store не має жодного схвалення, спонсорства чи авторизації від Google, Google Play, будь-яких застосунків, завантажених через Aurora Store, або будь-яких розробників програм; також Aurora Store не має жодного зв’язку, співпраці чи зв’язку з ними. Застосунок недоступний для вашого пристрою Улюблене - Улюблені застосунки не знайдено - Не вдалось імпортувати улюблене! - Не вдалось експортувати улюблене! - Улюблені імпортовано! - Улюблені експортовано! - Набір застосунків успішно експортовано - Не вдалось експортувати набір застосунків + Не знайдено улюблених застосунків + Помилка імпортування улюбленого! + Помилка експортування улюбленого! + «Улюблені» імпортовано! + «Улюблені» експортовано! + Набір застосунків успішно еспортовано + Не вдалося експортувати набір застосунків Улюблені застосунки Успішно видалено Хочете вийти з облікового запису? - Уведіть дійсну URL-адресу проксі-сервера, щоби передавати всі дані через нього. + Введіть дійсну URL-адресу проксі-сервера, щоби передавати всі дані через нього. Вийти з облікового запису? Перевірити оновлення - Дозволити встановлювати застосунки з невідомих джерел + Дозволяє встановлювати застосунки з невідомих джерел Безпека даних - Заявлені розробником практики приватності та безпеки даних - Спочатку потрібно надати дозвіл установлювачу - Необхідно - Необов\'язково + Задекларовані розробником практики приватності та безпеки даних + Спочатку вам потрібно надати дозвіл на встановлення + Можливо, вам доведеться повторно надати дозвіл через помилку в Storage Access Framework + Необхідний + Необов\'язковий Перезапустити Aurora Store - Aurora Store потребує перезапуску, щоб застосувати змінені налаштування - Експортер файлів - Зачекайте, експортування файлу + Aurora Store потрібно перезапустити, щоб застосувати змінені налаштування + File Exporter + Зачекайте, експортуємо файл Сповіщення про завантаження Сповіщення про встановлення Сповіщення про експорт застосунку @@ -381,96 +392,39 @@ Завершено Очікування Недоступно - Завантаження + Завантажується Скасовано - Сповіщення облікового запису + Сповіщення, пов\'язані з обліковим записом Потрібна автентифікація Увійдіть до свого облікового запису Google Play, щоб розархівувати застосунок! Перевірка оновлень Зроблено з %1$s в Індії Типово Доступно - Вилучити все - Останні - Не вдалось імпортувати чорний список! - Не вдалось експортувати чорний список! + Можливо, вам доведеться перезапустити застосунок, щоб показати наданий дозвіл. + Видалити все + Останнє + Не вдалося імпортувати чорний список! + Не вдалося експортувати чорний список! Чорний список експортовано! - Обрати все + Вибрати все Чорний список імпортовано! Перевірка Розархівувати Не вдалося відкрити застосунок - Потребує сервіси Google Play + Потрібні сервіси Google Play З проєктом microG - Сумісний: працює без проблем + Сумісність: працює без проблем Без сервісів Google Play - На основі Plexus + Працює від Plexus Сумісність - Можливо, вам знадобиться встановити власницьку бібліотеку Google або вільну реалізацію, таку як microG. + Можливо, вам знадобиться встановити власну бібліотеку Google або повторну реалізацію FOSS, наприклад microG. Працює без сервісів Google Play - Цей застосунок працює без власницької бібліотеки Google. Однак, для належної роботи можуть знадобитися сторонні бібліотеки. + Цей застосунок працює без власної бібліотеки Google. Однак для належної роботи можуть знадобитися сторонні бібліотеки. Перевірка сумісності… Обмежений: працює з обмеженими можливостями Не підтримується: не працює Невідомо: ще не перевірено Установлено %1$d застосунків Немає доступних застосунків - Використовуйте microG для входу в облікові записи - Автентифікуйте за допомогою microG під час входу в облікові записи Google для спрощення процесу входу - Змінити - Вимкнути - Обмеження автоматичного оновлення - Налаштування обмежень пристроїв для автоматичних оновлень - Лише в безлімітних мережах - Коли пристрій неактивний - Проксі успішно вимкнено - Перегляд та керування налаштуваннями проксі - Коли акумулятор не розряджений - Не вдалося перевірити завантажені файли - Розширені - Джерело застосунку - Останнє оновлення - Мінімальна версія Android - Цільовий рівень API - Завантаження - %1$d дозволи - Встановлення пакета microG - Сумісність програм - Відсутні залежності - Я прочитав(-ла) та погоджуюся з Умовами надання послуг та Політикою конфіденційності microG - Нам не вдалося знайти Сервіси Google Play на вашому пристрої. Тепер кілька популярних програм потребують їх для належної роботи! - microG — це безкоштовна реалізація з відкритим кодом, яка забезпечує аналогічну функціональність для запуску програм, що залежать від Сервісів Google Play для пристроїв Android, шляхом повторної реалізації.\n\nmicroG дозволяє програмам отримувати доступ до цих API Google, покращуючи сумісність для користувачів, а також пропонуючи переваги конфіденційності.\n\nmicroG автоматично запускатиметься у фоновому режимі, коли ви відкриваєте програми, що залежать від Сервісів Google Mobile. - Ознайомитися з Політикою приватності microG - Прочитати ліцензію та угоду microG - Відвідати вебсайт проєкту microG - Дані, які може збирати цей додаток - Розробник стверджує, що цей додаток не збирає дані користувачів. - Дані, які може ділитися ця програма - Розробник стверджує, що цей додаток не передає дані користувачів іншим компаніям чи організаціям. - Ця версія програми може містити більше трекерів, яких ще немає в базі даних Exodus Privacy. - %1$d відомих трекерів знайдено в %2$s - Опис недоступний - Більше інформації - Цілі - Назва пакета - Рейтинг контенту - Виберіть додаток для отримання додаткової інформації - Без реклами - Немає ігрових сервісів - Код версії може містити лише цифри - Підготовка до встановлення - - Потрібен дозвіл - Потрібні дозволи - Потрібні дозволи - Потрібні дозволи - - Встановлювач MicroG не зміг встановити застосунок, ймовірно, через неправильну конфігурацію. - Встановлювач MicroG - Необхідно встановити супутній застосунок microG - Допомагає обійти перевірку цілісності застосунків (тільки встановлювач) - Триває завантаження - Сторінка %1$d - Пропустити - Перезапустити, щоб застосувати зміни? diff --git a/app/src/main/res/values-ur/strings.xml b/app/src/main/res/values-ur/strings.xml deleted file mode 100644 index b66b8b698..000000000 --- a/app/src/main/res/values-ur/strings.xml +++ /dev/null @@ -1,430 +0,0 @@ - - - وکی - اکثر پوچھے گئے سوالات (F.A.Q.) کے جوابات تلاش کریں، ٹربل شوٹنگ کے اقدامات اور مزید بہت کچھ - بھیم - یو پی آئی - UPI کے ذریعے عطیہ کریں - بٹ کوائن کیش - بٹ کوائن کیش (BCH) کے ذریعے عطیہ کریں - بٹ کوائن - بٹ کوائن (BTC) کے ذریعے عطیہ کریں - ایتھریم - ایتھرئم (ای ٹی ایچ) کے ذریعے عطیہ کریں - ایف ڈروڈ - ایف ڈروڈ کے ذریعے ارورہ اسٹور حاصل کریں۔ - بات چیت یا تجاویز کے لئے ارورہ اسٹور XDA تھریڈ دیکھیں۔ - گمنام - گوگل - سب - درخواست دیں - انسٹال کرنا - شامل ہوں - بعد میں - بیٹا پروگرام میں شامل ہوں؟ - عوام کے کام کرنے سے پہلے آپ کو نئی خصوصیات اور کیڑے نظر آئیں گے۔ ڈویلپرز کو اپنی رائے دیں تاکہ ان کی بہتری میں مدد ملے۔ - چینلگ فراہم نہیں کیا گیا - پتہ - ای میل - %1$d h %2$d m %3$d s بائیں - %1$d m %2$d s بائیں - ڈاؤن لوڈ نہیں - متضاد ایپ - دستبرداری - ارورہ اسٹور کو پس منظر میں ایپس کو ڈاؤن لوڈ اور اپ ڈیٹ کرنے کی اجازت دیں - صرف اورورا اسٹور ایپس - صرف ارورہ اسٹور کے ذریعہ نصب ایپس کے لئے اپ ڈیٹس چیک کریں - سب سے اوپر کی کمائی - سب سے زیادہ ادائیگی - ٹرینڈنگ - کے بارے میں - اکاؤنٹس - ایپس - ایپ انسٹالر - ایڈوانسڈ - دستی ڈاؤن لوڈ - گمنام اکاؤنٹس پر دستیاب نہیں - بلیک لسٹ - ایپس اور کھیلوں کی تلاش کریں - نئے سیشن کی درخواست کرنا - رازداری کی رپورٹ لانے میں ناکام - رسائی سے انکار! کیا آپ وی پی این یا ٹور استعمال کر رہے ہیں؟ - ڈیفالٹ ٹیب منتخب کریں - ایپ لنکس - ارورہ اسٹور کو معاون لنکس کھولنے کی اجازت دیں - پس منظر کی تنصیبات کے لئے انسٹالر - ورژن کوڈ درج کریں جس کی آپ ڈاؤن لوڈ کرنا چاہتے ہیں - سوالات ہیں؟ جوابات تلاش کریں - ارورہ اسٹور کے بارے میں مزید معلومات حاصل کریں - کامیابی کے ساتھ ان انسٹال - گمنام لاگ ان کیلئے ٹوکن ڈسپینسروں کو دیکھیں اور ان کا نظم کریں - کوئی ڈسپینسر دستیاب نہیں ہے - پسندیدہ برآمد! - بلیک لسٹ درآمد کرنے میں ناکام! - براہ کرم ایپ کو غیر سنجیدہ کرنے کے لئے اپنے گوگل پلے اکاؤنٹ میں لاگ ان کریں! - پہلے سے طے شدہ - دستیاب ہے - یہ ایپ گوگل کی ملکیتی لائبریری کے بغیر کام کرتی ہے۔ تاہم ، اس کے باوجود بھی تیسری پارٹی کے دیگر لائبریریوں کو مناسب طریقے سے کام کرنے کی ضرورت ہوسکتی ہے۔ - مائکروگ پروجیکٹ کے ساتھ - غیر تعاون یافتہ: فعال نہیں - خودکار تازہ کاریوں کی پابندیاں - گٹ لیب - لبرپے - لبرپے پر سرپرست بنیں - پے پال - پے پال کے توسط سے عطیہ کریں - ٹیلیگرام - مباحثوں یا تجاویز کے لئے ارورہ سپورٹ گروپ میں شامل ہوں۔ - ایکس ڈی اے فورمز - استعمال میں لاگ ان کریں - ارورہ سے لاگ آؤٹ کریں - پیچھے - گٹ لیب پر Aurora OSS سے Aurora Store سورس کوڈ حاصل کریں۔ - منسوخ کریں - بلیکلسٹ میں شامل کریں - صاف - بند کرو - کاپی - کاپی لنک - غیر فعال - برآمد - درآمد - پسندیدہ - فلٹرز - اشتہارات کے ساتھ ایپس - ڈاؤن لوڈ - جی ایس ایف انحصار - متفرق - ادا - درجہ بندی - ختم - ایپ بنڈل کو بچائیں - گرانٹ - عطا - نظرانداز کریں - انسٹال کریں - تنصیبات - چھوڑ دو - لاگ آؤٹ - اگلا - نئے تجزیہ کی درخواست کریں - ٹھیک ہے - کھلا - زیر التوا - پوسٹ - سب کو ہٹا دیں - دوبارہ شروع کریں - دوبارہ شروع - تلاش - سب کو منتخب کریں - شیئر کریں - ان انسٹال - ہوم اسکرین میں شامل کریں - ایپ کی معلومات - تازہ کاری - سب کو اپ ڈیٹ کریں - وائٹ لسٹ - بیٹا پروگرام - آپ بیٹا ٹیسٹر ہیں - اندراج میں کچھ وقت لگ سکتا ہے ، آپ بعد میں حیثیت چیک کرسکتے ہیں۔ - چینلگ - اشتہارات پر مشتمل ہے - انحصار - تفصیل - ڈویلپر سے رابطہ - ڈویلپر پروفائل - ویب سائٹ - مفت - جی ایس ایف کی ضرورت ہے - ایپ کے بارے میں مزید - کوئی اشتہار نہیں - کوئی ایپ میچ نہیں ملا - کوئی پسندیدہ ایپس نہیں ملی - کوئی انحصار نہیں - کوئی اجازت نہیں - کوئی تازہ کاری دستیاب نہیں ہے - ادا - اجازت - ڈیٹا سیفٹی - رازداری - ڈیٹا کی رازداری اور سیکیورٹی کے طریقوں کو ڈویلپر کے ذریعہ اعلان کیا گیا ہے - درجہ بندی اور جائزے - جائزہ عنوان - آپ اس ایپ کے بارے میں کیا سوچتے ہیں؟ - سب منسوخ کریں - ڈاؤن لوڈ مکمل - حساب کتاب - منسوخ - صاف ختم - %1$d s بائیں - ڈاؤن لوڈ ناکام - سب کو صاف کریں - میٹا ڈیٹا حاصل کرنا - سب کو روکیں - سب کو دوبارہ شروع کریں - %1$d %2$dرک گیا • / - %1$d %2$d %3$sڈاؤن لوڈ کرنا • / • - قطار - تخمینہ لگانا - کوئی معلوم ٹریکر نہیں ہے - خروج کی رازداری کے ذریعہ تقویت یافتہ - ٹریکروں کی جانچ پڑتال… - سب - تازہ ترین - معلوم ٹریکر (زبانیں) میں پائے گئے - رپورٹ دیکھیں - تنقیدی - پانچ - چار - ایک - مثبت - تین - شیزوکو انسٹال نہیں ہے یا مناسب طریقے سے ترتیب نہیں ہے۔ - دو - ایپ مینیجر انسٹال کریں یا انسٹالر کو تبدیل کریں۔ - کوئی جڑ تک رسائی نہیں ہے۔ اسے دیں یا انسٹالر کو تبدیل کریں۔ - ارورہ خدمات دستیاب ہیں اور انسٹال کرنے کے لئے تیار ہیں۔ - ارورہ خدمات مرتب کریں اور پہلے تمام اجازتیں دیں۔ - ارورہ سروسز 1.0.9 یا اس سے اوپر انسٹال کریں ، یا انسٹالر کو تبدیل کریں۔ - انسٹالر ناکام ہوگیا - تنصیب کو مسدود کردیا گیا تھا - سیشن نہیں بناسکا - متضاد پیکیج موجود ہے - غلط یا خراب APK - ناکافی میموری کی جگہ - آپ آبائی انسٹالر کے ذریعہ بنڈل (اسپلٹ) ایپس انسٹال نہیں کرسکتے ہیں۔ اپنے انسٹالر کو سیشن ، خدمات یا جڑ میں تبدیل کریں۔ - صارف کی تصدیق کا انتظار - لائسنس - خدمت کی شرائط - میوئی کا پتہ چلا! - سیشن انسٹالر MIUI کی اصلاح کی وجہ سے ایپس انسٹال نہیں کرسکتا ہے۔ - براہ کرم ، تنصیبات کی اجازت دینے کے لئے MIUI کی اصلاح کو غیر فعال کریں ، بصورت دیگر آپ روٹ یا سروسز انسٹالر کا انتخاب کرسکتے ہیں۔ - اختیاری طور پر آپ مقامی انسٹالر کا انتخاب کرسکتے ہیں ، لیکن پھر آپ بنڈل (اسپلٹ) اے پی کے انسٹال نہیں کرسکتے ہیں ، لہذا انتخاب آپ کا ہے۔ - نئی تازہ کاری دستیاب ہے - اکاؤنٹ سے متعلق اطلاع - ایپ ایکسپورٹ نوٹیفکیشن - نوٹیفکیشن انسٹال کریں - ڈاؤن لوڈ کی اطلاع - ارورہ اسٹور کو مندرجہ ذیل اجازتوں کی ضرورت ہے - انسٹالر - خوش آمدید - تم کیسے کر رہے ہو؟ - بیرونی اسٹوریج تک رسائی - بڑے ایپس اور کھیلوں کے لئے اے پی کے توسیع فائلوں (OBBs) کو بچانے کے لئے۔ - بیرونی اسٹوریج منیجر - انسٹالر کی اجازت - ارورہ اسٹور سے ایپس کو انسٹال کرنے کی اجازت دیں - پس منظر ڈاؤن لوڈ - نامعلوم ذرائع سے ایپس کی تنصیب کی اجازت دیں - اطلاعات - تنصیبات کی حیثیت سے متعلق اطلاعات بھیجیں - ایکسٹرا - ایف ڈروڈ سے ڈاؤن لوڈ یا انسٹال کردہ ایپس کے لئے اپ ڈیٹس چیک نہ کریں - فلٹر ایف ڈروڈ ایپس - ڈاؤن لوڈ کردہ APKs انسٹالیشن کے فورا. بعد حذف کردیئے جائیں گے - APK پوسٹ انسٹال کو حذف کریں - AM انسٹالر - شیزوکو انسٹالر - آبائی انسٹالر (فرسودہ) - روٹ انسٹالر - ارورہ سروسز (فرسودہ) - سیشن انسٹالر - اے پی کے کی تنصیب کا موڈ منتخب کریں - تنصیب کا طریقہ - گوگل پلے ورژن - ڈیفالٹ (ڈیوائس کنفیگ سے) - نیٹ ورکنگ - پراکسی یو آر ایل - پراکسی کے ذریعے تمام ڈیٹا کو منتقل کرنے کے لئے ایک درست پراکسی یو آر ایل درج کریں۔ - تخصیص - آپ کے صفحات کے لئے - ہوم اسکرین پر آپ کے صفحات کے لئے ڈسپلے کریں - اسی طرح اور متعلقہ ایپس - متضاد تازہ ترین معلومات - ڈاؤن لوڈ ناکام - مطابقت پذیر یا غیر فعال ایپس کے لئے تازہ ترین معلومات دکھائیں جو انسٹال کرنے میں ناکام ہوسکتی ہیں - ایپ نہیں خریدی - ایپ کی حمایت نہیں کی گئی - ایپ نہیں ملی - فائلیں نہیں مل سکی - سیشن کی میعاد ختم ہوگئی ، نیا سیشن حاصل کرنے کے لئے دوبارہ لاگن۔ - لاگ ان کریں اور لطف اٹھائیں۔ - واہ! سب اچھا ہے۔ - چیزوں کو تیار کرنا… - براہ کرم اپنے گوگل پلے اکاؤنٹ میں لاگ ان کریں - گوگل کے ذریعے لاگ ان نہیں ہوسکا - آخری سیشن ختم ہوگیا - تصدیق کرنے والا سیشن - گوگل سیشن کی تصدیق کرنا - اس بات کو یقینی بنائیں کہ آپ کو دھوکہ دہی کا اطلاق کرنے کے لئے دوبارہ لاگ ان کریں - اس بات کو یقینی بنائیں کہ آپ تبدیلیوں کو لاگو کرنے کے لئے اپلی کیشن کو دوبارہ شروع کریں اور دوبارہ شروع کریں۔ - زمرے - ایڈیٹر کا انتخاب - آپ کے لئے - ٹاپ چارٹ - ٹاپ فری - ایپ کی ترتیبات - میرے ایپس اور گیمز - لائبریری میں ایپس - بلیک لسٹ منیجر - پسندیدہ ایپس - ڈیوائس - ڈاؤن لوڈ - پلے اسٹور - کھیل - تنصیب - انسٹال - زبان - لائبریری - کوئی نیٹ ورک نہیں - تاریخ خریدیں - ترتیبات - سپوف منیجر - تلاش کی تجویز - وائٹ لسٹڈ - تلاش کے نتائج - تازہ کارییں - ایپ آپ کے آلے کے لئے دستیاب نہیں ہے - کلپ بورڈ میں کاپی - ان کو کھولنے کے لئے ڈیوائس کی ترتیبات سے ڈویلپر کی ترتیبات کو آن کریں۔ - اجازت دی گئی - آپ کو پہلے انسٹالر کی اجازت دینے کی ضرورت ہے - ڈیوائس کی جعل سازی کا اطلاق ہوتا ہے۔ - ایپ کی خریداری گمنام اکاؤنٹس پر دستیاب نہیں ہے۔ - آپ جس ورژن کوڈ کی درخواست کر رہے ہیں وہ دستیاب نہیں ہے۔ - مبارکباد ، درخواست کردہ ورژن کوڈ دستیاب ہے ، ابھی ڈاؤن لوڈ کرنا۔ - صفحہ کو دستیاب نہیں ہے - درجہ بندی ، دکھانے میں کچھ وقت لگ سکتا ہے - درجہ بندی پیش نہیں کرسکا - آس ٹوکن پیدا نہیں کرسکا - ڈیوائس کنفیگ برآمد - ڈیوائس کنفیگ برآمد نہیں کرسکا - ڈیوائس کنفیگ درآمد شدہ - پراکسی کامیابی کے ساتھ سیٹ - آلہ کی تشکیل درآمد نہیں کرسکا - غلط پراکسی یو آر ایل ، فارمیٹ چیک کریں! - پراکسی سیٹ کرنے میں ناکام - پس منظر کی ایپ ڈاؤن لوڈ - پس منظر کی ایپ ڈاؤن لوڈ کو قابل بناتا ہے - تازہ کاری دستیاب ہے - تازہ ترین معلومات دستیاب ہیں - ایک خرابی واقع ہوئی! - مینو - توسیع - %1$s %2$s• API - ضروری ہے - اختیاری - مطلوبہ اجازتوں سے انکار کردیا گیا۔ براہ کرم کارروائی جاری رکھنے کے لئے انہیں دیں - بحالی کے لئے سرور نیچے - %1$sکے لئے اضافی فائلیں ڈاؤن لوڈ کرنا - نوٹیفیکیشن کو اپ ڈیٹ کریں - %1$dتازہ ترین معلومات دستیاب ہیں - %1$dتازہ کاری دستیاب ہے - %1$sکا ایک نیا ورژن دستیاب ہے - %1$s %2$sاور - %1$s %2$s %3$s، اور - %1$s %2$s %3$s %4$d، اور بہت کچھ - خودکار تازہ کارییں - خودکار اپ ڈیٹ کے طرز عمل کو تشکیل دیں - آٹو اپ ڈیٹ ایپس کو نہ کریں - دستیاب تازہ کاریوں کے لئے چیک اور مطلع کریں - دستیاب اپ ڈیٹس کو خود بخود چیک اور انسٹال کریں - خودکار اپ ڈیٹ فریکوینسی - گھنٹے میں ، خود کار طریقے سے تازہ کاریوں کے لئے وقت کے وقفے کو تشکیل دیں۔ - اندرونی غلطی! براہ کرم کچھ دیر بعد دوبارہ کوشش کریں - افوہ ، آپ کی شرح محدود ہے - سرور ناقابل رسائی - سیشن پیدا نہیں کرسکا - نئے سیشن کی تصدیق کرنا - انٹرنیٹ کنیکٹیویٹی چیک کریں - ایپ کی زبان - لے آؤٹ - گوگل پلے ، جسے گوگل پلے اسٹور اور سابقہ اینڈروئیڈ مارکیٹ کے نام سے بھی جانا جاتا ہے۔ - اینڈروئیڈ مارکیٹ ایک آن لائن اسٹور تھا جو سافٹ ویئر کی پیش کش کرتا تھا جو اینڈرائیڈ ڈیوائسز کے لئے ڈیزائن کیا گیا تھا ، جو 2017 میں ریٹائر ہوا تھا۔ - APKs برآمد کرنے میں ناکام - کوئی ایپس دستیاب نہیں ہے - بنڈل/اسپلٹ APKs کے لئے سیشن پر مبنی انسٹالر - تجویز کردہ ، ان بلٹ اور تمام Android ورژن کی حمایت کرتا ہے - روٹ اجازتوں کا استعمال کرتے ہوئے شیل پر مبنی انسٹالر - جڑ/سپر صارف مراعات کی ضرورت ہے ، تمام Android ورژن کی حمایت کرتا ہے۔ - ارادے پر مبنی انسٹالر ، تمام آلات پر دستیاب ہے - اینڈروئیڈ 4.4 کے نیچے چلنے والے آلات کے لئے بہترین موزوں - ارورہ خدمات کو مراعات یافتہ سسٹم ایپ کے طور پر انسٹال کرنے کی ضرورت ہے - مکمل خصوصیات والے اوپن سورس پیکیج مینیجر - ایپ مینیجر کی ضرورت ہے ، جب MIUI کی اصلاح جاری ہے تو انسٹال کرنے کے لئے ADB/روٹ موڈ کی ضرورت ہے - ADB/جڑ کے مراعات کے ساتھ براہ راست سسٹم APIs کا استعمال - شیزوکو یا سوئی کی ضرورت ہے ، سیٹ اپ اور اجازت دینے کی ضرورت ہے - ماخذ کوڈ - معلوم کریں کہ اندر کیا ہے - رازداری کی پالیسی - سیکھیں کہ ارورہ اسٹور آپ کے ڈیٹا کو کس طرح استعمال کرتا ہے - احتساب اور ذمہ داری - %1$sہندوستان میں بنایا گیا - ارورہ اسٹور کے بارے میں - آسان سائن ان فلو کے لیے گوگل اکاؤنٹس میں سائن ان کرتے وقت مائیکرو جی کا استعمال کرکے تصدیق کریں۔ - بلیکلسٹ - سیشن بنانے میں ناکام، ایرر کوڈ: %1$d - کامیابی سے انسٹال - اجازتیں - ڈسپینسروں کا انتظام کریں - ڈسپنسر شامل کریں - زیادہ - اپنے اکاؤنٹ کا نظم کریں - آلہ کا مالک صاف کریں - آلہ کے مالک ایپ کے طور پر ارورہ اسٹور کو ہٹا دیتا ہے - اس سے سیشن انسٹالر کی خاموشی سے ایپ انسٹال کرنے کی اجازت منسوخ ہوجائے گی۔ آلہ کی ملکیت کو صاف کرنے کے ساتھ آگے بڑھیں؟ - ارورہ اسٹور میں ٹوکن ڈسپنسر شامل کریں۔ ٹوکن ڈسپینسر گمنام میں لاگ ان کرنے کے لئے ارورہ اسٹور کو اکاؤنٹ کی اسناد فراہم کرتے ہیں۔ - غلط url - ڈسپنسر یو آر ایل - ڈسپنسر کو ہٹا دیں - %1$sکیا آپ ڈسپنسر کو ہٹانا چاہتے ہیں ؟ - شامل کریں - ہٹا دیں - پسندیدہ درآمد کرنے میں ناکام! - پسندیدہ برآمد کرنے میں ناکام! - پسندیدہ درآمد! - بلیک لسٹ برآمد کرنے میں ناکام! - بلیک لسٹ درآمد! - بلیک لسٹ برآمد! - فائل برآمد کنندہ - اپنی فائل برآمد کریں ، پکڑو - کامیابی کے ساتھ برآمد شدہ ایپ بنڈل - برآمد شدہ ایپ بنڈل میں ناکام - لاگ آؤٹ؟ - کیا آپ واقعی لاگ آؤٹ کرنا چاہتے ہیں؟ - تازہ کاریوں کے لئے چیک کریں - تازہ کاریوں کے لئے جانچ پڑتال - ارورہ اسٹور کو دوبارہ شروع کریں - نئی تبدیل شدہ ترتیبات کو لاگو کرنے کے لئے ارورہ اسٹور کو دوبارہ شروع کرنے کی ضرورت ہے - ڈاؤن لوڈ ، اتارنا - ناکام - منسوخ - مکمل - قطار میں - دستیاب نہیں - تصدیق کرنا - توثیق کی ضرورت ہے - غیر سنجیدہ - ایپ کھولنے سے قاصر ہے - Plexus کے ذریعہ طاقت - مطابقت کی جانچ پڑتال… - مطابقت - گوگل پلے سروسز کی ضرورت ہے - آپ کو گوگل کی ملکیتی لائبریری یا FOSS کی اصلاح جیسے مائکروگ کو انسٹال کرنے کی ضرورت پڑسکتی ہے۔ - گوگل پلے سروسز کے بغیر کام کرتا ہے - گوگل پلے سروسز کے بغیر - ہم آہنگ: بغیر کسی مسئلے کے کام کرتا ہے - محدود: محدود خصوصیات کے ساتھ کام کرتا ہے - نامعلوم: ابھی تک چیک نہیں کیا گیا - %1$dایپس انسٹال ہیں - اکاؤنٹس میں سائن ان کرنے کے لئے مائکروگ کا استعمال کریں - سیٹ - غیر فعال - پراکسی کامیابی کے ساتھ غیر فعال - پراکسی کنفیگریشن دیکھیں اور ان کا نظم کریں - خودکار تازہ کاریوں کے لئے آلہ کی پابندیوں کو تشکیل دیں۔ - صرف بے ہودہ نیٹ ورکس پر - جب آلہ بیکار ہے - جب بیٹری کم نہیں ہے - ڈاؤن لوڈ فائلوں کی تصدیق کرنے میں ناکام - ارورہ اسٹور آپ کو گوگل کے سرکاری پلے اسٹور سے ایپس کو تلاش کرنے اور ڈاؤن لوڈ کرنے کے قابل بناتا ہے۔ آپ ایپ کی تفصیل ، اسکرین شاٹس ، اپ ڈیٹ ، دوسرے صارفین کے تبصرے چیک کرسکتے ہیں ، اور APK کو گوگل پلے سے براہ راست اپنے آلے پر ڈاؤن لوڈ کرسکتے ہیں۔ ارورہ اسٹور کو استعمال کرنے کے ل you ، آپ کو گوگل پلے اکاؤنٹ رکھنے کی ضرورت ہے ، اور جب آپ پہلی بار ارورہ اسٹور کو کھولتے اور تشکیل دیتے ہیں تو اپنے گوگل پلے اکاؤنٹ میں لاگ ان ہوجاتے ہیں۔ \n \n روایتی ایپ اسٹور کے برعکس ، ارورہ اسٹور کسی بھی ایپس کا مالک ، لائسنس یا تقسیم نہیں کرتا ہے۔ ارورہ اسٹور میں تمام ایپس ، ایپ کی تفصیل ، اسکرین شاٹس اور دیگر مواد کو براہ راست رسائی ، ڈاؤن لوڈ اور/یا گوگل پلے سے ظاہر کیا جاتا ہے۔ ارورہ اسٹور بالکل دروازے یا براؤزر کی طرح کام کرتا ہے ، جس سے آپ اپنے گوگل پلے اکاؤنٹ میں لاگ ان ہوسکتے ہیں اور گوگل پلے سے ایپس تلاش کرسکتے ہیں۔ \n \n براہ کرم نوٹ کریں کہ ارورہ اسٹور کے پاس گوگل، گوگل پلے ، کسی بھی ایپس کو اورورا اسٹور یا کسی بھی ایپ ڈویلپرز کے ذریعہ ڈاؤن لوڈ کردہ کوئی بھی ایپس کی منظوری ، کفالت یا اجازت نہیں ہے۔ نہ ہی ارورہ اسٹور میں ان کے ساتھ کوئی وابستگی ، تعاون یا رابطہ ہے۔ - diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 734df630c..d82ae4243 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -55,7 +55,7 @@ Đóng Xoá Huỷ bỏ - Thêm vô danh sách đen + Thêm vào Danh sách đen Danh sách đen Trở về Đăng xuất khỏi Aurora @@ -94,7 +94,7 @@ Đã vào danh sách trắng Đã vào danh dách đen Không khả dụng trên tài khoản ẩn danh - Cập nhật + Bản cập nhật Trình quản lý giả mạo Thiết đặt Lịch sử giao dịch @@ -109,6 +109,7 @@ Tải xuống Thiết bị Trình quản lý danh sách đen + Ứng dụng giảm giá Ứng dụng trong thư viện Ứng dụng & trò chơi của tôi Ứng dụng @@ -141,7 +142,7 @@ Xóa APK sau khi cài đặt APK đã tải xuống sẽ bị xóa ngay sau khi cài đặt Lọc ứng dụng F-Droid - Không kiểm tra bản cập nhật cho các ứng dụng được cài đặt từ F-Droid + Không kiểm tra cập nhật cho các ứng dụng được tải xuống hoặc cài đặt từ F-Droid Cho phép cài đặt các ứng dụng từ Aurora Store Quyền của trình cài đặt Trình quản lý bộ nhớ ngoài @@ -190,12 +191,12 @@ Tạm dừng tất cả Không có tải xuống Đang lấy metadata - Buộc dọn dẹp tất cả + Buộc làm sạch tất cả Tải xuống thất bại Đang tính toán Tải xuống hoàn tất Đã huỷ - Hủy hết + Huỷ bỏ tất cả Bạn nghĩ thế nào về ứng dụng này\? Đánh giá và nhận xét Riêng tư @@ -218,6 +219,7 @@ Chúc mừng, mã phiên bản được yêu cầu đang có sẵn, đang tải xuống ngay bây giờ. Mã phiên bản bạn đang yêu cầu không có sẵn. Tải xuống thủ công + Hiển thị các cụm tương tự và liên quan trên trang chi tiết ứng dụng Các ứng dụng tương tự và liên quan Hiển thị trang Cho bạn trên màn hình chính Trang Cho Bạn @@ -264,8 +266,8 @@ có cập nhật Có lỗi xảy ra! Menu - %1$d cập nhật - %1$d cập nhật + %1$d có bản cập nhật + %1$d có bản cập nhật Có phiên bản mới cho %1$s Gợi ý tìm kiếm Kết quả tìm kiếm @@ -282,8 +284,11 @@ Cho phép Aurora Store mở các liên kết được hỗ trợ Tự động kiểm tra & cài đặt các bản cập nhật có sẵn Không xuất được APK + Nhà cung cấp - bestappsale.com Cho phép Aurora Store tải xuống và cập nhật ứng dụng trong nền Mặc định (từ cấu hình thiết bị) + Bật proxy + Cho phép tất cả lưu lượng truy cập từ ứng dụng đi qua proxy Thiết đặt ứng dụng URL proxy không hợp lệ, hãy kiểm tra định dạng! Kiểm tra kết nối internet @@ -304,10 +309,11 @@ Cập nhật không tương thích Hiển thị các bản cập nhật cho các ứng dụng không tương thích hoặc bị vô hiệu hóa có thể không cài đặt được Thêm vào màn hình chính - Dọn tệp đã cài + Xóa xong Tiêu đề đánh giá Tải xuống trong nền URL proxy + Proxy Trình cài đặt để cài đặt nền Trình quản lý gói nguồn mở đầy đủ tính năng Yêu cầu cài đặt Dịch vụ Aurora dưới dạng ứng dụng hệ thống đặc quyền @@ -358,8 +364,9 @@ Dữ liệu yêu thích đã được nhập vào! Yêu thích An toàn của dữ liệu - Những ứng dụng yêu thích + Những app yêu thích Trước tiên, bạn cần cấp quyền cho phép “Cài đặt ứng dụng\" + Bạn chắc phải cần cấp lại quyền cho phép bởi vì lỗi trong \"Khung truy cập lưu trữ\" Bắt buộc Không bắt buộc Quyền riêng tư của dữ liệu và những thực hành bảo mật được tuyên bố bởi nhà phát triển @@ -370,7 +377,11 @@ Đã xoá hoàn công Không có app yêu thích Quản lý bộ phân phối - Aurora Store cho phép bạn tìm kiếm và tải về những ứng dụng bạn thích từ chính Cửa hàng Google Play. Bạn có thể kiểm tra mô tả ứng dụng, những ảnh chụp ứng dụng, những cập nhật ứng dụng, những đánh giá từ những người khác, và tải về APK của ứng dụng từ Google Play vào máy của bạn. Để dùng Aurora Store, bạn cần có một tài khoản Google Play, và đăng nhập vào tài khoản Google Play của bạn khi bạn đã vào và chỉnh cài đặt của Aurora Store lần đầu tiên. \n \nKhông giống như một cửa hàng ứng dụng bình thường, Aurora Store không có sở hữu, cấp phép li-xăng hay phát ra ứng dụng nào hết. Tất cả các ứng dụng, mô tả ứng dụng và những nội dung ứng dụng khác trong Aurora Store đều được trực tiếp truy cập, tải về, và/hay hiển thị từ Google Play. Aurora Store hoạt động như một cái cửa hay là một trình duyệt, cho phép bạn để đăng nhập vào tài khoản Google Play của bạn và tìm những ứng dụng từ Google Play. \n \nXin lưu ý rằng Aurora Store không có quyền cho phép, tiền tài trợ, hay quyền phép từ Google, Google Play, những ứng dụng tải qua Aurora Store, hay bất cứ nhà phát triển nào; Aurora Store cũng không có liên kết nào, hợp tác hay kết nồi nào với họ. + Aurora Store cho phép bạn tìm kiếm và tải về những ứng dụng bạn thích từ chính Cửa hàng Google Play. Bạn có thể kiểm tra mô tả ứng dụng, những ảnh chụp ứng dụng, những cập nhật ứng dụng, những đánh giá từ những người khác, và tải về APK của ứng dụng từ Google Play vào máy của bạn. Để dùng Aurora Store, bạn cần có một tài khoản Google Play, và đăng nhập vào tài khoản Google Play của bạn khi bạn đã vào và chỉnh cài đặt của Aurora Store lần đầu tiên. +\n +\nKhông giống như một cửa hàng ứng dụng bình thường, Aurora Store không có sở hữu, cấp phép li-xăng hay phát ra ứng dụng nào hết. Tất cả các ứng dụng, mô tả ứng dụng và những nội dung ứng dụng khác trong Aurora Store đều được trực tiếp truy cập, tải về, và/hay hiển thị từ Google Play. Aurora Store hoạt động như một cái cửa hay là một trình duyệt, cho phép bạn để đăng nhập vào tài khoản Google Play của bạn và tìm những ứng dụng từ Google Play. +\n +\nXin lưu ý rằng Aurora Store không có quyền cho phép, tiền tài trợ, hay quyền phép từ Google, Google Play, những ứng dụng tải qua Aurora Store, hay bất cứ nhà phát triển nào; Aurora Store cũng không có liên kết nào, hợp tác hay kết nồi nào với họ. Dữ liệu yêu thích đã được xuất ra! Đăng xuất? Bạn có chắc muốn đăng xuất hay không? @@ -391,6 +402,7 @@ Chọn tất cả Xóa tất cả Mới nhất + Bạn có thể phải khởi động lại ứng dụng để phản ánh việc cấp quyền. Lỗi khi xuất Danh sách đen! Danh sách đen đã được nhập! Lỗi khi nhập Danh sách đen! @@ -399,30 +411,4 @@ Đang xác thực Dừng lưu trữ Có sẵn - Không có ứng dụng nào - Không thể mở được app - Được hỗ trợ bởi Plexus - Đang kiểm tra tính tương thích… - Tương Thích - Yêu cầu Dịch vụ Google Play - Bạn có thể cần phải cài đặt thư viện độc quyền của Google hoặc bản triển khai lại FOSS như microG. - Hoạt động không cần dịch vụ Google Play - Dữ liệu mà ứng dụng này có thể thu thập - Nhà phát triển cho biết ứng dụng này không thu thập dữ liệu người dùng. - Dữ liệu mà ứng dụng này có thể chia sẻ - Nhà phát triển cho biết ứng dụng này không chia sẻ dữ liệu người dùng với các công ty hoặc tổ chức khác. - Tải xuống - Cập nhật mới nhất - Tương thích ứng dụng - Tôi đã đọc và đồng ý với Điều khoản dịch vụ và Chính sách bảo mật của microG - Chúng tôi không tìm thấy Dịch vụ Google Play trên thiết bị của bạn, một số ứng dụng phổ biến hiện nay yêu cầu dịch vụ này để hoạt động bình thường! - Đọc Chính sách bảo mật của microG - Đọc Giấy phép và Thỏa thuận microG - Thông tin thêm - Mục tiêu - Xếp hạng nội dung - Chuẩn bị cài đặt - - Cần có sự cho phép - diff --git a/app/src/main/res/values-yue/strings.xml b/app/src/main/res/values-yue/strings.xml index b32133ea9..a4d6019d8 100644 --- a/app/src/main/res/values-yue/strings.xml +++ b/app/src/main/res/values-yue/strings.xml @@ -201,14 +201,18 @@ 個 App 用咩文 %1$d 個更新出咗喇 其他 + 啟用代理伺服器 評論標題 代理伺服器 URL + 代理伺服器 自訂 代理伺服器 URL 無效,請睇過個格式! 代理伺服器設定成功 對上一個工作階段已經報銷 App 設定 + 提供:bestappsales.com 設定唔到代理伺服器 + 等個 app 所有網絡通訊都流經代理伺服器 安裝方法 下載嘅 APK 一安裝完就即刻剷走 安裝之後剷走 APK diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 4d5989729..58e455572 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -1,6 +1,6 @@ - Aurora 服务已可用并准备好安装。 + Aurora 服务已可用并准备安装。 无 Root 权限。授予 Root 权限或更改安装程序。 2★ 3★ @@ -97,7 +97,7 @@ 通过 PayPal 捐款 在 Liberapay 成为捐款者 Liberapay - 在 GitLab 上的Aurora OSS获取 Aurora Store 源代码 + 在 GitLab 上的 Aurora OSS 获取 Aurora Store 源代码。 GitLab 在 F-Droid 获取 Aurora Store。 F-Droid @@ -124,7 +124,7 @@ 正在安装 等待中 你好吗? - 应用购买在匿名账户上不可用。 + 应用购买在匿名帐号上不可用。 已应用设备伪装。 已授予权限 从设备设置开启开发者设置来打开它们。 @@ -147,6 +147,7 @@ 下载 设备 黑名单管理 + 促销应用 库内应用 我的应用和游戏 应用 @@ -177,9 +178,9 @@ 安装后删除 APK 安装后将立即删除所下载的 APK 文件 过滤 F-Droid 应用 - 不检查从 F-Droid 安装的应用的更新 + 不检查从 F-Droid 下载或安装的应用的更新 允许 Aurora 商店安装应用 - 安装器权限 + 安装权限 外部存储管理器 为了保存大型应用和游戏的 APK 扩展文件(OBBs)。 访问外部存储 @@ -208,6 +209,7 @@ 安装 Aurora 服务 1.09 或以上版本,或更改安装程序。 确保你重新登录并重新启动应用程序以应用更改。 网络 + 在应用程序详细信息页面上显示相似和相关的集群 相似及相关应用 在主页展示 For You 页面 For You 页面 @@ -272,32 +274,36 @@ 获取隐私报告失败 访问被拒!你在使用 VPN 或 Tor 吗? 内部错误!请在将来某个时刻重试 - 你被限制速率了 + 啊偶,你被限制速率了 服务器不可达 未能生成会话,错误码:%1$d 检查互联网连接 语言 无法生成会话 正在验证新会话 - 链接 + 应用链接 允许 Aurora 商店打开受支持的链接 Google Play,也称 Google Play 商店,之前叫 Android Market。 Android Market 是一个提供为 Android 设备设计的软件应用程序的在线商店,于 2017 年退役。 评价标题 - 配置小时为单位的自动间隔。 - 筛选其他来源的应用 - 不检查从 Aurora 商店以外来源安装的应用的更新 + 提供商 - bestappsales.com + 配置小时为单位的自动更新和 Aurora Store 自更新间隔。 + 仅 Aurora Store 应用 + 只检查 Aurora Store 安装应用的更新 设置 自动更新频率 + 启用代理 代理 URL + 代理 无效的代理 URL,请检查格式! 成功设置了代理 设置代理失败 + 允许本应用所有流量经代理服务器发出 默认(来自设备配置) Google Play 版本 后台下载 允许 Aurora Store 在后台下载并更新应用 - 自动更新 + 自动更新应用 检查并提示可用更新 不自动更新应用 配置自动更新行为 @@ -305,7 +311,7 @@ 请求新分析 导出 APK 失败 清除已完成 - 显示可能失败的更新 + 不兼容的更新 显示不兼容或已停用应用的更新,可能安装失败 添加到主屏 用于后台安装的安装包 @@ -342,13 +348,17 @@ 无效 URL 分发程序 URL 删除 - 删除分发程序? + 删除分发程序 添加 你希望删除分发程序 \"%1$s\"吗? 请登录你的 Google 账户 关于 Aurora 商店 了解更多有关 Aurora 商店的信息 - Aurora 商店允许你从官方 Google Play 商店搜索并下载应用。你可以查看应用描述、截图、更新和其他用户的评论并直接将 APK 从 Google Play 下载到你的设备上。要使用 Aurora 商店,你需要有 Google Play 账户,并在你首次打开并配置 Aurora 商店时登录你的 Google Play 商店。 \n \n和传统的应用商店不同, Aurora 商店并不拥有、许可或分发任何应用。所有的应用、应用描述、截图以及 Aurora 商店中的其他内容均直接从 Google Play 访问、下载并/或展示。Aurora 商店的工作方式就像一扇门或一个浏览器,允许你登录你的 Google Play 账户并从 Google Play 寻找应用。 \n \n请注意 Aurora 商店没有来自 Google、Google Play、任何经 Aurora 商店下载的应用或任何应用开发者的任何批准、赞助或授权; Aurora 商店也与它们没有任何从属、合作或联系。 + Aurora 商店允许你从官方 Google Play 商店搜索并下载应用。你可以查看应用描述、截图、更新和其他用户的评论并直接将 APK 从 Google Play 下载到你的设备上。要使用 Aurora 商店,你需要有 Google Play 账户,并在你首次打开并配置 Aurora 商店时登录你的 Google Play 商店。 +\n +\n和传统的应用商店不同, Aurora 商店并不拥有、许可或分发任何应用。所有的应用、应用描述、截图以及 Aurora 商店中的其他内容均直接从 Google Play 访问、下载并/或展示。Aurora 商店的工作方式就像一扇门或一个浏览器,允许你登录你的 Google Play 账户并从 Google Play 寻找应用。 +\n +\n请注意 Aurora 商店没有来自 Google、Google Play、任何经 Aurora 商店下载的应用或任何应用开发者的任何批准、赞助或授权; Aurora 商店也与它们没有任何从属、合作或联系。 应用对你的设备不可用 收藏 收藏应用 @@ -365,6 +375,7 @@ 输入有效的代理 URL 让所有数据都经过代理。 检查更新 允许从未知来源安装应用 + 由于存储访问框架的故障,你可能必须重新授予此权限 必需的 可选 数据安全 @@ -387,9 +398,10 @@ 需要身份验证 请登录 Google Play 账户取消存档该应用! 正在检查更新 - 印度制作 %1$s + Made with %1$s in India 默认 可用 + 可能必须重启应用权限授予才能生效。 全部删除 全选 最新 @@ -415,59 +427,4 @@ 兼容:没有任何问题可以工作 安装了 %1$d 应用 无应用可用 - 使用 microG 来登录账户 - 登录 Google 账户时使用 microG 验证身份简化登录流程 - 设置 - 停用 - 成功停用了代理 - 查看并管理代理配置 - 自动更新限制 - 配置设备自动更新限制 - 仅在不按流量计费网络上 - 当设备闲置时 - 当电量不低时 - 验证已下载文件失败 - 高级 - 应用来源 - 下载 - 上次更新 - 最低 Android 版本 - 目标 API 等级 - %1$d 个权限 - 安装 microG 套件 - 应用兼容性 - 缺少依赖项 - 我已阅读并同意 microG 的服务条款和隐私政策 - 我们在设备上找不到 Google Play 服务,几款流行应用现在需要它才能正常工作! - microG 是自由开源的 Google Play 服务实现,通过重新实现向安卓设备提供运行依赖 Google Play 服务的手机应用的相似功能。\n\nmicroG 允许应用访问 Google APIs,增强用户兼容性同时提供隐私益处。\n\n打开依赖 Google Mobile 服务的应用时,microG 会自动在后台运行。 - 阅读 microG 隐私政策 - 阅读 microG 许可和协议 - 访问 microG 项目网站 - 此应用可收集的数据 - 开发者称该应用不收集用户数据。 - 该应用可能分享的数据 - 开发者称该应用不与其他公司或组织分享用户数据。 - 应用的这个版本仍可能包括尚不在 Exodus Privacy 数据库中的更多跟踪器。 - %2$s 中找到了 %1$d 个 已知的跟踪器 - 无描述可用 - 更多信息 - 目标 API - 包名 - 内容评级 - 选择一个应用了解更多详情 - 无广告 - 无 play 服务 - 版本码只能包含数字 - 准备安装中 - - 需要权限 - - MicroG 安装器安装应用失败,可能由于错误配置。 - MicroG 安装器 - 需要安装 microG 助手应用 - 帮助绕过应用完整性(仅安装包)检查 - 正在加载 - %1$d - 跳过 - 重启应用更改吗? diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 4966b3075..552e5e1f4 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -47,19 +47,19 @@ 檢視 Aurora 商店的 XDA 討論串來討論或提供意見。 加入 Aurora 支援社群來討論或提供建議。 Telegram - 通過 PayPal 捐款 + 通過 PayPal 捐贈 PayPal Liberapay 從 GitLab 上的 Aurora OSS 取得 Aurora 商店的原始碼。 GitLab - 從 F-Droid 取得 Aurora Store。 + 透過 F-Droid 取得 Aurora Store。 F-Droid 透過 Ethereum (ETH) 捐款 Ethereum 透過 Bitcoin (BTC) 捐款 Bitcoin 透過 Bitcoin Cash (BCH) 捐款 - 比特幣現金 + Bitcoin Cash 透過 UPI 捐款 啟用背景程式下載 背景程式下載 @@ -71,7 +71,7 @@ 瀏覽頁面不可用 恭喜!要求的版本代碼可用,正在下載。 你正在要求的版本代碼不可用。 - 不可於匿名帳戶上購買應用程式。 + 應用購買在匿名帳戶上不可用。 以應用裝置偽裝。 已授予權限 從裝置設定中啟用開發者選項,以開啟它們。 @@ -88,7 +88,7 @@ 媒體庫中的應用程式 媒體庫 語言 - 應用程式安裝器 + 程式安裝器 已安裝 安裝 遊戲 @@ -96,6 +96,7 @@ 下載 裝置 黑名單管理 + 特價中的應用程式 我的程式和遊戲 應用程式 帳戶 @@ -111,15 +112,16 @@ 請重新登入並重新啟動應用程式以應用變動。 請重新登入以套用偽裝 連線階段已過期,請重新登入。 - 無法取得檔案 + 無法獲取檔案 找不到應用程式 尚未支援該應用程式 尚未購買該應用程式 下載失敗 + 在詳細說明頁面顯示「相似及相關」 相似及相關的程式 在首頁顯示「為你精選」頁面 為你精選頁面 - 選擇預設標籤頁 + 選擇預設標籤 佈局 個人化 網路 @@ -132,7 +134,7 @@ 安裝後刪除 APK 已下載的 APK 將在安裝後立即刪除 篩選 F-Droid 應用程式 - 不檢查從 F-Droid 安裝的應用程式更新 + 在更新與已安裝的應用程式中,忽略 F-Droid 應用程式 額外功能 允許從 Aurora Store 安裝應用程式 安裝器權限 @@ -144,7 +146,7 @@ Aurora Store 需要以下權限 你無法透過原生安裝器安裝捆包(分裂的)應用程式。請將你的安裝方式改成階段、Aurora 服務或 Root。 由於 MIUI 最佳化,階段安裝器無法安裝應用程式。 - 有更新可用 + 有新更新可用 另外你可以選原生安裝器,但如此你就無法安裝分裂的 APK 了,所以由你決定。 請禁用 MIUI 最佳化以允許安裝,另外你可以選 Root 或者 Aurora 服務安裝器。 偵測到 MIUI! @@ -159,7 +161,7 @@ 與已安裝應用程式衝突 無法建立安裝階段 安裝被封鎖 - 安裝失敗 + 安裝器失敗 請先設定好 Aurora 服務並取得權限。 安裝 Aurora 服務 1.0.9 以上的版本,或者更換安裝器。 Aurora 服務可用並已經準備好安裝。 @@ -189,7 +191,7 @@ 下載完成 已取消 取消全部 - 您覺得這個應用程式如何? + 你覺得這個 app 如何? 評分及評論 隱私 權限 @@ -197,13 +199,13 @@ 暫無更新可用 沒有權限 無依賴元件 - 未找到符合的應用程式 + 未找到符合的程式 無廣告 同類應用程式 需要 Google 服務架構 免費 開發人員資料 - 開發人員聯絡資訊 + 開發人員聯絡資料 地址 簡介 依賴元件 @@ -211,16 +213,16 @@ 未提供更動記錄 更動紀錄 加入需要一點時間,等一下再回來查看狀態。 - 你會比大眾更早體驗到新功能以及錯誤,向開發人員回報問題以幫助改進。 - 要加入 beta 計畫嗎? - 你已經是 beta 測試人員啦 - Beta 計畫 + 你會先於大眾體驗到新功能以及 bugs,向開發人員回報問題以幫助改進。 + 要加入 beta 項目嗎? + 你已經是 beta 測試員啦 + Beta(測試版)項目 白名單 更新全部 更新 應用程式資訊 解除安裝 - 儲存 App bundle + 保存 App bundle(程式捆包) 更多選項 XDA 論壇 在 Liberapay 上贊助我們 @@ -268,32 +270,36 @@ 登入並享用。 有更新可用 Google Play 版本 - 顯示不相容的更新 - 為不相容或已停用的應用程式顯示可能安裝失敗的更新 - 不檢查於 Aurora Store 外所安裝的應用程式更新 + 代理伺服器 + 啟用代理伺服器 + 不相容的更新 + 為不相容或已停用的應用程式,顯示可能安裝失敗的更新 + 在更新與已安裝的應用程式中,僅顯示由 Aurora Store 安裝的應用程式 應用程式設定 + 提供:bestappsales.com 搜尋建議 無效的代理伺服器網址,請檢查格式! 已成功設定代理 - 你被限制速率了 + 噢嗚,你被限制速率了 無法連接伺服器 無法產生工作階段 驗證新的工作階段 應用程式語言 匯出 APK 失敗 預設(來自裝置配置) + 允許所有來自於應用程式的網路活動經過代理伺服器 代理伺服器網址 - 排除其他來源所安裝的應用程式 + 僅限 Aurora Store 應用程式 設定自動更新行為 不要自動更新應用程式 檢查網路連線 評論標題 存取被拒!你是否正開著 VPN 或者 Tor? - 自動更新 + 自動更新應用程式 檢查並自動安裝可用的更新 取得隱私報告失敗 自動更新頻率 - 以小時為單位,設定自動更新的時間間隔。 + 以小時為單位,設定自動與自我更新的時間間隔。 應用程式連結 允許 Aurora Store 開啟支援的連結 內部錯誤!請一段時間後重試 @@ -337,7 +343,8 @@ 基於工作階段的安裝程式,用於安裝整合或分割的 APK 資料安全 允許安裝來自未知來源的應用程式 - 您需要先授予安裝應用程式的權限 + 您需要先授予安裝程式權限 + 由於儲存存取框架 (Storage Access Framework) 的問題,您可能需要重新授予權限 無法匯入我的最愛! 匯出我的最愛失敗! 已匯入我的最愛! @@ -354,7 +361,11 @@ 需要 Shizuku 或 Sui,並且需要設定及授予權限 背景安裝程式 了解 Aurora Store 是如何使用您的資料 - Aurora Store 可讓你搜尋並下載來自官方 Google Play 商店的應用程式。你可以查看應用程式描述、螢幕截圖、更新、其他使用者的評論,並可直接從 Google Play 將 APK 下載至你的裝置。要使用 Aurora Store,你需要擁有 Google Play 帳戶,並在首次開啟與設定 Aurora Store 時登入你的 Google Play 帳戶。\n\n與傳統的應用程式商店不同,Aurora Store 不擁有、授權或發佈任何應用程式。Aurora Store 中的所有應用程式、描述、螢幕截圖與其他內容,皆直接自 Google Play 存取、下載與/或顯示。Aurora Store 的運作方式就像一扇門或一個瀏覽器,讓你登入 Google Play 帳戶並從 Google Play 找到應用程式。\n\n請注意,Aurora Store 並未獲得 Google,Google Play 透過 Aurora Store 下載的任何應用程式或任何應用程式開發者的批准、贊助或授權;Aurora Store 亦與它們沒有任何隸屬關係、合作或聯繫。 + Aurora Store 讓您可以搜尋並下載來自官方 Google Play 商店的應用程式。您可以檢視應用程式的描述、截圖、更新內容、其他使用者的評論,並直接從 Google Play 下載 APK 到您的裝置上。要使用 Aurora Store,您需要擁有 Google Play 帳戶,並在首次開啟和設定 Aurora Store 時登入您的 Google Play 帳戶。 +\n +\n與傳統的應用程式商店不同,Aurora Store 不擁有、授權或散佈任何應用程式。Aurora Store 中的所有應用程式、應用程式描述、截圖及其他內容,都是直接從 Google Play 取得、下載及顯示。Aurora Store 的運作方式與入口網站或瀏覽器相似,讓您可以登入 Google Play 帳戶並從 Google Play 尋找應用程式。 +\n +\n請注意,Aurora Store 未經 Google、Google Play、透過 Aurora Store 下載的任何應用程式或其開發者的核准、贊助或授權;Aurora Store 也與他們沒有任何關聯、合作或連結。 登出? 您確定要登出嗎? 檢查更新 @@ -372,102 +383,4 @@ 預設 必要 選用 - 選擇全部 - 移除全部 - 最新 - 匯出黑名單失敗! - 下載通知 - 帳戶相關通知 - 檔案匯出工具 - 請稍等,正在匯出你的檔案 - 已匯出黑名單! - 驗證中 - 檢查相容性中… - 由 Plexus 提供支持 - 相容性 - 需要 Google Play 服務 - 沒有 Google Play 服務 - 安裝通知 - 正在檢查更新 - 已安裝 %1$d 個應用程式 - 無應用程式可用 - 找出裡面有什麼 - 無法打開應用程式 - 匯入黑名單失敗! - 已匯入黑名單! - 應用程式匯出通知 - 安裝 microG Bundle - 下載 - 上次更新 - 最小 Android 版本 - 目標 API 級別 - 應用程式相容性 - 缺少的依賴 - 我已經閱讀並同意 microG 服務條款與隱私政策 - 找不到 Google Play 服務,某些應用程式需要它才能正常使用! - microG 是一個免費開源的 Google Play 服務替代,讓依賴 Google Play 服務的應用程式能夠正常運作。\n\nmicroG 能讓應用程式存取 Google API,提供使用者方便的同時保護使用者的隱私。\n\nmicroG 將於開啟依賴 Google 行動服務的應用程式時自動於背景中執行。 - 閱覽 microG 隱私政策 - 閱覽 microG 許可與同意書 - 前往 microG 官網 - %1$s 與血於印度製造 - 此將會撤銷階段安裝器能夠安靜地安裝應用程式的權限。是否繼續? - 管理供應者 - 查看與管理於匿名登入時的權杖供應者 - 沒有供應者 - 新增供應者 - 於 Aurora Store 中新增供應者。權杖供應者將提供帳號證明於 Aurora Store 以匿名地登入。 - 供應者網址 - 移除供應者? - 是否移除供應者「%1$s」? - %1$d 個權限 - 解壓縮 - 您可能需要安裝 Google 的閉源資料庫或是開源的替代,例如 microG。 - 不需要 Google Play 服務 - 此應用程式不須 Google 的閉源資料庫,不過其可能需要其他第三方資料庫才能正常運作。 - microG 相容性 - 可運作:沒有任何問題 - 有限制:僅有某些功能正常運作 - 不支援:無法使用 - 未知:尚未檢查 - 使用 microG 登入帳號 - 登入 Google 帳號時以 microG 驗證帳號以簡化登入流程 - 確認 - 停用 - 已成功停用代理伺服器 - 檢視並管理代理伺服器設定 - 更多 - 自動更新限制 - 設定自動更新的裝置限制 - 僅限於非計量付費網路 - 於裝置閒置時 - 於裝置電量足夠時 - 應用程式來源 - 檢驗檔案失敗 - 此應用程式可能收集的資料 - 開發者表示此應用程式不會收集使用者資料。 - 此應用程式可能分享的資料 - 開發者表示此應用程式不會與其他公司或組織分享使用者資料。 - 此版本的應用程式可能仍包含 Exodus Privacy 資料庫中尚未收錄的更多追蹤器。 - %2$s 中發現 %1$d 個已知追蹤器 - 版本代碼只能包含數字 - 沒有可用的描述 - 更多資訊 - 目標 - 套件名稱 - 內容分級 - 正在準備安裝 - 選擇一個應用程式以查看更多詳細資訊 - 無廣告 - 無 Play 服務 - - 需要權限 - - MicroG 安裝器安裝應用失敗,可能由於錯誤配置。 - MicroG 安裝器 - 需要安裝 microG 助手應用 - 幫助繞過應用程式完整性(僅限安裝包)檢查 - 正在加載 - %1$d - 跳過 - 重新啟動以套用變更? diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 7c98db554..8edc74762 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -76,7 +76,7 @@ "https://xdaforums.com/t/app-5-0-aurora-store-open-source-google-play-client.3739733/" "https://t.me/AuroraSupport" "https://gitlab.com/AuroraOSS/AuroraStore" - "https://f-droid.org/packages/com.aurora.store/" + "https://f-droid.org/en/packages/com.aurora.store/" "bc1qu7cy9fepjj309y4r2x3rymve7mw4ff39c8cpe0" "qpqus3qdlz8guf476vwz0fjl8s34fseukcmrl6eknl" "0x6977446933EC8b5964D921f7377950992337B1C6" @@ -134,6 +134,7 @@ 3.0 4.0 4.5 + 4.7 @@ -143,10 +144,15 @@ 3★ + 4★ + 4.5★ + + 4.7★ + 0 + 100 + 1000 + 10000 + 50000 100000 1000000 10000000 @@ -156,6 +162,10 @@ @string/action_filter_all + 100 + + 1K + + 10K + + 50K + 100K + 1M + 10M + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 3bebb6e80..3c6e0acd3 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -61,11 +61,7 @@ 200dp 52dp 64dp - 48dp 148dp - 96dp - - 200dp 8dp 10dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dc933a1e2..d0593b313 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -51,12 +51,12 @@ Log out from Aurora "Back" "Blacklist" - "Add to blacklist" + "Add to Blacklist" "Cancel" "Clear" "Close" "Copy" - "Copy link" + "Copy Link" "Disable" "Export" "Import" @@ -71,12 +71,11 @@ "Paid" "Ratings" "Finish" - "Save app bundle" + "Save App bundle" "Grant" "Granted" "Ignore" "Install" - "Install microG Bundle" "Installations" "Installing" "Join" @@ -97,19 +96,19 @@ "Share" "Uninstall" "Successfully uninstalled" - Add to home screen - "App info" + Add to Home screen + "App Info" "Update" "Update all" "Whitelist" "Beta program" "You're a beta tester" - "Join beta program?" + "Join beta program ?" "You will see new features and bugs before the public does. Give your feedback to developers to help them improve." "Enrollment may take some time, you can check status later." "Changelog" "Changelog not provided" - "Contains ads" + "Contains Ads" "Dependencies" "Description" "Address" @@ -123,15 +122,11 @@ "No ads" "No app match found" "No favourite apps found" - "No dependencies" + "No Dependencies" "No permissions" "No updates available" "Paid" "Permission" - Data that this app may collect - The developer says this app doesn\'t collect user data. - Data that this app may share - The developer says this app doesn\'t share user data with other companies or organizations. Data safety Data privacy and security practices declared by developer "Privacy" @@ -157,11 +152,9 @@ "Resume all" "Estimating" "Contains no known trackers" - This version of the app may still contain more trackers not present yet in the Exodus Privacy\'s database. "Powered by Exodus Privacy" "Checking for trackers…" known trackers(s) found in - %1$d known trackers(s) found in %2$s "View report" "All" "Latest" @@ -175,10 +168,9 @@ Install App Manager or change the installer. No root access. Grant it or change the installer. Shizuku is not installed or set up properly. - "Aurora Services is available and ready to install." - Install Aurora Services 1.0.9 or above, or change the installer. - Set up Aurora Services and grant all permissions first. - MicroG installer failed to install app, likely due to misconfiguration. + "Aurora services is available and ready to install." + Install Aurora services 1.0.9 or above, or change the installer. + Set up Aurora services and grant all permissions first. "Installer failed" "Installation was blocked" "Could not create session" @@ -196,13 +188,28 @@ "Please, disable MIUI optimizations to allow installations, otherwise you can choose Root or Services installer." "Optionally you can choose Native installer, but then you can not install bundled (split) APKs, so choice is yours." "New update available" - "You can not install bundled (split) apps via Native Installer. Change your installer to Session, Services or Root." + "You can not install bundled(split) apps via Native Installer. Change your installer to Session, Services or Root." Account-related notification App export notification Install notification Downloads notification + "Aurora Store requires following permissions" + "Installer" + "Permissions" + "Welcome" + "How you doing?" + "External Storage Access" + To save APK expansion files (OBBs) for large apps & games. + "External Storage Manager" + "Installer Permission" + "Allow installing apps from Aurora Store" + "Allow installation of apps from unknown sources" + "Notifications" + "Send notifications regarding installations status" + "Background Downloads" + "Allow Aurora Store to download and update apps in background" "Extras" - "Don't check updates for apps installed from F-Droid" + "Don't check updates for apps downloaded or installed from F-Droid" "Filter F-Droid apps" Downloaded APKs will be deleted immediately after installation "Delete APK post-install" @@ -212,23 +219,26 @@ "Root installer" "Aurora Services (Deprecated)" "Session installer" - "MicroG installer" "Select mode of APK installation" "Installation method" - Google Play version + Google Play Version Default (from device config) "Networking" + Proxy + "Enable proxy" + "Allow all traffic from app to go through the proxy" "Proxy URL" Enter a valid proxy URL to pass all data through the proxy. "Customization" - "For you pages" - "Display For you pages on home screen" + "For You Pages" + "Display For You Pages on home screen" "Similar and related apps" - Show updates that may fail - Display updates for incompatible or disabled apps that may fail to install - Filter apps from other sources - Don\'t check for updates for apps installed from sources outside Aurora Store - "Download failed" + "Display similar and related clusters on app details page" + Incompatible updates + Show updates for incompatible or disabled apps that may fail to install + Aurora Store apps only + Only check updates for apps installed by Aurora Store + "Download Failed" "App not purchased" "App not supported" "App not found" @@ -241,7 +251,7 @@ Could not log in via Google Last session scrapped Verifying session - Verifying Google session + Verifying Google Session "Make sure you re-login to apply the spoof" "Make sure you re-login and restart app to apply changes." "Categories" @@ -255,18 +265,20 @@ About "Accounts" "Apps" - "App settings" + "App Settings" "My apps & games" "Apps in library" + "Apps on sale" + "Provider - bestappsales.com" "Blacklist manager" - "Favourite apps" + "Favourite Apps" "Device" "Downloads" "Play Store" "Games" "Installation" "Installed" - "App installer" + "App Installer" "Language" "Library" "No network" @@ -285,9 +297,11 @@ "Copied to clipboard" Turn on developer settings from the device settings to open them. "Permission granted" - "You need to grant installer permission first" + "You need to grant Installer Permission first" + "You may have to re-grant the permission due to bug in Storage Access Framework" + "You may have to restart app to reflect the permission grant." Device spoof applied. - "App purchases not available on anonymous accounts." + "App purchases not available on Anonymous accounts." "The version code you are requesting is unavailable." "Congrats, requested version code is available, downloading now." Browse page unavailable @@ -312,37 +326,37 @@ Required Optional Required permissions were denied. Please grant them in order to continue the action - Search for apps & games + Search for Apps & Games Requesting new session Server down for maintenance Downloading additional files for %1$s - Update notifications + Updates notifications %1$d updates available %1$d update available A new version of %1$s is available %1$s and %2$s %1$s, %2$s and %3$s %1$s, %2$s, %3$s and %4$d more - Automatic updates - Configure automatic updates behaviour + Auto-update apps + Configure auto-updates behaviour Do not auto-update apps Check & notify for available updates Check & install available updates automatically Automatic updates frequency - Configure time interval for automatic updates, in hour. + Configure intervals for auto and self updates, in hour. Failed to fetch privacy report Access denied! Are you using VPN or Tor? Internal error! Please retry after sometime - You are rate limited + Oops, You are rate limited Server unreachable Could not generate session Verifying new session Failed to generate session, error code: %1$d Check internet connectivity - App language + App Language Layout Select default tab - App links + App Links Allow Aurora Store to open supported links play.google.com Google Play, also known as the Google Play Store and formerly Android Market. @@ -350,36 +364,6 @@ Android Market was an online store offering software applications designed for Android devices, retired in 2017. Failed to export APKs No apps available - "Downloads" - "Last updated" - "Minimum Android Version" - "Target API Level" - - - Skip - "Installer" - "App Compatibility" - "Missing dependencies" - "Permissions" - "Welcome" - "How you doing?" - "External storage access" - To save APK expansion files (OBBs) for large apps & games. - "External storage manager" - "Installer permission" - "Allow installing apps from Aurora Store" - "Allow installation of apps from unknown sources" - "Notifications" - "Send notifications regarding installations status" - "Background downloads" - "Allow Aurora Store to download and update apps in background" - "Aurora Store requires following permissions" - "I have read and agree to the microG Terms of Service and Privacy Policy" - "We couldn't find Google Play Services on your device, several popular apps now require it to function properly!" - "microG is a free and open-source implementation that provides similar functionality to run apps dependent on Google Play Services for Android devices through re-implementation.\n\nmicroG enables apps to access those Google APIs, enhancing compatibility for users while offering privacy benefits. \n\nmicroG will run automatically in the background when you open applications dependent on Google Mobile Services." - Read microG Privacy Policy - Read microG License and Agreement - Visit microG Project Website Session based installer for bundled/split APKs @@ -390,8 +374,6 @@ Best suited for devices running below Android 4.4 Installer for background installations Requires Aurora Services to be installed as a privileged-system app - Requires microG companion app to be installed - Helps you bypass App Integrity (installer only) check Full-featured open source package manager Requires App Manager, need adb/root mode to install when miui optimization is on Using system APIs directly with adb/root privileges @@ -399,7 +381,6 @@ Enter version code you wish to download - Version code can only contain digits FAQs @@ -416,7 +397,7 @@ v%1$s (%2$d) About Aurora Store Learn more about Aurora Store - Aurora Store enables you to search and download apps from the official Google Play Store. You can check app descriptions, screenshots, updates, other users\' comments, and download the APK directly from Google Play to your device. To use Aurora Store, you need to have a Google Play account, and log in to your Google Play account when you first open and configure Aurora Store.\n\nUnlike a traditional app store, Aurora Store does not own, license or distribute any apps. All the apps, app descriptions, screenshots and other content in Aurora Store are directly accessed, downloaded and/or displayed from Google Play. Aurora Store works exactly like a door or a browser, allowing you to log in to your Google Play account and find the apps from Google Play.\n\nPlease note that Aurora Store does not have any approval, sponsorship or authorization from Google, Google Play, any apps downloaded through Aurora Store or any app developers; neither does Aurora Store have any affiliation, cooperation or connection with them. + Aurora Store enables you to search and download apps from the official Google Play store. You can check app descriptions, screenshots, updates, other users\' comments, and download the APK directly from Google Play to your device. To use Aurora Store, you need to have a Google Play account, and log in to your Google Play account when you first open and configure Aurora Store.\n\nUnlike a traditional app store, Aurora Store does not own, license or distribute any apps. All the apps, app descriptions, screenshots and other content in Aurora Store are directly accessed, downloaded and/or displayed from Google Play. Aurora Store works exactly like a door or a browser, allowing you to log in to your Google Play account and find the apps from Google Play.\n\nPlease note that Aurora Store does not have any approval, sponsorship or authorization from Google, Google Play, any apps downloaded through Aurora Store or any app developers; neither does Aurora Store have any affiliation, cooperation or connection with them. More @@ -438,7 +419,7 @@ Add a token dispenser to Aurora Store. Token dispensers provide account credentials to Aurora Store for logging in anonymously. Invalid URL Dispenser URL - Remove dispenser? + Remove dispenser Do you wish to remove the dispenser \"%1$s\"? Add Remove @@ -456,10 +437,10 @@ Blacklist exported! - File exporter + File Exporter Hold on, exporting your file Successfully exported app bundle - Failed to export app bundle + Failed to exported app bundle Log out? @@ -470,7 +451,6 @@ Checking for updates - Restart to apply changes? Restart Aurora Store Aurora Store needs to be restarted to apply the newly changed settings @@ -492,14 +472,9 @@ Available - No description available - %1$d permissions - More info - Targets - Package name - Content rating Unarchive Unable to open app + %1$s (%2$d) ➔ %3$s (%4$d) Powered by Plexus Checking compatibility… Compatibility @@ -513,42 +488,7 @@ Limited: Works with limited features Unsupported: Not functional Unknown: Not checked yet - Preparing to install - - Permission required - Permissions required - %1$d apps installed - - - Use microG to sign in to accounts - Authenticate using microG when signing into Google accounts for a simpler sign-in flow - Set - Disable - Proxy disabled successfully - View and manage proxy configuration - protocol://user:password@host:port - - - Advanced - Automatic updates restrictions - Configure device restrictions for automated updates - Only on unmetered networks - When device is idle - When battery is not low - App source - - - Failed to verify downloaded files - - - Select an app for more details - No advertisements - No play services - - - Loading in progress - Page %1$d diff --git a/app/src/main/res/xml/preferences_network.xml b/app/src/main/res/xml/preferences_network.xml index fd55ab4d3..e0f4856d7 100644 --- a/app/src/main/res/xml/preferences_network.xml +++ b/app/src/main/res/xml/preferences_network.xml @@ -25,26 +25,24 @@ app:summary="@string/pref_dispenser_summary" app:title="@string/pref_dispenser_title" /> - - + app:summary="protocol://user:password@host:port" + app:title="@string/pref_network_proxy_title" /> + app:key="PREFERENCE_PROXY_ENABLED" + app:summary="@string/pref_network_proxy_enable_desc" + app:title="@string/pref_network_proxy_enable" /> + + + + diff --git a/app/src/main/res/xml/preferences_updates.xml b/app/src/main/res/xml/preferences_updates.xml index 868001e9f..a803bf3a3 100644 --- a/app/src/main/res/xml/preferences_updates.xml +++ b/app/src/main/res/xml/preferences_updates.xml @@ -40,17 +40,10 @@ app:min="1" app:showSeekBarValue="true" /> - - + app:title="@string/action_filter" /> + app:title="@string/pref_common_extra" /> - - - - - - diff --git a/app/src/preload/java/com/aurora/store/util/FlavouredUtil.kt b/app/src/preload/java/com/aurora/store/util/FlavouredUtil.kt deleted file mode 100644 index e92b09b7d..000000000 --- a/app/src/preload/java/com/aurora/store/util/FlavouredUtil.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.aurora.store.util - -import android.content.Context -import com.aurora.Constants - -object FlavouredUtil : IFlavouredUtil { - - override val defaultDispensers = setOf(Constants.URL_DISPENSER) - - override fun promptMicroGInstall(context: Context): Boolean = false -} diff --git a/app/src/vanilla/java/com/aurora/store/data/receiver/InstallerStatusReceiver.kt b/app/src/test/java/com/aurora/store/ExampleUnitTest.kt similarity index 68% rename from app/src/vanilla/java/com/aurora/store/data/receiver/InstallerStatusReceiver.kt rename to app/src/test/java/com/aurora/store/ExampleUnitTest.kt index 440a1070d..b63b40f22 100644 --- a/app/src/vanilla/java/com/aurora/store/data/receiver/InstallerStatusReceiver.kt +++ b/app/src/test/java/com/aurora/store/ExampleUnitTest.kt @@ -16,9 +16,20 @@ * along with Aurora Store. If not, see . * */ -package com.aurora.store.data.receiver -import dagger.hilt.android.AndroidEntryPoint +package com.aurora.store -@AndroidEntryPoint -class InstallerStatusReceiver : BaseInstallerStatusReceiver() +import org.junit.Assert.* +import org.junit.Test + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/app/src/vanilla/java/com/aurora/store/util/FlavouredUtil.kt b/app/src/vanilla/java/com/aurora/store/util/FlavouredUtil.kt deleted file mode 100644 index e92b09b7d..000000000 --- a/app/src/vanilla/java/com/aurora/store/util/FlavouredUtil.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.aurora.store.util - -import android.content.Context -import com.aurora.Constants - -object FlavouredUtil : IFlavouredUtil { - - override val defaultDispensers = setOf(Constants.URL_DISPENSER) - - override fun promptMicroGInstall(context: Context): Boolean = false -} diff --git a/build.gradle.kts b/build.gradle.kts index 810cdf068..72296555a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,22 @@ /* - * SPDX-FileCopyrightText: 2021-2025 Aurora OSS - * SPDX-FileCopyrightText: 2022-2025 The Calyx Institute - * SPDX-FileCopyrightText: 2023 grrfe - * SPDX-License-Identifier: GPL-3.0-or-later + * Aurora Store + * Copyright (C) 2021, Rahul Kumar Patel + * Copyright (C) 2022, The Calyx Institute + * Copyright (C) 2023, grrfe + * + * Aurora Store is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Aurora Store is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Aurora Store. If not, see . + * */ plugins { @@ -10,7 +24,6 @@ plugins { alias(libs.plugins.jetbrains.kotlin.android) apply false alias(libs.plugins.jetbrains.kotlin.compose) apply false alias(libs.plugins.jetbrains.kotlin.parcelize) apply false - alias(libs.plugins.jetbrains.kotlin.serialization) apply false alias(libs.plugins.google.ksp) apply false alias(libs.plugins.androidx.navigation) apply false alias(libs.plugins.ktlint) apply false diff --git a/build_output.txt b/build_output.txt new file mode 100644 index 000000000..8e7640add --- /dev/null +++ b/build_output.txt @@ -0,0 +1,401 @@ +> Task :jmods:app:preBuild UP-TO-DATE +> Task :jmods:app:preDebugBuild UP-TO-DATE +> Task :jmods:app:mergeDebugNativeDebugMetadata NO-SOURCE +> Task :jmods:app:checkKotlinGradlePluginConfigurationErrors SKIPPED +> Task :jmods:core-auth:preBuild UP-TO-DATE +> Task :jmods:core-auth:preDebugBuild UP-TO-DATE +> Task :jmods:core-auth:writeDebugAarMetadata UP-TO-DATE +> Task :jmods:core-data:preBuild UP-TO-DATE +> Task :jmods:core-data:preDebugBuild UP-TO-DATE +> Task :jmods:core-data:writeDebugAarMetadata UP-TO-DATE +> Task :jmods:core-database:preBuild UP-TO-DATE +> Task :jmods:core-database:preDebugBuild UP-TO-DATE +> Task :jmods:core-database:writeDebugAarMetadata UP-TO-DATE +> Task :jmods:core-domain:preBuild UP-TO-DATE +> Task :jmods:core-domain:preDebugBuild UP-TO-DATE +> Task :jmods:core-domain:writeDebugAarMetadata UP-TO-DATE +> Task :jmods:core-installer:preBuild UP-TO-DATE +> Task :jmods:core-installer:preDebugBuild UP-TO-DATE +> Task :jmods:core-installer:writeDebugAarMetadata UP-TO-DATE +> Task :jmods:core-navigation:preBuild UP-TO-DATE +> Task :jmods:core-navigation:preDebugBuild UP-TO-DATE +> Task :jmods:core-navigation:writeDebugAarMetadata UP-TO-DATE +> Task :jmods:core-network:preBuild UP-TO-DATE +> Task :jmods:core-network:preDebugBuild UP-TO-DATE +> Task :jmods:core-network:writeDebugAarMetadata UP-TO-DATE +> Task :jmods:core-ui:preBuild UP-TO-DATE +> Task :jmods:core-ui:preDebugBuild UP-TO-DATE +> Task :jmods:core-ui:writeDebugAarMetadata UP-TO-DATE +> Task :jmods:feature-categories:preBuild UP-TO-DATE +> Task :jmods:feature-categories:preDebugBuild UP-TO-DATE +> Task :jmods:feature-categories:writeDebugAarMetadata UP-TO-DATE +> Task :jmods:feature-details:preBuild UP-TO-DATE +> Task :jmods:feature-details:preDebugBuild UP-TO-DATE +> Task :jmods:feature-details:writeDebugAarMetadata UP-TO-DATE +> Task :jmods:feature-home:preBuild UP-TO-DATE +> Task :jmods:feature-home:preDebugBuild UP-TO-DATE +> Task :jmods:feature-home:writeDebugAarMetadata UP-TO-DATE +> Task :jmods:feature-search:preBuild UP-TO-DATE +> Task :jmods:feature-search:preDebugBuild UP-TO-DATE +> Task :jmods:feature-search:writeDebugAarMetadata UP-TO-DATE +> Task :jmods:feature-updates:preBuild UP-TO-DATE +> Task :jmods:feature-updates:preDebugBuild UP-TO-DATE +> Task :jmods:feature-updates:writeDebugAarMetadata UP-TO-DATE +> Task :jmods:app:checkDebugAarMetadata UP-TO-DATE +> Task :jmods:app:generateDebugResValues UP-TO-DATE +> Task :jmods:core-auth:generateDebugResValues UP-TO-DATE +> Task :jmods:core-auth:generateDebugResources UP-TO-DATE +> Task :jmods:core-auth:packageDebugResources UP-TO-DATE +> Task :jmods:core-data:generateDebugResValues UP-TO-DATE +> Task :jmods:core-data:generateDebugResources UP-TO-DATE +> Task :jmods:core-data:packageDebugResources UP-TO-DATE +> Task :jmods:core-database:generateDebugResValues UP-TO-DATE +> Task :jmods:core-database:generateDebugResources UP-TO-DATE +> Task :jmods:core-database:packageDebugResources UP-TO-DATE +> Task :jmods:core-domain:generateDebugResValues UP-TO-DATE +> Task :jmods:core-domain:generateDebugResources UP-TO-DATE +> Task :jmods:core-domain:packageDebugResources UP-TO-DATE +> Task :jmods:core-installer:generateDebugResValues UP-TO-DATE +> Task :jmods:core-installer:generateDebugResources UP-TO-DATE +> Task :jmods:core-installer:packageDebugResources UP-TO-DATE +> Task :jmods:core-navigation:generateDebugResValues UP-TO-DATE +> Task :jmods:core-navigation:generateDebugResources UP-TO-DATE +> Task :jmods:core-navigation:packageDebugResources UP-TO-DATE +> Task :jmods:core-network:generateDebugResValues UP-TO-DATE +> Task :jmods:core-network:generateDebugResources UP-TO-DATE +> Task :jmods:core-network:packageDebugResources UP-TO-DATE +> Task :jmods:core-ui:generateDebugResValues UP-TO-DATE +> Task :jmods:core-ui:generateDebugResources UP-TO-DATE +> Task :jmods:core-ui:packageDebugResources UP-TO-DATE +> Task :jmods:feature-categories:generateDebugResValues UP-TO-DATE +> Task :jmods:feature-categories:generateDebugResources UP-TO-DATE +> Task :jmods:feature-categories:packageDebugResources UP-TO-DATE +> Task :jmods:feature-details:generateDebugResValues UP-TO-DATE +> Task :jmods:feature-details:generateDebugResources UP-TO-DATE +> Task :jmods:feature-details:packageDebugResources UP-TO-DATE +> Task :jmods:feature-home:generateDebugResValues UP-TO-DATE +> Task :jmods:feature-home:generateDebugResources UP-TO-DATE +> Task :jmods:feature-home:packageDebugResources UP-TO-DATE +> Task :jmods:feature-search:generateDebugResValues UP-TO-DATE +> Task :jmods:feature-search:generateDebugResources UP-TO-DATE +> Task :jmods:feature-search:packageDebugResources UP-TO-DATE +> Task :jmods:feature-updates:generateDebugResValues UP-TO-DATE +> Task :jmods:feature-updates:generateDebugResources UP-TO-DATE +> Task :jmods:feature-updates:packageDebugResources UP-TO-DATE +> Task :jmods:app:mapDebugSourceSetPaths UP-TO-DATE +> Task :jmods:app:generateDebugResources UP-TO-DATE +> Task :jmods:app:mergeDebugResources UP-TO-DATE +> Task :jmods:app:packageDebugResources UP-TO-DATE +> Task :jmods:app:parseDebugLocalResources UP-TO-DATE +> Task :jmods:app:createDebugCompatibleScreenManifests UP-TO-DATE +> Task :jmods:app:extractDeepLinksDebug UP-TO-DATE +> Task :jmods:core-auth:extractDeepLinksDebug UP-TO-DATE +> Task :jmods:core-auth:processDebugManifest UP-TO-DATE +> Task :jmods:core-data:extractDeepLinksDebug UP-TO-DATE +> Task :jmods:core-data:processDebugManifest UP-TO-DATE +> Task :jmods:core-database:extractDeepLinksDebug UP-TO-DATE +> Task :jmods:core-database:processDebugManifest UP-TO-DATE +> Task :jmods:core-domain:extractDeepLinksDebug UP-TO-DATE +> Task :jmods:core-domain:processDebugManifest UP-TO-DATE +> Task :jmods:core-installer:extractDeepLinksDebug UP-TO-DATE +> Task :jmods:core-installer:processDebugManifest UP-TO-DATE +> Task :jmods:core-navigation:extractDeepLinksDebug UP-TO-DATE +> Task :jmods:core-navigation:processDebugManifest UP-TO-DATE +> Task :jmods:core-network:extractDeepLinksDebug UP-TO-DATE +> Task :jmods:core-network:processDebugManifest UP-TO-DATE +> Task :jmods:core-ui:extractDeepLinksDebug UP-TO-DATE +> Task :jmods:core-ui:processDebugManifest UP-TO-DATE +> Task :jmods:feature-categories:extractDeepLinksDebug UP-TO-DATE +> Task :jmods:feature-categories:processDebugManifest UP-TO-DATE +> Task :jmods:feature-details:extractDeepLinksDebug UP-TO-DATE +> Task :jmods:feature-details:processDebugManifest UP-TO-DATE +> Task :jmods:feature-home:extractDeepLinksDebug UP-TO-DATE +> Task :jmods:feature-home:processDebugManifest UP-TO-DATE +> Task :jmods:feature-search:extractDeepLinksDebug UP-TO-DATE +> Task :jmods:feature-search:processDebugManifest UP-TO-DATE +> Task :jmods:feature-updates:extractDeepLinksDebug UP-TO-DATE +> Task :jmods:feature-updates:processDebugManifest UP-TO-DATE +> Task :jmods:app:processDebugMainManifest UP-TO-DATE +> Task :jmods:app:processDebugManifest UP-TO-DATE +> Task :jmods:app:processDebugManifestForPackage UP-TO-DATE +> Task :jmods:core-auth:compileDebugLibraryResources UP-TO-DATE +> Task :jmods:core-auth:parseDebugLocalResources UP-TO-DATE +> Task :jmods:core-auth:generateDebugRFile UP-TO-DATE +> Task :jmods:core-data:compileDebugLibraryResources UP-TO-DATE +> Task :jmods:core-data:parseDebugLocalResources UP-TO-DATE +> Task :jmods:core-data:generateDebugRFile UP-TO-DATE +> Task :jmods:core-database:compileDebugLibraryResources UP-TO-DATE +> Task :jmods:core-database:parseDebugLocalResources UP-TO-DATE +> Task :jmods:core-database:generateDebugRFile UP-TO-DATE +> Task :jmods:core-domain:compileDebugLibraryResources UP-TO-DATE +> Task :jmods:core-domain:parseDebugLocalResources UP-TO-DATE +> Task :jmods:core-domain:generateDebugRFile UP-TO-DATE +> Task :jmods:core-installer:compileDebugLibraryResources UP-TO-DATE +> Task :jmods:core-installer:parseDebugLocalResources UP-TO-DATE +> Task :jmods:core-installer:generateDebugRFile UP-TO-DATE +> Task :jmods:core-navigation:compileDebugLibraryResources UP-TO-DATE +> Task :jmods:core-navigation:parseDebugLocalResources UP-TO-DATE +> Task :jmods:core-navigation:generateDebugRFile UP-TO-DATE +> Task :jmods:core-network:compileDebugLibraryResources UP-TO-DATE +> Task :jmods:core-network:parseDebugLocalResources UP-TO-DATE +> Task :jmods:core-network:generateDebugRFile UP-TO-DATE +> Task :jmods:core-ui:compileDebugLibraryResources UP-TO-DATE +> Task :jmods:core-ui:parseDebugLocalResources UP-TO-DATE +> Task :jmods:core-ui:generateDebugRFile UP-TO-DATE +> Task :jmods:feature-categories:compileDebugLibraryResources UP-TO-DATE +> Task :jmods:feature-categories:parseDebugLocalResources UP-TO-DATE +> Task :jmods:feature-categories:generateDebugRFile UP-TO-DATE +> Task :jmods:feature-details:compileDebugLibraryResources UP-TO-DATE +> Task :jmods:feature-details:parseDebugLocalResources UP-TO-DATE +> Task :jmods:feature-details:generateDebugRFile UP-TO-DATE +> Task :jmods:feature-home:compileDebugLibraryResources UP-TO-DATE +> Task :jmods:feature-home:parseDebugLocalResources UP-TO-DATE +> Task :jmods:feature-home:generateDebugRFile UP-TO-DATE +> Task :jmods:feature-search:compileDebugLibraryResources UP-TO-DATE +> Task :jmods:feature-search:parseDebugLocalResources UP-TO-DATE +> Task :jmods:feature-search:generateDebugRFile UP-TO-DATE +> Task :jmods:feature-updates:compileDebugLibraryResources UP-TO-DATE +> Task :jmods:feature-updates:parseDebugLocalResources UP-TO-DATE +> Task :jmods:feature-updates:generateDebugRFile UP-TO-DATE +> Task :jmods:app:processDebugResources UP-TO-DATE +> Task :jmods:core-auth:checkKotlinGradlePluginConfigurationErrors SKIPPED +> Task :jmods:core-domain:checkKotlinGradlePluginConfigurationErrors SKIPPED +> Task :jmods:core-domain:compileDebugKotlin UP-TO-DATE +> Task :jmods:core-domain:javaPreCompileDebug UP-TO-DATE +> Task :jmods:core-domain:compileDebugJavaWithJavac NO-SOURCE +> Task :jmods:core-domain:bundleLibCompileToJarDebug UP-TO-DATE +> Task :jmods:core-auth:kspDebugKotlin UP-TO-DATE +> Task :jmods:core-auth:compileDebugKotlin UP-TO-DATE +> Task :jmods:core-auth:javaPreCompileDebug UP-TO-DATE +> Task :jmods:core-auth:compileDebugJavaWithJavac UP-TO-DATE +> Task :jmods:core-domain:bundleLibRuntimeToJarDebug UP-TO-DATE +> Task :jmods:core-auth:transformDebugClassesWithAsm UP-TO-DATE +> Task :jmods:core-auth:bundleLibRuntimeToJarDebug UP-TO-DATE +> Task :jmods:core-data:checkKotlinGradlePluginConfigurationErrors SKIPPED +> Task :jmods:core-database:checkKotlinGradlePluginConfigurationErrors SKIPPED +> Task :jmods:core-database:kspDebugKotlin UP-TO-DATE +> Task :jmods:core-database:compileDebugKotlin UP-TO-DATE +> Task :jmods:core-database:javaPreCompileDebug UP-TO-DATE +> Task :jmods:core-database:compileDebugJavaWithJavac UP-TO-DATE +> Task :jmods:core-database:transformDebugClassesWithAsm UP-TO-DATE +> Task :jmods:core-database:bundleLibCompileToJarDebug UP-TO-DATE +> Task :jmods:core-auth:bundleLibCompileToJarDebug UP-TO-DATE +> Task :jmods:core-network:checkKotlinGradlePluginConfigurationErrors SKIPPED +> Task :jmods:core-network:kspDebugKotlin UP-TO-DATE +> Task :jmods:core-network:compileDebugKotlin UP-TO-DATE +> Task :jmods:core-network:javaPreCompileDebug UP-TO-DATE +> Task :jmods:core-network:compileDebugJavaWithJavac UP-TO-DATE +> Task :jmods:core-network:transformDebugClassesWithAsm UP-TO-DATE +> Task :jmods:core-network:bundleLibCompileToJarDebug UP-TO-DATE +> Task :jmods:core-data:kspDebugKotlin UP-TO-DATE +> Task :jmods:core-data:javaPreCompileDebug UP-TO-DATE +> Task :jmods:core-database:bundleLibRuntimeToJarDebug UP-TO-DATE +> Task :jmods:core-network:bundleLibRuntimeToJarDebug UP-TO-DATE +> Task :jmods:core-navigation:checkKotlinGradlePluginConfigurationErrors SKIPPED +> Task :jmods:core-navigation:compileDebugKotlin UP-TO-DATE +> Task :jmods:core-navigation:javaPreCompileDebug UP-TO-DATE +> Task :jmods:core-navigation:compileDebugJavaWithJavac NO-SOURCE +> Task :jmods:core-navigation:bundleLibCompileToJarDebug UP-TO-DATE +> Task :jmods:core-ui:checkKotlinGradlePluginConfigurationErrors SKIPPED +> Task :jmods:core-ui:compileDebugKotlin UP-TO-DATE +> Task :jmods:core-ui:javaPreCompileDebug UP-TO-DATE +> Task :jmods:core-ui:compileDebugJavaWithJavac NO-SOURCE +> Task :jmods:core-ui:bundleLibCompileToJarDebug UP-TO-DATE +> Task :jmods:core-navigation:bundleLibRuntimeToJarDebug UP-TO-DATE +> Task :jmods:core-ui:bundleLibRuntimeToJarDebug UP-TO-DATE +> Task :jmods:feature-categories:checkKotlinGradlePluginConfigurationErrors SKIPPED +> Task :jmods:feature-categories:kspDebugKotlin UP-TO-DATE +> Task :jmods:feature-categories:compileDebugKotlin UP-TO-DATE +> Task :jmods:feature-categories:javaPreCompileDebug UP-TO-DATE +> Task :jmods:feature-categories:compileDebugJavaWithJavac UP-TO-DATE +> Task :jmods:feature-categories:transformDebugClassesWithAsm UP-TO-DATE +> Task :jmods:feature-categories:bundleLibCompileToJarDebug UP-TO-DATE +> Task :jmods:core-installer:checkKotlinGradlePluginConfigurationErrors SKIPPED +> Task :jmods:core-installer:kspDebugKotlin UP-TO-DATE +> Task :jmods:core-installer:compileDebugKotlin UP-TO-DATE +> Task :jmods:core-installer:javaPreCompileDebug UP-TO-DATE +> Task :jmods:core-installer:compileDebugJavaWithJavac UP-TO-DATE +> Task :jmods:core-installer:transformDebugClassesWithAsm UP-TO-DATE +> Task :jmods:core-installer:bundleLibCompileToJarDebug UP-TO-DATE +> Task :jmods:core-installer:bundleLibRuntimeToJarDebug UP-TO-DATE +> Task :jmods:feature-details:checkKotlinGradlePluginConfigurationErrors SKIPPED +> Task :jmods:feature-details:javaPreCompileDebug UP-TO-DATE +> Task :jmods:feature-home:checkKotlinGradlePluginConfigurationErrors SKIPPED +> Task :jmods:feature-home:kspDebugKotlin UP-TO-DATE +> Task :jmods:feature-home:compileDebugKotlin UP-TO-DATE +> Task :jmods:feature-home:javaPreCompileDebug UP-TO-DATE +> Task :jmods:feature-home:compileDebugJavaWithJavac UP-TO-DATE +> Task :jmods:feature-home:transformDebugClassesWithAsm UP-TO-DATE +> Task :jmods:feature-home:bundleLibCompileToJarDebug UP-TO-DATE +> Task :jmods:feature-search:checkKotlinGradlePluginConfigurationErrors SKIPPED +> Task :jmods:feature-search:kspDebugKotlin UP-TO-DATE +> Task :jmods:feature-search:compileDebugKotlin UP-TO-DATE +> Task :jmods:feature-search:javaPreCompileDebug UP-TO-DATE +> Task :jmods:feature-search:compileDebugJavaWithJavac UP-TO-DATE +> Task :jmods:feature-search:transformDebugClassesWithAsm UP-TO-DATE +> Task :jmods:feature-search:bundleLibCompileToJarDebug UP-TO-DATE +> Task :jmods:feature-updates:checkKotlinGradlePluginConfigurationErrors SKIPPED +> Task :jmods:feature-updates:javaPreCompileDebug UP-TO-DATE +> Task :jmods:app:javaPreCompileDebug UP-TO-DATE +> Task :jmods:app:mergeDebugShaders UP-TO-DATE +> Task :jmods:app:compileDebugShaders NO-SOURCE +> Task :jmods:app:generateDebugAssets UP-TO-DATE +> Task :jmods:core-auth:mergeDebugShaders UP-TO-DATE +> Task :jmods:core-auth:compileDebugShaders NO-SOURCE +> Task :jmods:core-auth:generateDebugAssets UP-TO-DATE +> Task :jmods:core-auth:packageDebugAssets UP-TO-DATE +> Task :jmods:core-data:mergeDebugShaders UP-TO-DATE +> Task :jmods:core-data:compileDebugShaders NO-SOURCE +> Task :jmods:core-data:generateDebugAssets UP-TO-DATE +> Task :jmods:core-data:packageDebugAssets UP-TO-DATE +> Task :jmods:core-database:mergeDebugShaders UP-TO-DATE +> Task :jmods:core-database:compileDebugShaders NO-SOURCE +> Task :jmods:core-database:generateDebugAssets UP-TO-DATE +> Task :jmods:core-database:packageDebugAssets UP-TO-DATE +> Task :jmods:core-domain:mergeDebugShaders UP-TO-DATE +> Task :jmods:core-domain:compileDebugShaders NO-SOURCE +> Task :jmods:core-domain:generateDebugAssets UP-TO-DATE +> Task :jmods:core-domain:packageDebugAssets UP-TO-DATE +> Task :jmods:core-installer:mergeDebugShaders UP-TO-DATE +> Task :jmods:core-installer:compileDebugShaders NO-SOURCE +> Task :jmods:core-installer:generateDebugAssets UP-TO-DATE +> Task :jmods:core-installer:packageDebugAssets UP-TO-DATE +> Task :jmods:core-navigation:mergeDebugShaders UP-TO-DATE +> Task :jmods:core-navigation:compileDebugShaders NO-SOURCE +> Task :jmods:core-navigation:generateDebugAssets UP-TO-DATE +> Task :jmods:core-navigation:packageDebugAssets UP-TO-DATE +> Task :jmods:core-network:mergeDebugShaders UP-TO-DATE +> Task :jmods:core-network:compileDebugShaders NO-SOURCE +> Task :jmods:core-network:generateDebugAssets UP-TO-DATE +> Task :jmods:core-network:packageDebugAssets UP-TO-DATE +> Task :jmods:core-ui:mergeDebugShaders UP-TO-DATE +> Task :jmods:core-ui:compileDebugShaders NO-SOURCE +> Task :jmods:core-ui:generateDebugAssets UP-TO-DATE +> Task :jmods:core-ui:packageDebugAssets UP-TO-DATE +> Task :jmods:feature-categories:mergeDebugShaders UP-TO-DATE +> Task :jmods:feature-categories:compileDebugShaders NO-SOURCE +> Task :jmods:feature-categories:generateDebugAssets UP-TO-DATE +> Task :jmods:feature-categories:packageDebugAssets UP-TO-DATE +> Task :jmods:feature-details:mergeDebugShaders UP-TO-DATE +> Task :jmods:feature-details:compileDebugShaders NO-SOURCE +> Task :jmods:feature-details:generateDebugAssets UP-TO-DATE +> Task :jmods:feature-details:packageDebugAssets UP-TO-DATE +> Task :jmods:feature-home:mergeDebugShaders UP-TO-DATE +> Task :jmods:feature-home:compileDebugShaders NO-SOURCE +> Task :jmods:feature-home:generateDebugAssets UP-TO-DATE +> Task :jmods:feature-home:packageDebugAssets UP-TO-DATE +> Task :jmods:feature-search:mergeDebugShaders UP-TO-DATE +> Task :jmods:feature-search:compileDebugShaders NO-SOURCE +> Task :jmods:feature-search:generateDebugAssets UP-TO-DATE +> Task :jmods:feature-search:packageDebugAssets UP-TO-DATE +> Task :jmods:feature-updates:mergeDebugShaders UP-TO-DATE +> Task :jmods:feature-updates:compileDebugShaders NO-SOURCE +> Task :jmods:feature-updates:generateDebugAssets UP-TO-DATE +> Task :jmods:feature-updates:packageDebugAssets UP-TO-DATE +> Task :jmods:app:mergeDebugAssets UP-TO-DATE +> Task :jmods:app:compressDebugAssets UP-TO-DATE +> Task :jmods:feature-home:bundleLibRuntimeToJarDebug UP-TO-DATE +> Task :jmods:feature-categories:bundleLibRuntimeToJarDebug UP-TO-DATE +> Task :jmods:feature-search:bundleLibRuntimeToJarDebug UP-TO-DATE +> Task :jmods:app:desugarDebugFileDependencies UP-TO-DATE +> Task :jmods:core-auth:processDebugJavaRes UP-TO-DATE +> Task :jmods:core-database:processDebugJavaRes UP-TO-DATE +> Task :jmods:core-domain:processDebugJavaRes UP-TO-DATE +> Task :jmods:core-installer:processDebugJavaRes UP-TO-DATE +> Task :jmods:core-navigation:processDebugJavaRes UP-TO-DATE +> Task :jmods:core-network:processDebugJavaRes UP-TO-DATE +> Task :jmods:core-ui:processDebugJavaRes UP-TO-DATE +> Task :jmods:feature-categories:processDebugJavaRes UP-TO-DATE +> Task :jmods:feature-home:processDebugJavaRes UP-TO-DATE +> Task :jmods:feature-search:processDebugJavaRes UP-TO-DATE +> Task :jmods:app:checkDebugDuplicateClasses UP-TO-DATE +> Task :jmods:app:mergeExtDexDebug UP-TO-DATE +> Task :jmods:core-network:bundleLibRuntimeToDirDebug UP-TO-DATE +> Task :jmods:feature-home:bundleLibRuntimeToDirDebug UP-TO-DATE +> Task :jmods:feature-categories:bundleLibRuntimeToDirDebug UP-TO-DATE +> Task :jmods:feature-search:bundleLibRuntimeToDirDebug UP-TO-DATE +> Task :jmods:core-ui:bundleLibRuntimeToDirDebug UP-TO-DATE +> Task :jmods:core-auth:bundleLibRuntimeToDirDebug UP-TO-DATE +> Task :jmods:core-installer:bundleLibRuntimeToDirDebug UP-TO-DATE +> Task :jmods:core-domain:bundleLibRuntimeToDirDebug UP-TO-DATE +> Task :jmods:core-navigation:bundleLibRuntimeToDirDebug UP-TO-DATE +> Task :jmods:core-database:bundleLibRuntimeToDirDebug UP-TO-DATE +> Task :jmods:app:mergeDebugJniLibFolders UP-TO-DATE +> Task :jmods:core-auth:mergeDebugJniLibFolders UP-TO-DATE +> Task :jmods:core-auth:mergeDebugNativeLibs NO-SOURCE +> Task :jmods:core-auth:copyDebugJniLibsProjectOnly UP-TO-DATE +> Task :jmods:core-data:mergeDebugJniLibFolders UP-TO-DATE +> Task :jmods:core-data:mergeDebugNativeLibs NO-SOURCE +> Task :jmods:core-data:copyDebugJniLibsProjectOnly UP-TO-DATE +> Task :jmods:core-database:mergeDebugJniLibFolders UP-TO-DATE +> Task :jmods:core-database:mergeDebugNativeLibs NO-SOURCE +> Task :jmods:core-database:copyDebugJniLibsProjectOnly UP-TO-DATE +> Task :jmods:core-domain:mergeDebugJniLibFolders UP-TO-DATE +> Task :jmods:core-domain:mergeDebugNativeLibs NO-SOURCE +> Task :jmods:core-domain:copyDebugJniLibsProjectOnly UP-TO-DATE +> Task :jmods:core-installer:mergeDebugJniLibFolders UP-TO-DATE +> Task :jmods:core-installer:mergeDebugNativeLibs NO-SOURCE +> Task :jmods:core-installer:copyDebugJniLibsProjectOnly UP-TO-DATE +> Task :jmods:core-navigation:mergeDebugJniLibFolders UP-TO-DATE +> Task :jmods:core-navigation:mergeDebugNativeLibs NO-SOURCE +> Task :jmods:core-navigation:copyDebugJniLibsProjectOnly UP-TO-DATE +> Task :jmods:core-network:mergeDebugJniLibFolders UP-TO-DATE +> Task :jmods:core-network:mergeDebugNativeLibs NO-SOURCE +> Task :jmods:core-network:copyDebugJniLibsProjectOnly UP-TO-DATE +> Task :jmods:core-ui:mergeDebugJniLibFolders UP-TO-DATE +> Task :jmods:core-ui:mergeDebugNativeLibs NO-SOURCE +> Task :jmods:core-ui:copyDebugJniLibsProjectOnly UP-TO-DATE +> Task :jmods:feature-categories:mergeDebugJniLibFolders UP-TO-DATE +> Task :jmods:feature-categories:mergeDebugNativeLibs NO-SOURCE +> Task :jmods:feature-categories:copyDebugJniLibsProjectOnly UP-TO-DATE +> Task :jmods:feature-details:mergeDebugJniLibFolders UP-TO-DATE +> Task :jmods:feature-details:mergeDebugNativeLibs NO-SOURCE +> Task :jmods:feature-details:copyDebugJniLibsProjectOnly UP-TO-DATE +> Task :jmods:feature-home:mergeDebugJniLibFolders UP-TO-DATE +> Task :jmods:feature-home:mergeDebugNativeLibs NO-SOURCE +> Task :jmods:feature-home:copyDebugJniLibsProjectOnly UP-TO-DATE +> Task :jmods:feature-search:mergeDebugJniLibFolders UP-TO-DATE +> Task :jmods:feature-search:mergeDebugNativeLibs NO-SOURCE +> Task :jmods:feature-search:copyDebugJniLibsProjectOnly UP-TO-DATE +> Task :jmods:feature-updates:mergeDebugJniLibFolders UP-TO-DATE +> Task :jmods:feature-updates:mergeDebugNativeLibs NO-SOURCE +> Task :jmods:feature-updates:copyDebugJniLibsProjectOnly UP-TO-DATE +> Task :jmods:app:mergeDebugNativeLibs UP-TO-DATE +> Task :jmods:app:stripDebugDebugSymbols UP-TO-DATE +> Task :jmods:app:validateSigningDebug UP-TO-DATE +> Task :jmods:app:writeDebugAppMetadata UP-TO-DATE +> Task :jmods:app:writeDebugSigningConfigVersions UP-TO-DATE + +> Task :jmods:core-data:compileDebugKotlin FAILED +e: file:///app/jmods-android/core-data/src/main/kotlin/com/jmods/data/repository/AppRepositoryImpl.kt:49:13 Unresolved reference 'searchApps'. +e: file:///app/jmods-android/core-data/src/main/kotlin/com/jmods/data/repository/AppRepositoryImpl.kt:49:41 Cannot infer type for this parameter. Please specify it explicitly. +e: file:///app/jmods-android/core-data/src/main/kotlin/com/jmods/data/repository/AppRepositoryImpl.kt:50:13 Suspension functions can only be called within coroutine body. +e: file:///app/jmods-android/core-data/src/main/kotlin/com/jmods/data/repository/AppRepositoryImpl.kt:50:18 Argument type mismatch: actual type is 'kotlinx.coroutines.flow.Flow', but 'kotlin.collections.List' was expected. +e: file:///app/jmods-android/core-data/src/main/kotlin/com/jmods/data/repository/AppRepositoryImpl.kt:50:23 Cannot infer type for this parameter. Please specify it explicitly. +e: file:///app/jmods-android/core-data/src/main/kotlin/com/jmods/data/repository/AppRepositoryImpl.kt:50:27 Cannot infer type for this parameter. Please specify it explicitly. +e: file:///app/jmods-android/core-data/src/main/kotlin/com/jmods/data/repository/AppRepositoryImpl.kt:65:51 Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type 'android.content.pm.ApplicationInfo?'. +e: file:///app/jmods-android/core-data/src/main/kotlin/com/jmods/data/repository/AppRepositoryImpl.kt:82:29 Unresolved reference 'versionCode'. + +[Incubating] Problems report is available at: file:///app/build/reports/problems/problems-report.html + +FAILURE: Build failed with an exception. + +* What went wrong: +Execution failed for task ':jmods:core-data:compileDebugKotlin'. +> A failure occurred while executing org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction + > Compilation error. See log for more details + +* Try: +> Run with --stacktrace option to get the stack trace. +> Run with --info or --debug option to get more log output. +> Run with --scan to get full insights. +> Get more help at https://help.gradle.org. + +Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0. + +You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins. + +For more on this, please refer to https://docs.gradle.org/8.12/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. + +BUILD FAILED in 7s +281 actionable tasks: 1 executed, 280 up-to-date diff --git a/components/app-card.tsx b/components/app-card.tsx new file mode 100644 index 000000000..fa979abcc --- /dev/null +++ b/components/app-card.tsx @@ -0,0 +1,99 @@ +import Link from 'next/link' +import Image from 'next/image' +import { Star, GitBranch } from 'lucide-react' +import type { App } from '@/lib/types' +import { formatRatingCount } from '@/lib/format' +import { CategoryBadge } from './category-badge' + +interface AppCardProps { + app: App + variant?: 'grid' | 'row' +} + +export function AppCard({ app, variant = 'grid' }: AppCardProps) { + if (variant === 'row') { + return ( + +
+ {`${app.name} +
+
+
+

+ {app.name} +

+ {app.isOpenSource && ( + + )} +
+

{app.developer}

+
+
+
+
+ +
+ + ) + } + + return ( + +
+
+ {`${app.name} +
+
+
+

+ {app.name} +

+ {app.isOpenSource && ( + + )} +
+

{app.developer}

+ +
+
+ +

+ {app.shortDescription} +

+ +
+
+
+ {app.downloads} +
+ + ) +} diff --git a/components/app-carousel.tsx b/components/app-carousel.tsx new file mode 100644 index 000000000..b4aeab949 --- /dev/null +++ b/components/app-carousel.tsx @@ -0,0 +1,20 @@ +'use client' + +import type { App } from '@/lib/types' +import { AppCard } from './app-card' + +interface AppCarouselProps { + apps: App[] +} + +export function AppCarousel({ apps }: AppCarouselProps) { + return ( +
+ {apps.map((app) => ( +
+ +
+ ))} +
+ ) +} diff --git a/components/bottom-nav.tsx b/components/bottom-nav.tsx new file mode 100644 index 000000000..adeff9262 --- /dev/null +++ b/components/bottom-nav.tsx @@ -0,0 +1,121 @@ +'use client' + +import Link from 'next/link' +import { usePathname, useRouter, useSearchParams } from 'next/navigation' +import { Home, Search, Download, RefreshCcw, LayoutGrid } from 'lucide-react' +import { useState, useEffect, Suspense } from 'react' +import { cn } from '@/lib/utils' + +function BottomNavContent() { + const pathname = usePathname() + const searchParams = useSearchParams() + const router = useRouter() + const [query, setQuery] = useState(searchParams.get('q') ?? '') + const [searchOpen, setSearchOpen] = useState(false) + + // Keep search input in sync with URL + useEffect(() => { + setQuery(searchParams.get('q') ?? '') + }, [searchParams]) + + function handleSearchSubmit(e: React.FormEvent) { + e.preventDefault() + const trimmed = query.trim() + setSearchOpen(false) + if (trimmed) { + router.push(`/?q=${encodeURIComponent(trimmed)}`) + } else { + router.push('/') + } + } + + const navItems = [ + { label: 'Browse', href: '/', icon: Home }, + { label: 'Categories', href: '/categories', icon: LayoutGrid }, + { label: 'Updates', href: '/updates', icon: RefreshCcw }, + { label: 'Downloads', href: '/downloads', icon: Download }, + ] + + return ( + <> + {/* Inline search drawer */} + {searchOpen && ( +
+
+ + setQuery(e.target.value)} + className="h-11 flex-1 rounded-lg border border-gray-200 bg-gray-50 px-4 text-sm text-gray-900 placeholder:text-gray-500 focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500" + /> + +
+
+ )} + + {/* Bottom tab bar */} + + + ) +} + +export function BottomNav() { + return ( + + + + ) +} diff --git a/components/category-badge.tsx b/components/category-badge.tsx new file mode 100644 index 000000000..14ed92bd8 --- /dev/null +++ b/components/category-badge.tsx @@ -0,0 +1,34 @@ +import { cn } from '@/lib/utils' +import type { AppCategory } from '@/lib/types' + +const CATEGORY_STYLES: Record = { + Productivity: 'bg-blue-500/10 text-blue-400 border-blue-500/20', + Social: 'bg-blue-500/10 text-blue-400 border-blue-500/20', + Games: 'bg-orange-500/10 text-orange-400 border-orange-500/20', + Tools: 'bg-slate-500/10 text-slate-400 border-slate-500/20', + Media: 'bg-rose-500/10 text-rose-400 border-rose-500/20', + Security: 'bg-green-500/10 text-green-400 border-green-500/20', + Finance: 'bg-yellow-500/10 text-yellow-400 border-yellow-500/20', + Health: 'bg-emerald-500/10 text-emerald-400 border-emerald-500/20', +} + +interface CategoryBadgeProps { + category: AppCategory + size?: 'xs' | 'sm' + className?: string +} + +export function CategoryBadge({ category, size = 'sm', className }: CategoryBadgeProps) { + return ( + + {category} + + ) +} diff --git a/components/home/app-grid-section.tsx b/components/home/app-grid-section.tsx new file mode 100644 index 000000000..bf38b28d6 --- /dev/null +++ b/components/home/app-grid-section.tsx @@ -0,0 +1,62 @@ +'use client' + +import { useId } from 'react' +import type { App } from '@/lib/types' +import { AppCard } from '@/components/app-card' +import { AppCarousel } from '@/components/app-carousel' +import { Empty } from '@/components/ui/empty' +import { Search } from 'lucide-react' + +interface AppGridSectionProps { + apps: App[] + title: string + description?: string + variant?: 'grid' | 'row' | 'carousel' +} + +export function AppGridSection({ apps, title, description, variant = 'grid' }: AppGridSectionProps) { + const headingId = useId() + + return ( +
+
+

+ {title} +

+ {apps.length > 0 && ( + + )} +
+ {description && ( +

{description}

+ )} + + {apps.length === 0 ? ( + } + /> + ) : variant === 'carousel' ? ( + + ) : variant === 'grid' ? ( +
+ {apps.map((app) => ( + + ))} +
+ ) : ( +
+ {apps.map((app) => ( + + ))} +
+ )} +
+ ) +} diff --git a/components/home/featured-banner.tsx b/components/home/featured-banner.tsx new file mode 100644 index 000000000..2ac71056a --- /dev/null +++ b/components/home/featured-banner.tsx @@ -0,0 +1,57 @@ +import Link from 'next/link' +import Image from 'next/image' +import { ArrowRight } from 'lucide-react' +import type { App } from '@/lib/types' +import { CategoryBadge } from '@/components/category-badge' +import { StarRating } from '@/components/star-rating' + +interface FeaturedBannerProps { + app: App +} + +export function FeaturedBanner({ app }: FeaturedBannerProps) { + return ( + +
+ {`${app.name} +
+
+ +
+
+ {`${app.name} +
+ +
+
+

+ {app.name} +

+
+

{app.developer}

+
+ +
+ + + +
+
+ + ) +} diff --git a/components/home/search-hero.tsx b/components/home/search-hero.tsx new file mode 100644 index 000000000..f87ca60c6 --- /dev/null +++ b/components/home/search-hero.tsx @@ -0,0 +1,67 @@ +'use client' + +import { useRouter } from 'next/navigation' +import { ALL_CATEGORIES } from '@/lib/mock-data' + +interface SearchHeroProps { + initialQuery?: string + activeCategory?: string +} + +export function SearchHero({ initialQuery, activeCategory }: SearchHeroProps) { + const router = useRouter() + const isFiltering = Boolean(initialQuery || activeCategory) + + function handleCategory(cat: string) { + router.push(`/?category=${encodeURIComponent(cat)}`) + } + + return ( +
+
+ {isFiltering ? ( +

+ Showing results for{' '} + + {initialQuery ?? activeCategory} + + {' · '} + +

+ ) : ( + <> +

+ Open-source Android apps,{' '} + without the tracking +

+

+ Browse, search, and install apps privately. No account required. +

+ + )} + +
+ {ALL_CATEGORIES.map((cat) => ( + + ))} +
+
+
+ ) +} diff --git a/components/navbar.tsx b/components/navbar.tsx new file mode 100644 index 000000000..0134a6e66 --- /dev/null +++ b/components/navbar.tsx @@ -0,0 +1,85 @@ +'use client' + +import Link from 'next/link' +import { useState, useEffect, Suspense } from 'react' +import { Search, Shield } from 'lucide-react' +import { useRouter, useSearchParams } from 'next/navigation' + +function NavbarContent() { + const searchParams = useSearchParams() + const [query, setQuery] = useState(searchParams.get('q') ?? '') + const router = useRouter() + + useEffect(() => { + setQuery(searchParams.get('q') ?? '') + }, [searchParams]) + + function handleSearch(e: React.FormEvent) { + e.preventDefault() + if (query.trim()) { + router.push(`/?q=${encodeURIComponent(query.trim())}`) + } + } + + return ( +
+
+
+ +
+
+ + J MODS + + + +
+ +
+
+
+ ) +} + +export function Navbar() { + return ( + }> + + + ) +} diff --git a/components/star-rating.tsx b/components/star-rating.tsx new file mode 100644 index 000000000..4f2c3d382 --- /dev/null +++ b/components/star-rating.tsx @@ -0,0 +1,32 @@ +import { Star } from 'lucide-react' +import { cn } from '@/lib/utils' + +interface StarRatingProps { + value: number + max?: number + className?: string +} + +export function StarRating({ value, max = 5, className }: StarRatingProps) { + return ( + + {Array.from({ length: max }).map((_, i) => { + const filled = i < Math.floor(value) + const partial = !filled && i < value + return ( + + + ) + })} + + ) +} diff --git a/components/ui/drawer.tsx b/components/ui/drawer.tsx new file mode 100644 index 000000000..d0392579e --- /dev/null +++ b/components/ui/drawer.tsx @@ -0,0 +1,65 @@ +'use client' + +import * as React from 'react' +import { useEffect } from 'react' +import { cn } from '@/lib/utils' +import { X } from 'lucide-react' + +interface DrawerProps { + isOpen: boolean + onClose: () => void + title?: string + children: React.ReactNode +} + +export function Drawer({ isOpen, onClose, title, children }: DrawerProps) { + useEffect(() => { + if (isOpen) { + document.body.style.overflow = 'hidden' + } else { + document.body.style.overflow = '' + } + return () => { + document.body.style.overflow = '' + } + }, [isOpen]) + + if (!isOpen) return null + + return ( +
+ {/* Overlay */} +
+ + {/* Content */} +
+ {/* Handle for mobile */} +
+
+
+ +
+
+
+

{title}

+
+
+ +
+ +
+ {children} +
+
+
+
+ ) +} diff --git a/components/ui/empty.tsx b/components/ui/empty.tsx new file mode 100644 index 000000000..f13bcbeae --- /dev/null +++ b/components/ui/empty.tsx @@ -0,0 +1,11 @@ +import { ReactNode } from "react"; + +export function Empty({ title, description, icon }: { title: string, description: string, icon: ReactNode }) { + return ( +
+
{icon}
+

{title}

+

{description}

+
+ ); +} diff --git a/components/ui/player.tsx b/components/ui/player.tsx new file mode 100644 index 000000000..8beee206c --- /dev/null +++ b/components/ui/player.tsx @@ -0,0 +1,84 @@ +'use client' + +import * as React from 'react' +import { useState, useEffect } from 'react' +import { Play, Pause, SkipForward, SkipBack, X, Maximize2, Volume2 } from 'lucide-react' +import { cn } from '@/lib/utils' + +interface PlayerProps { + title: string + subtitle?: string + isOpen: boolean + onClose: () => void +} + +export function Player({ title, subtitle, isOpen, onClose }: PlayerProps) { + const [isPlaying, setIsPlaying] = useState(false) + const [progress, setProgress] = useState(35) + + if (!isOpen) return null + + return ( +
+
+ {/* Progress bar with glow */} +
+
+
+ +
+
+
+

{title}

+ {subtitle && ( +
+ +

{subtitle}

+
+ )} +
+
+ + +
+
+ +
+
+ + + +
+ +
+ +
+
+
+
+
+
+
+
+ ) +} diff --git a/fastlane/metadata/android/ar/changelogs/66.txt b/fastlane/metadata/android/ar/changelogs/66.txt deleted file mode 100644 index e14097010..000000000 --- a/fastlane/metadata/android/ar/changelogs/66.txt +++ /dev/null @@ -1,5 +0,0 @@ -• تصنيفات توافق التطبيق الجديدة مدعومة ب Plexus -• تحسينات على مدير القائمة السوداء -• القدرة على تغيير قيود التحديث التلقائي -• إصلاحات الأخطاء الطفيفة والتحسينات -• تحديثات الترجمة؛ سلاسل إضافية ترجمت diff --git a/fastlane/metadata/android/ar/changelogs/67.txt b/fastlane/metadata/android/ar/changelogs/67.txt deleted file mode 100644 index 7ae1b672c..000000000 --- a/fastlane/metadata/android/ar/changelogs/67.txt +++ /dev/null @@ -1,4 +0,0 @@ -• يستهدف أندرويد 16 -• إصلاح خطأ في فتح الروابط للتطبيقات -• دعم فتح صفحة تفاصيل التطبيق من إعدادات معلومات التطبيق -• تحديثات الترجمة diff --git a/fastlane/metadata/android/ar/changelogs/68.txt b/fastlane/metadata/android/ar/changelogs/68.txt deleted file mode 100644 index 76b5f8761..000000000 --- a/fastlane/metadata/android/ar/changelogs/68.txt +++ /dev/null @@ -1,5 +0,0 @@ -• التبديل إلى واجهات برمجة التطبيقات الجديدة للبحث وتثبيت التطبيقات -• تصفية البحث لم يعد متاحًا، وسيتم إضافته لاحقًا -• إصلاح تعطل عند الانتقال إلى صفحة تفاصيل التطبيق -• إصلاح تعطل عند تزوير الإعدادات الإقليمية -• تحديثات الترجمة diff --git a/fastlane/metadata/android/ar/changelogs/71.txt b/fastlane/metadata/android/ar/changelogs/71.txt deleted file mode 100644 index 4251d17d2..000000000 --- a/fastlane/metadata/android/ar/changelogs/71.txt +++ /dev/null @@ -1,2 +0,0 @@ -• إصلاح مشكلة تثبيت التطبيق على أجهزة هواوي -• تحديثات الترجمة diff --git a/fastlane/metadata/android/ar/changelogs/72.txt b/fastlane/metadata/android/ar/changelogs/72.txt deleted file mode 100644 index 6da45d18c..000000000 --- a/fastlane/metadata/android/ar/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• الحد الأدنى لإصدار أندرويد المدعوم هو الآن أندرويد 6.0 -• بُدّل إلى سمة Material3 Expressive -• دعم محسّن للأجهزة ذات الشاشات العريضة -• تم إصلاح مشكلة عدم تعيين اللغة العبرية بشكل صحيح مع اللغة لكل تطبيق -• استعادة وظيفة تصفيات البحث diff --git a/fastlane/metadata/android/ar/changelogs/73.txt b/fastlane/metadata/android/ar/changelogs/73.txt deleted file mode 100644 index d94b94882..000000000 --- a/fastlane/metadata/android/ar/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• تم إصلاح أيقونة مؤشر السهم الخاطئة للترقية في تخطيطات النصوص من اليمين لليسار -• تم إصلاح مشاكل التقسيم إلى صفحات وواجهة إدخال النصوص في البحث -• تم إصلاح خلل كان يتجاوز اختيار المستخدم للمثبت -• تم تحديث الترجمات، وقاعدة بيانات متتبعات exodus، وشهادات جذر Google diff --git a/fastlane/metadata/android/ar/full_description.txt b/fastlane/metadata/android/ar/full_description.txt index 5181733a0..e94d2b62f 100644 --- a/fastlane/metadata/android/ar/full_description.txt +++ b/fastlane/metadata/android/ar/full_description.txt @@ -1,4 +1,6 @@ -Aurora Store هو عميل FOSS غير رسمي لـ Google Play بتصميم أنيق. متجر أورورا يتيح للمستخدمين تنزيل التطبيقات وتحديثها والبحث عنها مثل متجر Play. أنه يعمل بشكل جيد تماما مع أو بدون خدمات Google Play أو microG. +Aurora Store هو عميل FOSS غير رسمي لـ Google Play بتصميم أنيق. متجر أورورا +يتيح للمستخدمين تنزيل التطبيقات وتحديثها والبحث عنها مثل متجر Play. أنه يعمل بشكل جيد تماما +مع أو بدون خدمات Google Play أو MicroG. الميزات: @@ -7,5 +9,4 @@ Aurora Store هو عميل FOSS غير رسمي لـ Google Play بتصميم أ • تسجيل الدخول إلى الحساب: يمكنك تسجيل الدخول باستخدام حساب شخصي أو مجهول • انتحال الجهاز واللغة: قم بتغيير جهازك و/أو اللغة للوصول إلى التطبيقات المقفلة جغرافيًا • التكامل مع Exodus Privacy: رؤية أجهزة التتبع في التطبيق على الفور -• تكامل Plexus: انظر على الفور توافق التطبيق دون خدمات تشغيل Google أو مع microG • تحديثات القائمة السوداء: تجاهل التحديثات لتطبيقات معينة diff --git a/fastlane/metadata/android/ca/changelogs/72.txt b/fastlane/metadata/android/ca/changelogs/72.txt deleted file mode 100644 index bb9e1e4f9..000000000 --- a/fastlane/metadata/android/ca/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Ara la versió mínima suportada es Android 6.0 -• S'ha migrat al tema Material3 Expressive -• S'ha millor el suport de pantalles ultraamples -• S'ha arreglat un problema en el que l'idioma hebreu no s'aplicava correctament a les aplicacions -• S'ha restaurat el funcionament dels filtres de cerca diff --git a/fastlane/metadata/android/ca/full_description.txt b/fastlane/metadata/android/ca/full_description.txt deleted file mode 100644 index 05c78dfa8..000000000 --- a/fastlane/metadata/android/ca/full_description.txt +++ /dev/null @@ -1,11 +0,0 @@ -L'Aurora Store es un client no oficial i de codi obert per a Google Play amb un disseny elegant. L'Aurora Store permet als usuaris baixar, actualitzar i cercar aplicacions com la Play Store. Funciona perfectamente amb/sense els serveis de Google Play o microG. - -Features: - -• Lliure i de codi obert: Amb llicència GPLv3 -• Disseny preciós: Construït seguint les últimes directrius de Material 3 -• Inici de sessió: Pots iniciar sessió amb un compte personal o anònimament -• Suplantació de dispositiu i localització: Canvia el teu dispositiu i la localització per accedir aplicacions restringides -• Integració amb Exodus Privacy: Consulta els rastrejadors en la pàgina de l'aplicació -• Integració amb Plexus: Consulta la compatibilitat sense serveis de Google Play o amb microG -• Llista negra d'actualitzacions: Ignora les actualitzacions d'aplicacions específiques diff --git a/fastlane/metadata/android/ca/short_description.txt b/fastlane/metadata/android/ca/short_description.txt deleted file mode 100644 index c9d7796bd..000000000 --- a/fastlane/metadata/android/ca/short_description.txt +++ /dev/null @@ -1 +0,0 @@ -Client de codi obert per a Google Play amb un disseny elegant i privacitat diff --git a/fastlane/metadata/android/cs-CZ/changelogs/66.txt b/fastlane/metadata/android/cs-CZ/changelogs/66.txt deleted file mode 100644 index b3ed029f3..000000000 --- a/fastlane/metadata/android/cs-CZ/changelogs/66.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Nové hodnocení kompatibility aplikací (využívá Plexus) -• Vylepšení správce blokovaných -• Možnost změny omezení automatických aktualizací -• Menší opravy chyb a vylepšení -• Aktualizace překladů; přeloženy další řetězce diff --git a/fastlane/metadata/android/cs-CZ/changelogs/67.txt b/fastlane/metadata/android/cs-CZ/changelogs/67.txt deleted file mode 100644 index cfadd9410..000000000 --- a/fastlane/metadata/android/cs-CZ/changelogs/67.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Cíl Android 16 -• Opravena chyba při otevírání odkazů do aplikací -• Podpora otevření stránky s podrobnostmi aplikace z informací o aplikaci -• Aktualizace překladů diff --git a/fastlane/metadata/android/cs-CZ/changelogs/68.txt b/fastlane/metadata/android/cs-CZ/changelogs/68.txt deleted file mode 100644 index c6d6d3eb6..000000000 --- a/fastlane/metadata/android/cs-CZ/changelogs/68.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Změna na nová rozhraní API pro hledání a instalaci aplikací -• Filtr vyhledávání již není dostupný, bude znovu přidán později -• Opraven pád při navigaci na podrobnosti aplikace -• Opraven pád při falšování místní předvolby -• Aktualizace překladů diff --git a/fastlane/metadata/android/cs-CZ/changelogs/71.txt b/fastlane/metadata/android/cs-CZ/changelogs/71.txt deleted file mode 100644 index e97323db2..000000000 --- a/fastlane/metadata/android/cs-CZ/changelogs/71.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Oprava problému s instalací aplikací na zařízeních Huawei -• Aktualizace překladů diff --git a/fastlane/metadata/android/cs-CZ/changelogs/72.txt b/fastlane/metadata/android/cs-CZ/changelogs/72.txt deleted file mode 100644 index c9a95633c..000000000 --- a/fastlane/metadata/android/cs-CZ/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Minimální podporovaná verze systému Android je nyní Android 6.0 -• Změna na motiv Material 3 Expressive -• Zlepšena podpora širokoúhlých zařízení -• Opraven problém, kdy nebyl hebrejský jazyk správně nastaven -• Obnovena funkcionalita filtrů vyhledávání diff --git a/fastlane/metadata/android/cs-CZ/changelogs/73.txt b/fastlane/metadata/android/cs-CZ/changelogs/73.txt deleted file mode 100644 index 4e4af869a..000000000 --- a/fastlane/metadata/android/cs-CZ/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Opraven nesprávná ikona indikátoru šipky u rozložení RTL -• Opraveny problémy se stránkováním a IME u vyhledávání -• Opravena chyba která přepsala uživatelský výběr instalátoru -• Aktualizovány překlady, databáze prvků Exodus a kořenové certifikáty Google diff --git a/fastlane/metadata/android/cs-CZ/full_description.txt b/fastlane/metadata/android/cs-CZ/full_description.txt index decc9b5b8..71dd5ee4b 100644 --- a/fastlane/metadata/android/cs-CZ/full_description.txt +++ b/fastlane/metadata/android/cs-CZ/full_description.txt @@ -1,4 +1,6 @@ -Aurora Store je neoficiální, svobodný a otevřený klient pro Google Play s elegantním designem. Aurora Store umožňuje uživatelům stahovat, aktualizovat a vyhledávat aplikace, stejně jako Obchod Play. Funguje bez problémů s i bez Služeb Google Play či microG. +Aurora Store je neoficiální, svobodný a otevřený klient pro Google Play s elegantním designem. Aurora Store +umožňuje uživatelům stahovat, aktualizovat a vyhledávat aplikace, stejně jako Obchod Play. Funguje bez problémů +s i bez Služeb Google Play či MicroG. Funkce: @@ -7,5 +9,4 @@ Aurora Store je neoficiální, svobodný a otevřený klient pro Google Play s e • Přihlášení k účtu: můžete se přihlásit buď s osobním, nebo s anonymním účtem • Spoofing zařízení a umístění: změňte své zařízení a/nebo umístění pro přístup k geograficky uzamčeným aplikacím • Integrace Exodus Privacy: okamžité zobrazení sledovacích prvků v aplikaci -• Integrace Plexus: okamžité zobrazení kompatibility aplikací bez Služeb Google Play nebo s microG • Zakázání aktualizací: ignorování aktualizací pro určité aplikace diff --git a/fastlane/metadata/android/da-DK/changelogs/41.txt b/fastlane/metadata/android/da-DK/changelogs/41.txt index e0600749c..07e8363d3 100644 --- a/fastlane/metadata/android/da-DK/changelogs/41.txt +++ b/fastlane/metadata/android/da-DK/changelogs/41.txt @@ -1 +1 @@ -• Hotfix - FC'er til nogle enheder +• Hotfix - FCer til nogle enheder diff --git a/fastlane/metadata/android/da-DK/changelogs/42.txt b/fastlane/metadata/android/da-DK/changelogs/42.txt deleted file mode 100644 index 184ddb3a0..000000000 --- a/fastlane/metadata/android/da-DK/changelogs/42.txt +++ /dev/null @@ -1,15 +0,0 @@ -• Målrettet Android 13 -• Aktivér lokalisering for flere strenge -• Tilføj monokromt ikon til Android 13 -• Opdater afhængigheder -• Vis servicevilkår ved opstart -• Tillad at fortsætte opsætning uden at give tilladelser -• Brug systemets XML-denyliste til udelukkelse af opdateringer -• Ret forkert titel på opsætningsside 5 -• Aktivér frem-knap, når du går tilbage i opsætning -• Erstat afkrydsningsfelter i opsætningen med radioknapper -• Brug stregfarve til baggrunde på opsætningsfaner -• Ret no-theme-fejl i opsætning med radioknapper -• Bloker nye GSF- og Vending-versioner -• Refaktorer opsætning af lagertilladelser -• Opdater oversættelser diff --git a/fastlane/metadata/android/da-DK/changelogs/43.txt b/fastlane/metadata/android/da-DK/changelogs/43.txt deleted file mode 100644 index ab28bbdbe..000000000 --- a/fastlane/metadata/android/da-DK/changelogs/43.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Aktivér altid afslut-knap på tilladelsesside (løser introduktion for nye brugere) -• Bevar GSON-bibliotekets TypeToken under build-optimering (løser opstartsnedbrud) diff --git a/fastlane/metadata/android/da-DK/changelogs/44.txt b/fastlane/metadata/android/da-DK/changelogs/44.txt deleted file mode 100644 index c9d5fcc58..000000000 --- a/fastlane/metadata/android/da-DK/changelogs/44.txt +++ /dev/null @@ -1,6 +0,0 @@ -• Ret nedbrud relateret til meddelelser fra installationsservice -• Vis kun gyldige forfalskningsegenskaber i appen -• Underret brugere, når deres søgehastighed begrænses -• Vis en flimrende animation under søgning for at angive fremgang -• Ret navigationens adfærd, når standardfanen ændres -• Ret hurtig afslut-mulighed diff --git a/fastlane/metadata/android/da-DK/changelogs/45.txt b/fastlane/metadata/android/da-DK/changelogs/45.txt deleted file mode 100644 index 830109496..000000000 --- a/fastlane/metadata/android/da-DK/changelogs/45.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Små fejlrettelser og forbedringer -• Opdater oversættelser diff --git a/fastlane/metadata/android/da-DK/changelogs/46.txt b/fastlane/metadata/android/da-DK/changelogs/46.txt deleted file mode 100644 index 1ceb5bcd7..000000000 --- a/fastlane/metadata/android/da-DK/changelogs/46.txt +++ /dev/null @@ -1,8 +0,0 @@ -• Undgå at bede om lagertilladelse, før det er nødvendigt -• Omdesign forfalskningskonfiguration for at undgå lagertilladelse ved import-eksport -• Tilføj mulighed for at søge efter app-opdateringer automatisk (kræver en aktiv konto) -• Ret fejl, hvor påkrævede biblioteker ikke blev installeret med apps som chrome- og trichrome-bibliotek -• Udelad downloads-mappen fra sikkerhedskopiering af Aurora Store -• Implementer Shizuku-installationsprogram (kræver Android 8.0+) -• Fjern understøttelse af Android 4.4 — Minimum er Android 5.0+ -• Små fejlrettelser og forbedringer diff --git a/fastlane/metadata/android/da-DK/changelogs/47.txt b/fastlane/metadata/android/da-DK/changelogs/47.txt deleted file mode 100644 index c1815f9b3..000000000 --- a/fastlane/metadata/android/da-DK/changelogs/47.txt +++ /dev/null @@ -1 +0,0 @@ -• Hotfix - Ret nedbrud på nogle skærme diff --git a/fastlane/metadata/android/da-DK/changelogs/48.txt b/fastlane/metadata/android/da-DK/changelogs/48.txt deleted file mode 100644 index 2fc9f62a8..000000000 --- a/fastlane/metadata/android/da-DK/changelogs/48.txt +++ /dev/null @@ -1,3 +0,0 @@ -• Store interne ændringer relateret til UI -• Opdater oversættelser -• Små fejlrettelser og forbedringer diff --git a/fastlane/metadata/android/da-DK/changelogs/49.txt b/fastlane/metadata/android/da-DK/changelogs/49.txt deleted file mode 100644 index 640a980f3..000000000 --- a/fastlane/metadata/android/da-DK/changelogs/49.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Store interne ændringer relateret til UI -• Tillad brugere at aktivere app-links under opsætning -• Opdater oversættelser -• Små fejlrettelser og forbedringer diff --git a/fastlane/metadata/android/da-DK/full_description.txt b/fastlane/metadata/android/da-DK/full_description.txt index 92495f90e..654f52e96 100644 --- a/fastlane/metadata/android/da-DK/full_description.txt +++ b/fastlane/metadata/android/da-DK/full_description.txt @@ -1,11 +1,10 @@ -Aurora Store er en uofficiel, FOSS klient for Google Play med et elegant design. Aurora Store tillader brugere at hente, -opdatere og søge efter apps som i Play Butik. Den virker helt fint med eller uden Google Play-Tjenester eller MicroG. +Aurora Store er en uofficiel FOSS klient for Google Play med et elegant design. I Aurora Store kan brugere hente, opdatere og søge efter apps som i Play Butik. Den virker helt fint med eller uden Google Play Services eller MicroG. Funktioner: • FOSS: Har GPLv3-licens • Smukt design: Bygget på de seneste Material 3-retningslinjer -• Konto log-in: Du kan enten logge ind med en personlig eller anonym konto -• Enheds- og lokalitetsforfalskning: Skift din enhed og/eller lokalitet for at få adgang til geo-låste apps -• Integration af Exodus Privacy: Se straks sporingselementer i appen -• Sortliste for opdateringer: Ignorér opdateringer til bestemte apps +• Konto-login: Du kan logge ind med en personlig eller anonym konto +• Enheds- og lokalitetsspoofing: Skift din enhed og/eller lokalitet for at få adgang til geo-låste apps +• Integration af Exodus Privacy: Se straks trackere i appen +• Sortliste for opdateringer: Ignorer opdateringer til bestemte apps diff --git a/fastlane/metadata/android/de-DE/changelogs/66.txt b/fastlane/metadata/android/de-DE/changelogs/66.txt deleted file mode 100644 index d2debef55..000000000 --- a/fastlane/metadata/android/de-DE/changelogs/66.txt +++ /dev/null @@ -1,5 +0,0 @@ -- Neue von Plexus unterstützte App-Kompatibilitätsbewertungen -- Verbesserungen an der Sperrlisten-Verwaltung -- Einschränkungen für automatische Updates können geändert werden -- Kleinere Fehlerbehebungen und Verbesserungen -- Übersetzungen aktualisiert; zusätzliche Zeichenketten lokalisiert diff --git a/fastlane/metadata/android/de-DE/changelogs/67.txt b/fastlane/metadata/android/de-DE/changelogs/67.txt deleted file mode 100644 index 941149964..000000000 --- a/fastlane/metadata/android/de-DE/changelogs/67.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Android 16 -• Fehler beim Öffnen von Links zu Apps behoben -• Unterstützung des Öffnens der App-Detailseite über die App-Info-Einstellungen -• Übersetzungen aktualisiert diff --git a/fastlane/metadata/android/de-DE/changelogs/68.txt b/fastlane/metadata/android/de-DE/changelogs/68.txt deleted file mode 100644 index d5b0e25bd..000000000 --- a/fastlane/metadata/android/de-DE/changelogs/68.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Umstellung auf neue APIs für die Suche und Installation von Apps -• Der Suchfilter ist aktuell nicht verfügbar, wird aber später wieder hinzugefügt -• Behebung eines Absturzes beim Navigieren zur App-Detailseite -• Behebung eines Absturzes beim Vortäuschen des Gebietsschemas -• Übersetzungen aktualisiert diff --git a/fastlane/metadata/android/de-DE/changelogs/72.txt b/fastlane/metadata/android/de-DE/changelogs/72.txt deleted file mode 100644 index 2f1b3256c..000000000 --- a/fastlane/metadata/android/de-DE/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Die minimal unterstützte Android-Version ist jetzt Android 6.0. -• Umstellung auf das Material3-Expressive-Design -• Verbesserte Unterstützung für Breitbildgeräte -• Behebung eines Problems, bei dem die hebräische Sprache in den Spracheinstellungen der App nicht richtig eingestellt war -• Wiederherstellung der Suchfilterfunktionalität diff --git a/fastlane/metadata/android/de-DE/changelogs/73.txt b/fastlane/metadata/android/de-DE/changelogs/73.txt deleted file mode 100644 index 3989695ea..000000000 --- a/fastlane/metadata/android/de-DE/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Fehlerhaftes Upgrade-Pfeilsymbol in RTL-Layouts behoben -• Probleme mit der Seitenanzeige und der Eingabemethode bei der Suche behoben -• Fehler behoben, der die Benutzerauswahl beim Installer überschrieb -• Übersetzungen, Exodus-Tracker-Datenbank und Google-Root-Zertifikate aktualisiert diff --git a/fastlane/metadata/android/de-DE/full_description.txt b/fastlane/metadata/android/de-DE/full_description.txt index 7a6b55ace..40be37160 100644 --- a/fastlane/metadata/android/de-DE/full_description.txt +++ b/fastlane/metadata/android/de-DE/full_description.txt @@ -1,4 +1,6 @@ -Aurora Store ist ein inoffizieller FOSS-Client für Google Play mit elegantem Design. Aurora Store ermöglicht Benutzern das Herunterladen, Aktualisieren und Suchen nach Apps wie dem Play Store. Es funktioniert einwandfrei mit oder ohne Google-Play-Dienste oder microG. +Aurora Store ist ein inoffizieller FOSS-Client für Google Play mit elegantem Design. Aurora Store +ermöglicht Benutzern das Herunterladen, Aktualisieren und Suchen nach Apps wie dem Play Store. Es funktioniert einwandfrei +mit oder ohne Google-Play-Dienste oder microG. Eigenschaften: @@ -7,5 +9,4 @@ Aurora Store ist ein inoffizieller FOSS-Client für Google Play mit elegantem De • Kontoanmeldung: Du kannst dich entweder mit einem persönlichen oder einem anonymen Konto anmelden • Geräte- und Gebietsschema-Spoofing: Ändere dein Gerät und/oder Ihr Gebietsschema, um auf geografisch gesperrte Apps zuzugreifen • Exodus-Privacy-Integration: Tracker sofort in der App sehen -• Plexus-Integration: Sofortige Anzeige der App-Kompatibilität ohne Google-Play-Dienste oder mit microG • Sperrliste für Updates: Updates für bestimmte Apps ignorieren diff --git a/fastlane/metadata/android/el-GR/changelogs/42.txt b/fastlane/metadata/android/el-GR/changelogs/42.txt deleted file mode 100644 index 3443ca0bc..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/42.txt +++ /dev/null @@ -1,15 +0,0 @@ -- Στόχος το Android 13 -- Ενεργοποίηση εντοπισμού πολλαπλών συμβολοσειρών -- Προσθήκη μονόχρωμου εικονιδίου για το Android 13 -- Ενημέρωση εξαρτήσεων στην τελευταία έκδοση -- Εμφάνιση προτροπής Όρων χρήσης κατά την εκκίνηση αμέσως -- Επιτρέψτε τη μετάβαση προς τα εμπρός χωρίς την παροχή δικαιωμάτων κατά την αρχική εγκατάσταση -- Διάβασμα της λίστας denylist του συστήματος xml ως προεπιλογή για τον αποκλεισμό από τις ενημερώσεις -- Εμφάνιση του σωστού τίτλου στην 5η σελίδα εγκατάστασης -- Ενεργοποίηση του κουμπιού προώθησης στην εγκατάσταση κατά την επιστροφή -- Αντικατάσταση των κουτιών ελέγχου στον εγκαταστάτη εγκατάστασης με κουμπιά επιλογής -- Χρήση χρώματος εγκεφαλικού επεισοδίου για το φόντο των καρτελών εγκατάστασης -- Fix no- theme bug στην εγκατάσταση με τη χρήση κουμπιών επιλογής -- Μην χρησιμοποιείτε τις νέες εκδόσεις GSF & Vending -- Ανασχεδιασμός της εγκατάστασης δικαιωμάτων που σχετίζονται με την αποθήκευση -- Μεταφραστικές ενημερώσεις diff --git a/fastlane/metadata/android/el-GR/changelogs/43.txt b/fastlane/metadata/android/el-GR/changelogs/43.txt deleted file mode 100644 index 2d080aefb..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/43.txt +++ /dev/null @@ -1,2 +0,0 @@ -- Ενεργοποιήστε πάντα το κουμπί τερματισμού στο τμήμα δικαιωμάτων (διορθώνει την εισαγωγή νέου χρήστη) -- Διατηρήστε το TypeToken της βιβλιοθήκης GSON κατά τη βελτιστοποίηση της κατασκευής (διορθώνει τη συντριβή κατά την εκκίνηση) diff --git a/fastlane/metadata/android/el-GR/changelogs/44.txt b/fastlane/metadata/android/el-GR/changelogs/44.txt deleted file mode 100644 index 0de9f43e1..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/44.txt +++ /dev/null @@ -1,6 +0,0 @@ -- Διορθώστε τη συντριβή που σχετίζεται με την ειδοποίηση των υπηρεσιών εγκατάστασης -- Εμφάνιση μόνο έγκυρων ιδιοτήτων παραποίησης στην εφαρμογή -- Ειδοποίηση των χρηστών όταν έχουν περιορισμένο ρυθμό κατά την αναζήτηση -- Εμφάνιση κινούμενης εικόνας λάμψης κατά την αναζήτηση για την ένδειξη της προόδου -- Διορθώστε τη συμπεριφορά πλοήγησης όταν αλλάζει η προεπιλεγμένη καρτέλα -- Διορθώστε την επιλογή γρήγορης εξόδου diff --git a/fastlane/metadata/android/el-GR/changelogs/46.txt b/fastlane/metadata/android/el-GR/changelogs/46.txt deleted file mode 100644 index be679048c..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/46.txt +++ /dev/null @@ -1,8 +0,0 @@ -- Αποφεύγετε να ζητάτε άδεια αποθήκευσης μέχρι να απαιτείται -- Αναθεωρημένη διαμόρφωση παραποίησης για να αποφεύγετε την άδεια αποθήκευσης για εισαγωγή-εξαγωγή -- Προσθήκη επιλογής για αυτόματο έλεγχο για ενημερώσεις εφαρμογών (απαιτεί συνδεδεμένο λογαριασμό εργασίας) -- Διορθώθηκε το πρόβλημα όπου οι απαιτούμενες βιβλιοθήκες δεν εγκαθίσταντο με εφαρμογές όπως η βιβλιοθήκη chrome & trichrome -- Αγνοήστε τον κατάλογο λήψεων από τα αντίγραφα ασφαλείας κατά τη δημιουργία αντιγράφων ασφαλείας του Aurora Store -- Εφαρμογή του εγκαταστάτη Shizuku (απαιτεί Android 8.0+) -- Διακοπή υποστήριξης για Android 4.4. Η ελάχιστη απαιτούμενη έκδοση Android είναι 5.0+. -- Μικρές διορθώσεις σφαλμάτων και βελτιώσεις diff --git a/fastlane/metadata/android/el-GR/changelogs/47.txt b/fastlane/metadata/android/el-GR/changelogs/47.txt deleted file mode 100644 index f9649f162..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/47.txt +++ /dev/null @@ -1 +0,0 @@ -- Hotfix - Διορθώθηκε το κρασάρισμα σε ορισμένες οθόνες diff --git a/fastlane/metadata/android/el-GR/changelogs/48.txt b/fastlane/metadata/android/el-GR/changelogs/48.txt deleted file mode 100644 index 530c64f00..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/48.txt +++ /dev/null @@ -1,3 +0,0 @@ -- Σημαντικές εσωτερικές αλλαγές που σχετίζονται με το UI -- Μεταφραστικές ενημερώσεις -- Μικρές διορθώσεις και βελτιώσεις σφαλμάτων diff --git a/fastlane/metadata/android/el-GR/changelogs/49.txt b/fastlane/metadata/android/el-GR/changelogs/49.txt deleted file mode 100644 index 499f8dee5..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/49.txt +++ /dev/null @@ -1,4 +0,0 @@ -- Σημαντικές εσωτερικές αλλαγές που σχετίζονται με το UI -- Επιτρέψτε στους χρήστες να ενεργοποιήσουν τις συνδέσεις εφαρμογών κατά την πρώτη εγκατάσταση -- Ενημερώσεις μεταφράσεων -- Μικρές διορθώσεις και βελτιώσεις σφαλμάτων diff --git a/fastlane/metadata/android/el-GR/changelogs/50.txt b/fastlane/metadata/android/el-GR/changelogs/50.txt deleted file mode 100644 index 0cc6416d4..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/50.txt +++ /dev/null @@ -1,9 +0,0 @@ -- Η εναλλαγή στο θέμα συστήματος από ένα σκοτεινό θέμα ενημερώνει σωστά το UI -- Τα παράθυρα διαλόγου στην αρχική οθόνη δεν κρύβουν πλέον ορισμένες προβολές -- Το άνοιγμα ενός συνδέσμου Google Play διασφαλίζει τώρα ότι υπάρχει ένας έγκυρος και λειτουργικός λογαριασμός -- Το συρτάρι πλοήγησης μπορεί να ανοίξει μόνο στην κύρια οθόνη -- Η ενέργεια «Πίσω» τερματίζει τώρα σωστά την εφαρμογή σε ορισμένες οθόνες -- Τα κουμπιά ρυθμίσεων έχουν τώρα σωστή απόχρωση στο σκοτεινό θέμα -- Το όνομα της εφαρμογής είναι και πάλι ορατό στη γραμμή εργαλείων για τις αναφορές εξόδου -- Εσωτερικές βελτιώσεις σχετικά με τις εικόνες -- Μεταφραστικές ενημερώσεις diff --git a/fastlane/metadata/android/el-GR/changelogs/51.txt b/fastlane/metadata/android/el-GR/changelogs/51.txt deleted file mode 100644 index 955898103..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/51.txt +++ /dev/null @@ -1 +0,0 @@ -- Επιδιόρθωση προβλήματος αναζήτησης, χρησιμοποιεί δεδομένα WebAPI diff --git a/fastlane/metadata/android/el-GR/changelogs/52.txt b/fastlane/metadata/android/el-GR/changelogs/52.txt deleted file mode 100644 index 0add85920..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/52.txt +++ /dev/null @@ -1,6 +0,0 @@ -- Διορθώστε τη συντριβή σε ορισμένες συσκευές κατά την αναζήτηση μη αγγλικών λέξεων-κλειδιών -- Βελτίωση της σελίδας Apps & Games -- Προσθήκη εναλλασσόμενου διακόπτη για την αυτόματη εγκατάσταση μετά τη λήψη της εφαρμογής -- Μην αναπαράγετε ήχο ειδοποίησης όταν εγκαθίσταται ή ενημερώνεται η εφαρμογή -- Διορθώστε τη συντριβή σε ορισμένες συσκευές κατά το άνοιγμα των λεπτομερειών της εφαρμογής -- Προσθήκη διαλόγου επιβεβαίωσης απεγκατάστασης εάν χρησιμοποιείτε root installer diff --git a/fastlane/metadata/android/el-GR/changelogs/53.txt b/fastlane/metadata/android/el-GR/changelogs/53.txt deleted file mode 100644 index 629b209ed..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/53.txt +++ /dev/null @@ -1,3 +0,0 @@ -- Διορθώστε τις εφαρμογές που δεν εγκαθίστανται μετά τη λήψη -- Επιτρέψτε την επιλογή προσαρμοσμένου καταλόγου λήψης -- Προσθέστε την επιλογή λήψης μόνο Wifi-only diff --git a/fastlane/metadata/android/el-GR/changelogs/54.txt b/fastlane/metadata/android/el-GR/changelogs/54.txt deleted file mode 100644 index 49ee17220..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/54.txt +++ /dev/null @@ -1,18 +0,0 @@ -- Σημαντικές εσωτερικές αλλαγές στο σύστημα λήψεων - - Το Aurora Store απαιτεί τώρα νέα άδεια για λήψη στο παρασκήνιο - - Οι λειτουργίες παύσης και συνέχισης έχουν καταργηθεί για τις λήψεις - - Οι ταυτόχρονες λήψεις έχουν καταργηθεί (περιορίζονται σε μία λήψη κάθε φορά) - - Αυτόματη επαλήθευση SHA256 & SHA1 για τα κατεβασμένα αρχεία - - Καλύτερη υποστήριξη για εφαρμογές με κοινόχρηστες βιβλιοθήκες, όπως το Chrome και το WebView -- Σημαντικές αλλαγές στο σύστημα ενημερώσεων - - Νέες αυτόματες ενημερώσεις για εφαρμογές (ενεργοποιούνται από προεπιλογή) - - Νέα αυτόματη επαλήθευση πιστοποιητικών για ενημερώσεις - - Υποστήριξη για ενημερώσεις με εναλλαγή κλειδιών υπογραφής (εισήχθη μετά το Android 9. 0+) - - Οι αυτοενημερώσεις (Aurora Store) έχουν απενεργοποιηθεί από προεπιλογή (ενεργοποίηση στις ρυθμίσεις > ενημέρωση) -- Ο εγγενής εγκαταστάτης και οι υπηρεσίες Aurora έχουν καταργηθεί -- Η εξαγωγή εγκατεστημένων εφαρμογών δεν απαιτεί πλέον δικαιώματα αποθήκευσης -- Η ελάχιστη απαιτούμενη έκδοση Android για τις εφαρμογές είναι πλέον ορατή στη σελίδα λεπτομερειών της εφαρμογής (Περισσότερα για αυτή την εφαρμογή > Πληροφορίες) -- Ενημερώσεις μεταφράσεων & σημαντικές διορθώσεις σφαλμάτων -- Υποστήριξη για την εγκατάσταση εφαρμογών με Sui (Shizuku Magisk Module) -- Δυνατότητα παράκαμψης της έκδοσης GMS από τις Ρυθμίσεις > Δίκτυο -- Το Material3 χρησιμοποιείται πλέον σε περισσότερα σημεία diff --git a/fastlane/metadata/android/el-GR/changelogs/55.txt b/fastlane/metadata/android/el-GR/changelogs/55.txt deleted file mode 100644 index febd31677..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/55.txt +++ /dev/null @@ -1,18 +0,0 @@ -- Σημαντικές εσωτερικές αλλαγές στο σύστημα λήψεων - - Το Aurora Store απαιτεί τώρα νέα άδεια για λήψη στο παρασκήνιο - - Οι λειτουργίες παύσης και συνέχισης έχουν καταργηθεί για τις λήψεις - - Οι ταυτόχρονες λήψεις έχουν καταργηθεί (περιορίζονται σε μία λήψη κάθε φορά) - - Αυτόματη επαλήθευση SHA256 & SHA1 για τα αρχεία που έχουν ληφθεί - - Καλύτερη υποστήριξη για εφαρμογές με κοινές βιβλιοθήκες, όπως το Chrome και το WebView -- Σημαντικές αλλαγές στο σύστημα ενημερώσεων - - Νέες αυτόματες ενημερώσεις για εφαρμογές (ενεργοποιούνται από προεπιλογή) - - Νέα αυτόματη επαλήθευση πιστοποιητικών για ενημερώσεις - - Υποστήριξη για ενημερώσεις με εναλλαγή κλειδιών υπογραφής (εισήχθη μετά το Android 9. 0+) - - Οι αυτοενημερώσεις (Aurora Store) έχουν απενεργοποιηθεί από προεπιλογή (ενεργοποίηση στις ρυθμίσεις > ενημέρωση) -- Ο εγγενής εγκαταστάτης και οι υπηρεσίες Aurora έχουν καταργηθεί -- Η εξαγωγή εγκατεστημένων εφαρμογών δεν απαιτεί πλέον δικαιώματα αποθήκευσης -- Η ελάχιστη απαιτούμενη έκδοση Android για τις εφαρμογές είναι πλέον ορατή στη σελίδα λεπτομερειών της εφαρμογής (Περισσότερα για αυτή την εφαρμογή > Πληροφορίες) -- Ενημερώσεις μεταφράσεων και σημαντικές διορθώσεις σφαλμάτων -- Υποστήριξη για την εγκατάσταση εφαρμογών με Sui (Shizuku Magisk Module) -- Δυνατότητα παράκαμψης της έκδοσης GMS από τις Ρυθμίσεις > Δίκτυο -- Το Material3 χρησιμοποιείται πλέον σε περισσότερα σημεία diff --git a/fastlane/metadata/android/el-GR/changelogs/56.txt b/fastlane/metadata/android/el-GR/changelogs/56.txt deleted file mode 100644 index ffd483725..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/56.txt +++ /dev/null @@ -1,7 +0,0 @@ -- Στόχος Android 14 -- Βελτίωση του φίλτρου πακέτων F-Droid για ενημερώσεις -- Ανάληψη ευθύνης για μελλοντικές ενημερώσεις κατά την εγκατάσταση εφαρμογών με χρήση του SessionInstaller (Android 14+) -- Μετονομασία "Extended Updates" σε "Incompatible Updates" -- Προσθήκη ενέργειας μενού για τη δημιουργία συντόμευσης για την εγκατεστημένη εφαρμογή -- Διορθώσεις σφαλμάτων και βελτιώσεις -- Μεταφραστικές ενημερώσεις diff --git a/fastlane/metadata/android/el-GR/changelogs/57.txt b/fastlane/metadata/android/el-GR/changelogs/57.txt deleted file mode 100644 index 3a23abafa..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/57.txt +++ /dev/null @@ -1,7 +0,0 @@ -- Πολλαπλές διορθώσεις σφαλμάτων και βελτιώσεις UI/UX -- Τα νέα δικαιώματα επισημαίνονται τώρα στο φύλλο δικαιωμάτων -- Νέες διαμορφώσεις απομίμησης για συσκευές x86 -- Αλλαγές στο σύστημα λήψεων - - Η προεπιλεγμένη τοποθεσία λήψεων άλλαξε σε εσωτερικό κατάλογο cache - - Οι λήψεις συνεχίζονται τώρα αυτόματα κατά την επανεκκίνηση αν υπάρχουν αρχεία -- Μεταφραστικές ενημερώσεις diff --git a/fastlane/metadata/android/el-GR/changelogs/58.txt b/fastlane/metadata/android/el-GR/changelogs/58.txt deleted file mode 100644 index d524a561e..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/58.txt +++ /dev/null @@ -1,4 +0,0 @@ -- Διορθώθηκε το πρόβλημα με τη σύνδεση που σχετίζεται με τους λογαριασμούς Google -- Μετακίνησε τα στοιχεία του συρταριού πλοήγησης σε ξεχωριστό διάλογο -- Μεταπήδηση στο NavigationRail για συσκευές μεγάλης οθόνης -- Δυνατότητα εξαγωγής λήψεων σε εξωτερική τοποθεσία diff --git a/fastlane/metadata/android/el-GR/changelogs/59.txt b/fastlane/metadata/android/el-GR/changelogs/59.txt deleted file mode 100644 index 427f85b1d..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/59.txt +++ /dev/null @@ -1,6 +0,0 @@ -- Υποστήριξη για τρίτους διανομείς κουπονιών -- Πολλαπλές βελτιώσεις UI/UX και διορθώσεις σφαλμάτων -- Νέα λειτουργία αυτόματου καθαρισμού της προσωρινής μνήμης για την αφαίρεση παλαιών λήψεων -- Η ρύθμιση χρώματος έμφασης έχει αποσυρθεί για συσκευές Android 12+ -- SessionInstaller: Δυνατότητα ορισμού του Aurora Store ως ιδιοκτήτη συσκευής και σιωπηλής εγκατάστασης (credits: @s1204IT) -- SessionInstaller: Υποστήριξη ουράς εγκατάστασης diff --git a/fastlane/metadata/android/el-GR/changelogs/60.txt b/fastlane/metadata/android/el-GR/changelogs/60.txt deleted file mode 100644 index f55570d7b..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/60.txt +++ /dev/null @@ -1,2 +0,0 @@ -- Διορθώθηκε σφάλμα που προκαλούσε συντριβή του SessionInstaller σε παλιές εκδόσεις Android -- Ενημερώσεις μεταφράσεων diff --git a/fastlane/metadata/android/el-GR/changelogs/61.txt b/fastlane/metadata/android/el-GR/changelogs/61.txt deleted file mode 100644 index 694177fea..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/61.txt +++ /dev/null @@ -1,8 +0,0 @@ -- Στόχοι Android 15 -- Αλλαγή σε Web APIs για την ανώνυμη λειτουργία (καλύτερη απόδοση, περισσότερη ανωνυμία) -- Υποστήριξη για την ενότητα ασφάλειας δεδομένων στη σελίδα λεπτομερειών της εφαρμογής -- Ορισμός ανασφαλούς ανώνυμης λειτουργίας ως προεπιλεγμένη ανώνυμη λειτουργία -- Νέα λειτουργία για την προσθήκη αγαπημένων εφαρμογών στη λίστα εισαγωγής/εξαγωγής -- Εφαρμογή Material You για τα υπόλοιπα στοιχεία με σημαντικές βελτιώσεις UI και UX -- Πολλαπλές διορθώσεις σφαλμάτων και βελτιώσεις επιδόσεων -- Μεταφραστικές ενημερώσεις diff --git a/fastlane/metadata/android/el-GR/changelogs/62.txt b/fastlane/metadata/android/el-GR/changelogs/62.txt deleted file mode 100644 index 7670d590f..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/62.txt +++ /dev/null @@ -1,6 +0,0 @@ -- Διόρθωση προβλήματος UI στο Android 15 -- Βελτιώσεις στη διαμόρφωση και χρήση διακομιστή μεσολάβησης -- SSL pinning για γνωστούς τομείς που χρησιμοποιούν πιστοποιητικά ρίζας -- Καλύτερη υποστήριξη για δυναμικά θέματα σε υποστηριζόμενες συσκευές -- Σταμάτησε η υποστήριξη για προσαρμοσμένα θέματα και χρώματα έμφασης -- Μεταφραστικές ενημερώσεις diff --git a/fastlane/metadata/android/el-GR/changelogs/63.txt b/fastlane/metadata/android/el-GR/changelogs/63.txt deleted file mode 100644 index 63146e6b5..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/63.txt +++ /dev/null @@ -1,3 +0,0 @@ -- Διορθώθηκε μικρό πρόβλημα μετανάστευσης -- Προστέθηκε αυτόματη ενημέρωση για νυχτερινά builds -- Μεταφραστικές ενημερώσεις diff --git a/fastlane/metadata/android/el-GR/changelogs/64.txt b/fastlane/metadata/android/el-GR/changelogs/64.txt deleted file mode 100644 index 139b5e869..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/64.txt +++ /dev/null @@ -1,6 +0,0 @@ -- Υποστήριξη για την αρχειοθέτηση/απο-αρχειοθέτηση εφαρμογών στο Android 15+ -- Υποστήριξη για την εγκατάσταση εφαρμογών σε ιδιωτικό χώρο στο Android 15+ -- Προσαρμογές του UI για την υποστήριξη edge-to-edge -- Πολλαπλές διορθώσεις σφαλμάτων και βελτιώσεις -- Βελτιώσεις στα κανάλια ειδοποιήσεων και στις ειδοποιήσεις -- Μεταφραστικές ενημερώσεις diff --git a/fastlane/metadata/android/el-GR/changelogs/65.txt b/fastlane/metadata/android/el-GR/changelogs/65.txt deleted file mode 100644 index 4da56e1f0..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/65.txt +++ /dev/null @@ -1,4 +0,0 @@ -- Διορθώθηκαν προβλήματα με την εγκατάσταση κοινής βιβλιοθήκης για εφαρμογές όπως το Chrome και το WebView -- Υποστήριξη για σύνδεση σε προσωπικό λογαριασμό με χρήση microG -- Διορθώθηκε ένα πρόβλημα με την επαλήθευση auth -- Μεταφραστικές ενημερώσεις; Πρόσθετες συμβολοσειρές εντοπισμένες diff --git a/fastlane/metadata/android/el-GR/changelogs/66.txt b/fastlane/metadata/android/el-GR/changelogs/66.txt deleted file mode 100644 index 5d51ea853..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/66.txt +++ /dev/null @@ -1,5 +0,0 @@ -- Νέες αξιολογήσεις συμβατότητας εφαρμογών που υποστηρίζονται από το Plexus -- Βελτιώσεις στον διαχειριστή μαύρης λίστας -- Δυνατότητα αλλαγής των περιορισμών αυτόματης ενημέρωσης -- Μικρές διορθώσεις σφαλμάτων και βελτιώσεις -- Μεταφραστικές ενημερώσεις- επιπλέον συμβολοσειρές εντοπισμένες diff --git a/fastlane/metadata/android/el-GR/changelogs/73.txt b/fastlane/metadata/android/el-GR/changelogs/73.txt deleted file mode 100644 index c2d356446..000000000 --- a/fastlane/metadata/android/el-GR/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Διορθώθηκε το λάθος εικονίδιο βέλους αναβάθμισης σε διατάξεις RTL -• Διορθώθηκαν προβλήματα σελιδοποίησης και IME στην αναζήτηση -• Διορθώθηκε ένα σφάλμα που παρακάμπτει την επιλογή εγκατάστασης χρήστη -• Ενημέρωση μεταφράσεων, βάσης δεδομένων exodus trackers και πιστοποιητικών root της Google diff --git a/fastlane/metadata/android/el-GR/full_description.txt b/fastlane/metadata/android/el-GR/full_description.txt index 79b54f070..9bbbdce86 100644 --- a/fastlane/metadata/android/el-GR/full_description.txt +++ b/fastlane/metadata/android/el-GR/full_description.txt @@ -1,11 +1,12 @@ -Το Aurora Store είναι ένας ανεπίσημος, FOSS πελάτης του Google Play με κομψό σχεδιασμό. Το Aurora Store επιτρέπει στους χρήστες να κατεβάζουν, να ενημερώνουν και να αναζητούν εφαρμογές όπως το Play Store. Λειτουργεί άψογα με ή χωρίς Google Play Services ή microG. +Το Aurora Store είναι ένας ανεπίσημος πελάτης FOSS στο Google Play με κομψό σχεδιασμό. Το Aurora Store +επιτρέπει στους χρήστες να κατεβάζουν, ενημερώνουν και αναζητούν apps όπως και στο Play Store. Λειτουργεί τέλεια +με ή χωρίς Υπηρεσίες Google Play ή MicroG. -Χαρακτηριστικά: +Δυνατότητες: -- FOSS: Έχει άδεια χρήσης GPLv3 -- Όμορφος σχεδιασμός: Χτισμένο με βάση τις πιο πρόσφατες κατευθυντήριες γραμμές του Material 3 -- Σύνδεση λογαριασμού: Μπορείτε να συνδεθείτε είτε με προσωπικό είτε με ανώνυμο λογαριασμό -- Πλαστογράφηση συσκευής και τοπικής κατάστασης: Αλλάξτε τη συσκευή ή/και την τοποθεσία σας για να αποκτήσετε πρόσβαση σε εφαρμογές με γεωγραφικό κλείδωμα -- Ενσωμάτωση του Exodus Privacy: Ενσωμάτωση του Exodus: Δείτε αμέσως τους ανιχνευτές στην εφαρμογή -- Ενσωμάτωση του Plexus: Άμεση προβολή της συμβατότητας εφαρμογών χωρίς υπηρεσίες Google Play ή με microG -- Μαύρη λίστα ενημερώσεων: Αγνοήστε ενημερώσεις για συγκεκριμένες εφαρμογές +• FOSS: Διαθέτει άδεια GPLv3 +• Όμορφη σχεδίαση: Κατασκευασμένο σύμφωνα με τις τελευταίες οδηγίες Material 3 +• Είσοδος λογαριασμού: Μπορείτε να συνδεθείτε είτε με προσωπικό είτε με ανώνυμο λογαριασμό +• Παραποίηση Συσκευής και Τοποθεσίας: Αλλάξτε τη συσκευή σας ή/και την τοποθεσία σας για πρόσβαση σε apps κλειδωμένα γεωγραφικά +• Ενσωμάτωση [Exodus Privacy](https://exodus-privacy.eu.org/): Δείτε άμεσα προγράμματα παρακολούθησης στο app +• Μαύρη λίστα ενημερώσεων: Αγνοήστε τις ενημερώσεις για συγκεκριμένα apps diff --git a/fastlane/metadata/android/en-US/changelogs/66.txt b/fastlane/metadata/android/en-US/changelogs/66.txt deleted file mode 100644 index 462d1f762..000000000 --- a/fastlane/metadata/android/en-US/changelogs/66.txt +++ /dev/null @@ -1,5 +0,0 @@ -• New app compatibility ratings powered by Plexus -• Improvements to blacklist manager -• Ability to change auto-update restrictions -• Minor bug fixes and improvements -• Translation updates; additional strings localized diff --git a/fastlane/metadata/android/en-US/changelogs/67.txt b/fastlane/metadata/android/en-US/changelogs/67.txt deleted file mode 100644 index ff85142fb..000000000 --- a/fastlane/metadata/android/en-US/changelogs/67.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Target Android 16 -• Fix bug with opening links to apps -• Support opening the app's detail page from app info settings -• Translation updates diff --git a/fastlane/metadata/android/en-US/changelogs/68.txt b/fastlane/metadata/android/en-US/changelogs/68.txt deleted file mode 100644 index 525439a39..000000000 --- a/fastlane/metadata/android/en-US/changelogs/68.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Switch to new APIs for searching and installing apps -• Search filter is no longer available, will be added back later -• Fix crash on navigating to app details page -• Fix crash on spoofing locale -• Translation updates diff --git a/fastlane/metadata/android/en-US/changelogs/69.txt b/fastlane/metadata/android/en-US/changelogs/69.txt deleted file mode 100644 index 1050dca02..000000000 --- a/fastlane/metadata/android/en-US/changelogs/69.txt +++ /dev/null @@ -1,3 +0,0 @@ -• Add capability to install microG bundle on Huawei devices -• Minor bug fixes and improvements -• Translation updates diff --git a/fastlane/metadata/android/en-US/changelogs/70.txt b/fastlane/metadata/android/en-US/changelogs/70.txt deleted file mode 100644 index e8b87208a..000000000 --- a/fastlane/metadata/android/en-US/changelogs/70.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Do not prompt for microG installs on non-huawei builds -• Translation updates diff --git a/fastlane/metadata/android/en-US/changelogs/71.txt b/fastlane/metadata/android/en-US/changelogs/71.txt deleted file mode 100644 index 01a764ba3..000000000 --- a/fastlane/metadata/android/en-US/changelogs/71.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Fix app install issue on huawei devices -• Translation updates \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/72.txt b/fastlane/metadata/android/en-US/changelogs/72.txt deleted file mode 100644 index 1dd37f5d9..000000000 --- a/fastlane/metadata/android/en-US/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Minimum supported Android version is now Android 6.0 -• Switched to Material3 Expressive theme -• Improved support for wide-screen devices -• Fixed an issue where Hebrew language wasn't set properly with per-app language -• Restored search filters functionality diff --git a/fastlane/metadata/android/en-US/changelogs/73.txt b/fastlane/metadata/android/en-US/changelogs/73.txt deleted file mode 100644 index 6bf1bb91d..000000000 --- a/fastlane/metadata/android/en-US/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Fixed wrong upgrade arrow indicator icon on RTL layouts -• Fixed paging and IME issues on search -• Fixed a bug that override user installer choice -• Update translations, exodus trackers database and google's root certificates diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt index c07470b3f..fc3165d9b 100644 --- a/fastlane/metadata/android/en-US/full_description.txt +++ b/fastlane/metadata/android/en-US/full_description.txt @@ -1,4 +1,6 @@ -Aurora Store is an unofficial, FOSS client to Google Play with an elegant design. Aurora Store allows users to download, update, and search for apps like the Play Store. It works perfectly fine with or without Google Play Services or microG. +Aurora Store is an unofficial, FOSS client to Google Play with an elegant design. Aurora Store +allows users to download, update, and search for apps like the Play Store. It works perfectly fine +with or without Google Play Services or MicroG. Features: @@ -7,5 +9,4 @@ Aurora Store is an unofficial, FOSS client to Google Play with an elegant design • Account login: You can login with either personal or an anonymous account • Device & Locale spoofing: Change your device and/or locale to access geo locked apps • Exodus Privacy integration: Instantly see trackers in app -• Plexus integration: Instantly see app compatibility without Google Play Services or with microG • Updates blacklisting: Ignore updates for specific apps diff --git a/fastlane/metadata/android/es-ES/changelogs/57.txt b/fastlane/metadata/android/es-ES/changelogs/57.txt index 00f254689..02be72e86 100644 --- a/fastlane/metadata/android/es-ES/changelogs/57.txt +++ b/fastlane/metadata/android/es-ES/changelogs/57.txt @@ -1,5 +1,5 @@ • Se han corregido varios errores y se ha mejorado la interfaz de usuario. -• Los permisos nuevos aparecen resaltados en la hoja de permisos. +• Los nuevos permisos aparecen resaltados en la hoja de permisos. • Nuevas configuraciones de suplantación para dispositivos x86 • Cambios en el sistema de descargas • Se ha cambiado la ubicación predeterminada de las descargas al directorio de caché interno. diff --git a/fastlane/metadata/android/es-ES/changelogs/65.txt b/fastlane/metadata/android/es-ES/changelogs/65.txt deleted file mode 100644 index bd7809890..000000000 --- a/fastlane/metadata/android/es-ES/changelogs/65.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Se corrigieron problemas con la instalación de la biblioteca compartida para aplicaciones como Chrome y WebView -• Soporte para iniciar sesión en la cuenta personal utilizando microG -• Se corrigió un problema con la verificación de autenticación -• Actualizaciones de traducción; se localizaron cadenas adicionales diff --git a/fastlane/metadata/android/es-ES/changelogs/72.txt b/fastlane/metadata/android/es-ES/changelogs/72.txt deleted file mode 100644 index 921562610..000000000 --- a/fastlane/metadata/android/es-ES/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• La versión mínima compatible de Android ahora es Android 6.0 -• Se ha cambiado al tema Material3 Expressive -• Se ha mejorado la compatibilidad con dispositivos de pantalla ancha -• Se ha corregido un problema por el que el idioma hebreo no se configuraba correctamente con el idioma por aplicación -• Se ha restaurado la funcionalidad de los filtros de búsqueda diff --git a/fastlane/metadata/android/es-ES/changelogs/73.txt b/fastlane/metadata/android/es-ES/changelogs/73.txt deleted file mode 100644 index a80a4525b..000000000 --- a/fastlane/metadata/android/es-ES/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Se ha corregido el icono indicador de flecha de actualización incorrecto en los diseños RTL -• Se han corregido los problemas de paginación y del IME en la búsqueda -• Se ha corregido un bug que anulaba la elección del instalador del usuario -• Se han actualizado las traducciones, la base de datos de rastreadores de Exodus y los certificados raíz de Google diff --git a/fastlane/metadata/android/es-ES/full_description.txt b/fastlane/metadata/android/es-ES/full_description.txt index f2d6fb8d7..50ea7a811 100644 --- a/fastlane/metadata/android/es-ES/full_description.txt +++ b/fastlane/metadata/android/es-ES/full_description.txt @@ -1,11 +1,12 @@ -Aurora Store es un cliente de software libre no oficial para Google Play con un diseño elegante. Aurora Store permite a los usuarios descargar, actualizar y buscar aplicaciones como la Play Store. Funciona perfectamente con o sin los Servicios de Google Play o MicroG. +Aurora Store es un cliente de software libre no oficial para Google Play con un diseño elegante. Aurora Store +permite a los usuarios descargar, actualizar y buscar aplicaciones como la Play Store. Funciona perfectamente bien. +con o sin Google Play Services o MicroG. Características: • FOSS: Tiene licencia GPLv3 -• Diseño atractivo: Basado en las últimas directrices de Material 3 -• Inicio de sesión con cuenta: Puedes iniciar sesión con una cuenta personal o anónima +• Diseño atractivo: basado en las últimas directrices de Material 3 +• Inicio de sesión con cuenta: puede iniciar sesión con una cuenta personal o anónima • Suplantación de dispositivo y configuración regional: Cambia tu dispositivo y/o configuración regional para acceder a aplicaciones bloqueadas geográficamente -• Integración con Exodus Privacy: Visualiza al instante los rastreadores en la aplicación -• Integración con Plexus: Comprueba la compatibilidad de una aplicación instantáneamente sin los servicios de Google Play ni microG -• Lista negra de actualizaciones: Ignora actualizaciones para aplicaciones específicas +• Integración a Exodus Privacy ver instantáneamente los rastreadores en la aplicación +• Lista negra de actualizaciones: Ignorar las actualizaciones para aplicaciones específicas diff --git a/fastlane/metadata/android/es-ES/short_description.txt b/fastlane/metadata/android/es-ES/short_description.txt index 9ec4f8939..4438cdd25 100644 --- a/fastlane/metadata/android/es-ES/short_description.txt +++ b/fastlane/metadata/android/es-ES/short_description.txt @@ -1 +1 @@ -Un cliente FOSS no oficial para Google Play con diseño elegante y privacidad +Cliente FOSS no oficial para Google Play con diseño elegante y privacidad diff --git a/fastlane/metadata/android/et/changelogs/38.txt b/fastlane/metadata/android/et/changelogs/38.txt deleted file mode 100644 index ad3db3862..000000000 --- a/fastlane/metadata/android/et/changelogs/38.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Aurora Teenuste paigalduse vea parandus -• Tõlgete uuendused diff --git a/fastlane/metadata/android/et/changelogs/40.txt b/fastlane/metadata/android/et/changelogs/40.txt deleted file mode 100644 index e5e9349e1..000000000 --- a/fastlane/metadata/android/et/changelogs/40.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Veaparandused ja täiendused -• Tõlgete uuendused diff --git a/fastlane/metadata/android/et/changelogs/67.txt b/fastlane/metadata/android/et/changelogs/67.txt deleted file mode 100644 index 6d184acde..000000000 --- a/fastlane/metadata/android/et/changelogs/67.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Kompileerimise alusplatvormiks on nüüd Android 16 -• Rakenduste linkide avamisel tekkinud vea parandus -• Rakenduse üldisest infovaatest üksikasjaliku teabe lehe avamine -• Tõlgete uuendused diff --git a/fastlane/metadata/android/et/changelogs/68.txt b/fastlane/metadata/android/et/changelogs/68.txt deleted file mode 100644 index ff7c231a9..000000000 --- a/fastlane/metadata/android/et/changelogs/68.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Rakenduse üksikasjade vaate avamisel tekkinud kokkujooksmise parandus -• Tõlgete uuendused diff --git a/fastlane/metadata/android/et/changelogs/71.txt b/fastlane/metadata/android/et/changelogs/71.txt deleted file mode 100644 index 6ccb2f64c..000000000 --- a/fastlane/metadata/android/et/changelogs/71.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Parandasime rakenduste paigalduse vea Huawei seadmetes -• Tõlgete täiendused diff --git a/fastlane/metadata/android/et/changelogs/72.txt b/fastlane/metadata/android/et/changelogs/72.txt deleted file mode 100644 index 1b33b6e5e..000000000 --- a/fastlane/metadata/android/et/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Minimaalne toetatud Androidi versioon on nüüd Android 6.0 -• Võtsime kasutusele Material3 Expressive kujunduse -• Parem tugi laiekraanseadmetel -• Parandasime heebrea keele määramisel rakendusekohaseks keeleks tekkinud vea -• Taastasime otsingufiltrite funktsionaalsuse diff --git a/fastlane/metadata/android/et/changelogs/73.txt b/fastlane/metadata/android/et/changelogs/73.txt deleted file mode 100644 index 764255b74..000000000 --- a/fastlane/metadata/android/et/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Uuenduse nooleikoon on paremalt vasakule paigutustes õige -• Lihtede grupeerimise ja sisendmeetodi parandused otsinguvaates -• Veaparandus olukorrale, kus kasutaja paigaldaja valik sai sürjutatud -• Tõlgete, Exoduse jälitajate andmekogu ja Google'i juursertifikaatide täiendused ja uuendused diff --git a/fastlane/metadata/android/et/full_description.txt b/fastlane/metadata/android/et/full_description.txt deleted file mode 100644 index 0e5ca3229..000000000 --- a/fastlane/metadata/android/et/full_description.txt +++ /dev/null @@ -1,11 +0,0 @@ -Aurora rakendustepood on ilusa kujundusega mitteametlik ja avatud lähtekoodiga Google Play klient. Siit saad laadida alla, uuendada ja otsida rakendust Play Store rakendustepoest. Toimib korralikult sõltumata sellest, kas Google Play teenused või microG on nutiseadmes olemas. - -Funktsionaalsused: - -• Vaba ja avatud lähtekoodiga tarkvara, mis on avaldatud GPLv3 litsentsi alusel -• Ilus kujundus: järgib Material 3 kujunduskeele reegleid -• Sisselogimiseks kasutatav konto: võid logida sisse nii isikliku kui anonüümse kontoga -• Seadme ja lokaadi hämamine: geoblokeeringuga rakenduste paigaldamiseks saad muuta nutiseadme ja/või lokaadi seadistusi -• Exodus Privacy lõiming: rakendustes leiduvad jälitajad on kohe näha -• Plexuse lõiming: rakenduse ühilduvus kasutamiseks ilma Google Play teenusteta või microG-ta on kohe näha -• Uuenduste keelamine: vajadusel saad välistada valitud rakenduste uuendamise diff --git a/fastlane/metadata/android/et/short_description.txt b/fastlane/metadata/android/et/short_description.txt deleted file mode 100644 index ac0606d61..000000000 --- a/fastlane/metadata/android/et/short_description.txt +++ /dev/null @@ -1 +0,0 @@ -Elegantse kujundusega ja privaatne mitteametlik ning vaba Google Play klient diff --git a/fastlane/metadata/android/fi-FI/changelogs/58.txt b/fastlane/metadata/android/fi-FI/changelogs/58.txt deleted file mode 100644 index e5345a5fe..000000000 --- a/fastlane/metadata/android/fi-FI/changelogs/58.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Korjattu Google-tileihin liittyvä sisäänkirjautumisongelma -• Siirretty navigointilaatikon kohteet erilliseen valintaikkunaan -• Vaihdettu NavigationRailiin suuren näytön laitteille -• Mahdollisuus viedä latauksia ulkoiseen paikkaan diff --git a/fastlane/metadata/android/fi-FI/changelogs/65.txt b/fastlane/metadata/android/fi-FI/changelogs/65.txt deleted file mode 100644 index 31b157e2e..000000000 --- a/fastlane/metadata/android/fi-FI/changelogs/65.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Korjattu ongelmat jaetun kirjaston asentamisessa sovelluksille, kuten Chrome ja WebView -• Tuki sisäänkirjautumiseen henkilökohtaiselle tilille microG:n avulla -• Korjattu todennusta koskeva ongelma -• Käännöspäivitykset; Muut merkkijonot lokalisoitu diff --git a/fastlane/metadata/android/fi-FI/changelogs/72.txt b/fastlane/metadata/android/fi-FI/changelogs/72.txt deleted file mode 100644 index 4a3736345..000000000 --- a/fastlane/metadata/android/fi-FI/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Vanhin tuettu Android-versio on nyt Android 6.0 -• Vaihdettiin Material 3 Expressive -teemaan -• Parannettiin tukea leveille näytöille -• Korjattiin ongelma, jossa Heprean kieli ei asettunut kunnolla sovelluskohtaisen kielen kautta -• Palautettiin ominaisuus suodattaa hakutuloksia diff --git a/fastlane/metadata/android/fi-FI/changelogs/73.txt b/fastlane/metadata/android/fi-FI/changelogs/73.txt deleted file mode 100644 index f045ed673..000000000 --- a/fastlane/metadata/android/fi-FI/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Korjattiin väärä päivitysnuolimerkki oikealta vasemmalle -esitystavassa -• Korjattiin sivutus ja IME-ongelmia haussa -• Korjattiin bugi, joka vaihtoi käyttäjän valitseman sovellusasentajan -• Päivitettiin käännöksiä, Exodus-seuraajia sekä Google:n juurisertifikaatteja diff --git a/fastlane/metadata/android/fi-FI/full_description.txt b/fastlane/metadata/android/fi-FI/full_description.txt deleted file mode 100644 index f92f93410..000000000 --- a/fastlane/metadata/android/fi-FI/full_description.txt +++ /dev/null @@ -1,11 +0,0 @@ -Aurora Store on Google Play:n epävirallinen FOSS-asiakas, jolla on tyylikäs muotoilu. Aurora Store:n avulla käyttäjät voivat ladata, päivittää ja etsiä sovelluksia, kuten Play Kaupassa. Se toimii täydellisesti sekä Google Play Palveluiden tai microG:n kanssa, että ilman niitä. - -Ominaisuudet: - -• FOSS: Käyttää GPLv3-lisenssiä -• Kaunis muotoilu: Rakennettu uusimpien Material 3 -ohjeiden mukaan -• Tilin kirjautuminen: Voit kirjautua sisään joko henkilökohtaisella tai nimettömällä tilillä -• Laitteen ja kielen huijaus: Vaihda laitettasi ja/tai maa-asetusta, jotta voit käyttää maantieteellisesti lukittuja sovelluksia -• Exodus Privacy -integraatio: näet välittömästi seurantalaitteet sovelluksessa -• Plexus integraatio: Näe sovellusten yhteensopivuus välittömästi ilman Google Play Palveluita tai microG:tä -• Päivitykset mustalle listalle: Ohita tiettyjen sovellusten päivitykset diff --git a/fastlane/metadata/android/fi-FI/short_description.txt b/fastlane/metadata/android/fi-FI/short_description.txt deleted file mode 100644 index 7b22d5785..000000000 --- a/fastlane/metadata/android/fi-FI/short_description.txt +++ /dev/null @@ -1 +0,0 @@ -Epävirallinen ja yksityinen FOSS-asiakas Google Play:lle siistillä ulkoasulla diff --git a/fastlane/metadata/android/fr-FR/changelogs/46.txt b/fastlane/metadata/android/fr-FR/changelogs/46.txt index 255420f98..cd3fd2fb3 100644 --- a/fastlane/metadata/android/fr-FR/changelogs/46.txt +++ b/fastlane/metadata/android/fr-FR/changelogs/46.txt @@ -1,8 +1,8 @@ -• Ne demander l’autorisation d’accès à la mémoire que si cela est nécessaire -• Refonte de la configuration de l’usurpation pour contourner l’autorisation d’accès à la mémoire pour l’importation et l’exportation -• Ajout d’une option de vérification automatique de la présence de mises à jour pour les applis (un compte authentifié fonctionnel est nécessaire) -• Correction du problème de bibliothèques nécessaires qui n’étaient pas installées avec certaines applis, telles que Chrome et la bibliothèque trichrome -• Ignorer le dossier Downloads des sauvegardes lors de la sauvegarde du magasin Aurora -• Implémenter le programme d’installation Shizuku (Android 8.0 et version ultérieure requise) -• Fin de la prise en charge d’Android 4.4. La plus petite version d’Android requise est la version 5.0 -• Corrections mineures de bogues et améliorations +• Ne demande plus la permission de stockage sauf si cela est indispensable +• Refonte de la configuration de l'usurpation pour contourner la permission de stockage lors de l'import-export +• Ajout d'une option de vérification auto des mises à jour d'appli (un compte authentifié fonctionnel est nécessaire) +• Correction du problème de librairie supplémentaire requise lors de l'installation d'une appli (ex : librairie trichrome) +• Ignore désormais le dossier de téléchargement lors de la restauration d'une sauvegarde Aurora +• Ajout de l'installateur Shizuku (Android 8.0+ requis) +• Fin de support d'Android 4.4. Le minimum requis étant désormais la version 5.0+ +• Corrections mineures et améliorations diff --git a/fastlane/metadata/android/fr-FR/changelogs/47.txt b/fastlane/metadata/android/fr-FR/changelogs/47.txt index d67170d46..d6ddf8de3 100644 --- a/fastlane/metadata/android/fr-FR/changelogs/47.txt +++ b/fastlane/metadata/android/fr-FR/changelogs/47.txt @@ -1 +1 @@ -• Correctif d’urgence - Correction d'un plantage pour certains écrans +• Correction d'un crash pour certains écrans diff --git a/fastlane/metadata/android/fr-FR/changelogs/48.txt b/fastlane/metadata/android/fr-FR/changelogs/48.txt index 77e533fb1..e0ececf3a 100644 --- a/fastlane/metadata/android/fr-FR/changelogs/48.txt +++ b/fastlane/metadata/android/fr-FR/changelogs/48.txt @@ -1,3 +1,3 @@ -• Changements internes importants relatifs à l’interface utilisateur +• Modifications internes importantes relatives à l'interface utilisateur • Mise à jour des traductions -• Corrections de bogues mineurs et améliorations +• Corrections mineures et améliorations diverses diff --git a/fastlane/metadata/android/fr-FR/changelogs/49.txt b/fastlane/metadata/android/fr-FR/changelogs/49.txt index a72ef3617..edd6a21fc 100644 --- a/fastlane/metadata/android/fr-FR/changelogs/49.txt +++ b/fastlane/metadata/android/fr-FR/changelogs/49.txt @@ -1,4 +1,4 @@ -• Changement internes importants relatifs à l'interface utilisateur -• Permettre aux utilisateurs d’activer les liens d’appli lors du lancement initial +• Modifications internes importantes relatives à l'interface utilisateur +• Prise en charge des liens d'application activable au premier lancement • Mise à jour des traductions -• Corrections de bogues mineurs et améliorations +• Corrections mineures et améliorations diverses diff --git a/fastlane/metadata/android/fr-FR/changelogs/50.txt b/fastlane/metadata/android/fr-FR/changelogs/50.txt index 4f9516f9b..417745aab 100644 --- a/fastlane/metadata/android/fr-FR/changelogs/50.txt +++ b/fastlane/metadata/android/fr-FR/changelogs/50.txt @@ -1,9 +1,9 @@ -• Le passage d'un thème sombre au thème système met correctement à jour l'interface utilisateur. -• Les dialogues de l’écran d'accueil ne cachent plus certaines zones -• Un compte valide et fonctionnel doit être configuré pour ouvrir un lien Google Play -• Le tiroir de navigation ne peut être ouvert que sur l’écran principal -• Le bouton de retour ferme désormais l'appli correctement sur certains écrans -• Les boutons des paramètres affichent la bonne couleur pour le thème sombre -• Le nom de l'appli est de nouveau visible dans la barre d’outils pour les relevés Exodus. -• Améliorations internes relatives aux images +• L'interface s'affiche désormais correctement lors du passage du système en thème sombrey +• Les informations sur la page d'accueil ne masquent plus certaines zones +• L'ouverture d'un lien Google Play est désormais précédée d'une vérification de la présence d'un compte fonctionnel +• Le panneau de navigation est désormais accessible uniquement depuis l'écran principal +• Le bouton de retour permet désormais de quitter l'application normalement depuis certains écrans +• Les boutons dans les paramètres ont désormais la bonne coloration quand le thème sombre est activé +• Le nom de l'appli est de nouveau visible dans le panneau des rapports Exodus. +• Améliorations internes relatives aux visuels • Mises à jour des traductions diff --git a/fastlane/metadata/android/fr-FR/changelogs/51.txt b/fastlane/metadata/android/fr-FR/changelogs/51.txt index 91654cd0e..db4581baa 100644 --- a/fastlane/metadata/android/fr-FR/changelogs/51.txt +++ b/fastlane/metadata/android/fr-FR/changelogs/51.txt @@ -1 +1 @@ -• Correction d'un problème de recherche, utilise les données WebAPI +• Correction d'un problème dans la recherche, utilise désormais les données WebAPI diff --git a/fastlane/metadata/android/fr-FR/changelogs/52.txt b/fastlane/metadata/android/fr-FR/changelogs/52.txt index 58500da6d..2d97ba963 100644 --- a/fastlane/metadata/android/fr-FR/changelogs/52.txt +++ b/fastlane/metadata/android/fr-FR/changelogs/52.txt @@ -1,6 +1,6 @@ -• Correction d’un plantage sur certains appareils lors de la recherche de mot-clé dans des langues autres que l’anglais -• Amélioration de la page « Mes applis et jeux » -• Remise en place d’un commutateur pour installer automatiquement une appli après l’avoir téléchargée -• Suppression de la notification sonore lors de l’installation ou de la mise à jour d’une appli -• Correction d’un plantage sur certains appareils lors de la consultation des détails d’une appli -• Ajout d’une confirmation de désinstallation si le programme d’installation est utilisé en mode racine +• Correction d'un crash sur certains appareils lors de la recherche de mots non-anglophones +• Amélioration de la page "Mes applis et jeux" +• Ajout d'un bouton retour lors de l'installation automatique d'une appli après téléchargement +• Suppression de la notification sonore lorsqu'une appli est installée ou mise à jour +• Correction d'un crash sur certains appareils lors de la consultation des détails d'une appli +• Ajout d'une confirmation de désinstallation quand l'installateur racine est activé diff --git a/fastlane/metadata/android/fr-FR/changelogs/53.txt b/fastlane/metadata/android/fr-FR/changelogs/53.txt index 3c8e7c457..288169740 100644 --- a/fastlane/metadata/android/fr-FR/changelogs/53.txt +++ b/fastlane/metadata/android/fr-FR/changelogs/53.txt @@ -1,3 +1,3 @@ -• Correction du problème qui empêchait l’installation des applis après leur téléchargement -• Possibilité de choisir le dossier de téléchargement -• Ajout d’une option de téléchargement par Wi-Fi seulement +• Correction du problème qui empêchait l'installation d'une appli après son téléchargement +• Possibilité de personnaliser le dossier de téléchargement +• Ajout de la permission de téléchargement uniquement si le Wifi est activé diff --git a/fastlane/metadata/android/fr-FR/changelogs/58.txt b/fastlane/metadata/android/fr-FR/changelogs/58.txt index 87010737d..dfca40d16 100644 --- a/fastlane/metadata/android/fr-FR/changelogs/58.txt +++ b/fastlane/metadata/android/fr-FR/changelogs/58.txt @@ -1,4 +1,4 @@ • Correction d'un problème de connexion aux comptes Google -• Déplacement du tiroir de navigation dans une fenêtre de dialogue séparée -• Implémentation de NavigationRail pour les appareils à grand écran -• Possibilité d'exporter les téléchargements vers un emplacement externe +• Déplacement du panneau de navigation dans une fenêtre dédiée +• Prise en charge du composant NavigationRail pour les écrans larges +• Possibilité d'exporter les téléchargements vers un stockage externe diff --git a/fastlane/metadata/android/fr-FR/changelogs/66.txt b/fastlane/metadata/android/fr-FR/changelogs/66.txt deleted file mode 100644 index 5e2e7824f..000000000 --- a/fastlane/metadata/android/fr-FR/changelogs/66.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Nouvelles évaluations de compatibilité des applis propulsées par Plexus -• Amélioration du gestionnaire d’exclusions -• Possibilité de changer les restrictions de mise à jour automatique -• Corrections de bogues mineurs et améliorations -• Mises à jour des traductions ; des chaînes supplémentaires sont traduites diff --git a/fastlane/metadata/android/fr-FR/changelogs/67.txt b/fastlane/metadata/android/fr-FR/changelogs/67.txt deleted file mode 100644 index ba75b69df..000000000 --- a/fastlane/metadata/android/fr-FR/changelogs/67.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Cibler Android 16 -• Corriger un bogue d’ouverture des liens vers les applis -• Permettre d’ouvrir la page détaillée de l'appli à partir des renseignements de l'appli -• Mise à jour des traductions diff --git a/fastlane/metadata/android/fr-FR/changelogs/68.txt b/fastlane/metadata/android/fr-FR/changelogs/68.txt deleted file mode 100644 index 12c313bdf..000000000 --- a/fastlane/metadata/android/fr-FR/changelogs/68.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Nouvelles API pour la recherche et l’installation d’applis -• Le filtre de recherche n’est plus accessible, il sera ajouté ultérieurement. -• Correction d’un plantage lors de la navigation vers la page des détails de l’appli -• Correction d’un plantage lors de l’usurpation des paramètres régionaux -• Mises à jour des traductions diff --git a/fastlane/metadata/android/fr-FR/changelogs/72.txt b/fastlane/metadata/android/fr-FR/changelogs/72.txt deleted file mode 100644 index 21e402ef9..000000000 --- a/fastlane/metadata/android/fr-FR/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• La version minimale d’Android prise en charge est désormais Android 6.0 ; -• Passage au thème Material3 Expressive ; -• Amélioration de la prise en charge des appareils à écran large ; -• Correction d’un problème lié au réglage incorrect de la langue hébraïque dans les paramètres de langue par appli ; -• Rétablissement de la fonction des filtres de recherche. diff --git a/fastlane/metadata/android/fr-FR/changelogs/73.txt b/fastlane/metadata/android/fr-FR/changelogs/73.txt deleted file mode 100644 index 980c854b9..000000000 --- a/fastlane/metadata/android/fr-FR/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Correction d’une icône de flèche de mise à niveau incorrecte pour les dispositions de droite à gauche -• Correction de problèmes de pagination et d’IME lors des recherches -• Correction d’un bogue qui remplaçait le choix de programme d’installation de l’utilisateur -• Mise à jour des traductions, de la base de données des traceurs Exodus et des certificats racine de Google diff --git a/fastlane/metadata/android/fr-FR/full_description.txt b/fastlane/metadata/android/fr-FR/full_description.txt index d301cbf71..a6ea11075 100644 --- a/fastlane/metadata/android/fr-FR/full_description.txt +++ b/fastlane/metadata/android/fr-FR/full_description.txt @@ -1,11 +1,13 @@ -Avec sa conception élégante, Aurora Store est un client libre non officiel de remplacement de Google Play. Comme le magasin Play Store, Aurora Store permet aux utilisateurs de télécharger, mettre à jour et chercher des applis. Il fonctionne parfaitement avec ou sans les services Google Play ou microG. +Aurora Store est un client non-officiel alternatif pour Google Play, libre et gratuit (FOSS). +Doté d’un design élégant, il garantit le respect des données personnelles. +Aurora Store offre la possibilité de télécharger, mettre à jour et rechercher des applications de la même manière que Play Store. +Il est capable de fonctionner avec ou sans les services Google Play ou MicroG. Caractéristiques : -• Libre : dispose d’une licence GPLv3 -• Conception attirante : conçu selon les dernières directives Material 3 -• Connexion au compte : vous pouvez vous connecter soit avec un compte personnel soit anonyme -• Usurpation d’appareil et de paramètres régionaux : changez votre type appareil ou vos paramètres régionaux pour accéder aux applis verrouillées géographiquement -• Intégration d’« Exodus Privacy » : voyez instantanément les traqueurs des applis -• Intégration de Plexus : constatez instantanément la compatibilité des applis sans les services Google Play Services avec microG -• Mise à jour de la liste d’exclusions : ignorez les mises à jour pour certaines applis +• Logiciel libre : sous licence GPLv3 +• Conception et design élégants - bâti avec les normes du référentiel Material Design 3 +• Prise en charge des comptes Google - Vous pouvez vous connecter à un compte personnel ou de manière anonyme +• Mode furtif - Changez votre profil d’appareil et/ou vos informations de localisation afin de contourner les limitations régionales et accéder à toutes les applications géo-verrouillées +• Intégration d’Exodus Privacy - Repérez instantanément les traqueurs de données personnelles dans les applications +• Fonction liste noire des mises à jour - Choisissez les applications pour lesquelles vous souhaitez ignorer les mises à jour diff --git a/fastlane/metadata/android/fr-FR/short_description.txt b/fastlane/metadata/android/fr-FR/short_description.txt index 0db0ac4fa..0e910c308 100644 --- a/fastlane/metadata/android/fr-FR/short_description.txt +++ b/fastlane/metadata/android/fr-FR/short_description.txt @@ -1 +1 @@ -Client Google Play libre non officiel. Élégant et respectueux de la vie privée +Un client alternatif libre pour Google Play, élégant et respectueux des données diff --git a/fastlane/metadata/android/hi/changelogs/42.txt b/fastlane/metadata/android/hi/changelogs/42.txt index cc07afbec..b38dd766f 100644 --- a/fastlane/metadata/android/hi/changelogs/42.txt +++ b/fastlane/metadata/android/hi/changelogs/42.txt @@ -1,15 +1,15 @@ • लक्ष्य Android 13 -• कई स्ट्रिंग स्थानीयकरण -• Android 13 मोनोक्रोम आइकन -• नवीनतम निर्भरताएँ -• लॉन्च पर सेवा शर्तें -• बिना अनुमति आगे बढ़ें -• डिफ़ॉल्ट डेनीलिस्ट पढ़ें -• 5वें पेज पर सही शीर्षक -• वापस पर आगे बटन -• रेडियो बटन सेटअप -• स्ट्रोक रंग टैब -• रेडियो बटन से थीम बग ठीक -• नए GSF/वेंडिंग नहीं -• भंडारण अनुमति रिफैक्टर -• अनुवाद अपडेट +• एकाधिक स्ट्रिंग्स का स्थानीयकरण सक्षम करें +• एंड्रॉइड 13 के लिए मोनोक्रोम आइकन जोड़ें +• निर्भरताओं को नवीनतम संस्करण में अद्यतन करें +• लॉन्च पर तुरंत सेवा की शर्तें दिखाएं +• प्रारंभिक सेटअप के दौरान अनुमति दिए बिना आगे बढ़ने की अनुमति दें +• अपडेट से बाहर करने के लिए सिस्टम xml डेनिलिस्ट को डिफ़ॉल्ट के रूप में पढ़ें +• पांचवें सेटअप पृष्ठ पर सही शीर्षक दिखाएँ +• वापस जाते समय सेटअप पर फॉरवर्ड बटन सक्षम करें +• सेटअप इंस्टॉलर में चेकबॉक्स को रेडियो बटन से बदलें +• सेटअप टैब की पृष्ठभूमि के लिए स्ट्रोक रंग का उपयोग करें +• रेडियो बटन का उपयोग करके सेटअप में नो-थीम बग को ठीक करें +• नए जीएसएफ और वेंडिंग संस्करणों का उपयोग न करें +• रिफैक्टर भंडारण संबंधी अनुमतियाँ सेटअप +• अनुवाद अद्यतन diff --git a/fastlane/metadata/android/hi/changelogs/46.txt b/fastlane/metadata/android/hi/changelogs/46.txt index 4785e2a79..b67cc908b 100644 --- a/fastlane/metadata/android/hi/changelogs/46.txt +++ b/fastlane/metadata/android/hi/changelogs/46.txt @@ -1,8 +1,8 @@ -• आवश्यकता तक भंडारण अनुमति से बचें -• आयात-निर्यात हेतु भंडारण अनुमति से बचने के लिए स्पूफ कॉन्फ़िगरेशन में बदलाव -• ऐप अपडेट स्वचालित रूप से जाँचने का विकल्प (लॉग इन खाता आवश्यक) -• क्रोम और ट्राइक्रोम जैसी लाइब्रेरी के साथ आवश्यक लाइब्रेरी स्थापित न होने की समस्या ठीक -• Aurora Store का बैकअप लेते समय डाउनलोड निर्देशिका अनदेखा करें -• शिज़ुकु इंस्टॉलर लागू करें (Android 8.0+ आवश्यक) -• Android 4.4 का समर्थन समाप्त। न्यूनतम Android संस्करण 5.0+। -• मामूली बग फिक्स और सुधार +• जब तक आवश्यक न हो स्टोरेज की अनुमति मांगने से बचें +• आयात-निर्यात के लिए स्टोरेज की अनुमति से बचने के लिए स्पूफ कॉन्फ़िगरेशन पर दोबारा काम किया गया +• ऐप अपडेट के लिए स्वचालित रूप से जांच करने का विकल्प जोड़ें (एक कामकाजी खाते से लॉग इन होना आवश्यक है) +• उस समस्या को ठीक किया गया जहां क्रोम और ट्राइक्रोम लाइब्रेरी जैसे ऐप्स के साथ आवश्यक लाइब्रेरी इंस्टॉल नहीं की जा रही थीं +• ऑरोरा स्टोर का बैकअप लेते समय बैकअप से डाउनलोड निर्देशिका पर ध्यान न दें +• शिज़ुकु इंस्टॉलर लागू करें (एंड्रॉइड 8.0+ की आवश्यकता है) +• एंड्रॉइड 4.4 के लिए समर्थन बंद करें। न्यूनतम आवश्यक Android संस्करण 5.0+ है। +• मामूली बग समाधान और सुधार diff --git a/fastlane/metadata/android/hi/changelogs/54.txt b/fastlane/metadata/android/hi/changelogs/54.txt index f88fbd7bb..7e2fc9a93 100644 --- a/fastlane/metadata/android/hi/changelogs/54.txt +++ b/fastlane/metadata/android/hi/changelogs/54.txt @@ -1,18 +1,18 @@ -• डाउनलोड सिस्टम बदला - • पृष्ठभूमि डाउनलोड हेतु नई अनुमति - • रोकें/फिर शुरू अप्रचलित - • एक साथ एक डाउनलोड - • SHA सत्यापन - • Chrome/WebView बेहतर -• अपडेट सिस्टम बदला - • स्वचालित अपडेट (डिफ़ॉल्ट) - • प्रमाणपत्र सत्यापन - • कुंजी रोटेशन समर्थन (9.0+) - • स्व-अपडेट अक्षम (सेटिंग्स) -• नेटिव इंस्टॉलर/Aurora Services अप्रचलित -• निर्यात हेतु भंडारण अनुमति नहीं -• न्यूनतम Android संस्करण ऐप विवरण में -• अनुवाद/बग फिक्स -• Sui से इंस्टॉल -• GMS ओवरराइड -• Material3 उपयोग +• डाउनलोड सिस्टम में प्रमुख आंतरिक परिवर्तन + • ऑरोरा स्टोर को अब पृष्ठभूमि में डाउनलोड करने के लिए नई अनुमति की आवश्यकता है + • डाउनलोड के लिए रोकें और फिर से शुरू करने की सुविधाओं को रोक दिया गया है + • समवर्ती डाउनलोड को रोक दिया गया है (एक समय में एक डाउनलोड तक सीमित) + • डाउनलोड की गई फ़ाइलों के लिए स्वचालित SHA256 और SHA1 सत्यापन + • Chrome और WebView जैसी साझा लाइब्रेरी वाले ऐप्स के लिए बेहतर समर्थन +• अद्यतन प्रणाली में प्रमुख परिवर्तन + • ऐप्स के लिए नए स्वचालित अपडेट (डिफ़ॉल्ट रूप से सक्षम) + • अपडेट के लिए नया स्वचालित प्रमाणपत्र सत्यापन + • साइनिंग कुंजी रोटेशन के साथ अपडेट के लिए समर्थन (एंड्रॉइड 9.0+ के बाद पेश किया गया) + • सेल्फ-अपडेट (ऑरोरा स्टोर) को डिफ़ॉल्ट रूप से अक्षम कर दिया गया है (सेटिंग्स> अपडेट में सक्षम करें) +• नेटिव इंस्टालर और ऑरोरा सेवाओं को हटा दिया गया है +• इंस्टॉल किए गए ऐप्स को निर्यात करने के लिए अब स्टोरेज अनुमति की आवश्यकता नहीं है +• ऐप्स के लिए न्यूनतम आवश्यक एंड्रॉइड संस्करण अब ऐप विवरण पृष्ठ पर दिखाई दे रहा है (इस ऐप के बारे में अधिक जानकारी > जानकारी) +• अनुवाद अपडेटस और प्रमुख बग समाधान +• सुई (शिज़ुकु मैजिक मॉड्यूल) के साथ ऐप्स इंस्टॉल करने के लिए समर्थन +• सेटिंग्स > नेटवर्क से जीएमएस संस्करण को ओवरराइड करने की क्षमता +• मटेरियल3 का उपयोग अब अधिक स्थानों पर किया जा रहा है diff --git a/fastlane/metadata/android/hi/changelogs/55.txt b/fastlane/metadata/android/hi/changelogs/55.txt index 8882162dc..7e2fc9a93 100644 --- a/fastlane/metadata/android/hi/changelogs/55.txt +++ b/fastlane/metadata/android/hi/changelogs/55.txt @@ -1,18 +1,18 @@ -• डाउनलोड सिस्टम बदला - • पृष्ठभूमि डाउनलोड हेतु नई अनुमति - • रोकें/फिर शुरू अप्रचलित - • एक साथ एक डाउनलोड - • SHA सत्यापन - • Chrome/WebView बेहतर -• अपडेट सिस्टम बदला - • स्वचालित अपडेट (डिफ़ॉल्ट) - • प्रमाणपत्र सत्यापन - • कुंजी रोटेशन (9.0+) - • स्व-अपडेट बंद (सेटिंग्स) -• नेटिव इंस्टॉलर/Aurora Services हटे -• निर्यात हेतु भंडारण अनुमति नहीं -• न्यूनतम Android संस्करण ऐप विवरण में -• अनुवाद/बग फिक्स -• Sui से इंस्टॉल -• GMS ओवरराइड -• Material3 उपयोग +• डाउनलोड सिस्टम में प्रमुख आंतरिक परिवर्तन + • ऑरोरा स्टोर को अब पृष्ठभूमि में डाउनलोड करने के लिए नई अनुमति की आवश्यकता है + • डाउनलोड के लिए रोकें और फिर से शुरू करने की सुविधाओं को रोक दिया गया है + • समवर्ती डाउनलोड को रोक दिया गया है (एक समय में एक डाउनलोड तक सीमित) + • डाउनलोड की गई फ़ाइलों के लिए स्वचालित SHA256 और SHA1 सत्यापन + • Chrome और WebView जैसी साझा लाइब्रेरी वाले ऐप्स के लिए बेहतर समर्थन +• अद्यतन प्रणाली में प्रमुख परिवर्तन + • ऐप्स के लिए नए स्वचालित अपडेट (डिफ़ॉल्ट रूप से सक्षम) + • अपडेट के लिए नया स्वचालित प्रमाणपत्र सत्यापन + • साइनिंग कुंजी रोटेशन के साथ अपडेट के लिए समर्थन (एंड्रॉइड 9.0+ के बाद पेश किया गया) + • सेल्फ-अपडेट (ऑरोरा स्टोर) को डिफ़ॉल्ट रूप से अक्षम कर दिया गया है (सेटिंग्स> अपडेट में सक्षम करें) +• नेटिव इंस्टालर और ऑरोरा सेवाओं को हटा दिया गया है +• इंस्टॉल किए गए ऐप्स को निर्यात करने के लिए अब स्टोरेज अनुमति की आवश्यकता नहीं है +• ऐप्स के लिए न्यूनतम आवश्यक एंड्रॉइड संस्करण अब ऐप विवरण पृष्ठ पर दिखाई दे रहा है (इस ऐप के बारे में अधिक जानकारी > जानकारी) +• अनुवाद अपडेटस और प्रमुख बग समाधान +• सुई (शिज़ुकु मैजिक मॉड्यूल) के साथ ऐप्स इंस्टॉल करने के लिए समर्थन +• सेटिंग्स > नेटवर्क से जीएमएस संस्करण को ओवरराइड करने की क्षमता +• मटेरियल3 का उपयोग अब अधिक स्थानों पर किया जा रहा है diff --git a/fastlane/metadata/android/hi/changelogs/62.txt b/fastlane/metadata/android/hi/changelogs/62.txt deleted file mode 100644 index e0f90a91f..000000000 --- a/fastlane/metadata/android/hi/changelogs/62.txt +++ /dev/null @@ -1,6 +0,0 @@ -• Android 15 पर UI समस्या को ठीक किया गया -• प्रॉक्सी कॉन्फ़िगरेशन और उपयोग में सुधार -• रूट प्रमाणपत्रों का उपयोग करके ज्ञात डोमेन के लिए SSL पिनिंग -• समर्थित डिवाइस पर डायनेमिक थीम के लिए बेहतर समर्थन -• कस्टम थीम और एक्सेंट रंगों के लिए समर्थन हटा दिया गया -• अनुवाद अपडेट diff --git a/fastlane/metadata/android/hi/changelogs/63.txt b/fastlane/metadata/android/hi/changelogs/63.txt deleted file mode 100644 index ef308f28c..000000000 --- a/fastlane/metadata/android/hi/changelogs/63.txt +++ /dev/null @@ -1,3 +0,0 @@ -• प्रवास से जुड़े छोटे मुद्दों को ठीक किया -• रात्रि-निर्माणों के लिये स्व-अद्यतन जोड़ा गया -• अद्यतनित अनुवाद diff --git a/fastlane/metadata/android/hi/changelogs/64.txt b/fastlane/metadata/android/hi/changelogs/64.txt deleted file mode 100644 index db36ec295..000000000 --- a/fastlane/metadata/android/hi/changelogs/64.txt +++ /dev/null @@ -1,6 +0,0 @@ -• Android 15+ पर ऐप्स को संग्रहित/अन-संग्रहित करने के लिए समर्थन -• Android 15+ पर ऐप्स को निजी स्थान में इंस्टॉल करने के लिए समर्थन -• एज-टू-एज समर्थन के लिए UI समायोजन -• कई बग फिक्स और सुधार -• अधिसूचना चैनलों और सूचनाओं में सुधार -• अनुवाद अपडेट; अतिरिक्त स्ट्रिंग्स को स्थानीयकृत किया गया diff --git a/fastlane/metadata/android/hi/changelogs/65.txt b/fastlane/metadata/android/hi/changelogs/65.txt deleted file mode 100644 index 0f9a371a4..000000000 --- a/fastlane/metadata/android/hi/changelogs/65.txt +++ /dev/null @@ -1,4 +0,0 @@ -• क्रोम और वेबव्यू जैसे ऐप के लिए साझा लाइब्रेरी इंस्टॉलेशन से जुड़ी समस्याओं को ठीक किया गया -• माइक्रोजी का उपयोग करके व्यक्तिगत खाते में लॉगिन करने के लिए सहायता -• प्रमाणीकरण सत्यापन से जुड़ी समस्या को ठीक किया गया -• अनुवाद अपडेट; अतिरिक्त स्ट्रिंग्स को स्थानीयकृत किया गया diff --git a/fastlane/metadata/android/hi/changelogs/66.txt b/fastlane/metadata/android/hi/changelogs/66.txt deleted file mode 100644 index db53b768b..000000000 --- a/fastlane/metadata/android/hi/changelogs/66.txt +++ /dev/null @@ -1,5 +0,0 @@ -• प्लेक्सस द्वारा संचालित नई ऐप संगतता रेटिंग -• ब्लैकलिस्ट मैनेजर में सुधार -• ऑटो-अपडेट प्रतिबंधों को बदलने की क्षमता -• मामूली बग फिक्स और सुधार -• अनुवाद अपडेट; अतिरिक्त स्ट्रिंग्स स्थानीयकृत diff --git a/fastlane/metadata/android/hi/changelogs/72.txt b/fastlane/metadata/android/hi/changelogs/72.txt deleted file mode 100644 index ef05ec21f..000000000 --- a/fastlane/metadata/android/hi/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• अब न्यूनतम समर्थित एंड्रॉइड संस्करण है एंड्रॉइड ६.० -• Material3 Expressive रूपरेखा का प्रयोग -• बड़े-पटल के यंत्रों के लिये बेहतर समर्थन -• एक समस्या ठीक की जिसमें प्रति-एप भाषा में हिब्रू भाषा ठीक से सेट नहीं थी -• खोज छन्नी की मरम्मत की गयी diff --git a/fastlane/metadata/android/hi/full_description.txt b/fastlane/metadata/android/hi/full_description.txt index fa9b64331..3f0d3a5db 100644 --- a/fastlane/metadata/android/hi/full_description.txt +++ b/fastlane/metadata/android/hi/full_description.txt @@ -1,11 +1,12 @@ -ऑरोरा स्टोर एक अनौपचारिक, Google Play के लिए FOSS क्लाइंट है जिसका डिज़ाइन बहुत सुंदर है। ऑरोरा स्टोर उपयोगकर्ताओं को Play Store जैसे ऐप डाउनलोड करने, अपडेट करने और खोजने की अनुमति देता है। यह Google Play सेवाओं या microG के साथ या उसके बिना पूरी तरह से ठीक काम करता है। +Aurora Store एक सुंदर डिज़ाइन के साथ Google Play का एक अनौपचारिक, FOSS क्लाइंट है। Aurora Store +उपयोगकर्ताओं को प्ले स्टोर जैसे ऐप्स डाउनलोड करने, अपडेट करने और खोजने देता है। यह Google Play Services या MicroG परवाह +किए बिना काम करता हैै। -विशेषताएँ: +विशेषताएं: • FOSS: GPLv3 लाइसेंस है -• सुंदर डिज़ाइन: नवीनतम मटेरियल 3 दिशा-निर्देशों पर बनाया गया +• सुंदर डिज़ाइन: नवीनतम Material 3 दिशानिर्देशों पर निर्मित • खाता लॉगिन: आप व्यक्तिगत या अनाम खाते से लॉगिन कर सकते हैं -• डिवाइस और लोकेल स्पूफिंग: जियो लॉक किए गए ऐप तक पहुँचने के लिए अपना डिवाइस और/या लोकेल बदलें -• एक्सोडस प्राइवेसी इंटीग्रेशन: ऐप में तुरंत ट्रैकर्स देखें -• प्लेक्सस इंटीग्रेशन: Google Play सेवाओं या microG के बिना ऐप संगतता तुरंत देखें -• अपडेट ब्लैकलिस्टिंग: विशिष्ट ऐप के लिए अपडेट को अनदेखा करें +• डिवाइस और लोकेल स्पूफिंग: जियो लॉक किए गए ऐप्स तक पहुंचने के लिए अपना डिवाइस और/या लोकेल बदलें +• Exodus Privacy एकीकरण: ऐप में तुरंत ट्रैकर्स देखें +• अपडेट ब्लैकलिस्टिंग: विशिष्ट ऐप्स के लिए अपडेट को अनदेखा करें diff --git a/fastlane/metadata/android/hr/changelogs/72.txt b/fastlane/metadata/android/hr/changelogs/72.txt deleted file mode 100644 index f3a3e5f68..000000000 --- a/fastlane/metadata/android/hr/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Najmanja podržana Android verzija je sada Android 6.0 -• Prebačeno na **Material3 Expressive** temu -• Poboljšana podrška za uređaje sa širokim ekranom -• Ispravljen problem kod kojeg hebrejski jezik nije bio ispravno postavljen kod odabira jezika po aplikaciji -• Vraćena funkcionalnost filtara pretraživanja diff --git a/fastlane/metadata/android/hr/full_description.txt b/fastlane/metadata/android/hr/full_description.txt index d025ce66a..a7b22726b 100644 --- a/fastlane/metadata/android/hr/full_description.txt +++ b/fastlane/metadata/android/hr/full_description.txt @@ -1,4 +1,6 @@ -Aurora Store je neslužbeni, FOSS klijent za Google Play s elegantnim dizajnom. Aurora Store omogućuje korisnicima preuzimanje, aktualiziranje i pretraživanje aplikacija poput Play Storea. Savršeno funkcionira s ili bez Google Play usluga ili MicroG-a. +Aurora Store je neslužbeni, FOSS klijent za Google Play s elegantnim dizajnom. Aurora Store +omogućuje korisnicima preuzimanje, aktualiziranje i pretraživanje aplikacija poput Play Storea. +Savršeno funkcionira s ili bez Google Play usluga ili MicroG-a. Značajke: @@ -7,5 +9,4 @@ Aurora Store je neslužbeni, FOSS klijent za Google Play s elegantnim dizajnom. • Prijava na račun: Prijavi se s osobnim ili anonimnim računom • Promjena uređaja i lokacije: Promijeni uređaj i/ili lokaciju za pristup aplikacijama koje su zaključane za određene regije • Integracija s Exodus Privacy: Programi za praćenje se trenutno prikazuju unutar aplikacije -• Integracija s Plexusom: Trenutno provjerite kompatibilnost aplikacija bez usluga Google Play ili s microG-om -• Aktualizira blokirane: Zanemari aktualiziranja za određene aplikacije +• Crna lista aktualiziranja: Zanemari aktualiziranja za određene aplikacije diff --git a/fastlane/metadata/android/hu-HU/changelogs/42.txt b/fastlane/metadata/android/hu-HU/changelogs/42.txt index e2cd683ac..1b57f062c 100644 --- a/fastlane/metadata/android/hu-HU/changelogs/42.txt +++ b/fastlane/metadata/android/hu-HU/changelogs/42.txt @@ -1,4 +1,4 @@ -• Koncentrálás Android 13-ra +• Android 13 célzása • További szövegek lokalizációjának lehetővé tétele • Monokróm ikon az Android 13-hoz • Függőségek frissítése @@ -6,10 +6,5 @@ • Továbblépés engedélyezése a jogosultságok megadása nélkül • Rendszer kizárási listájának figyelembe vétele a frissítéseknél • Cím javítása az 5. beállítólapon -• Tovább gomb megjelenítése visszalépésnél -• Jelölőnégyzetek lecserélése rádiós gombokra a telepítőben -• Söprő szín beállítása a telepítő hátterének -• A témátlan hiba kiküszöbölése a telepítőben rádió gombokkal -• Ne használja az új GSF & Vending verziókat • Tárhellyel kapcsolatos jogosultságbeállítások refaktorálása • Frissített fordítások diff --git a/fastlane/metadata/android/hu-HU/changelogs/46.txt b/fastlane/metadata/android/hu-HU/changelogs/46.txt deleted file mode 100644 index 264547938..000000000 --- a/fastlane/metadata/android/hu-HU/changelogs/46.txt +++ /dev/null @@ -1,8 +0,0 @@ -• Tárhely engedély visszatartása, míg valóban szükséges -• Újradolgozott álca konfiguráció, az importálás-exportáláshoz így nem kell tárhely engedély -• Opció, hogy automatikusan ellenőrzi az app frissítéseket (szükséges egy működő fiókkal való bejelentkezés) -• Hiba javítása, amikor szükséges könyvtárak nem kerülnek telepítésre appoknál mint a chrome & trichrome -• A letöltés mappa figyelmen kívül hagyása az Aurora Bolt biztonsági mentésénél -• Shizuku telepítő implementálása (Android 8.0+ szükséges) -• Android 4.4 támogatás kivezetése. A minimum elvárt verziószám immáron 5.0+. -• Kisebb hibajavítások és fejlesztések diff --git a/fastlane/metadata/android/hu-HU/changelogs/72.txt b/fastlane/metadata/android/hu-HU/changelogs/72.txt deleted file mode 100644 index a5a5eca09..000000000 --- a/fastlane/metadata/android/hu-HU/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• A minimálisan támogatott Android verzió mostantól Android 6.0 -• Átállás a Material3 Expressive témára -• Javítva a széles képernyős eszközök támogatása -• Javítva lett az a hiba, amely miatt a héber nyelv nem volt megfelelően beállítva az alkalmazásonkénti nyelvbeállításoknál -• A keresési szűrők, mint funkció visszaállítása diff --git a/fastlane/metadata/android/hu-HU/changelogs/73.txt b/fastlane/metadata/android/hu-HU/changelogs/73.txt deleted file mode 100644 index 7aeca6aff..000000000 --- a/fastlane/metadata/android/hu-HU/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Javítva lett a hibás frissítési nyíl ikon RTL (jobbról balra írt) elrendezéseken -• Javítva lettek a lapozási és IME (billentyűzet) problémák a keresésnél -• Javítva egy hiba, amely felülírta a felhasználó által választott telepítőt -• Frissítve a fordítások, az Exodus követőadatbázis és a Google gyökértanúsítványai diff --git a/fastlane/metadata/android/hu-HU/full_description.txt b/fastlane/metadata/android/hu-HU/full_description.txt index 2c41294b9..940afdcd2 100644 --- a/fastlane/metadata/android/hu-HU/full_description.txt +++ b/fastlane/metadata/android/hu-HU/full_description.txt @@ -1,13 +1,12 @@ -Az Aurora Store egy nem hivatalos, nyílt forráskódú Google Play-kliens, elegáns dizájnnal. +Az Aurora Store egy nem hivatalos, nyílt forráskódú Google Play kliens, elegáns dizájnnal. Az Aurora Store lehetővé teszi alkalmazások frissítését, letöltését és keresését, akárcsak a Google Play. -Tökéletesen működik Google Play-szolgáltatások, illetve a microG nélkül is. +Tökéletesen működik Google Play Szolgáltatások, illetve MicroG nélkül is. Funkciók: • FOSS: GPLv3 licenc -• Gyönyörű dizájn: a legmodernebb Material 3 irányelvek alapján -• Fiókbejelentkezés: használható saját, illetve anonim fiók is -• Eszköz-, névszimuláció: az eszköz típusa, neve és régiója eszközszimuláció segítségével álcázható, így a földrajzilag korlátozott alkalmazások is elérhető -• Exodus Privacy integráció: az alkalmazások nyomkövetőinek azonnali kimutatása -• Plexus integráció: az alkalmazások Google Play-szolgáltatások nélküli vagy microG-vel történő kompatibilitása azonnal megtekinthető -• Frissítési tiltólista: egyes alkalmazások frissítései tiltólistára helyezhetők +• Gyönyörű dizájn: A legmodernebb Material 3 irányelvek alapján +• Fiók és bejelentkezés: Használható saját, illetve anonim fiók is +• Eszköz és nyelv álcázása: A készülék típusa, illetve nyelve is álcázható, így a földrajzilag korlátolt alkalmazások is elérhetők +• Exodus Privacy integráció: Alkalmazások nyomkövetőinek azonnali kimutatása +• Frissítési tiltólista: Egyes alkalmazások frissítései tiltólistára tehetők diff --git a/fastlane/metadata/android/id/changelogs/42.txt b/fastlane/metadata/android/id/changelogs/42.txt index 428df119b..3cdf969b9 100644 --- a/fastlane/metadata/android/id/changelogs/42.txt +++ b/fastlane/metadata/android/id/changelogs/42.txt @@ -1,15 +1,15 @@ -• Target Android 13 -• Aktifkan terjemahan lokal beberapa string -• Menambah ikon monokrom untuk Android 13 -• Perbarui dependensi ke versi terbaru -• Tampilkan prompt Persyaratan Layanan saat pertama kali diluncurkan -• Izinkan pengguna melanjutkan tanpa memberikan izin selama pengaturan awal -• Baca daftar penolakan XML sistem sebagai bawaan untuk pengecualian dari pembaruan -• Tampilkan judul yang benar di halaman pengaturan ke-5 -• Aktifkan tombol maju di pengaturan saat kembali -• Ganti kotak centang di penginstal pengaturan dengan tombol radio -• Gunakan warna garis untuk latar belakang tab pengaturan -• Perbaiki bug tanpa tema di pengaturan dengan menggunakan tombol radio -• Jangan gunakan versi baru GSF & Vending -• Perbarui pengaturan izin terkait penyimpanan -• Pembaruan terjemahan +- Dukungan Android 13 +- Aktifkan pelokalan beberapa string +- Tambahkan ikon monokrom untuk Android 13 +- Perbarui dependensi ke versi terbaru +- Tampilkan segera Ketentuan Layanan saat peluncuran +- Izinkan untuk melanjutkan tanpa memberikan izin selama penyiapan awal +- Baca daftar tolak xml sistem sebagai default untuk mengecualikan dari pembaruan +- Tampilkan judul yang benar pada halaman penyiapan ke-5 +- Aktifkan tombol maju pada penyiapan saat kembali +- Ganti kotak centang pada penginstalasi penyiapan dengan tombol radio +- Gunakan warna goresan untuk latar belakang tab pengaturan +- Perbaiki bug tanpa tema di pengaturan dengan menggunakan tombol radio +- Jangan gunakan versi GSF & Vending yang baru +- Memperbaiki pengaturan izin terkait penyimpanan +- Pembaruan terjemahan diff --git a/fastlane/metadata/android/id/changelogs/65.txt b/fastlane/metadata/android/id/changelogs/65.txt index ebaa2b45a..ed0844e63 100644 --- a/fastlane/metadata/android/id/changelogs/65.txt +++ b/fastlane/metadata/android/id/changelogs/65.txt @@ -1,4 +1,7 @@ • Memperbaiki masalah dengan penginstalan pustaka bersama untuk aplikasi seperti Chrome dan WebView + • Dukungan untuk masuk ke akun pribadi menggunakan microG + • Memperbaiki masalah dengan verifikasi autentikasi + • Pembaruan terjemahan; String tambahan dilokalkan diff --git a/fastlane/metadata/android/id/changelogs/66.txt b/fastlane/metadata/android/id/changelogs/66.txt deleted file mode 100644 index a987b079c..000000000 --- a/fastlane/metadata/android/id/changelogs/66.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Peringkat kompatibilitas aplikasi baru yang diberdayakan oleh Plexus -• Perbaikan untuk manajer daftar hitam -• Kemampuan untuk mengubah pembatasan pembaruan otomatis -• Perbaikan dan perbaikan bug minor -• Pembaruan terjemahan; penambahan teks yang telah diterjemahkan diff --git a/fastlane/metadata/android/id/changelogs/67.txt b/fastlane/metadata/android/id/changelogs/67.txt deleted file mode 100644 index 4f08a71f6..000000000 --- a/fastlane/metadata/android/id/changelogs/67.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Target Android 16 -• Perbaikan bug saat membuka tautan ke aplikasi -• Dukungan untuk membuka halaman detail aplikasi dari pengaturan informasi aplikasi -• Pembaruan terjemahan diff --git a/fastlane/metadata/android/id/changelogs/68.txt b/fastlane/metadata/android/id/changelogs/68.txt deleted file mode 100644 index 28604ca39..000000000 --- a/fastlane/metadata/android/id/changelogs/68.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Ganti ke API baru untuk mencari dan memasang aplikasi -• Saringan pencarian sementara tidak tersedia, akan ditambahkan lagi -• Perbaikan crash saat membuka halaman detail aplikasi -• Perbaikan crash saat memalsukan wilayah -• Pembaruan terjemahan diff --git a/fastlane/metadata/android/id/changelogs/72.txt b/fastlane/metadata/android/id/changelogs/72.txt deleted file mode 100644 index 6e48ea626..000000000 --- a/fastlane/metadata/android/id/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Versi Android minimum yang didukung sekarang adalah Android 6.0 -• Beralih ke tema Material3 Expressive -• Peningkatan dukungan untuk perangkat layar lebar -• Perbaikan masalah di mana bahasa Ibrani tidak diatur dengan benar pada pengaturan bahasa per aplikasi -• Pemulihan fungsi filter pencarian diff --git a/fastlane/metadata/android/id/changelogs/73.txt b/fastlane/metadata/android/id/changelogs/73.txt deleted file mode 100644 index 22fc5825a..000000000 --- a/fastlane/metadata/android/id/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Perbaikan indikator ikon panah pembaruan yang salah pada tata letak RTL -• Perbaikan masalah pemuatan halaman dan IME pada pencarian -• Perbaikan bug yang mengabaikan pilihan penginstal pengguna -• Pembaruan terjemahan, basis data pelacak exodus, dan sertifikat akar Google diff --git a/fastlane/metadata/android/id/full_description.txt b/fastlane/metadata/android/id/full_description.txt index 82f86ea12..406012959 100644 --- a/fastlane/metadata/android/id/full_description.txt +++ b/fastlane/metadata/android/id/full_description.txt @@ -1,11 +1,12 @@ -Aurora Store adalah klien yang tidak resmi, FOSS untuk Google Play dengan desain yang elegan. Aurora Store memungkinkan pengguna mengunduh, memperbarui, dan mencari aplikasi seperti Play Store. Aplikasi ini bekerja dengan sempurna dengan atau tanpa Layanan Google Play atau microG. +Aurora Store adalah klien yang tidak resmi, FOSS untuk Google Play dengan desain yang elegan. Aurora Store +memungkinkan pengguna mengunduh, memperbarui, dan mencari aplikasi seperti Play Store. Aplikasi ini bekerja dengan sempurna +dengan atau tanpa Layanan Google Play atau MicroG. Fitur: • FOSS: Berlisensi GPLv3 • Desain yang indah: Dibangun berdasarkan panduan Material 3 versi terbaru • Akun: Anda dapat masuk dengan akun pribadi atau anonim -• Pemalsuan Perangkat & Lokal: Mengubah perangkat Anda dan/atau lokal untuk mengakses aplikasi dengan geografis terkunci +• Spoofing Perangkat & Lokal: Mengubah perangkat Anda dan/atau lokal untuk mengakses aplikasi dengan geografis terkunci • Integrasi Exodus Privacy: pelacak di aplikasi dapat dilihat secara instan -• Integrasi Plexus: Lihat kompatibilitas aplikasi tanpa Layanan Google Play atau dengan microG secara langsung • Memperbarui daftar hitam: Mengabaikan pembaruan untuk aplikasi tertentu diff --git a/fastlane/metadata/android/it-IT/changelogs/38.txt b/fastlane/metadata/android/it-IT/changelogs/38.txt deleted file mode 100644 index c3aa00b4c..000000000 --- a/fastlane/metadata/android/it-IT/changelogs/38.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Corretta l'installazione dei Servizi Aurora -• Aggiornate le traduzioni diff --git a/fastlane/metadata/android/it-IT/changelogs/40.txt b/fastlane/metadata/android/it-IT/changelogs/40.txt deleted file mode 100644 index 7a2e49d2d..000000000 --- a/fastlane/metadata/android/it-IT/changelogs/40.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Miglioramenti e correzioni di errori -• Traduzioni Aggiornate diff --git a/fastlane/metadata/android/it-IT/changelogs/41.txt b/fastlane/metadata/android/it-IT/changelogs/41.txt deleted file mode 100644 index 3c361dd64..000000000 --- a/fastlane/metadata/android/it-IT/changelogs/41.txt +++ /dev/null @@ -1 +0,0 @@ -• Hotfix - FC per alcuni dispositivi diff --git a/fastlane/metadata/android/it-IT/changelogs/42.txt b/fastlane/metadata/android/it-IT/changelogs/42.txt deleted file mode 100644 index ab235b1a0..000000000 --- a/fastlane/metadata/android/it-IT/changelogs/42.txt +++ /dev/null @@ -1,15 +0,0 @@ -• Target Android 13 -• Abilitata la traduzione di molte stringhe -• Aggiunta icona monocromatica per Android 13 -• Aggiornate le dependencies alle versioni più recenti -• Mostra la prompt dei Termini di Servizio subito dopo l'avvio -• Permetti di procedere senza dare i permessi durante il setup iniziale -• Lettura automatica della lista nera xml di sistema come default per escludere aggiornamenti -• Mostra il titolo corretto sulla quinta pagina di setup -• Abilitato il bottone per andare avanti nel setup quando si torna indietro ad una pagina precente -• Rimpiazzate le checkboxes durante il setup con bottoni radiali -• Utilizza il colore selezionato dall'utente per il background del setup -• Risolto bug che precludeva la presenza di un tema nel setup quando si utilizzavano bottoni radiali -• Non utilizzare nuovi GSF & versioni dei Vendor -• Ripensato il setup dei permessi di storage -• Aggiornamenti sulle traduzioni diff --git a/fastlane/metadata/android/it-IT/changelogs/43.txt b/fastlane/metadata/android/it-IT/changelogs/43.txt deleted file mode 100644 index e0902d081..000000000 --- a/fastlane/metadata/android/it-IT/changelogs/43.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Abilita sempre il bottone di fine sui frammenti dei permessi (rosolve il setup per i nuovi utenti) -• Mantieni il TypeToken della libreria GSON durante l'ottimizzazione della build (risolve un crash durante lo startup) diff --git a/fastlane/metadata/android/it-IT/changelogs/45.txt b/fastlane/metadata/android/it-IT/changelogs/45.txt deleted file mode 100644 index 882994785..000000000 --- a/fastlane/metadata/android/it-IT/changelogs/45.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Miglioramenti e correzioni di errori minori -• Traduzioni aggiornate diff --git a/fastlane/metadata/android/it-IT/changelogs/47.txt b/fastlane/metadata/android/it-IT/changelogs/47.txt deleted file mode 100644 index c47a4c4ef..000000000 --- a/fastlane/metadata/android/it-IT/changelogs/47.txt +++ /dev/null @@ -1 +0,0 @@ -• Hotfix - Risolto un crash su alcuni dispositivi diff --git a/fastlane/metadata/android/it-IT/changelogs/51.txt b/fastlane/metadata/android/it-IT/changelogs/51.txt deleted file mode 100644 index dc24533d0..000000000 --- a/fastlane/metadata/android/it-IT/changelogs/51.txt +++ /dev/null @@ -1 +0,0 @@ -• Risolto un problema di ricerca, utilizza dati WebAPI diff --git a/fastlane/metadata/android/it-IT/changelogs/60.txt b/fastlane/metadata/android/it-IT/changelogs/60.txt deleted file mode 100644 index 0c172f82b..000000000 --- a/fastlane/metadata/android/it-IT/changelogs/60.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Corretto un errore che causava l'arresto di SessionInstaller su alcune vecchie versioni di Android -• Traduzioni aggiornate diff --git a/fastlane/metadata/android/it-IT/changelogs/73.txt b/fastlane/metadata/android/it-IT/changelogs/73.txt deleted file mode 100644 index 60f94f7e9..000000000 --- a/fastlane/metadata/android/it-IT/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Risolta l'icona sbagliata dell'indicatore di aggiornamento sui layout RTL -• Risolti problemi di paging e IME sulla ricerca -• Risolto un bug che sovrascriveva la scelta del programma di installazione dell'utente -• Aggiornate le traduzioni, il database dei tracker Exodus e i certificati di root di google diff --git a/fastlane/metadata/android/it-IT/full_description.txt b/fastlane/metadata/android/it-IT/full_description.txt index b53207002..bc82853ee 100644 --- a/fastlane/metadata/android/it-IT/full_description.txt +++ b/fastlane/metadata/android/it-IT/full_description.txt @@ -1,11 +1,12 @@ -Aurora Store è un client non ufficiale, libero e open-source di Google Play dal design elegante. Consente agli utenti di scaricare, aggiornare e cercare applicazioni come nel Play Store. Funziona perfettamente con o senza Google Play Services o microG. +Aurora Store è un client FOSS non ufficiale di Google Play con un design elegante. Aurora Store +consente agli utenti di scaricare, aggiornare e cercare applicazioni come il Play Store. Funziona perfettamente +con o senza Google Play Services o MicroG. Caratteristiche: -- Libero e open-source: rilasciato secondo i termini della licenza GPLv3 -- Design favoloso: basato sulle più recenti linee guida del Material Design 3 -- Accesso con account: è possibile effettuare il login con un account personale o anonimo -- Falsifica dispositivo o posizione: cambia il tuo dispositivo e/o la tua posizione per accedere alle app con restrizioni geografiche -- Integrazione con Exodus Privacy: visualizza a colpo d'occhio i tracker contenuti nelle app -- Integrazione con Plexus: visualizza a colpo d'occhio la compatibilità delle app in assenza di Google Play Services o con microG -- Lista nera degli aggiornamenti: ignora gli aggiornamenti per applicazioni specifiche +- FOSS: ha licenza GPLv3 +- Bellissimo design: Costruito sulle ultime linee guida di Material 3 +- Accesso all'account: È possibile effettuare il login con un account personale o anonimo +- Falsifica dispositivo o posizione: Cambia il tuo dispositivo e/o la tua posizione per accedere alle app geo-bloccate. +- Integrazione con [Exodus Privacy](https://exodus-privacy.eu.org/): Visualizzazione immediata dei tracker nell'app +- Lista nera degli aggiornamenti: Ignora gli aggiornamenti per applicazioni specifiche diff --git a/fastlane/metadata/android/it-IT/short_description.txt b/fastlane/metadata/android/it-IT/short_description.txt index 668f7059f..e7b783c29 100644 --- a/fastlane/metadata/android/it-IT/short_description.txt +++ b/fastlane/metadata/android/it-IT/short_description.txt @@ -1 +1 @@ -Un client open-source non ufficiale per Google Play elegante e riservato +Un client FOSS non ufficiale per Google Play con design elegante e privacy diff --git a/fastlane/metadata/android/ja-JP/changelogs/72.txt b/fastlane/metadata/android/ja-JP/changelogs/72.txt deleted file mode 100644 index d4c47ddc9..000000000 --- a/fastlane/metadata/android/ja-JP/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• 最小対応AndroidバージョンをAndroid 6.0に更新 -• Material3 エクスプレッシブテーマに切り替え -• ワイドスクリーン機器のサポートを改善 -• アプリ単位の言語設定でヘブライ語が正しく設定されない問題を修正 -• 検索フィルター機能を復元 diff --git a/fastlane/metadata/android/ja-JP/full_description.txt b/fastlane/metadata/android/ja-JP/full_description.txt index fbf11f6cd..30f0a6518 100644 --- a/fastlane/metadata/android/ja-JP/full_description.txt +++ b/fastlane/metadata/android/ja-JP/full_description.txt @@ -1,4 +1,6 @@ -Aurora Store は、エレガントなデザインを備えた Googleの非公式 FOSS クライアントです。 Aurora Store の利用者は、Play ストアなどのアプリをダウンロード、更新、検索できます。 Google Play開発者サービス や microG の有無に問わず正常に動作します。 +Aurora Store は、エレガントなデザインを備えた Googleの非公式 FOSS クライアントです。 +Aurora Store の利用者は、Play ストアなどのアプリをダウンロード、更新、検索できます。 +Google Play開発者サービス や microG の有無に問わず正常に動作します。 機能 @@ -7,5 +9,4 @@ Aurora Store は、エレガントなデザインを備えた Googleの非公式 • アカウント:個人のGoogleアカウントまたは匿名アカウントでログイン • 端末と国の偽装:一部の端末または国に限定されたアプリにアクセス • [Exodus Privacy](https://exodus-privacy.eu.org/) の統合:アプリのトラッカーを即座に確認 -• Plexus の統合:Google Play サービスなし、または microG でのアプリ互換性を即座に確認 • ブラックリスト: 特定のアプリの更新を無視する diff --git a/fastlane/metadata/android/kw/full_description.txt b/fastlane/metadata/android/kw/full_description.txt deleted file mode 100644 index 4b1a8b206..000000000 --- a/fastlane/metadata/android/kw/full_description.txt +++ /dev/null @@ -1,11 +0,0 @@ -Aurora Store yw unn kliens ansodhogel rydh rag Google Play gans unn desin afinys. Aurora Store ow gasa usyoryon dhe iskarga, nowedhi, ha hwilas rag appys avel an Play Store. Y'n oberi yn perfyth gans po heb Gonisyow Google Play po microG. - -Nasyow: - -• Rydh: Leshyans GPLv3 -• Desin teg: Byldys war gidys diwettha Material 3 -• Omgelm akont: Ty gallos omgelmi gans po akont personel po dihanow -• Fugya devis hag yeth: Chanjya dha devis hag/po yeth rag drehedhes appys strothys gans tyller -• Nas Exodus Privacy: Gweles a-dhesempis aspioryon yn app -• Nas Plexus: Gweles a-dhesempis mar app yw kesplegadow heb Gonisyow Google Play po gans microG -• Rol-Du nowedhyansow: Skonya aswon nowedhyansow rag appys komparek diff --git a/fastlane/metadata/android/kw/short_description.txt b/fastlane/metadata/android/kw/short_description.txt deleted file mode 100644 index d55753504..000000000 --- a/fastlane/metadata/android/kw/short_description.txt +++ /dev/null @@ -1 +0,0 @@ -Unn kliens ansodhogel rydh rag Google Play gans unn desin afinys ha privetter diff --git a/fastlane/metadata/android/lv/changelogs/45.txt b/fastlane/metadata/android/lv/changelogs/45.txt deleted file mode 100644 index 9dc1f5ee2..000000000 --- a/fastlane/metadata/android/lv/changelogs/45.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Nelieli kļūdu labojumi un uzlabojumi -• Atjaunināts tulkojums diff --git a/fastlane/metadata/android/lv/changelogs/47.txt b/fastlane/metadata/android/lv/changelogs/47.txt deleted file mode 100644 index 2160ca483..000000000 --- a/fastlane/metadata/android/lv/changelogs/47.txt +++ /dev/null @@ -1 +0,0 @@ -• Steidzams labojums - novērsta avārija dažos ekrānos diff --git a/fastlane/metadata/android/lv/changelogs/48.txt b/fastlane/metadata/android/lv/changelogs/48.txt deleted file mode 100644 index 4532c3620..000000000 --- a/fastlane/metadata/android/lv/changelogs/48.txt +++ /dev/null @@ -1,3 +0,0 @@ -• Būtiskas iekšējas izmaiņas saistībā ar lietotāja saskarni -• Tulkojumu atjauninājumi -• Nelieli kļūdu labojumi un uzlabojumi diff --git a/fastlane/metadata/android/lv/changelogs/49.txt b/fastlane/metadata/android/lv/changelogs/49.txt deleted file mode 100644 index bb17830f0..000000000 --- a/fastlane/metadata/android/lv/changelogs/49.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Būtiskas iekšējas izmaiņas saistībā ar lietotāja saskarni -• Ļauj lietotājiem iespējot lietotņu saites sākotnējā lietotnes iestatīšanas reizē -• Tulkojumu atjauninājumi -• Nelieli kļūdu labojumi un uzlabojumi diff --git a/fastlane/metadata/android/lv/changelogs/51.txt b/fastlane/metadata/android/lv/changelogs/51.txt deleted file mode 100644 index 15f8e25ca..000000000 --- a/fastlane/metadata/android/lv/changelogs/51.txt +++ /dev/null @@ -1 +0,0 @@ -• Novērsta meklēšanas nepilnība; izmanto WebAPI datus diff --git a/fastlane/metadata/android/lv/changelogs/53.txt b/fastlane/metadata/android/lv/changelogs/53.txt deleted file mode 100644 index 44ba6f6fc..000000000 --- a/fastlane/metadata/android/lv/changelogs/53.txt +++ /dev/null @@ -1,3 +0,0 @@ -• Novērsta lietotņu neuzstādīšana pēc lejupielādes -• Ļauts izvēlēties pielāgotu lejupielāžu mapi -• Pievienota iespēja "Lejupielādēt tikai izmantojot Wi-Fi" diff --git a/fastlane/metadata/android/lv/changelogs/58.txt b/fastlane/metadata/android/lv/changelogs/58.txt deleted file mode 100644 index e56d0d68d..000000000 --- a/fastlane/metadata/android/lv/changelogs/58.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Novērsta pieteikšanās nepilnība, kas saistīta ar Google kontiem -• Pārvietošanās izslīdošās izvēlnes vienumi pārvietoti atsevišķā dialoglodziņā -• Veikta pārslēgšanās uz NavigationRail ierīcēm ar lielu ekrānu -• Iespēja izgūt lejupielādes ārējā atrašanās vietā diff --git a/fastlane/metadata/android/lv/changelogs/60.txt b/fastlane/metadata/android/lv/changelogs/60.txt deleted file mode 100644 index 87a7e470c..000000000 --- a/fastlane/metadata/android/lv/changelogs/60.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Novērsta kļūda, kuras dēļ SessionInstaller avarēja vecākās Android versijās -• Tulkojumu atjauninājumi diff --git a/fastlane/metadata/android/lv/changelogs/62.txt b/fastlane/metadata/android/lv/changelogs/62.txt index 53eacb0b1..f718bbdc7 100644 --- a/fastlane/metadata/android/lv/changelogs/62.txt +++ b/fastlane/metadata/android/lv/changelogs/62.txt @@ -1,6 +1,6 @@ • Novērsta lietotāja saskarnes nepilnība Android 15+ -• Starpniekservera konfigurēšanas un lietojuma uzlabojumi +• Starpniekservera konfigurēšanas un lietošanas uzlabojumi • SSL piespraušana zināmiem domēniem izmantojot saknes sertifikātu -• Labāks mainīga izskata nodrošinājums atbalstītajās ierīcēs +• Labāks mainīgo izskatu nodrošinājums atbalstītajās ierīcēs • Noņemts pielāgotu izskatu un uzsvara krāsu atbalsts • Tulkojumu atjauninājumi diff --git a/fastlane/metadata/android/lv/changelogs/65.txt b/fastlane/metadata/android/lv/changelogs/65.txt index f398ad985..3f34adc50 100644 --- a/fastlane/metadata/android/lv/changelogs/65.txt +++ b/fastlane/metadata/android/lv/changelogs/65.txt @@ -1,4 +1,4 @@ • Novērstas nepilnības ar kopīgoto bibliotēku uzstādīšanu tādām lietotnēm kā Chrome un WebView • Pieteikšanās personīgajā kontā ar microG atbalsts • Novērsta nepilnība ar pilnvarošanas apliecināšanu -• Tulkojumu atjauninājumi; lokalizētas papildu virknes +• Tulkojumu atjauninājumi; jauni tulkojami teksti diff --git a/fastlane/metadata/android/lv/changelogs/66.txt b/fastlane/metadata/android/lv/changelogs/66.txt deleted file mode 100644 index ec819d9d2..000000000 --- a/fastlane/metadata/android/lv/changelogs/66.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Jauni lietotņu savietojamības vērtējumi no Plexus -• Uzlabojumi izņēmumu saraksta pārvaldībā -• Var mainīt automātisko atjauninājumu ierobežojumus -• Nelieli kļūdu labojumi un uzlabojumi -• Tulkojuma atjauninājumi; lokalizētas papildu virknes diff --git a/fastlane/metadata/android/lv/changelogs/67.txt b/fastlane/metadata/android/lv/changelogs/67.txt deleted file mode 100644 index d8a0cc014..000000000 --- a/fastlane/metadata/android/lv/changelogs/67.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Mērķēts uz Android 16 -• Novērsta nepilnība ar lietotņu saišu atvēršanu -• Lietotnes informācijas lapas atvēršanas no informācijas par lietotni iestatījumiem -• Tulkojumu atjauninājumi diff --git a/fastlane/metadata/android/lv/changelogs/68.txt b/fastlane/metadata/android/lv/changelogs/68.txt deleted file mode 100644 index 60812a843..000000000 --- a/fastlane/metadata/android/lv/changelogs/68.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Pārslēgšanās uz jaunajiem API lietotņu meklēšanai un uzstādīšanai -• Meklētājs vairs nav pieejams, tiks atkal pievienots vēlāk -• Novērsta avārija pārvietojoties uz lietotnes informācijas lapu -• Novērsta atrašanās vietas atdarināšanas avārija -• Tulkojumu atjauninājumi diff --git a/fastlane/metadata/android/lv/changelogs/72.txt b/fastlane/metadata/android/lv/changelogs/72.txt deleted file mode 100644 index bffdfde1f..000000000 --- a/fastlane/metadata/android/lv/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Zemākā atbalstītā Android versija tagad ir Android 6.0 -• Pārslēdzāmies uz Material3 Expressive izskatu -• Uzlabots atbalsts platekrāna ierīcēm -• Novērsta nepilnība, kurā ebreju valoda netika pareizi iestatīta ar lietotnei atsevišķi norādītu valodu -• Atjaunoti meklēšanas atsijātāji diff --git a/fastlane/metadata/android/lv/changelogs/73.txt b/fastlane/metadata/android/lv/changelogs/73.txt deleted file mode 100644 index 7ba9ebf30..000000000 --- a/fastlane/metadata/android/lv/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• RTL izkārtojumos salabota nepareiza norādes uz atjauninājumiem bultas ikona -• Meklēšanā novērstas lapošanas un ievades veida redaktora nepilnības -• Novērsta nepilnība, kas pārrakstīja lietotāja izvēlēto uzstādītāju -• Atjaunināti tulkojumi, Exodus izsekotāju datubāze un Google sakņu sertifikāti diff --git a/fastlane/metadata/android/lv/full_description.txt b/fastlane/metadata/android/lv/full_description.txt index 8be403c92..b79bcd1e8 100644 --- a/fastlane/metadata/android/lv/full_description.txt +++ b/fastlane/metadata/android/lv/full_description.txt @@ -1,11 +1,12 @@ -Aurora Store ir neoficiāls FOSS Google Play klients ar pievilcīgu izskatu. Aurora Store ļauj lietotājiem lejupielādēt, atjaunināt un meklēt lietotnes kā Play veikalā. Tā vienlīdz labi darbojas gan ar, gan bez Google Play pakalpojumiem vai microG. +Aurora Store ir neoficiāls FOSS Google Play klients ar pievilcīgu izskatu. Aurora Store +ļauj lietotājiem lejupielādēt, atjaunināt un meklēt lietotnes kā Play Store. Tā vienlīdz labi darbojas +gan ar, gan bez Google Play pakalpojumiem vai MicroG. Iespējas: -• FOSS: ir GPLv3 licence; -• skaists izskats: veidots vadoties pēc jaunākajām Material 3 vadlīnijām; -• pieteikšanās kontā: var pieteikties gan ar personīgo, gan ar anonīmu kontu; -• ierīces un atrašanās vietas atdarināšana: var mainīt savu ierīci un/vai atrašanās vietu, lai varētu piekļūt ģeogrāfiski ierobežotām lietotnēm; -• iekļauts Exodus Privacy: uzreiz ir redzami lietotnē izmantotie izsekotāji; -• Plexus iekļaušana: tūlītēji apskatāma saderība bez Google Play pakalpojumiem vai ar microG; -• atjauninājumu izņēmumu sarakts: noteiktu lietotņu atjauninājumu neņemšana vērā. +• FOSS: ir GPLv3 licence +• Skaists izskats: veidots vadoties pēc jaunākajām Material 3 vadlīnijām +• Konta pieteikšanās: var pieteikties gan ar personīgo, fan ar anonīmu kontu +• Ierīces un darbības vietas atdarināšana: var mainīt savu ierīci un/vai darbības vietu, lai piekļūtu ierobežotām lietotnēm +• Iekļauts Exodus Privacy: lietotnē uzreiz ir redzami izsekotāji +• Atjauninājumu izņēmumu sarakts: noteiktu lietotņu atjauninājumu neņemšana vērā diff --git a/fastlane/metadata/android/pl-PL/changelogs/72.txt b/fastlane/metadata/android/pl-PL/changelogs/72.txt deleted file mode 100644 index aaf4e831e..000000000 --- a/fastlane/metadata/android/pl-PL/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Minimalna wspierana wersja Androida to od teraz Android 6.0 -• Przejście na motyw Material3 Expressive -• Poprawiono wsparcie dla urządzeń z szerokimi ekranami -• Naprawiono błąd, przez który język hebrajski nie był ustawiany poprawnie -• Przywrócono funkcjonalność wyszukiwania za pomocą filtrów diff --git a/fastlane/metadata/android/pl-PL/full_description.txt b/fastlane/metadata/android/pl-PL/full_description.txt index afd03eca8..151ed110d 100644 --- a/fastlane/metadata/android/pl-PL/full_description.txt +++ b/fastlane/metadata/android/pl-PL/full_description.txt @@ -1,11 +1,12 @@ -Aurora Store to nieoficjalny, FOSS klient Google Play o eleganckim wyglądzie. Aurora Store pozwala użytkownikom pobierać, aktualizować i wyszukiwać aplikacje, podobnie jak Play Store. Działa doskonale zarówno z Usługami Google Play lub microG, jak i bez nich. +Aurora Store to nieoficjalny, FOSS klient Google Play o eleganckim wyglądzie. Aurora Store +pozwala użytkownikom pobierać, aktualizować i wyszukiwać aplikacje, podobnie jak Play Store. +Działa doskonale zarówno z Usługami Google Play lub MicroG, jak i bez nich. Funkcje: -• FOSS: aplikacja jest na licencji GPLv3 +• FOSS: posiada licencję GPLv3 • Piękny design: zbudowany w oparciu o najnowsze wytyczne Material 3 -• Logowanie do konta: możesz zalogować się za pomocą osobistego konta Google lub anonimowego +• Logowanie do konta: możesz zalogować się za pomocą konta osobistego lub anonimowego • Podszywanie się pod urządzenie i lokalizację: zmień swoje urządzenie i/lub lokalizację, aby uzyskać dostęp do aplikacji z blokadą geograficzną • Integracja z Exodus Privacy: natychmiastowe wyświetlanie elementów śledzących w aplikacji -• Integracja z Plexus: natychmiastowe wyświetlanie kompatybilność bez „Usług Google Play” lub z „microG” • Czarna lista aktualizacji: ignorowanie aktualizacji dla określonych aplikacji diff --git a/fastlane/metadata/android/pl-PL/short_description.txt b/fastlane/metadata/android/pl-PL/short_description.txt index 7fae4053b..a66abefe0 100644 --- a/fastlane/metadata/android/pl-PL/short_description.txt +++ b/fastlane/metadata/android/pl-PL/short_description.txt @@ -1 +1 @@ -Nieoficjalny FOSS klient sklepu Google Play z eleganckim wyglądem i prywatnością +Nieoficjalny FOSS klient Google Play z eleganckim wyglądem i prywatnością diff --git a/fastlane/metadata/android/pt-BR/changelogs/66.txt b/fastlane/metadata/android/pt-BR/changelogs/66.txt deleted file mode 100644 index 3ee15a837..000000000 --- a/fastlane/metadata/android/pt-BR/changelogs/66.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Novas avaliações de compatibilidade de apps disponibilizadas pelo Plexus -• Melhorias ao gerenciador de lista negra -• Capacidade de alterar as restrições das atualizações automáticas -• Correções de bugs menores e melhorias -• Traduções atualizadas; mais textos traduzíveis diff --git a/fastlane/metadata/android/pt-BR/changelogs/67.txt b/fastlane/metadata/android/pt-BR/changelogs/67.txt deleted file mode 100644 index cf95fd0ba..000000000 --- a/fastlane/metadata/android/pt-BR/changelogs/67.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Suporte ao Android 16 -• Corrigido bug ao abrir links para apps -• Suporte a abrir a página de detalhes de um app a partir das configurações de informação do app -• Atualizações de tradução diff --git a/fastlane/metadata/android/pt-BR/changelogs/68.txt b/fastlane/metadata/android/pt-BR/changelogs/68.txt deleted file mode 100644 index 300b7f326..000000000 --- a/fastlane/metadata/android/pt-BR/changelogs/68.txt +++ /dev/null @@ -1,6 +0,0 @@ -• Mudança para novas APIs para buscar e instalar apps -• Filtro de busca não está mais disponível, será readicionado depois -• Corrigida uma falha ao navegar à pagina de detalhes do app -• Corrigida uma falha ao simular o idioma -• Corrigida falha ao simular localização -• Traduções atualizadas diff --git a/fastlane/metadata/android/pt-BR/changelogs/71.txt b/fastlane/metadata/android/pt-BR/changelogs/71.txt deleted file mode 100644 index f6381bbad..000000000 --- a/fastlane/metadata/android/pt-BR/changelogs/71.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Consertar problema de instalação do app em dispositivos huawei -• Atualizações de tradução diff --git a/fastlane/metadata/android/pt-BR/changelogs/72.txt b/fastlane/metadata/android/pt-BR/changelogs/72.txt deleted file mode 100644 index e53f0bdb2..000000000 --- a/fastlane/metadata/android/pt-BR/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• A versão do Android mínima suportada agora é o Android 6.0 -• O tema foi alterado para o Material3 Expressive -• O suporte para dispositivos de tela larga foi melhorado -• Foi corrigido um problema onde o idioma hebraico não era configurado corretamente ao selecionar o idioma no app -• Foi restaurada a funcionalidade de filtros de pesquisa diff --git a/fastlane/metadata/android/pt-BR/changelogs/73.txt b/fastlane/metadata/android/pt-BR/changelogs/73.txt deleted file mode 100644 index 07b2e5411..000000000 --- a/fastlane/metadata/android/pt-BR/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Corrigido ícone de seta indicadora de upgrade errado em layouts RTL -• Corrigidos erros de paginação e IME na busca -• Corrigido bug que revogava a escolha de instalador do usuário -• Atualização de traduções, banco de dados de rastreadores exodus e certificados-raiz do Google diff --git a/fastlane/metadata/android/pt-BR/full_description.txt b/fastlane/metadata/android/pt-BR/full_description.txt index e82790cd0..49165f624 100644 --- a/fastlane/metadata/android/pt-BR/full_description.txt +++ b/fastlane/metadata/android/pt-BR/full_description.txt @@ -1,11 +1,12 @@ -A Aurora Store é um cliente FOSS não oficial do Google Play com um design elegante. A Aurora Store permite que usuários baixem, atualizem, e busquem apps assim como a Play Store. Ele funciona perfeitamente sem o Google Play Services ou o microG. +Aurora Store é um cliente FOSS não oficial com um design elegante. Aurora Store +permite que usuários baixem, atualizem, e pesquisem por apps assim como a Play Store. Ele funciona perfeitamente bem +sem o Google Play Services ou MicroG. -Recursos: +Funcionalidades: -• FOSS (software livre): licença GPLv3 -• Interface bonita: construído com base nas diretrizes do Material Design 3 mais recentes -• Conta: Você pode se conectar com uma conta pessoal ou anônima -• Simulação de dispositivo e localidade: Altere seu dispositivo ou sua localidade para acessar apps bloqueados em certos lugares -• Integração com o Exodus Privacy: Veja os rastreadores diretamente no app -• Integração com o Plexus: Veja a compatibilidade dos apps sem o Google Play Services ou com o microG, diretamente no app -• Bloqueio de atualizações: Ignore as atualizações de apps específicos +• FOSS: usa a licença GPLv3 +• Design lindo: construído sobre as diretrizes do Material Design 3 +• Login com conta: Você pode iniciar uma sessão com uma conta pessoal ou anônima +• Mascaramento de dispositivo e localidade: Mude seu dispositivo ou localidade para acessar apps bloqueados por geolocalização +• Integração com o Exodus Privacy: Instantaneamente veja rastreadores no app +• Lista negra de atualizações: Ignore atualizações de apps específicos diff --git a/fastlane/metadata/android/pt-BR/short_description.txt b/fastlane/metadata/android/pt-BR/short_description.txt index 3d5c9598b..5d8a7479a 100644 --- a/fastlane/metadata/android/pt-BR/short_description.txt +++ b/fastlane/metadata/android/pt-BR/short_description.txt @@ -1 +1 @@ -Um cliente FOSS do Google Play com privacidade e um design elegante +Um cliente FOSS para a Google Play com um design elegante e privacidade diff --git a/fastlane/metadata/android/pt/changelogs/73.txt b/fastlane/metadata/android/pt/changelogs/73.txt deleted file mode 100644 index 23f8fb6c3..000000000 --- a/fastlane/metadata/android/pt/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Corrigido o ícone incorreto da seta indicadora de atualização em layouts RTL -• Corrigidos problemas de paginação e IME na pesquisa -• Corrigido um bug que sobrescrevia a escolha do instalador do usuário -• Atualizadas as traduções, o banco de dados de rastreadores do Exodus e os certificados raiz do Google diff --git a/fastlane/metadata/android/pt/full_description.txt b/fastlane/metadata/android/pt/full_description.txt index 3ac271a0e..2d684c5f2 100644 --- a/fastlane/metadata/android/pt/full_description.txt +++ b/fastlane/metadata/android/pt/full_description.txt @@ -1,11 +1,12 @@ -Aurora Store é um cliente não oficial e de código aberto (FOSS) para o Google Play com um design elegante. O Aurora Store permite que os usuários baixem, atualizem e pesquisem aplicativos como na Play Store. Funciona perfeitamente com ou sem os Serviços do Google Play ou microG. +A Aurora Store é um cliente FOSS não oficial do Google Play com um design elegante. +Permite aos utilizadores descarregar, atualizar e procurar aplicações como a Play Store. +Funciona perfeitamente bem com ou sem o Google Play Services ou o MicroG. -Recursos: +Funcionalidades: -• FOSS: Possui licença GPLv3 -• Design atraente: Construído com base nas diretrizes mais recentes do Material 3 -• Login de conta: Você pode fazer login com uma conta pessoal ou anônima -• Falsificação de dispositivo e idioma: Altere seu dispositivo e/ou idioma para acessar aplicativos com restrição geográfica -• Integração com Exodus Privacy: Veja instantaneamente os rastreadores no aplicativo -• Integração com Plexus: Veja instantaneamente a compatibilidade do aplicativo sem os Serviços do Google Play ou com microG -• Lista negra de atualizações: Ignore atualizações para aplicativos específicos +• FOSS: sob a licença GPLv3 +• Design bonito: construído com base nas mais recentes diretrizes do Material 3 +• Início de sessão com conta: pode iniciar sessão com uma conta pessoal ou anónima +• Disfarce de dispositivo e configuração regional: altere o seu dispositivo e/ou a configuração regional para aceder a aplicações bloqueadas geograficamente +• Integrado com o [Exodus Privacy](https://exodus-privacy.eu.org/): veja instantaneamente os rastreadores nas aplicações +• Lista negra de atualizações: ignora atualizações para aplicações específicas diff --git a/fastlane/metadata/android/ro/changelogs/72.txt b/fastlane/metadata/android/ro/changelogs/72.txt deleted file mode 100644 index bab55adbd..000000000 --- a/fastlane/metadata/android/ro/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Versiunea Android minimă acceptată este acum Android 6.0 -• S-a trecut la tema expresivă Material3 -• Suport îmbunătățit pentru dispozitivele cu ecran larg -• S-a rezolvat o problemă în care limbajul ebraic nu a fost stabilit în mod corespunzător cu limbajul per aplicație -• Funcționalitate restabilită pentru filtrele de căutare diff --git a/fastlane/metadata/android/ro/full_description.txt b/fastlane/metadata/android/ro/full_description.txt deleted file mode 100644 index 4e13c786e..000000000 --- a/fastlane/metadata/android/ro/full_description.txt +++ /dev/null @@ -1,11 +0,0 @@ -Aurora Store este un client neoficial, FOSS, pentru Google Play, cu un design elegant. Aurora Store permite utilizatorilor să descarce, să actualizeze și să caute aplicații precum Play Store. Funcționează perfect cu sau fără serviciile Google Play sau microG. - - Caracteristici: - -• FOSS: are licență GPLV3 -• Design frumos: Construit pe cel mai recent Material 3 -• Conectare cont: te poți conecta cu un cont personal, fie cu un cont anonim -• Falsificare pentru dispozitiv și locație: Schimbă dispozitivul și/sau locația pentru a accesa aplicațiile blocate -• Integrare Exodus: Vezi instantaneu urmăritorii în aplicație -• Integrare Plex: Consultă instantaneu compatibilitatea aplicației fără servicii Google Play sau cu microG -• Listă neagră pentru actualizări: ignoră actualizările pentru aplicații specifice diff --git a/fastlane/metadata/android/ru-RU/changelogs/71.txt b/fastlane/metadata/android/ru-RU/changelogs/71.txt deleted file mode 100644 index f26b65a5d..000000000 --- a/fastlane/metadata/android/ru-RU/changelogs/71.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Исправлена ошибка установки приложения на устройствах huawei -• Обновлены переводы diff --git a/fastlane/metadata/android/ru-RU/changelogs/72.txt b/fastlane/metadata/android/ru-RU/changelogs/72.txt deleted file mode 100644 index 376002dee..000000000 --- a/fastlane/metadata/android/ru-RU/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• С этого релиза минимальная поддерживаемая версия - Android 6.0. -• Тема по умолчанию теперь - Material3 Expressive -• Улучшена поддержка широкоформатных устройств -• Исправлена проблема, из-за которой иврит не устанавливался правильно в настройках языка приложения -• Восстановлена функциональность фильтров поиска diff --git a/fastlane/metadata/android/ru-RU/changelogs/73.txt b/fastlane/metadata/android/ru-RU/changelogs/73.txt deleted file mode 100644 index 42bdf6fa9..000000000 --- a/fastlane/metadata/android/ru-RU/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Исправлена неправильная стрелка индикатора улучшения на раскладках RTL -• Исправлены проблемы с страницированием и IME при поиске -• Исправлена ошибка, которая отменяет выбор установщика -• Обновление переводов, базы данных трекеров Exodus и корневых сертификатов Google diff --git a/fastlane/metadata/android/ru-RU/full_description.txt b/fastlane/metadata/android/ru-RU/full_description.txt index 1bc68b4d5..ef071bc6d 100644 --- a/fastlane/metadata/android/ru-RU/full_description.txt +++ b/fastlane/metadata/android/ru-RU/full_description.txt @@ -1,11 +1,12 @@ -Aurora Store — это неофициальный свободный клиент для Google Play с изящным дизайном. Aurora Store позволяет пользователям скачивать, обновлять и искать приложения подобно Google Play Store. Оно прекрасно работает как с сервисами Google Play или MicroG, так и без них. +Aurora Store - неофициальный FOSS-клиент для Google Play с элегантным дизайном. Aurora Store +позволяет пользователям загружать, обновлять и искать приложения подобно Play Store. Он прекрасно работает +как с Google Play Services или MicroG, так и без них. -Возможности: +Функции: -• Свободное ПО: имеет лицензию GPLv3 -• Красивый дизайн: построено на основе новейших рекомендаций Material 3 -• Вход в аккаунт: вы можете авторизоваться как с личной, так и с анонимной учетной записью -• Подмена устройства и локали: измените устройство и/или язык для доступа к приложениям доступным только из определенных стран -• Интеграция Exodus Privacy: трекеры отображаются непосредственно в приложении -• Интеграция с базой Plexus: мгновенный просмотр совместимости приложений без сервисов Google Play или с microG +• FOSS: имеет лицензию GPLv3 +• Красивый дизайн: Создан на основе новейших рекомендаций Material 3 +• Вход в аккаунт: Вы можете войти в систему как с личной, так и с анонимной учетной записью +• Подмена устройства и локали: Измените устройство и/или локали для доступа к приложениям с географической блокировкой +• Интеграция Exodus Privacy: Мгновенно просматривайте трекеры в приложении • Черный список обновлений: Игнорируйте обновления для определенных приложений diff --git a/fastlane/metadata/android/ru-RU/short_description.txt b/fastlane/metadata/android/ru-RU/short_description.txt index 3dd8b9181..858adcb75 100644 --- a/fastlane/metadata/android/ru-RU/short_description.txt +++ b/fastlane/metadata/android/ru-RU/short_description.txt @@ -1 +1 @@ -Неофициальный FOSS клиент для Google Play с элегантным дизайном и приватностью +Неофициальный FOSS-клиент для Google Play с элегантным дизайном и приватностью diff --git a/fastlane/metadata/android/sk/changelogs/66.txt b/fastlane/metadata/android/sk/changelogs/66.txt deleted file mode 100644 index 6d8294eb3..000000000 --- a/fastlane/metadata/android/sk/changelogs/66.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Nové hodnotenia kompatibility aplikácií od spoločnosti Plexus -• Vylepšenia správcu čiernej listiny -• Možnosť zmeniť obmedzenia automatických aktualizácií -• Opravy menších chýb a vylepšenia -• Aktualizácie prekladov; lokalizované ďalšie reťazce diff --git a/fastlane/metadata/android/sk/changelogs/67.txt b/fastlane/metadata/android/sk/changelogs/67.txt deleted file mode 100644 index 6a3fb8206..000000000 --- a/fastlane/metadata/android/sk/changelogs/67.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Podpora Android 16 -• Opravená chyba s otváraním odkazov do aplikácie -• Pridaná podpora s podrobnosťami o aplikácií v nastaveniach informácií o aplikácii -• Aktualizácie prekladov diff --git a/fastlane/metadata/android/sk/changelogs/68.txt b/fastlane/metadata/android/sk/changelogs/68.txt deleted file mode 100644 index 6c8279f91..000000000 --- a/fastlane/metadata/android/sk/changelogs/68.txt +++ /dev/null @@ -1,3 +0,0 @@ -• Oprava zlyhania pri prechode na stránku s podrobnosťami o aplikácií -• Oprava zlyhania v miestnom nastavení falšovania (spoofing) -• Aktualizácie prekladov diff --git a/fastlane/metadata/android/sk/changelogs/72.txt b/fastlane/metadata/android/sk/changelogs/72.txt deleted file mode 100644 index 7db4807ca..000000000 --- a/fastlane/metadata/android/sk/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -- Minimálna podporovaná verzia systému Android je teraz Android 6.0 -- Prepnutie na tému Material3 Expressive -- Vylepšená podpora pre širokouhlé zariadenia -- Opravený problém, pri ktorom nebola správne nastavená hebrejčina s jazykom na aplikáciu -- Obnovená funkčnosť vyhľadávacích filtrSOV diff --git a/fastlane/metadata/android/sk/full_description.txt b/fastlane/metadata/android/sk/full_description.txt index 3e0efcdad..a7f8e1e85 100644 --- a/fastlane/metadata/android/sk/full_description.txt +++ b/fastlane/metadata/android/sk/full_description.txt @@ -3,6 +3,7 @@ umožňuje používateľom sťahovať, aktualizovať a vyhľadávať aplikácie, so službami Google Play alebo MicroG alebo bez nich. Funkcie: + • FOSS: Má licenciu GPLv3 • Krásny dizajn: Postavený podľa najnovších smerníc Material 3 • Prihlásenie účtu: Môžete sa prihlásiť buď pomocou osobného alebo anonymného účtu diff --git a/fastlane/metadata/android/sk/short_description.txt b/fastlane/metadata/android/sk/short_description.txt index cbc820ad2..9a8cbcab2 100644 --- a/fastlane/metadata/android/sk/short_description.txt +++ b/fastlane/metadata/android/sk/short_description.txt @@ -1 +1 @@ -Neoficiálny FOSS alternatíva k Google Play s elegantným dizajnom a súkromie +Neoficiálny klient FOSS pre Google obchod s elegantným dizajnom a ochranou súkromia diff --git a/fastlane/metadata/android/sq/changelogs/67.txt b/fastlane/metadata/android/sq/changelogs/67.txt deleted file mode 100644 index 52864abcc..000000000 --- a/fastlane/metadata/android/sq/changelogs/67.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Version i synuar Android 16 -• Ndreqje të mete me hapje lidhjesh në aplikacione -• Mbulim hapje faqeje hollësish aplikacioni që nga rregullime hollësish aplikacioni -• Përditësime përkthimesh diff --git a/fastlane/metadata/android/sq/changelogs/68.txt b/fastlane/metadata/android/sq/changelogs/68.txt deleted file mode 100644 index 42e767bc3..000000000 --- a/fastlane/metadata/android/sq/changelogs/68.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Ndreqje vithisjeje gjatë kalimit te faqe hollësish aplikacioni -• Përditësime përkthimesh diff --git a/fastlane/metadata/android/sq/changelogs/73.txt b/fastlane/metadata/android/sq/changelogs/73.txt deleted file mode 100644 index c257f9250..000000000 --- a/fastlane/metadata/android/sq/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• U ndreq ikonë e gabuar treguesi shigjetë për përmirësimin në gjuhë DNM -• U ndreqën probleme faqosjeje dhe IME te kërkimi -• U ndreq një e metë që sjell anashkalim zgjedhjeje përdoruesi për instaluesin -• U përditësuan përkthime, si dhe dëshmi baze të dhënash ndjekësi Exodus dhe rrënje Google diff --git a/fastlane/metadata/android/sq/full_description.txt b/fastlane/metadata/android/sq/full_description.txt deleted file mode 100644 index e8aaa718f..000000000 --- a/fastlane/metadata/android/sq/full_description.txt +++ /dev/null @@ -1,11 +0,0 @@ -Aurora Store është një klient jozyrtar, FOSS, për Google Play me një hartim grafik elegant. Aurora Store u lejon përdoruesve të shkarkojnë, përditësojnë dhe të kërkojnë për aplikacione, si Play Store-i. Funksionon në mënyrë të përsosur me ose pa Google Play Servicesm apo microG. - -Veçori: - -• FOSS: Ka një licencë GPLv3 -• Hartim grafik i hijshëm: Ngritur mbi udhëzimet më të reja Material 3 -• Hyrje në llogari: Mund të bëni hyrjen ose me llogari tuajën personale, ose me një llogari anonime -• Imitim Pajisjeje & Vendoreje: Ndryshoni si identifikohet pajisja dhe/ose vendoren, që të përdorni aplikacione të kyçur sipas rajonesh gjeografike -• Integrim me Exodus Privacy: Shihni menjëherë gjurmues në aplikacion -• Integrim me Plexus: Shihni menjëherë përputhjen e aplikacionit, pa Google Play Services apo me microG -• Listë moslejimi përditësimesh: Shpërfill përditësime për aplikacione të caktuara diff --git a/fastlane/metadata/android/sq/short_description.txt b/fastlane/metadata/android/sq/short_description.txt deleted file mode 100644 index c73a574a6..000000000 --- a/fastlane/metadata/android/sq/short_description.txt +++ /dev/null @@ -1 +0,0 @@ -Një klient FOSS jozyrtar për Google Play, me një skicim elegant dhe privatësi diff --git a/fastlane/metadata/android/sr/full_description.txt b/fastlane/metadata/android/sr/full_description.txt index 23609b8bf..c0998f58e 100644 --- a/fastlane/metadata/android/sr/full_description.txt +++ b/fastlane/metadata/android/sr/full_description.txt @@ -8,6 +8,5 @@ Aurora Store је незванични, FOSS клијент за Google Play с • Прелеп дизајн: Заснован на најновијим смерницама за Material 3 дизајн • Пријава на налог: Можете се пријавити са личним или анонимним налогом • Лажирање уређаја и лажирање локала: Промените свој уређај и/или локализацију да бисте приступили географски закључаним апликацијама -• Интеграција Plexus: Одмах проверите компатибилност апликација без Google Play услуга или са microG • Интеграција [Exodus приватност](https://exodus-privacy.eu.org/): Одмах погледајте програме за праћење у апликацији • Црна листа за ажурирања: Занемарите ажурирања за одређене апликације diff --git a/fastlane/metadata/android/sv-SE/changelogs/73.txt b/fastlane/metadata/android/sv-SE/changelogs/73.txt deleted file mode 100644 index ae9b4bbd5..000000000 --- a/fastlane/metadata/android/sv-SE/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Fixade felaktig pilikon för uppgraderingsindikator på RTL-layouter -• Fixade sidnumrering och IME-fel i sökfunktionen -• Fixade en bug som skriver över användarval -• Uppdaterade översättningar, exodus spårardatamas och Googles rootcertifikat diff --git a/fastlane/metadata/android/sv-SE/full_description.txt b/fastlane/metadata/android/sv-SE/full_description.txt index 62c5468a5..0c7124bb2 100644 --- a/fastlane/metadata/android/sv-SE/full_description.txt +++ b/fastlane/metadata/android/sv-SE/full_description.txt @@ -1,4 +1,6 @@ -Aurora Store är en inofficiell FOSS-klient för Google Play med en elegant design. Aurora Store låter användare ladda ner, uppdatera och söka efter appar precis som Play Store. Det fungerar alldeles utmärkt med eller utan Google Play Services eller MicroG. +Aurora Store är en inofficiell FOSS-klient för Google Play med en elegant design. Aurora Store +låter användare ladda ner, uppdatera och söka efter appar som Play Store. Det fungerar alldeles utmärkt +med eller utan Google Play Services eller MicroG. Funktioner: @@ -6,6 +8,5 @@ Aurora Store är en inofficiell FOSS-klient för Google Play med en elegant desi • Vacker design: Byggd på de senaste Material 3-riktlinjerna • Kontoinloggning: Du kan logga in med antingen personligt eller anonymt konto • Enhets och språkförfalskning: Ändra din enhet och/eller språk för att komma åt geografiskt låsta appar -• [Exodus Privacy](https://exodus-privacy.eu.org/) integration: Se spårare direkt i appen' -• Plexusintegration: Se appkomplabilitet utan Google Play-tjänster eller med microG -• Uppdaterar svartlista: Ignorera uppdateringar för specifika appar +• [Exodus Privacy](https://exodus-privacy.eu.org/) integration: Se spårare direkt i appen +• Uppdateringssvartlista: Ignorera uppdateringar för specifika appar diff --git a/fastlane/metadata/android/ta-IN/changelogs/42.txt b/fastlane/metadata/android/ta-IN/changelogs/42.txt index bc73454f3..725748887 100644 --- a/fastlane/metadata/android/ta-IN/changelogs/42.txt +++ b/fastlane/metadata/android/ta-IN/changelogs/42.txt @@ -1,15 +1,15 @@ And இலக்கு ஆண்ட்ராய்டு 13 The பல சரங்களின் உள்ளூர்மயமாக்கலை இயக்கவும் And ஆண்ட்ராய்டு 13 க்கு மோனோக்ரோம் ஐகானைச் சேர்க்கவும் - Coverse அண்மைக் கால பதிப்பிற்கு சார்புகளைப் புதுப்பிக்கவும் - Authand உடனடியாகத் தொடங்குவதற்கான பணி வரியில் விதிமுறைகளைக் காட்டு - Stemper ஆரம்ப அமைப்பின்போது இசைவு வழங்காமல் முன்னேற அனுமதிக்கவும் - Cystem புதுப்பிப்புகளிலிருந்து விலக்குவதற்கு இயல்புநிலையாகக் கணினி எக்ச்எம்எல் டெனிலிச்டைப் படியுங்கள் + Coverse அண்மைக் கால பதிப்பிற்கு சார்புகளை புதுப்பிக்கவும் + Authand உடனடியாக தொடங்குவதற்கான பணி வரியில் விதிமுறைகளைக் காட்டு + Stemper ஆரம்ப அமைப்பின் போது இசைவு வழங்காமல் முன்னேற அனுமதிக்கவும் + Cystem புதுப்பிப்புகளிலிருந்து விலக்குவதற்கு இயல்புநிலையாக கணினி எக்ச்எம்எல் டெனிலிச்டைப் படியுங்கள் St 5 வது அமைவு பக்கத்தில் சரியான தலைப்பைக் காட்டு The திரும்பிச் செல்லும்போது அமைப்பில் முன்னோக்கி பொத்தானை இயக்கவும் வானொலி ரேடியோ பொத்தான்களுடன் அமைவு நிறுவியில் தேர்வுப்பெட்டிகளை மாற்றவும் கணம் அமைவு தாவல்களின் பின்னணிக்கு பக்கவாதம் நிறத்தைப் பயன்படுத்தவும் - Radia ரேடியோ பொத்தான்களைப் பயன்படுத்தி அமைப்பில் கருப்பொருள் பிழையைச் சரிசெய்யவும் + Radia ரேடியோ பொத்தான்களைப் பயன்படுத்தி அமைப்பில் கருப்பொருள் பிழையை சரிசெய்யவும் G புதிய சி.எச்.எஃப் மற்றும் விற்பனை பதிப்புகளைப் பயன்படுத்த வேண்டாம் • மறுசீரமைப்பு சேமிப்பு தொடர்பான அனுமதிகள் அமைப்பு • மொழிபெயர்ப்பு புதுப்பிப்புகள் diff --git a/fastlane/metadata/android/ta-IN/changelogs/46.txt b/fastlane/metadata/android/ta-IN/changelogs/46.txt index 20bc2d27d..5a1bad0be 100644 --- a/fastlane/metadata/android/ta-IN/changelogs/46.txt +++ b/fastlane/metadata/android/ta-IN/changelogs/46.txt @@ -1,8 +1,8 @@ The தேவைப்படும் வரை சேமிப்பக இசைவு கேட்பதைத் தவிர்க்கவும் Imp இறக்குமதி-ஏற்றுமதிக்கான சேமிப்பக அனுமதியைத் தவிர்க்க மறுவேலை செய்யப்பட்ட ச்பூஃப் உள்ளமைவு - பயன்பாடு பயன்பாட்டு புதுப்பிப்புகளை தானாகச் சரிபார்க்க விருப்பத்தைச் சேர்க்கவும் (உள்நுழைந்த வேலை கணக்குத் தேவை) + பயன்பாடு பயன்பாட்டு புதுப்பிப்புகளை தானாக சரிபார்க்க விருப்பத்தைச் சேர்க்கவும் (உள்நுழைந்த வேலை கணக்கு தேவை) Chrome தேவையான நூலகங்கள் குரோம் & ட்ரைக்ரோம் நூலகம் போன்ற பயன்பாடுகளுடன் நிறுவப்படாத இடங்களில் நிலையான சிக்கல் - Ara அரோரா கடையைக் காப்புப் பிரதி எடுக்கும்போது காப்புப்பிரதிகளிலிருந்து பதிவிறக்கங்களின் கோப்பகத்தை புறக்கணிக்கவும் + Ara அரோரா கடையை காப்புப் பிரதி எடுக்கும்போது காப்புப்பிரதிகளிலிருந்து பதிவிறக்கங்களின் கோப்பகத்தை புறக்கணிக்கவும் S சிசுகு நிறுவியை செயல்படுத்தவும் (Android 8.0+ தேவை) And ஆண்ட்ராய்டு 4.4 க்கான உதவி. குறைந்தபட்ச தேவையான ஆண்ட்ராய்டு பதிப்பு 5.0+ ஆகும். • சிறிய பிழைகள் மற்றும் மேம்பாடுகள் diff --git a/fastlane/metadata/android/ta-IN/changelogs/50.txt b/fastlane/metadata/android/ta-IN/changelogs/50.txt index 83fbd5008..777894ac2 100644 --- a/fastlane/metadata/android/ta-IN/changelogs/50.txt +++ b/fastlane/metadata/android/ta-IN/changelogs/50.txt @@ -1,8 +1,8 @@ -A ஒரு இருண்ட கருப்பொருளிலிருந்து கணினி கருப்பொருளுக்கு மாறுவது இடைமுகம் ஐ சரியாகப் புதுப்பிக்கிறது +A ஒரு இருண்ட கருப்பொருளிலிருந்து கணினி கருப்பொருளுக்கு மாறுவது இடைமுகம் ஐ சரியாக புதுப்பிக்கிறது Screen முகப்புத் திரையில் உரையாடல்கள் இனி சில காட்சிகளை மறைக்காது - Google Play இணைப்பைத் திறப்பது இப்போது செல்லுபடியாகும் மற்றும் வேலை கணக்கு இருப்பதை உறுதி செய்கிறது + Google Google Play இணைப்பைத் திறப்பது இப்போது செல்லுபடியாகும் மற்றும் வேலை கணக்கு இருப்பதை உறுதி செய்கிறது Surce வழிசெலுத்தல் அலமாரியை முதன்மையான திரையில் மட்டுமே திறக்க முடியும் - • பின் நடவடிக்கை இப்போது சில திரைகளில் பயன்பாட்டைச் சரியாக வெளியேறுகிறது + • பின் நடவடிக்கை இப்போது சில திரைகளில் பயன்பாட்டை சரியாக வெளியேறுகிறது • அமைப்புகள் பொத்தான்கள் இப்போது இருண்ட கருப்பொருளில் சரியான சாயலைக் கொண்டுள்ளன Ex ய எக்சோடச் அறிக்கைகளுக்கான கருவிப்பட்டியில் பயன்பாட்டு பெயர் மீண்டும் தெரியும் • படங்கள் தொடர்பான உள் மேம்பாடுகள் diff --git a/fastlane/metadata/android/ta-IN/changelogs/52.txt b/fastlane/metadata/android/ta-IN/changelogs/52.txt index 1d57f8e06..2b0ba7ab0 100644 --- a/fastlane/metadata/android/ta-IN/changelogs/52.txt +++ b/fastlane/metadata/android/ta-IN/changelogs/52.txt @@ -1,6 +1,6 @@ ஆங்கிலம் அல்லாத ஆங்கிலம் அல்லாத சொற்களைத் தேடும்போது சில சாதனங்களில் செயலிழப்பை சரிசெய்யவும் - பயன்பாடுகள் மற்றும் விளையாட்டுப் பக்கத்தை மேம்படுத்தவும் + பயன்பாடு பயன்பாடுகள் மற்றும் விளையாட்டு பக்கத்தை மேம்படுத்தவும் தானி ஆட்டோ நிறுவல் இடுகை பயன்பாட்டிற்கு மீண்டும் மாற்றவும் - பயன்பாடு நிறுவப்பட்டபோது அல்லது புதுப்பிக்கப்படும்போது அறிவிப்பு ஒலியை இயக்க வேண்டாம் + பயன்பாடு பயன்பாடு நிறுவப்பட்டபோது அல்லது புதுப்பிக்கப்படும் போது அறிவிப்பு ஒலியை இயக்க வேண்டாம் பயன்பாடு பயன்பாட்டு விவரங்களைத் திறக்கும்போது சில சாதனங்களில் செயலிழப்பை சரிசெய்யவும் மூலம் ரூட் நிறுவியைப் பயன்படுத்தினால் உறுதிப்படுத்தல் உரையாடலை நிறுவல் நீக்கவும் diff --git a/fastlane/metadata/android/ta-IN/changelogs/53.txt b/fastlane/metadata/android/ta-IN/changelogs/53.txt index 4bf6bf5e2..a626b8b44 100644 --- a/fastlane/metadata/android/ta-IN/changelogs/53.txt +++ b/fastlane/metadata/android/ta-IN/changelogs/53.txt @@ -1,3 +1,3 @@ -Post இடுகை பதிவிறக்கத்தை நிறுவாத பயன்பாடுகளைச் சரிசெய்யவும் - தனிப்பயன் பதிவிறக்க கோப்பகத்தைத் தேர்ந்தெடுக்க அனுமதிக்கவும் +Post இடுகை பதிவிறக்கத்தை நிறுவாத பயன்பாடுகளை சரிசெய்யவும் + தனிப்பயன் தனிப்பயன் பதிவிறக்க கோப்பகத்தைத் தேர்ந்தெடுக்க அனுமதிக்கவும் • வைஃபை-மட்டும் பதிவிறக்க விருப்பத்தைச் சேர்க்கவும் diff --git a/fastlane/metadata/android/ta-IN/changelogs/54.txt b/fastlane/metadata/android/ta-IN/changelogs/54.txt index e0d077f0c..70ac4fab3 100644 --- a/fastlane/metadata/android/ta-IN/changelogs/54.txt +++ b/fastlane/metadata/android/ta-IN/changelogs/54.txt @@ -1,9 +1,9 @@ பதிவிறக்கம் பதிவிறக்க அமைப்பில் முக்கிய உள் மாற்றங்கள் - • அரோரா கடைக்கு இப்போது பின்னணியில் பதிவிறக்கம் செய்யப் புதிய இசைவு தேவை + • அரோரா கடைக்கு இப்போது பின்னணியில் பதிவிறக்கம் செய்ய புதிய இசைவு தேவை The பதிவிறக்கங்களுக்கு இடைநிறுத்தம் மற்றும் விண்ணப்பம் நற்பொருத்தங்கள் நீக்கப்பட்டுள்ளன • ஒரே நேரத்தில் பதிவிறக்கங்கள் நீக்கப்பட்டன (ஒரு நேரத்தில் ஒரு பதிவிறக்கத்திற்கு மட்டுமே) பதிவிறக்கம் செய்யப்பட்ட கோப்புகளுக்கான தானியங்கி SHA256 & SHA1 சரிபார்ப்பு - Chrom Chrome மற்றும் WebWiew போன்ற பகிரப்பட்ட நூலகங்களுடன் பயன்பாடுகளுக்குச் சிறந்த உதவி + Chrom Chrome மற்றும் WebWiew போன்ற பகிரப்பட்ட நூலகங்களுடன் பயன்பாடுகளுக்கு சிறந்த உதவி புதுப்பிப்பு புதுப்பிப்புகள் அமைப்பில் பெரிய மாற்றங்கள் பயன்பாடு பயன்பாடுகளுக்கான புதிய தானியங்கி புதுப்பிப்புகள் (இயல்பாக இயக்கப்பட்டது) Aut புதுப்பிப்புகளுக்கான புதிய தானியங்கி சான்றிதழ் சரிபார்ப்பு @@ -11,7 +11,7 @@ • சுய-புதுப்பிப்புகள் (அரோரா ச்டோர்) இயல்பாகவே முடக்கப்பட்டுள்ளது (அமைப்புகள்> புதுப்பிப்பில் இயக்கு) Install சொந்த நிறுவி மற்றும் அரோரா சேவைகள் நீக்கப்பட்டன Application நிறுவப்பட்ட பயன்பாடுகளை ஏற்றுமதி செய்வதற்கு இனி சேமிப்பக அனுமதிகள் தேவையில்லை - பயன்பாடு பயன்பாடுகளுக்கான குறைந்தபட்ச தேவையான ஆண்ட்ராய்டு பதிப்பு இப்போது பயன்பாட்டு விவரங்கள் பக்கத்தில் தெரியும் (மேலும் இந்தப் பயன்பாடு> செய்திபற்றி மேலும்) + பயன்பாடு பயன்பாடுகளுக்கான குறைந்தபட்ச தேவையான ஆண்ட்ராய்டு பதிப்பு இப்போது பயன்பாட்டு விவரங்கள் பக்கத்தில் தெரியும் (மேலும் இந்த பயன்பாடு> செய்தி பற்றி மேலும்) • மொழிபெயர்ப்பு புதுப்பிப்புகள் மற்றும் முக்கிய பிழை திருத்தங்கள் Su சுய் உடன் பயன்பாடுகளை நிறுவுவதற்கான உதவி (சிசுகு மேகிச்க் தொகுதி) Sentions அமைப்புகள்> பிணையத்திலிருந்து GMS பதிப்பை மேலெழுதும் திறன் diff --git a/fastlane/metadata/android/ta-IN/changelogs/55.txt b/fastlane/metadata/android/ta-IN/changelogs/55.txt index e0d077f0c..70ac4fab3 100644 --- a/fastlane/metadata/android/ta-IN/changelogs/55.txt +++ b/fastlane/metadata/android/ta-IN/changelogs/55.txt @@ -1,9 +1,9 @@ பதிவிறக்கம் பதிவிறக்க அமைப்பில் முக்கிய உள் மாற்றங்கள் - • அரோரா கடைக்கு இப்போது பின்னணியில் பதிவிறக்கம் செய்யப் புதிய இசைவு தேவை + • அரோரா கடைக்கு இப்போது பின்னணியில் பதிவிறக்கம் செய்ய புதிய இசைவு தேவை The பதிவிறக்கங்களுக்கு இடைநிறுத்தம் மற்றும் விண்ணப்பம் நற்பொருத்தங்கள் நீக்கப்பட்டுள்ளன • ஒரே நேரத்தில் பதிவிறக்கங்கள் நீக்கப்பட்டன (ஒரு நேரத்தில் ஒரு பதிவிறக்கத்திற்கு மட்டுமே) பதிவிறக்கம் செய்யப்பட்ட கோப்புகளுக்கான தானியங்கி SHA256 & SHA1 சரிபார்ப்பு - Chrom Chrome மற்றும் WebWiew போன்ற பகிரப்பட்ட நூலகங்களுடன் பயன்பாடுகளுக்குச் சிறந்த உதவி + Chrom Chrome மற்றும் WebWiew போன்ற பகிரப்பட்ட நூலகங்களுடன் பயன்பாடுகளுக்கு சிறந்த உதவி புதுப்பிப்பு புதுப்பிப்புகள் அமைப்பில் பெரிய மாற்றங்கள் பயன்பாடு பயன்பாடுகளுக்கான புதிய தானியங்கி புதுப்பிப்புகள் (இயல்பாக இயக்கப்பட்டது) Aut புதுப்பிப்புகளுக்கான புதிய தானியங்கி சான்றிதழ் சரிபார்ப்பு @@ -11,7 +11,7 @@ • சுய-புதுப்பிப்புகள் (அரோரா ச்டோர்) இயல்பாகவே முடக்கப்பட்டுள்ளது (அமைப்புகள்> புதுப்பிப்பில் இயக்கு) Install சொந்த நிறுவி மற்றும் அரோரா சேவைகள் நீக்கப்பட்டன Application நிறுவப்பட்ட பயன்பாடுகளை ஏற்றுமதி செய்வதற்கு இனி சேமிப்பக அனுமதிகள் தேவையில்லை - பயன்பாடு பயன்பாடுகளுக்கான குறைந்தபட்ச தேவையான ஆண்ட்ராய்டு பதிப்பு இப்போது பயன்பாட்டு விவரங்கள் பக்கத்தில் தெரியும் (மேலும் இந்தப் பயன்பாடு> செய்திபற்றி மேலும்) + பயன்பாடு பயன்பாடுகளுக்கான குறைந்தபட்ச தேவையான ஆண்ட்ராய்டு பதிப்பு இப்போது பயன்பாட்டு விவரங்கள் பக்கத்தில் தெரியும் (மேலும் இந்த பயன்பாடு> செய்தி பற்றி மேலும்) • மொழிபெயர்ப்பு புதுப்பிப்புகள் மற்றும் முக்கிய பிழை திருத்தங்கள் Su சுய் உடன் பயன்பாடுகளை நிறுவுவதற்கான உதவி (சிசுகு மேகிச்க் தொகுதி) Sentions அமைப்புகள்> பிணையத்திலிருந்து GMS பதிப்பை மேலெழுதும் திறன் diff --git a/fastlane/metadata/android/ta-IN/changelogs/57.txt b/fastlane/metadata/android/ta-IN/changelogs/57.txt index 3e551402c..f488acd4a 100644 --- a/fastlane/metadata/android/ta-IN/changelogs/57.txt +++ b/fastlane/metadata/android/ta-IN/changelogs/57.txt @@ -3,5 +3,5 @@ ஃச் 86 சாதனங்களுக்கான புதிய SPOFF உள்ளமைவுகள் பதிவிறக்கம் பதிவிறக்க அமைப்பில் மாற்றங்கள் பதிவிறக்கம் இயல்புநிலை பதிவிறக்கங்கள் இருப்பிடம் உள் கேச் கோப்பகமாக மாற்றப்பட்டது - கோப்புகள் இருந்தால் மறுதொடக்கம் செய்யும்போது இப்போது தானாகவே பதிவிறக்கங்கள் மீண்டும் தொடங்குகின்றன + கோப்புகள் கோப்புகள் இருந்தால் மறுதொடக்கம் செய்யும்போது இப்போது தானாகவே பதிவிறக்கங்கள் மீண்டும் தொடங்குகின்றன • மொழிபெயர்ப்பு புதுப்பிப்புகள் diff --git a/fastlane/metadata/android/ta-IN/changelogs/58.txt b/fastlane/metadata/android/ta-IN/changelogs/58.txt index 84a1fb436..02dd9593d 100644 --- a/fastlane/metadata/android/ta-IN/changelogs/58.txt +++ b/fastlane/metadata/android/ta-IN/changelogs/58.txt @@ -1,4 +1,4 @@ -Google கணக்குகள் தொடர்பான உள்நுழைவுடன் நிலையான சிக்கல் +Google Google கணக்குகள் தொடர்பான உள்நுழைவுடன் நிலையான சிக்கல் வழிசெலுத்தல் டிராயர் உருப்படிகளை ஒரு தனி உரையாடலில் நகர்த்தியது Scrave பெரிய திரை சாதனங்களுக்காக நேவிகேசன் ரெயிலுக்கு மாறியது பதிவிறக்கம் வெளிப்புற இடத்திற்கு பதிவிறக்கங்களை ஏற்றுமதி செய்யும் திறன் diff --git a/fastlane/metadata/android/ta-IN/changelogs/64.txt b/fastlane/metadata/android/ta-IN/changelogs/64.txt deleted file mode 100644 index 418fd0fe8..000000000 --- a/fastlane/metadata/android/ta-IN/changelogs/64.txt +++ /dev/null @@ -1,6 +0,0 @@ -And ஆண்ட்ராய்டு 15+ இல் காப்பக/பிரித்தெடுக்க பயன்பாடுகளுக்கான உதவி -Android ஆண்ட்ராய்டு 15+ இல் பயன்பாடுகளைத் தனிப்பட்ட இடத்தில் நிறுவுவதற்கான உதவி -Edge விளிம்பிலிருந்து விளிம்பில் ஆதரவை இடைமுகம் சரிசெய்தல் -Buch பல பிழை திருத்தங்கள் மற்றும் மேம்பாடுகள் -Sanes அறிவிப்புச் சேனல்கள் மற்றும் அறிவிப்புகளுக்கான மேம்பாடுகள் -• மொழிபெயர்ப்பு புதுப்பிப்புகள்; கூடுதல் சரங்கள் மொழிபெயர்க்கப்பட்டவை diff --git a/fastlane/metadata/android/ta-IN/changelogs/65.txt b/fastlane/metadata/android/ta-IN/changelogs/65.txt deleted file mode 100644 index 799959b51..000000000 --- a/fastlane/metadata/android/ta-IN/changelogs/65.txt +++ /dev/null @@ -1,4 +0,0 @@ -Chrom மற்றும் வெப்வியூ போன்ற பயன்பாடுகளுக்கான பகிரப்பட்ட நூலக நிறுவலுடன் நிலையான சிக்கல்கள் -Microg மைக்ரோவைப் பயன்படுத்தி தனிப்பட்ட கணக்கில் உள்நுழைவதற்கான உதவி -Auth அங்கீகார சரிபார்ப்புடன் ஒரு சிக்கல் சரி செய்யப்பட்டது -• மொழிபெயர்ப்பு புதுப்பிப்புகள்; கூடுதல் சரங்கள் மொழிபெயர்க்கப்பட்டவை diff --git a/fastlane/metadata/android/ta-IN/changelogs/66.txt b/fastlane/metadata/android/ta-IN/changelogs/66.txt deleted file mode 100644 index 70f97d9c4..000000000 --- a/fastlane/metadata/android/ta-IN/changelogs/66.txt +++ /dev/null @@ -1,5 +0,0 @@ -பயன்பாடு பிளெக்சசால் இயக்கப்படும் புதிய பயன்பாட்டு பொருந்தக்கூடிய மதிப்பீடுகள் -Black பிளாக்லிச்ட் மேலாளருக்கு மேம்பாடுகள் -Auto தானியங்கு புதுப்பிப்பு கட்டுப்பாடுகளை மாற்றும் திறன் -Bug சிறிய பிழை திருத்தங்கள் மற்றும் மேம்பாடுகள் -• மொழிபெயர்ப்பு புதுப்பிப்புகள்; கூடுதல் சரங்கள் மொழிபெயர்க்கப்பட்டவை diff --git a/fastlane/metadata/android/ta-IN/full_description.txt b/fastlane/metadata/android/ta-IN/full_description.txt index c0342262c..1bcda2c21 100644 --- a/fastlane/metadata/android/ta-IN/full_description.txt +++ b/fastlane/metadata/android/ta-IN/full_description.txt @@ -1,11 +1,12 @@ -அரோரா கடை ஒரு நேர்த்தியான வடிவமைப்பைக் கொண்ட கூகிள் பிளேயிற்கு அதிகாரப்பூர்வமற்ற, ஃபோச் கிளையன்ட் ஆகும். அரோரா கடை பிளே கடை போன்ற பயன்பாடுகளைப் பதிவிறக்கம், புதுப்பித்தல் மற்றும் தேட பயனர்களை அனுமதிக்கிறது. இது நன்றாக வேலை செய்கிறது +அரோரா கடை ஒரு நேர்த்தியான வடிவமைப்பைக் கொண்ட கூகிள் பிளேயிற்கு அதிகாரப்பூர்வமற்ற, ஃபோச் கிளையன்ட் ஆகும். அரோரா கடை + பிளே கடை போன்ற பயன்பாடுகளை பதிவிறக்கம், புதுப்பித்தல் மற்றும் தேட பயனர்களை அனுமதிக்கிறது. இது நன்றாக வேலை செய்கிறது Google Play சேவைகள் அல்லது மைக்ரோவுடன் அல்லது இல்லாமல். - நற்பண்புகள்: + அம்சங்கள்: • FOSS: GPLV3 உரிமம் உள்ளது • அழகான வடிவமைப்பு: அண்மைக் கால பொருள் 3 வழிகாட்டுதல்களில் கட்டப்பட்டுள்ளது -• உள்நுழைவு: நீங்கள் தனிப்பட்ட அல்லது அநாமதேய கணக்குடன் உள்நுழையலாம் + உள்நுழைவு: நீங்கள் தனிப்பட்ட அல்லது அநாமதேய கணக்குடன் உள்நுழையலாம் • சாதனம் மற்றும் லோகேல் ச்பூஃபிங்: உலகம் பூட்டப்பட்ட பயன்பாடுகளை அணுக உங்கள் சாதனம் மற்றும்/அல்லது இருப்பிடத்தை மாற்றவும் • எக்சோடச் தனியுரிமை ஒருங்கிணைப்பு: பயன்பாட்டில் உடனடியாக டிராக்கர்களைக் காண்க -• கருப்பு பிளாக்லிச்டிங் புதுப்பிப்புகள்: குறிப்பிட்ட பயன்பாடுகளுக்கான புதுப்பிப்புகளை புறக்கணிக்கவும் + கருப்பு பிளாக்லிச்டிங் புதுப்பிப்புகள்: குறிப்பிட்ட பயன்பாடுகளுக்கான புதுப்பிப்புகளை புறக்கணிக்கவும் diff --git a/fastlane/metadata/android/ta-IN/short_description.txt b/fastlane/metadata/android/ta-IN/short_description.txt new file mode 100644 index 000000000..eb0adceeb --- /dev/null +++ b/fastlane/metadata/android/ta-IN/short_description.txt @@ -0,0 +1 @@ +ஒரு நேர்த்தியான வடிவமைப்பு மற்றும் தனியுரிமையுடன் கூகிள் விளையாடுவதற்கான அதிகாரப்பூர்வமற்ற FOSS வாடிக்கையாளர் diff --git a/fastlane/metadata/android/tr-TR/changelogs/66.txt b/fastlane/metadata/android/tr-TR/changelogs/66.txt deleted file mode 100644 index fe30fe9b8..000000000 --- a/fastlane/metadata/android/tr-TR/changelogs/66.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Plexus tarafından desteklenen yeni uyumluluk oylamaları -• Kara liste yöneticisinde iyileştirmeler -• Kendiliğinden güncelleme kısıtlarını değiştirme özelliği -• Küçük hata giderimleri ve iyileştirmeler -• Çeviri güncellemeleri; ek dizgeler yerelleştirildi diff --git a/fastlane/metadata/android/tr-TR/changelogs/67.txt b/fastlane/metadata/android/tr-TR/changelogs/67.txt deleted file mode 100644 index 01f4a73e5..000000000 --- a/fastlane/metadata/android/tr-TR/changelogs/67.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Android 16'yı hedefleyin -• Uygulamalara giden bağlantıları açma hatası düzeltildi -• Uygulamanın ayrıntı sayfasının uygulama bilgi ayarlarından açılması desteklendi -• Çeviri güncellemeleri diff --git a/fastlane/metadata/android/tr-TR/changelogs/68.txt b/fastlane/metadata/android/tr-TR/changelogs/68.txt deleted file mode 100644 index fc452a95b..000000000 --- a/fastlane/metadata/android/tr-TR/changelogs/68.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Uygulama arama ve kurma için yeni API'lere geçildi -• Arama süzgeci artık kullanılamıyor, daha sonra yeniden eklenecek -• Uygulama sayfasında gezinirken çöküş giderildi -• Yerel algılanırken çöküş giderildi -• Çeviri güncellemeleri diff --git a/fastlane/metadata/android/tr-TR/changelogs/72.txt b/fastlane/metadata/android/tr-TR/changelogs/72.txt deleted file mode 100644 index 0fe075102..000000000 --- a/fastlane/metadata/android/tr-TR/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Desteklenen en düşük Android sürümü şimdi Android 6.0 -• Material 3 Expressive temasına geçildi -• Geniş ekranlı aygıtlar için destek iyileştirildi -• Uygulama başı dille İbranice dilinin belirlenemediği bir hata giderildi -• Arama süzgeçleri işlevselliği geri kazanıldı diff --git a/fastlane/metadata/android/tr-TR/changelogs/73.txt b/fastlane/metadata/android/tr-TR/changelogs/73.txt deleted file mode 100644 index db8655451..000000000 --- a/fastlane/metadata/android/tr-TR/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Sağdan sola düzenlerde yanlış yükseltme oku belirteci simgesi düzeltildi -• Aramada sayfalama ve IME sorunları çözüldü -• Kullanıcı kurucu seçimini görmezden gelen hata düzeltildi -• Çeviriler, exodus izleyici veri tabanı ve google'ın kök sertifikaları güncellendi diff --git a/fastlane/metadata/android/tr-TR/full_description.txt b/fastlane/metadata/android/tr-TR/full_description.txt index a47fdad33..04b9ff78a 100644 --- a/fastlane/metadata/android/tr-TR/full_description.txt +++ b/fastlane/metadata/android/tr-TR/full_description.txt @@ -1,4 +1,6 @@ -Aurora Store, Google Play için şık tasarımlı bir gayriresmî FOSS istemcidir. Aurora Store, kullanıcıların Play Store ile benzer biçimde uygulama indirmesini, güncellemesini ve aramasını sağlar. Google Play Hizmetleri veya microG ile ya da bunlar olmadan sorunsuzca çalışır. +Aurora Store, Google Play için şık tasarımlı bir gayriresmî FOSS istemcidir. Aurora Store, +kullanıcıların Play Store ile benzer biçimde uygulama indirmesini, güncellemesini ve aramasını +sağlar. Google Play Hizmetleri veya MicroG ile ya da bunlar olmadan sorunsuzca çalışır. Özellikler: @@ -7,5 +9,4 @@ Aurora Store, Google Play için şık tasarımlı bir gayriresmî FOSS istemcidi • Hesapla oturum aç: Kişisel veya anonim bir hesapla oturum açabilirsiniz • Aygıt ve Yer gizle: Coğrafi kilitli uygulamalara erişmek için aygıtınızı ve/veya yer ayarını değiştirin • Exodus Gizlilik tümleşimi: Uygulamadaki izleyicileri anında görün -• Plexus tümleşimi: Uygulamanın Google Play Hizmetleri olmayan ve/veya microG olan sistemle uyumluluğunu anında görün. • Güncellemeleri kara listeye al: Belirli uygulamalar için güncellemeleri yok sayın diff --git a/fastlane/metadata/android/uk/changelogs/66.txt b/fastlane/metadata/android/uk/changelogs/66.txt deleted file mode 100644 index 9a0064ac3..000000000 --- a/fastlane/metadata/android/uk/changelogs/66.txt +++ /dev/null @@ -1,5 +0,0 @@ -- Нові рейтинги сумісності додатків на базі Plexus -- Покращення в менеджері чорних списків -- Можливість змінювати обмеження на автоматичне оновлення -- Дрібні виправлення та покращення -- Оновлення перекладу; локалізовано додаткові рядки diff --git a/fastlane/metadata/android/uk/changelogs/67.txt b/fastlane/metadata/android/uk/changelogs/67.txt deleted file mode 100644 index 9db20e6a1..000000000 --- a/fastlane/metadata/android/uk/changelogs/67.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Цільова версія Android 16 -• Виправлено помилку з відкриттям посилань на програми -• Підтримка відкриття сторінки з детальною інформацією про програму з налаштувань інформації про програму -• Оновлення перекладу diff --git a/fastlane/metadata/android/uk/changelogs/68.txt b/fastlane/metadata/android/uk/changelogs/68.txt deleted file mode 100644 index 349f680cf..000000000 --- a/fastlane/metadata/android/uk/changelogs/68.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Перехід на нові API для пошуку та встановлення програм -• Фільтр пошуку більше недоступний, його буде додано пізніше -• Виправлено збій під час переходу на сторінку з деталями програми -• Виправлено збій під час підміни локалі -• Оновлення перекладу diff --git a/fastlane/metadata/android/uk/changelogs/71.txt b/fastlane/metadata/android/uk/changelogs/71.txt deleted file mode 100644 index 84cab3c7c..000000000 --- a/fastlane/metadata/android/uk/changelogs/71.txt +++ /dev/null @@ -1,2 +0,0 @@ -• Виправлено проблему зі встановленням програм на пристроях Huawei -• Оновлення перекладу diff --git a/fastlane/metadata/android/uk/changelogs/72.txt b/fastlane/metadata/android/uk/changelogs/72.txt deleted file mode 100644 index 5b1cea17f..000000000 --- a/fastlane/metadata/android/uk/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Мінімальна підтримувана версія Android тепер Android 6.0 -• Перехід на тему Material3 Expressive -• Покращена підтримка широкоекранних пристроїв -• Виправлено проблему, через яку іврит не налаштовувався належним чином для мови окремого додатка -• Відновлено функціональність фільтрів пошуку diff --git a/fastlane/metadata/android/uk/changelogs/73.txt b/fastlane/metadata/android/uk/changelogs/73.txt deleted file mode 100644 index ac6a10516..000000000 --- a/fastlane/metadata/android/uk/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• Виправлено неправильний значок індикатора стрілки оновлення в макетах із напрямком тексту справа наліво (RTL) -• Виправлено проблеми зі сторінкуванням та IME під час пошуку -• Виправлено помилку, яка ігнорувала вибір встановлювача користувачем -• Оновлено переклади, базу даних відстежувачів Exodus та кореневі сертифікати Google diff --git a/fastlane/metadata/android/uk/full_description.txt b/fastlane/metadata/android/uk/full_description.txt index 23636b981..cd4dfd441 100644 --- a/fastlane/metadata/android/uk/full_description.txt +++ b/fastlane/metadata/android/uk/full_description.txt @@ -1,11 +1,12 @@ -Aurora Store — це неофіційний вільний клієнт для Google Play з елегантним дизайном. Aurora Store дозволяє користувачам завантажувати, оновлювати та шукати такі застосунки, як і Play Маркеті. Він чудово працює як із сервісами Google Play або microG, так і без них. +Aurora Store — це неофіційний FOSS клієнт для Google Play із елегантним дизайном. Aurora Store +дозволяє користувачам завантажувати, оновлювати та шукати застосунки, як в Play Store. Працює ідеально +із службами Google Play або MicroG або без них. Особливості: • FOSS: має ліцензію GPLv3 -• Гарний дизайн: розроблений відповідно до останніх рекомендацій Material 3 -• Вхід до облікового запису: ви можете ввійти за допомогою особистого або знеособленого облікового запису -• Підробка пристрою та місцеперебування: змініть інформацію про пристрій та/або місцеперебування, щоб отримати доступ до заблокованих застосунків за регіонами -• Інтеграція з Exodus Privacy: миттєво переглядайте відстежувачі в застосунку -• Інтеграція з Plexus: миттєво перевіряйте сумісність застосунків без сервісів Google Play або microG -• Чорний список оновлень: не зважати на оновлення для певних застосунків +• Гарний дизайн: розроблено відповідно до останніх рекомендацій Material 3 +• Вхід до облікового запису: ви можете увійти за допомогою особистого або анонімного облікового запису +• Підробка пристрою та мови: змініть свій пристрій і/або мову, щоб отримати доступ до геозаблокованих застосунків +• Інтеграція з Exodus Privacy: миттєво переглядайте трекери в застосунку +• Чорний список оновлень: ігнорувати оновлення для певних застосунків diff --git a/fastlane/metadata/android/uk/short_description.txt b/fastlane/metadata/android/uk/short_description.txt index b3c15f6cb..c2981359a 100644 --- a/fastlane/metadata/android/uk/short_description.txt +++ b/fastlane/metadata/android/uk/short_description.txt @@ -1 +1 @@ -Неофіційний вільний клієнт для Google Play з елегантним дизайном та приватністю +Неофіційний клієнт FOSS для Google Play з елегантним дизайном і приватністю diff --git a/fastlane/metadata/android/zh-CN/changelogs/46.txt b/fastlane/metadata/android/zh-CN/changelogs/46.txt index 5bdf889f1..429079f1c 100644 --- a/fastlane/metadata/android/zh-CN/changelogs/46.txt +++ b/fastlane/metadata/android/zh-CN/changelogs/46.txt @@ -1,6 +1,6 @@ ·在需要之前避免询问存储许可。 ·修改了欺骗配置,以避免进出口的存储权限。 -·添加自动检查应用程序更新的选项(需要登录的工作账户)。 +·添加自动检查应用程序更新的选项(需要登录的工作帐户)。 ·修复了所需的库未与Chrome和Trichrome库等应用程序一起安装的问题。 ·备份Aurora Store时忽略备份中的下载目录。 ·安装Shizuku安装程序(需要Android 8.0+)。 diff --git a/fastlane/metadata/android/zh-CN/changelogs/50.txt b/fastlane/metadata/android/zh-CN/changelogs/50.txt index 4eb085a99..69a5c6177 100644 --- a/fastlane/metadata/android/zh-CN/changelogs/50.txt +++ b/fastlane/metadata/android/zh-CN/changelogs/50.txt @@ -1,6 +1,6 @@ ·从黑色主题切换到系统主题可正确更新用户界面。 ·主屏幕上的对话框不再隐藏某些视图。 -·现在打开Google Play链接可确保存在有效的工作账户。 +·现在打开Google Play链接可确保存在有效的工作帐户。 ·导航抽屉只能在主屏幕上打开。 ·后退操作现在可以在某些屏幕上正确退出应用程序。 ·设置按钮现在在黑色主题中具有适当的色调。 diff --git a/fastlane/metadata/android/zh-CN/changelogs/58.txt b/fastlane/metadata/android/zh-CN/changelogs/58.txt index 8195f91c3..47eb7b0f2 100644 --- a/fastlane/metadata/android/zh-CN/changelogs/58.txt +++ b/fastlane/metadata/android/zh-CN/changelogs/58.txt @@ -1,4 +1,4 @@ -• 修复了与 Google 账户相关的登录问题 +• 修复了与 Google 帐户相关的登录问题 • 将导航抽屉项目移至单独的对话框 • 针对大屏幕设备切换到 NavigationRail • 能够将下载内容导出到外部位置 diff --git a/fastlane/metadata/android/zh-CN/changelogs/66.txt b/fastlane/metadata/android/zh-CN/changelogs/66.txt deleted file mode 100644 index ecfde5270..000000000 --- a/fastlane/metadata/android/zh-CN/changelogs/66.txt +++ /dev/null @@ -1,5 +0,0 @@ -• 新增应用兼容性评分,数据来自 Plexus -• 改进黑名单管理器 -• 允许更改自动更新限制 -• 微小的 bug 修复和改进 -• 翻译更新;本地化了额外的字符串 diff --git a/fastlane/metadata/android/zh-CN/changelogs/67.txt b/fastlane/metadata/android/zh-CN/changelogs/67.txt deleted file mode 100644 index a1f0c2e51..000000000 --- a/fastlane/metadata/android/zh-CN/changelogs/67.txt +++ /dev/null @@ -1,4 +0,0 @@ -• 目标 API 为 Android 16 -• 修复打开应用链接的错误 -• 支持从应用信息设置打开应用的详情页 -• 翻译更新 diff --git a/fastlane/metadata/android/zh-CN/changelogs/68.txt b/fastlane/metadata/android/zh-CN/changelogs/68.txt deleted file mode 100644 index 345e7c9fb..000000000 --- a/fastlane/metadata/android/zh-CN/changelogs/68.txt +++ /dev/null @@ -1,5 +0,0 @@ -• 切换到新的应用搜索和安装 API -• 搜索筛选器目前不可用,会在之后添加回来 -• 修复转到应用详情页的崩溃 -• 修复伪造语言环境造成的崩溃 -• 翻译更新 diff --git a/fastlane/metadata/android/zh-CN/changelogs/72.txt b/fastlane/metadata/android/zh-CN/changelogs/72.txt deleted file mode 100644 index b507589a4..000000000 --- a/fastlane/metadata/android/zh-CN/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• Android 6.0 现在是受支持的最低安卓系统版本 -• 切换到 Material3 Expressive 主题 -• 改进宽屏设备支持 -• 修复了希伯来语未正确设置的问题 -• 恢复了搜索筛选器功能 diff --git a/fastlane/metadata/android/zh-CN/changelogs/73.txt b/fastlane/metadata/android/zh-CN/changelogs/73.txt deleted file mode 100644 index e9bd53e02..000000000 --- a/fastlane/metadata/android/zh-CN/changelogs/73.txt +++ /dev/null @@ -1,4 +0,0 @@ -• 修复从右到左文字显示布局中错误的更新箭头指示器图标 -• 修复搜索的分页和输入法问题 -• 修复绕过用户安装程序选择的问题 -• 更新翻译、exodus trackers 数据库和 google 根证书 diff --git a/fastlane/metadata/android/zh-CN/full_description.txt b/fastlane/metadata/android/zh-CN/full_description.txt index 9c99fa541..5e6508bed 100644 --- a/fastlane/metadata/android/zh-CN/full_description.txt +++ b/fastlane/metadata/android/zh-CN/full_description.txt @@ -1,11 +1,12 @@ -Aurora Store 是一款 Google Play 的非官方、自由及开源软件客户端,设计优雅。Aurora Store 让用户如同在 Play 商店一样下载、更新和搜索应用程序。无论有没有 Google Play 服务或 MicroG 都能完美运行。 +Aurora Store 是一款 Google Play 的非官方、自由及开源软件客户端,设计优雅。 +Aurora Store 让用户如同在 Play 商店一样下载、更新和搜索应用程序。 +无论有没有 Google Play 服务或 MicroG 都能完美运行。 特点: ·自由/开源软件:具有 GPLv3 许可证 ·设计美观:基于最新的 Material 3 指南 -·账户登录:您可以使用个人账户或匿名账户登录 +·帐户登录:您可以使用个人帐户或匿名帐户登录 ·IP和地区虚拟:更改您的设备和/或区域设置以访问锁区的应用程序 ·Exodus Privacy 集成:即时查看应用程序中的跟踪器 -•Plexus 集成:即刻了解没有 Google Play Services 或使用 microG 情形下的应用兼容性 ·更新黑名单:忽略特定应用程序的更新 diff --git a/fastlane/metadata/android/zh-TW/changelogs/72.txt b/fastlane/metadata/android/zh-TW/changelogs/72.txt deleted file mode 100644 index de82e2bd4..000000000 --- a/fastlane/metadata/android/zh-TW/changelogs/72.txt +++ /dev/null @@ -1,5 +0,0 @@ -• 最低支援的 Android 版本現為 Android 6.0 -• 已切換至 Material3 Expressive 主題 -• 改善對寬螢幕裝置的支援 -• 修正希伯來語在應用程式語言設定中未正確套用的問題 -• 已恢復搜尋篩選功能 diff --git a/fastlane/metadata/android/zh-TW/full_description.txt b/fastlane/metadata/android/zh-TW/full_description.txt index 559af6edd..604946923 100644 --- a/fastlane/metadata/android/zh-TW/full_description.txt +++ b/fastlane/metadata/android/zh-TW/full_description.txt @@ -1,11 +1,10 @@ -Aurora Store 是個 Google Play 非官方 FOSS 客戶端,設計雅致。Aurora Store 讓使用者下載、更新和搜尋應用程式,有如 Play 商店一樣。不管有沒有 Google Play 服務或 MicroG 也運作如常。 +Aurora 商店乃 Google Play 非官方 FOSS 客戶端,設計雅致。Aurora 商店讓使用者下載、更新和搜尋應用程式,有如 Play 商店一樣。不管有沒有 Google Play 服務或 MicroG 也運作如常。 特色: -• FOSS:使用 GPLv3 授權 +• FOSS:按 GPLv3 授權 • 設計美觀:採用最新的 Material 3 指引建構 • 帳戶登入:可使用個人或匿名帳戶登入 -• 裝置與地區偽裝:變更您的裝置及/或地區以存取地域鎖定的應用程式 -• Exodus 隱私整合:即時查看應用程式中的追蹤器 -• Plexus 整合: 在沒有 Google Play 服務或 microG 的情況下即時查看應用程式相容性 -• 更新黑名單:忽略特定應用程式更新 +• 裝置與地區虛擬:變更您的裝置及/或地區以存取地域鎖定的應用程式 +• [Exodus 隱私](https://exodus-privacy.eu.org/)整合:瞬間一覧應用程式中的追蹤器 +• 更新黑名單:忽略特定應用程式的更新 diff --git a/gradle.properties b/gradle.properties index 8bad2bce4..8aaf803f1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,20 @@ # -# SPDX-FileCopyrightText: 2021 Rahul Kumar Patel -# SPDX-FileCopyrightText: 2023-2025 The Calyx Institute -# SPDX-License-Identifier: GPL-3.0-or-later +# Aurora Store +# Copyright (C) 2021, Rahul Kumar Patel +# +# Aurora Store is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# Aurora Store is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Aurora Store. If not, see . +# # # Project-wide Gradle settings. @@ -24,7 +37,5 @@ android.useAndroidX=true # Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=official -# https://r8.googlesource.com/r8/+/refs/heads/master/compatibility-faq.md#r8-full-mode +# Disable new R8 mode android.enableR8.fullMode=false -# https://docs.gradle.org/current/userguide/configuration_cache.html -org.gradle.configuration-cache=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c1340258b..7e1d3636a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,122 +1,100 @@ -# -# SPDX-FileCopyrightText: 2024-2025 The Calyx Institute -# SPDX-FileCopyrightText: 2024-2025 Aurora OSS -# SPDX-License-Identifier: GPL-3.0-or-later -# - [versions] -activity = "1.13.0" -agCoreservice = "13.3.1.300" -androidGradlePlugin = "8.13.2" -adaptive = "1.3.0-alpha09" -androidx-hilt = "1.3.0" -androidx-junit = "1.3.0" -browser = "1.9.0" -coil = "3.4.0" -composeBom = "2026.03.00" -composeMaterial = "1.5.0-alpha15" -core = "1.18.0" -epoxy = "5.2.1" -espresso = "3.7.0" -gplayapi = "3.5.9" -hiddenapibypass = "6.1" -hilt = "2.58" +activityCompose = "1.10.0" +androidGradlePlugin = "8.8.0" +browserVersion = "1.8.0" +coilVersion = "3.0.4" +composeBom = "2025.01.00" +coreVersion = "1.15.0" +epoxyVersion = "5.1.4" +espressoVersion = "3.6.1" +gplayapiVersion = "3.4.4" +gsonVersion = "2.11.0" +hiddenapibypassVersion = "4.3" +hiltVersion = "2.55" +hiltWorkVersion = "1.2.0" junit = "4.13.2" -kotlin = "2.3.10" -ksp = "2.3.6" -ktlint = "14.2.0" -leakcanary = "2.14" +junitVersion = "1.2.1" +kotlinVersion = "2.1.0" +kspVersion = "2.1.0-1.0.29" +ktlintVersion = "12.1.2" +leakcanaryAndroidVersion = "2.14" libsu = "6.0.0" -lifecycle = "2.10.0" -material = "1.13.0" -navigation = "2.9.7" -navigation3 = "1.0.1" -okhttp = "5.3.2" -paging = "3.4.2" -preference = "1.2.1" +lifeVersion = "2.8.7" +materialVersion = "1.12.0" +navVersion = "2.8.5" +okhttpVersion = "4.12.0" +preferenceVersion = "1.2.1" processPhoenix = "3.0.0" -protobufJavalite = "4.34.0" -rikkaHiddenAPI = "4.4.0" -rikkaTools = "4.4.0" -room = "2.8.4" -serialization = "1.10.0" -shimmer = "0.5.0" -shizuku = "13.1.5" -swiperefreshlayout = "1.2.0" -truth = "1.4.5" -viewpager2 = "1.1.0" -work = "2.11.1" +protobufJavaliteVersion = "4.29.3" +rikkaHiddenVersion = "4.3.3" +rikkaToolsVersion = "4.4.0" +roomVersion = "2.6.1" +shimmerVersion = "0.5.0" +shizukuVersion = "13.1.5" +swiperefreshlayoutVersion = "1.1.0" +truth = "1.4.4" +viewpager2Version = "1.1.0" +workVersion = "2.10.0" [libraries] -huawei-hms-coreservice = { module = "com.huawei.hms:ag-coreservice", version.ref = "agCoreservice" } -airbnb-epoxy-android = { module = "com.airbnb.android:epoxy", version.ref = "epoxy" } -airbnb-epoxy-processor = { module = "com.airbnb.android:epoxy-processor", version.ref = "epoxy" } -androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activity" } -androidx-browser = { module = "androidx.browser:browser", version.ref = "browser" } +airbnb-epoxy-android = { module = "com.airbnb.android:epoxy", version.ref = "epoxyVersion" } +airbnb-epoxy-processor = { module = "com.airbnb.android:epoxy-processor", version.ref = "epoxyVersion" } +androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } +androidx-browser = { module = "androidx.browser:browser", version.ref = "browserVersion" } androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } -androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "core" } -androidx-adaptive-core = { module = "androidx.compose.material3.adaptive:adaptive", version.ref = "adaptive" } -androidx-adaptive-layout = { module = "androidx.compose.material3.adaptive:adaptive-layout", version.ref = "adaptive" } -androidx-adaptive-navigation = { module = "androidx.compose.material3.adaptive:adaptive-navigation", version.ref = "adaptive" } -androidx-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "espresso" } -androidx-hilt-viewmodel = { module = "androidx.hilt:hilt-lifecycle-viewmodel-compose", version.ref = "androidx-hilt" } -androidx-junit = { module = "androidx.test.ext:junit-ktx", version.ref = "androidx-junit" } -androidx-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycle" } -androidx-lifecycle-navigation3 = { module = "androidx.lifecycle:lifecycle-viewmodel-navigation3", version.ref = "lifecycle" } -androidx-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "composeMaterial" } -androidx-navigation-fragment-ktx = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "navigation" } -androidx-navigation-ui-ktx = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "navigation" } -androidx-navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "navigation3" } -androidx-navigation3-ui = { module = "androidx.navigation3:navigation3-ui", version.ref = "navigation3" } -androidx-paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging" } -androidx-paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "paging" } -androidx-preference-ktx = { module = "androidx.preference:preference-ktx", version.ref = "preference" } -androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" } -androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" } -androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" } -androidx-room-paging = { module = "androidx.room:room-paging", version.ref = "room" } -androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "swiperefreshlayout" } +androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "coreVersion" } +androidx-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "espressoVersion" } +androidx-junit = { module = "androidx.test.ext:junit-ktx", version.ref = "junitVersion" } +androidx-lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version.ref = "lifeVersion" } +androidx-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifeVersion" } +androidx-material3 = { group = "androidx.compose.material3", name = "material3" } +androidx-navigation-fragment-ktx = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "navVersion" } +androidx-navigation-ui-ktx = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "navVersion" } +androidx-preference-ktx = { module = "androidx.preference:preference-ktx", version.ref = "preferenceVersion" } +androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "roomVersion" } +androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "roomVersion" } +androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "roomVersion" } +androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "swiperefreshlayoutVersion" } androidx-ui = { group = "androidx.compose.ui", name = "ui" } androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } -androidx-viewpager2 = { module = "androidx.viewpager2:viewpager2", version.ref = "viewpager2" } -androidx-work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "work" } -auroraoss-gplayapi = { module = "com.auroraoss:gplayapi", version.ref = "gplayapi" } -coil-kt = { module = "io.coil-kt.coil3:coil", version.ref = "coil" } -coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" } -coil-network = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil" } -facebook-shimmer = { module = "com.facebook.shimmer:shimmer", version.ref = "shimmer" } +androidx-viewpager2 = { module = "androidx.viewpager2:viewpager2", version.ref = "viewpager2Version" } +androidx-work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "workVersion" } +auroraoss-gplayapi = { module = "com.auroraoss:gplayapi", version.ref = "gplayapiVersion" } +coil-kt = { module = "io.coil-kt.coil3:coil", version.ref = "coilVersion" } +coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coilVersion" } +coil-network = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coilVersion" } +facebook-shimmer = { module = "com.facebook.shimmer:shimmer", version.ref = "shimmerVersion" } github-topjohnwu-libsu = { module = "com.github.topjohnwu.libsu:core", version.ref = "libsu" } -google-android-material = { module = "com.google.android.material:material", version.ref = "material" } -google-protobuf-javalite = { module = "com.google.protobuf:protobuf-javalite", version.ref = "protobufJavalite" } +google-android-material = { module = "com.google.android.material:material", version.ref = "materialVersion" } +google-gson = { module = "com.google.code.gson:gson", version.ref = "gsonVersion" } +google-protobuf-javalite = { module = "com.google.protobuf:protobuf-javalite", version.ref = "protobufJavaliteVersion" } google-truth = { module = "com.google.truth:truth", version.ref = "truth" } -hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hilt" } -hilt-android-core = { module = "com.google.dagger:hilt-android", version.ref = "hilt" } -hilt-android-testing = { module = "com.google.dagger:hilt-android-testing", version.ref = "hilt" } -hilt-androidx-compiler = { module = "androidx.hilt:hilt-compiler", version.ref = "androidx-hilt" } -hilt-androidx-work = { module = "androidx.hilt:hilt-work", version.ref = "androidx-hilt" } +hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hiltVersion" } +hilt-android-core = { module = "com.google.dagger:hilt-android", version.ref = "hiltVersion" } +hilt-android-testing = { module = "com.google.dagger:hilt-android-testing", version.ref = "hiltVersion" } +hilt-androidx-compiler = { module = "androidx.hilt:hilt-compiler", version.ref = "hiltWorkVersion" } +hilt-androidx-work = { module = "androidx.hilt:hilt-work", version.ref = "hiltWorkVersion" } junit = { module = "junit:junit", version.ref = "junit" } -kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization" } -lsposed-hiddenapibypass = { module = "org.lsposed.hiddenapibypass:hiddenapibypass", version.ref = "hiddenapibypass" } +lsposed-hiddenapibypass = { module = "org.lsposed.hiddenapibypass:hiddenapibypass", version.ref = "hiddenapibypassVersion" } process-phoenix = { module = "com.jakewharton:process-phoenix", version.ref = "processPhoenix" } -rikka-hidden-stub = { module = "dev.rikka.hidden:stub", version.ref = "rikkaHiddenAPI" } -rikka-shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizuku" } -rikka-shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizuku" } -rikka-tools-refine-runtime = { module = "dev.rikka.tools.refine:runtime", version.ref = "rikkaTools" } -squareup-leakcanary-android = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakcanary" } -squareup-okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" } +rikka-hidden-stub = { module = "dev.rikka.hidden:stub", version.ref = "rikkaHiddenVersion" } +rikka-shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizukuVersion" } +rikka-shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizukuVersion" } +rikka-tools-refine-runtime = { module = "dev.rikka.tools.refine:runtime", version.ref = "rikkaToolsVersion" } +squareup-leakcanary-android = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakcanaryAndroidVersion" } +squareup-okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttpVersion" } [plugins] android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } -androidx-navigation = { id = "androidx.navigation.safeargs.kotlin", version.ref = "navigation" } -google-ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } -hilt-android-plugin = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } -ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" } -jetbrains-kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } -jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } -jetbrains-kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" } -jetbrains-kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } -rikka-tools-refine-plugin = { id = "dev.rikka.tools.refine", version.ref = "rikkaTools" } +androidx-navigation = { id = "androidx.navigation.safeargs.kotlin", version.ref = "navVersion" } +google-ksp = { id = "com.google.devtools.ksp", version.ref = "kspVersion" } +hilt-android-plugin = { id = "com.google.dagger.hilt.android", version.ref = "hiltVersion" } +ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlintVersion" } +jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlinVersion" } +jetbrains-kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlinVersion" } +jetbrains-kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlinVersion" } +rikka-tools-refine-plugin = { id = "dev.rikka.tools.refine", version.ref = "rikkaToolsVersion" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d997cfc60..a4b76b953 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 92ed94347..b8cf2dd95 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,8 @@ +#Tue Dec 24 11:31:28 ICT 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=60ea723356d81263e8002fec0fcf9e2b0eee0c0850c7a3d7ab0a63f2ccc601f3 -distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip +distributionSha256Sum=7a00d51fb93147819aab76024feece20b6b84e420694101f276be952e08bef03 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 0262dcbd5..f3b75f3b0 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015 the original authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -114,6 +114,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -171,6 +172,7 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -203,14 +205,15 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index e509b2dd8..9b42019c7 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,10 +70,11 @@ goto fail :execute @rem Setup the command line +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/homepage_content.html b/homepage_content.html new file mode 100644 index 000000000..371cfff09 --- /dev/null +++ b/homepage_content.html @@ -0,0 +1,2 @@ +Aurora Next — Open-source Android App Store

Open-source Android apps, without the tracking

Browse, search, and install apps privately. No account required.

Aurora Next — Open-source Android app store. Not affiliated with Google.

\ No newline at end of file diff --git a/jmods-android/app/build.gradle.kts b/jmods-android/app/build.gradle.kts new file mode 100644 index 000000000..f49cff940 --- /dev/null +++ b/jmods-android/app/build.gradle.kts @@ -0,0 +1,70 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.jetbrains.kotlin.android) + alias(libs.plugins.jetbrains.kotlin.compose) + alias(libs.plugins.hilt.android.plugin) + id("com.google.devtools.ksp") +} + +android { + namespace = "com.jmods" + compileSdk = 35 + + defaultConfig { + applicationId = "com.jmods" + minSdk = 26 + targetSdk = 35 + versionCode = 1 + versionName = "1.0.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = "17" + } + + buildFeatures { + compose = true + } +} + +dependencies { + implementation(project(":jmods:core-domain")) + implementation(project(":jmods:core-data")) + implementation(project(":jmods:core-network")) + implementation(project(":jmods:core-navigation")) + implementation(project(":jmods:core-ui")) + implementation(project(":jmods:feature-home")) + implementation(project(":jmods:feature-details")) + implementation(project(":jmods:feature-categories")) + implementation(project(":jmods:feature-search")) + implementation(project(":jmods:feature-updates")) + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.process) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + implementation(libs.hilt.android.core) + ksp(libs.hilt.android.compiler) + implementation("androidx.hilt:hilt-navigation-compose:1.2.0") + implementation(libs.androidx.navigation.ui.ktx) + implementation(libs.androidx.work.runtime.ktx) + implementation("androidx.hilt:hilt-work:1.2.0") +} diff --git a/jmods-android/app/src/main/AndroidManifest.xml b/jmods-android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..a525e8bba --- /dev/null +++ b/jmods-android/app/src/main/AndroidManifest.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + diff --git a/jmods-android/app/src/main/kotlin/com/jmods/JModsApp.kt b/jmods-android/app/src/main/kotlin/com/jmods/JModsApp.kt new file mode 100644 index 000000000..91dbb205e --- /dev/null +++ b/jmods-android/app/src/main/kotlin/com/jmods/JModsApp.kt @@ -0,0 +1,7 @@ +package com.jmods + +import android.app.Application +import dagger.hilt.android.HiltAndroidApp + +@HiltAndroidApp +class JModsApp : Application() diff --git a/jmods-android/app/src/main/kotlin/com/jmods/MainActivity.kt b/jmods-android/app/src/main/kotlin/com/jmods/MainActivity.kt new file mode 100644 index 000000000..37c883a37 --- /dev/null +++ b/jmods-android/app/src/main/kotlin/com/jmods/MainActivity.kt @@ -0,0 +1,176 @@ +package com.jmods + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.List +import androidx.compose.material.icons.filled.* +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavDestination.Companion.hasRoute +import androidx.navigation.NavDestination.Companion.hierarchy +import androidx.navigation.NavGraph.Companion.findStartDestination +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.currentBackStackEntryAsState +import androidx.navigation.compose.rememberNavController +import com.jmods.feature.home.ui.HomeScreen +import com.jmods.feature.details.ui.DetailsScreen +import com.jmods.feature.categories.ui.CategoriesScreen +import com.jmods.feature.categories.ui.CategoryResultsScreen +import com.jmods.feature.search.ui.SearchScreen +import com.jmods.feature.updates.ui.UpdatesScreen +import com.jmods.navigation.AppDestination +import com.jmods.ui.component.JModsPlayer +import com.jmods.ui.theme.JMODSTheme +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch + +@AndroidEntryPoint +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + JMODSTheme { + val navController = rememberNavController() + val navBackStackEntry by navController.currentBackStackEntryAsState() + val currentDestination = navBackStackEntry?.destination + val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed) + val scope = rememberCoroutineScope() + var isPlayerVisible by remember { mutableStateOf(false) } + + ModalNavigationDrawer( + drawerState = drawerState, + drawerContent = { + ModalDrawerSheet { + Text( + "J MODS", + modifier = Modifier.padding(24.dp), + style = MaterialTheme.typography.headlineMedium, + fontWeight = androidx.compose.ui.text.font.FontWeight.Black + ) + HorizontalDivider() + NavigationDrawerItem( + label = { Text("Settings") }, + selected = false, + icon = { Icon(Icons.Default.Settings, contentDescription = null) }, + onClick = { scope.launch { drawerState.close() } } + ) + NavigationDrawerItem( + label = { Text("About") }, + selected = false, + icon = { Icon(Icons.Default.Info, contentDescription = null) }, + onClick = { scope.launch { drawerState.close() } } + ) + } + } + ) { + Scaffold( + bottomBar = { + Column { + if (isPlayerVisible) { + JModsPlayer( + title = "Community Radio", + onClose = { isPlayerVisible = false } + ) + } + NavigationBar { + val items = listOf( + NavigationItem("Home", AppDestination.Home, Icons.Default.Home), + NavigationItem("Categories", AppDestination.Categories, Icons.AutoMirrored.Filled.List), + NavigationItem("Updates", AppDestination.Updates, Icons.Default.Refresh), + NavigationItem("Search", AppDestination.Search, Icons.Default.Search) + ) + items.forEach { item -> + NavigationBarItem( + icon = { Icon(item.icon, contentDescription = item.name) }, + label = { Text(item.name) }, + selected = currentDestination?.hierarchy?.any { it.hasRoute(item.route::class) } == true, + onClick = { + navController.navigate(item.route) { + popUpTo(navController.graph.findStartDestination().id) { + saveState = true + } + launchSingleTop = true + restoreState = true + } + } + ) + } + } + } + } + ) { innerPadding -> + NavHost( + navController = navController, + startDestination = AppDestination.Home, + modifier = Modifier.padding(innerPadding) + ) { + composable { + HomeScreen( + viewModel = hiltViewModel(), + onAppClick = { packageName -> + navController.navigate(AppDestination.Details(packageName)) + }, + onSearchClick = { + navController.navigate(AppDestination.Search) + }, + onMenuClick = { + scope.launch { drawerState.open() } + } + ) + } + composable { + CategoriesScreen( + onCategoryClick = { category -> + navController.navigate(AppDestination.CategoryResults(category)) + } + ) + } + composable { + CategoryResultsScreen( + viewModel = hiltViewModel(), + onAppClick = { packageName -> + navController.navigate(AppDestination.Details(packageName)) + }, + onBack = { navController.popBackStack() } + ) + } + composable { + UpdatesScreen( + viewModel = hiltViewModel(), + onAppClick = { packageName -> + navController.navigate(AppDestination.Details(packageName)) + } + ) + } + composable { + SearchScreen( + viewModel = hiltViewModel(), + onAppClick = { packageName -> + navController.navigate(AppDestination.Details(packageName)) + }, + onBack = { navController.popBackStack() } + ) + } + composable { + DetailsScreen( + viewModel = hiltViewModel(), + onBack = { navController.popBackStack() } + ) + } + } + } + } + } + } + } +} + +data class NavigationItem(val name: String, val route: Any, val icon: androidx.compose.ui.graphics.vector.ImageVector) diff --git a/jmods-android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/jmods-android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..685298993 Binary files /dev/null and b/jmods-android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/jmods-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/jmods-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 000000000..685298993 Binary files /dev/null and b/jmods-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/jmods-android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/jmods-android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..5769c31fc Binary files /dev/null and b/jmods-android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/jmods-android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/jmods-android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 000000000..5769c31fc Binary files /dev/null and b/jmods-android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/jmods-android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/jmods-android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..fff4e420e Binary files /dev/null and b/jmods-android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/jmods-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/jmods-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 000000000..fff4e420e Binary files /dev/null and b/jmods-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/jmods-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/jmods-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..65ace096d Binary files /dev/null and b/jmods-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/jmods-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/jmods-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..65ace096d Binary files /dev/null and b/jmods-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/jmods-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/jmods-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..6b2ab3c26 Binary files /dev/null and b/jmods-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/jmods-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/jmods-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..6b2ab3c26 Binary files /dev/null and b/jmods-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/jmods-android/app/src/main/res/values/strings.xml b/jmods-android/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..38312f555 --- /dev/null +++ b/jmods-android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + J MODS + diff --git a/jmods-android/build.gradle.kts b/jmods-android/build.gradle.kts new file mode 100644 index 000000000..b332042ca --- /dev/null +++ b/jmods-android/build.gradle.kts @@ -0,0 +1 @@ +// Root build file for aurora-next diff --git a/jmods-android/core-auth/build.gradle.kts b/jmods-android/core-auth/build.gradle.kts new file mode 100644 index 000000000..e62b11fe3 --- /dev/null +++ b/jmods-android/core-auth/build.gradle.kts @@ -0,0 +1,26 @@ +plugins { + alias(libs.plugins.jetbrains.kotlin.android) + id("com.android.library") + alias(libs.plugins.hilt.android.plugin) + id("com.google.devtools.ksp") +} + +android { + namespace = "com.jmods.auth" + compileSdk = 35 + defaultConfig { minSdk = 26 } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } +} + +dependencies { + implementation(project(":jmods:core-domain")) + implementation(libs.auroraoss.gplayapi) + implementation(libs.hilt.android.core) + ksp(libs.hilt.android.compiler) +} diff --git a/jmods-android/core-auth/src/main/kotlin/com/jmods/auth/AuthManager.kt b/jmods-android/core-auth/src/main/kotlin/com/jmods/auth/AuthManager.kt new file mode 100644 index 000000000..80ca52a5f --- /dev/null +++ b/jmods-android/core-auth/src/main/kotlin/com/jmods/auth/AuthManager.kt @@ -0,0 +1,20 @@ +package com.jmods.auth + +import com.aurora.gplayapi.data.models.AuthData +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class AuthManager @Inject constructor() { + private val _authData = MutableStateFlow(null) + val authData: Flow = _authData.asStateFlow() + + fun setAuthData(data: AuthData) { + _authData.value = data + } + + fun getAuthData(): AuthData? = _authData.value +} diff --git a/jmods-android/core-data/build.gradle.kts b/jmods-android/core-data/build.gradle.kts new file mode 100644 index 000000000..3a43e9702 --- /dev/null +++ b/jmods-android/core-data/build.gradle.kts @@ -0,0 +1,30 @@ +plugins { + alias(libs.plugins.jetbrains.kotlin.android) + id("com.android.library") + alias(libs.plugins.hilt.android.plugin) + id("com.google.devtools.ksp") +} + +android { + namespace = "com.jmods.data" + compileSdk = 35 + defaultConfig { minSdk = 26 } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } +} + +dependencies { + implementation(project(":jmods:core-domain")) + implementation(project(":jmods:core-network")) + implementation(project(":jmods:core-database")) + implementation(libs.androidx.work.runtime.ktx) + implementation(libs.hilt.android.core) + implementation(libs.hilt.androidx.work) + ksp(libs.hilt.android.compiler) + ksp(libs.hilt.androidx.compiler) +} diff --git a/jmods-android/core-data/src/main/kotlin/com/jmods/data/di/DataModule.kt b/jmods-android/core-data/src/main/kotlin/com/jmods/data/di/DataModule.kt new file mode 100644 index 000000000..2213ede5b --- /dev/null +++ b/jmods-android/core-data/src/main/kotlin/com/jmods/data/di/DataModule.kt @@ -0,0 +1,17 @@ +package com.jmods.data.di + +import com.jmods.data.repository.AppRepositoryImpl +import com.jmods.domain.usecase.AppRepository +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +abstract class DataModule { + @Binds + @Singleton + abstract fun bindAppRepository(impl: AppRepositoryImpl): AppRepository +} diff --git a/jmods-android/core-data/src/main/kotlin/com/jmods/data/download/DownloadManager.kt b/jmods-android/core-data/src/main/kotlin/com/jmods/data/download/DownloadManager.kt new file mode 100644 index 000000000..4dbcc47e0 --- /dev/null +++ b/jmods-android/core-data/src/main/kotlin/com/jmods/data/download/DownloadManager.kt @@ -0,0 +1,67 @@ +package com.jmods.data.download + +import android.content.Context +import androidx.work.* +import com.jmods.domain.model.App +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class JModsDownloadManager @Inject constructor( + @ApplicationContext private val context: Context +) { + private val workManager = WorkManager.getInstance(context) + + fun enqueueDownload(app: App) { + val data = workDataOf( + "packageName" to app.packageName, + "appName" to app.name, + "iconUrl" to app.iconUrl, + "versionCode" to (app.version.toIntOrNull() ?: 0) + ) + + val request = OneTimeWorkRequestBuilder() + .setInputData(data) + .addTag(app.packageName) + .setConstraints( + Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build() + ) + .build() + + workManager.enqueueUniqueWork( + app.packageName, + ExistingWorkPolicy.KEEP, + request + ) + } + + fun getDownloadStatus(packageName: String): Flow { + return workManager.getWorkInfosByTagFlow(packageName).map { infos -> + val info = infos.firstOrNull() ?: return@map DownloadState.Idle + when (info.state) { + WorkInfo.State.RUNNING -> { + val progress = info.progress.getFloat("progress", 0f) + DownloadState.Downloading(progress) + } + WorkInfo.State.SUCCEEDED -> { + val apkPath = info.outputData.getString("apkPath") + if (apkPath != null) DownloadState.Completed(apkPath) else DownloadState.Failed("No APK path") + } + WorkInfo.State.FAILED -> DownloadState.Failed(info.outputData.getString("error") ?: "Download failed") + else -> DownloadState.Idle + } + } + } +} + +sealed class DownloadState { + object Idle : DownloadState() + data class Downloading(val progress: Float) : DownloadState() + data class Completed(val apkPath: String) : DownloadState() + data class Failed(val error: String) : DownloadState() +} diff --git a/jmods-android/core-data/src/main/kotlin/com/jmods/data/download/DownloadWorker.kt b/jmods-android/core-data/src/main/kotlin/com/jmods/data/download/DownloadWorker.kt new file mode 100644 index 000000000..26affd68f --- /dev/null +++ b/jmods-android/core-data/src/main/kotlin/com/jmods/data/download/DownloadWorker.kt @@ -0,0 +1,46 @@ +package com.jmods.data.download + +import android.content.Context +import androidx.work.CoroutineWorker +import androidx.work.WorkerParameters +import androidx.work.workDataOf +import com.jmods.network.api.DownloadProgress +import com.jmods.network.api.PlayApiService +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import androidx.hilt.work.HiltWorker +import java.io.File +import kotlinx.coroutines.flow.collect + +@HiltWorker +class DownloadWorker @AssistedInject constructor( + @Assisted context: Context, + @Assisted params: WorkerParameters, + private val apiService: PlayApiService +) : CoroutineWorker(context, params) { + + override suspend fun doWork(): Result { + val packageName = inputData.getString("packageName") ?: return Result.failure() + val versionCode = inputData.getInt("versionCode", 0) + + val outputFile = File(applicationContext.cacheDir, "$packageName.apk") + + return try { + apiService.downloadApp(packageName, versionCode, outputFile).collect { progress -> + when (progress) { + is DownloadProgress.Progress -> { + setProgress(workDataOf("progress" to progress.percentage)) + } + is DownloadProgress.Success -> { + } + is DownloadProgress.Failure -> { + throw Exception(progress.error) + } + } + } + Result.success(workDataOf("apkPath" to outputFile.absolutePath)) + } catch (e: Exception) { + Result.failure(workDataOf("error" to (e.message ?: "Unknown error"))) + } + } +} diff --git a/jmods-android/core-data/src/main/kotlin/com/jmods/data/mapper/AppMapper.kt b/jmods-android/core-data/src/main/kotlin/com/jmods/data/mapper/AppMapper.kt new file mode 100644 index 000000000..49f62ecfe --- /dev/null +++ b/jmods-android/core-data/src/main/kotlin/com/jmods/data/mapper/AppMapper.kt @@ -0,0 +1,47 @@ +package com.jmods.data.mapper + +import com.jmods.database.entity.AppEntity +import com.jmods.domain.model.App +import com.jmods.network.api.AppDto + +fun AppDto.toDomain(): App = App( + id = id, + name = name, + packageName = packageName, + description = description, + iconUrl = iconUrl, + version = version, + size = size, + developer = developer ?: "Unknown Developer", + rating = rating ?: 0f, + versionCode = versionCode, + screenshots = screenshots +) + +fun AppDto.toEntity(category: String): AppEntity = AppEntity( + packageName = packageName, + id = id, + name = name, + description = description, + iconUrl = iconUrl, + version = version, + size = size, + category = category, + developer = developer ?: "Unknown Developer", + rating = rating ?: 0f, + versionCode = versionCode +) + +fun AppEntity.toDomain(): App = App( + id = id, + name = name, + packageName = packageName, + description = description, + iconUrl = iconUrl, + version = version, + size = size, + developer = developer, + rating = rating, + versionCode = versionCode, + screenshots = emptyList() // Room doesn't store screenshots list by default +) diff --git a/jmods-android/core-data/src/main/kotlin/com/jmods/data/repository/AppRepositoryImpl.kt b/jmods-android/core-data/src/main/kotlin/com/jmods/data/repository/AppRepositoryImpl.kt new file mode 100644 index 000000000..c1033fb7a --- /dev/null +++ b/jmods-android/core-data/src/main/kotlin/com/jmods/data/repository/AppRepositoryImpl.kt @@ -0,0 +1,92 @@ +package com.jmods.data.repository + +import android.content.Context +import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager +import com.jmods.data.mapper.toDomain +import com.jmods.data.mapper.toEntity +import com.jmods.database.dao.AppDao +import com.jmods.domain.model.App +import com.jmods.domain.model.InstalledAppInfo +import com.jmods.domain.usecase.AppRepository +import com.jmods.network.api.PlayApiService +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.flow.* +import javax.inject.Inject + +class AppRepositoryImpl @Inject constructor( + private val api: PlayApiService, + private val appDao: AppDao, + @ApplicationContext private val context: Context +) : AppRepository { + + override fun getApps(category: String): Flow> = flow { + val cached = appDao.getAppsByCategory(category).first() + if (cached.isNotEmpty()) { + emit(cached.map { it.toDomain() }) + } + + api.getApps(category).collect { dtos -> + val entities = dtos.map { it.toEntity(category) } + appDao.insertApps(entities) + emit(dtos.map { it.toDomain() }) + } + } + + override fun getAppDetails(packageName: String): Flow = flow { + val cached = appDao.getAppByPackageName(packageName).first() + if (cached != null) { + emit(cached.toDomain()) + } + + api.getAppDetails(packageName).collect { dto -> + appDao.insertApp(dto.toEntity("unknown")) + emit(dto.toDomain()) + } + } + + override fun searchApps(query: String): Flow> = flow { + api.searchApps(query).collect { dtos -> + emit(dtos.map { it.toDomain() }) + } + } + + override fun getInstalledApps(): Flow> = flow { + val pm = context.packageManager + val apps = pm.getInstalledPackages(0).map { pkg -> + InstalledAppInfo( + packageName = pkg.packageName, + versionName = pkg.versionName ?: "", + versionCode = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) { + pkg.longVersionCode + } else { + pkg.versionCode.toLong() + }, + isSystemApp = (pkg.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM) != 0 + ) + } + emit(apps) + } + + override fun getAppsWithUpdates(): Flow> = flow { + val installed = getInstalledApps().first() + val updateable = mutableListOf() + + // This is a simplified implementation. + // In a production app, we would perform a bulk fetch for these package names. + installed.filter { !it.isSystemApp }.take(10).forEach { info -> + try { + // Fetch latest details for each app to check for updates + // We wrap in try-catch because not all installed apps might be in the store + api.getAppDetails(info.packageName).collect { dto -> + if (dto.versionCode > info.versionCode) { + updateable.add(dto.toDomain().copy(hasUpdate = true)) + } + } + } catch (e: Exception) { + // App not found or other error, skip + } + } + emit(updateable) + } +} diff --git a/jmods-android/core-data/src/test/kotlin/com/jmods/data/repository/AppRepositoryTest.kt b/jmods-android/core-data/src/test/kotlin/com/jmods/data/repository/AppRepositoryTest.kt new file mode 100644 index 000000000..47510dffd --- /dev/null +++ b/jmods-android/core-data/src/test/kotlin/com/jmods/data/repository/AppRepositoryTest.kt @@ -0,0 +1,45 @@ +package com.jmods.data.repository + +import android.content.Context +import com.jmods.database.dao.AppDao +import com.jmods.network.api.AppDto +import com.jmods.network.api.PlayApiService +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.mockito.kotlin.* + +class AppRepositoryTest { + + private val api: PlayApiService = mock() + private val appDao: AppDao = mock() + private val context: Context = mock() + private lateinit var repository: AppRepositoryImpl + + @Before + fun setup() { + repository = AppRepositoryImpl(api, appDao, context) + } + + @Test + fun getApps_shouldEmitCachedDataThenNetworkData() = runTest { + val category = "Games" + val cachedApps = emptyList() + val networkApps = listOf( + AppDto( + id = "1", name = "Game", packageName = "com.game", + description = "Desc", iconUrl = "", version = "1.0", versionCode = 1, size = 100 + ) + ) + + whenever(appDao.getAppsByCategory(category)).thenReturn(flowOf(cachedApps)) + whenever(api.getApps(category)).thenReturn(flowOf(networkApps)) + + val result = repository.getApps(category).first() + + verify(api).getApps(category) + verify(appDao).insertApps(any()) + } +} diff --git a/jmods-android/core-database/build.gradle.kts b/jmods-android/core-database/build.gradle.kts new file mode 100644 index 000000000..e8945e2aa --- /dev/null +++ b/jmods-android/core-database/build.gradle.kts @@ -0,0 +1,28 @@ +plugins { + alias(libs.plugins.jetbrains.kotlin.android) + id("com.android.library") + alias(libs.plugins.hilt.android.plugin) + id("com.google.devtools.ksp") +} + +android { + namespace = "com.jmods.database" + compileSdk = 35 + defaultConfig { minSdk = 26 } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } +} + +dependencies { + implementation(libs.androidx.room.runtime) + implementation(libs.androidx.room.ktx) + ksp(libs.androidx.room.compiler) + + implementation(libs.hilt.android.core) + ksp(libs.hilt.android.compiler) +} diff --git a/jmods-android/core-database/src/main/kotlin/com/jmods/database/AppDatabase.kt b/jmods-android/core-database/src/main/kotlin/com/jmods/database/AppDatabase.kt new file mode 100644 index 000000000..5d53b54ea --- /dev/null +++ b/jmods-android/core-database/src/main/kotlin/com/jmods/database/AppDatabase.kt @@ -0,0 +1,11 @@ +package com.jmods.database + +import androidx.room.Database +import androidx.room.RoomDatabase +import com.jmods.database.dao.AppDao +import com.jmods.database.entity.AppEntity + +@Database(entities = [AppEntity::class], version = 2, exportSchema = false) +abstract class AppDatabase : RoomDatabase() { + abstract fun appDao(): AppDao +} diff --git a/jmods-android/core-database/src/main/kotlin/com/jmods/database/dao/AppDao.kt b/jmods-android/core-database/src/main/kotlin/com/jmods/database/dao/AppDao.kt new file mode 100644 index 000000000..062f92ba0 --- /dev/null +++ b/jmods-android/core-database/src/main/kotlin/com/jmods/database/dao/AppDao.kt @@ -0,0 +1,26 @@ +package com.jmods.database.dao + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.jmods.database.entity.AppEntity +import kotlinx.coroutines.flow.Flow + +@Dao +interface AppDao { + @Query("SELECT * FROM apps WHERE category = :category") + fun getAppsByCategory(category: String): Flow> + + @Query("SELECT * FROM apps WHERE packageName = :packageName") + fun getAppByPackageName(packageName: String): Flow + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertApps(apps: List) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertApp(app: AppEntity) + + @Query("DELETE FROM apps WHERE category = :category") + suspend fun deleteByCategory(category: String) +} diff --git a/jmods-android/core-database/src/main/kotlin/com/jmods/database/di/DatabaseModule.kt b/jmods-android/core-database/src/main/kotlin/com/jmods/database/di/DatabaseModule.kt new file mode 100644 index 000000000..ecbd9f379 --- /dev/null +++ b/jmods-android/core-database/src/main/kotlin/com/jmods/database/di/DatabaseModule.kt @@ -0,0 +1,29 @@ +package com.jmods.database.di + +import android.content.Context +import androidx.room.Room +import com.jmods.database.AppDatabase +import com.jmods.database.dao.AppDao +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object DatabaseModule { + @Provides + @Singleton + fun provideAppDatabase(@ApplicationContext context: Context): AppDatabase { + return Room.databaseBuilder( + context, + AppDatabase::class.java, + "jmods.db" + ).build() + } + + @Provides + fun provideAppDao(database: AppDatabase): AppDao = database.appDao() +} diff --git a/jmods-android/core-database/src/main/kotlin/com/jmods/database/entity/AppEntity.kt b/jmods-android/core-database/src/main/kotlin/com/jmods/database/entity/AppEntity.kt new file mode 100644 index 000000000..2e02e2833 --- /dev/null +++ b/jmods-android/core-database/src/main/kotlin/com/jmods/database/entity/AppEntity.kt @@ -0,0 +1,20 @@ +package com.jmods.database.entity + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "apps") +data class AppEntity( + @PrimaryKey val packageName: String, + val id: String, + val name: String, + val description: String, + val iconUrl: String, + val version: String, + val size: Long, + val category: String, + val developer: String = "Unknown", + val rating: Float = 0f, + val lastUpdated: Long = System.currentTimeMillis(), + val versionCode: Int = 0 +) diff --git a/jmods-android/core-domain/build.gradle.kts b/jmods-android/core-domain/build.gradle.kts new file mode 100644 index 000000000..0bec9aab8 --- /dev/null +++ b/jmods-android/core-domain/build.gradle.kts @@ -0,0 +1,27 @@ +plugins { + alias(libs.plugins.jetbrains.kotlin.android) + id("com.android.library") +} + +android { + namespace = "com.jmods.domain" + compileSdk = 35 + + defaultConfig { + minSdk = 26 + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = "17" + } +} + +dependencies { + implementation(libs.androidx.core.ktx) + implementation("javax.inject:javax.inject:1") +} diff --git a/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/error/AppException.kt b/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/error/AppException.kt new file mode 100644 index 000000000..44f9c7858 --- /dev/null +++ b/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/error/AppException.kt @@ -0,0 +1,14 @@ +package com.jmods.domain.error + +sealed class AppException : Exception() { + object NetworkUnavailable : AppException() + data class InstallationFailed(val code: Int, override val message: String) : AppException() + object AuthExpired : AppException() + data class Unknown(override val message: String) : AppException() +} + +sealed class AppResult { + data class Success(val data: T) : AppResult() + data class Error(val exception: AppException) : AppResult() + object Loading : AppResult() +} diff --git a/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/model/App.kt b/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/model/App.kt new file mode 100644 index 000000000..62c4b6da9 --- /dev/null +++ b/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/model/App.kt @@ -0,0 +1,17 @@ +package com.jmods.domain.model + +data class App( + val id: String, + val name: String, + val packageName: String, + val description: String, + val iconUrl: String, + val version: String, + val size: Long, + val developer: String = "Unknown Developer", + val rating: Float = 0f, + val isInstalled: Boolean = false, + val hasUpdate: Boolean = false, + val versionCode: Int = 0, + val screenshots: List = emptyList() +) diff --git a/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/model/InstalledAppInfo.kt b/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/model/InstalledAppInfo.kt new file mode 100644 index 000000000..ab3bcb95b --- /dev/null +++ b/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/model/InstalledAppInfo.kt @@ -0,0 +1,8 @@ +package com.jmods.domain.model + +data class InstalledAppInfo( + val packageName: String, + val versionName: String, + val versionCode: Long, + val isSystemApp: Boolean +) diff --git a/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/usecase/AppRepository.kt b/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/usecase/AppRepository.kt new file mode 100644 index 000000000..6dbca2559 --- /dev/null +++ b/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/usecase/AppRepository.kt @@ -0,0 +1,13 @@ +package com.jmods.domain.usecase + +import com.jmods.domain.model.App +import com.jmods.domain.model.InstalledAppInfo +import kotlinx.coroutines.flow.Flow + +interface AppRepository { + fun getApps(category: String): Flow> + fun getAppDetails(packageName: String): Flow + fun searchApps(query: String): Flow> + fun getInstalledApps(): Flow> + fun getAppsWithUpdates(): Flow> +} diff --git a/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/usecase/GetAppDetailsUseCase.kt b/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/usecase/GetAppDetailsUseCase.kt new file mode 100644 index 000000000..4012ade95 --- /dev/null +++ b/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/usecase/GetAppDetailsUseCase.kt @@ -0,0 +1,12 @@ +package com.jmods.domain.usecase + +import com.jmods.domain.model.App +import com.jmods.domain.usecase.AppRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class GetAppDetailsUseCase @Inject constructor( + private val repository: AppRepository +) { + operator fun invoke(packageName: String): Flow = repository.getAppDetails(packageName) +} diff --git a/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/usecase/GetAppsUseCase.kt b/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/usecase/GetAppsUseCase.kt new file mode 100644 index 000000000..59a97fbef --- /dev/null +++ b/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/usecase/GetAppsUseCase.kt @@ -0,0 +1,11 @@ +package com.jmods.domain.usecase + +import com.jmods.domain.model.App +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class GetAppsUseCase @Inject constructor( + private val repository: AppRepository +) { + operator fun invoke(category: String): Flow> = repository.getApps(category) +} diff --git a/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/usecase/GetUpdatesUseCase.kt b/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/usecase/GetUpdatesUseCase.kt new file mode 100644 index 000000000..8156bdaf1 --- /dev/null +++ b/jmods-android/core-domain/src/main/kotlin/com/jmods/domain/usecase/GetUpdatesUseCase.kt @@ -0,0 +1,11 @@ +package com.jmods.domain.usecase + +import com.jmods.domain.model.App +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class GetUpdatesUseCase @Inject constructor( + private val repository: AppRepository +) { + operator fun invoke(): Flow> = repository.getAppsWithUpdates() +} diff --git a/jmods-android/core-installer/build.gradle.kts b/jmods-android/core-installer/build.gradle.kts new file mode 100644 index 000000000..f2be0ee16 --- /dev/null +++ b/jmods-android/core-installer/build.gradle.kts @@ -0,0 +1,25 @@ +plugins { + alias(libs.plugins.jetbrains.kotlin.android) + id("com.android.library") + alias(libs.plugins.hilt.android.plugin) + id("com.google.devtools.ksp") +} + +android { + namespace = "com.jmods.installer" + compileSdk = 35 + defaultConfig { minSdk = 26 } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } +} + +dependencies { + implementation(project(":jmods:core-domain")) + implementation(libs.hilt.android.core) + ksp(libs.hilt.android.compiler) +} diff --git a/jmods-android/core-installer/src/main/kotlin/com/jmods/installer/AndroidPackageInstaller.kt b/jmods-android/core-installer/src/main/kotlin/com/jmods/installer/AndroidPackageInstaller.kt new file mode 100644 index 000000000..d82675707 --- /dev/null +++ b/jmods-android/core-installer/src/main/kotlin/com/jmods/installer/AndroidPackageInstaller.kt @@ -0,0 +1,103 @@ +package com.jmods.installer + +import android.app.PendingIntent +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.content.pm.PackageInstaller +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.callbackFlow +import java.io.File +import java.io.FileInputStream +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class AndroidPackageInstaller @Inject constructor( + @ApplicationContext private val context: Context +) : AppInstaller { + + override fun install(packageName: String, apkUri: String): Flow = callbackFlow { + val installer = context.packageManager.packageInstaller + val params = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL) + params.setAppPackageName(packageName) + + val sessionId = installer.createSession(params) + val session = installer.openSession(sessionId) + + val apkFile = File(apkUri) + val inputStream = FileInputStream(apkFile) + val outputStream = session.openWrite("package_install", 0, apkFile.length()) + + inputStream.use { input -> + outputStream.use { output -> + input.copyTo(output) + } + } + session.fsync(outputStream) + + val receiver = object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + val status = intent?.getIntExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE) + when (status) { + PackageInstaller.STATUS_SUCCESS -> { + trySend(InstallStatus.Success) + close() + } + else -> { + val msg = intent?.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) ?: "Unknown error" + trySend(InstallStatus.Failure(msg)) + close() + } + } + } + } + + val action = "com.jmods.INSTALL_COMPLETE" + context.registerReceiver(receiver, IntentFilter(action)) + + val intent = Intent(action) + val pendingIntent = PendingIntent.getBroadcast(context, sessionId, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE) + + session.commit(pendingIntent.intentSender) + session.close() + + awaitClose { + try { + context.unregisterReceiver(receiver) + } catch (e: Exception) {} + } + } + + override fun uninstall(packageName: String): Flow = callbackFlow { + val installer = context.packageManager.packageInstaller + + val action = "com.jmods.UNINSTALL_COMPLETE" + val receiver = object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + val status = intent?.getIntExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE) + if (status == PackageInstaller.STATUS_SUCCESS) { + trySend(InstallStatus.Success) + } else { + trySend(InstallStatus.Failure("Uninstall failed")) + } + close() + } + } + + context.registerReceiver(receiver, IntentFilter(action)) + val intent = Intent(action) + val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE) + + installer.uninstall(packageName, pendingIntent.intentSender) + + awaitClose { + try { + context.unregisterReceiver(receiver) + } catch (e: Exception) {} + } + } +} diff --git a/jmods-android/core-installer/src/main/kotlin/com/jmods/installer/AppInstaller.kt b/jmods-android/core-installer/src/main/kotlin/com/jmods/installer/AppInstaller.kt new file mode 100644 index 000000000..34e0e7229 --- /dev/null +++ b/jmods-android/core-installer/src/main/kotlin/com/jmods/installer/AppInstaller.kt @@ -0,0 +1,15 @@ +package com.jmods.installer + +import kotlinx.coroutines.flow.Flow + +interface AppInstaller { + fun install(packageName: String, apkUri: String): Flow + fun uninstall(packageName: String): Flow +} + +sealed class InstallStatus { + object Idle : InstallStatus() + data class Progress(val percentage: Float) : InstallStatus() + object Success : InstallStatus() + data class Failure(val error: String) : InstallStatus() +} diff --git a/jmods-android/core-installer/src/main/kotlin/com/jmods/installer/di/InstallerModule.kt b/jmods-android/core-installer/src/main/kotlin/com/jmods/installer/di/InstallerModule.kt new file mode 100644 index 000000000..a88fd0343 --- /dev/null +++ b/jmods-android/core-installer/src/main/kotlin/com/jmods/installer/di/InstallerModule.kt @@ -0,0 +1,17 @@ +package com.jmods.installer.di + +import com.jmods.installer.AndroidPackageInstaller +import com.jmods.installer.AppInstaller +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +abstract class InstallerModule { + @Binds + @Singleton + abstract fun bindAppInstaller(impl: AndroidPackageInstaller): AppInstaller +} diff --git a/jmods-android/core-navigation/build.gradle.kts b/jmods-android/core-navigation/build.gradle.kts new file mode 100644 index 000000000..b8ebdfc52 --- /dev/null +++ b/jmods-android/core-navigation/build.gradle.kts @@ -0,0 +1,23 @@ +plugins { + alias(libs.plugins.jetbrains.kotlin.android) + id("com.android.library") + id("org.jetbrains.kotlin.plugin.serialization") version "2.1.0" +} + +android { + namespace = "com.jmods.navigation" + compileSdk = 35 + defaultConfig { minSdk = 26 } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } +} + +dependencies { + implementation(libs.androidx.core.ktx) + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3") +} diff --git a/jmods-android/core-navigation/src/main/kotlin/com/jmods/navigation/AppDestination.kt b/jmods-android/core-navigation/src/main/kotlin/com/jmods/navigation/AppDestination.kt new file mode 100644 index 000000000..5b201c84b --- /dev/null +++ b/jmods-android/core-navigation/src/main/kotlin/com/jmods/navigation/AppDestination.kt @@ -0,0 +1,23 @@ +package com.jmods.navigation + +import kotlinx.serialization.Serializable + +sealed interface AppDestination { + @Serializable + object Home : AppDestination + + @Serializable + object Categories : AppDestination + + @Serializable + object Updates : AppDestination + + @Serializable + object Search : AppDestination + + @Serializable + data class Details(val packageName: String) : AppDestination + + @Serializable + data class CategoryResults(val categoryName: String) : AppDestination +} diff --git a/jmods-android/core-network/build.gradle.kts b/jmods-android/core-network/build.gradle.kts new file mode 100644 index 000000000..df8894cc8 --- /dev/null +++ b/jmods-android/core-network/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + alias(libs.plugins.jetbrains.kotlin.android) + id("com.android.library") + alias(libs.plugins.hilt.android.plugin) + id("com.google.devtools.ksp") +} + +android { + namespace = "com.jmods.network" + compileSdk = 35 + defaultConfig { minSdk = 26 } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } +} + +dependencies { + implementation(project(":jmods:core-domain")) + implementation(project(":jmods:core-auth")) + implementation(libs.auroraoss.gplayapi) + implementation(libs.squareup.okhttp) + implementation(libs.google.gson) + implementation(libs.hilt.android.core) + ksp(libs.hilt.android.compiler) +} diff --git a/jmods-android/core-network/src/main/kotlin/com/jmods/network/api/AppDto.kt b/jmods-android/core-network/src/main/kotlin/com/jmods/network/api/AppDto.kt new file mode 100644 index 000000000..61346838d --- /dev/null +++ b/jmods-android/core-network/src/main/kotlin/com/jmods/network/api/AppDto.kt @@ -0,0 +1,21 @@ +package com.jmods.network.api + +import com.google.gson.annotations.SerializedName + +data class AppDto( + @SerializedName("id") val id: String, + @SerializedName("name") val name: String, + @SerializedName("packageName") val packageName: String, + @SerializedName("description") val description: String, + @SerializedName("iconUrl") val iconUrl: String, + @SerializedName("version") val version: String, + @SerializedName("size") val size: Long, + @SerializedName("developer") val developer: String? = null, + @SerializedName("rating") val rating: Float? = null, + @SerializedName("versionCode") val versionCode: Int = 0, + @SerializedName("screenshots") val screenshots: List = emptyList() +) + +data class AppListResponse( + @SerializedName("apps") val apps: List +) diff --git a/jmods-android/core-network/src/main/kotlin/com/jmods/network/api/PlayApiService.kt b/jmods-android/core-network/src/main/kotlin/com/jmods/network/api/PlayApiService.kt new file mode 100644 index 000000000..b8824fdf0 --- /dev/null +++ b/jmods-android/core-network/src/main/kotlin/com/jmods/network/api/PlayApiService.kt @@ -0,0 +1,17 @@ +package com.jmods.network.api + +import kotlinx.coroutines.flow.Flow +import java.io.File + +interface PlayApiService { + fun getApps(category: String): Flow> + fun getAppDetails(packageName: String): Flow + fun searchApps(query: String): Flow> + suspend fun downloadApp(packageName: String, versionCode: Int, outputFile: File): Flow +} + +sealed class DownloadProgress { + data class Progress(val percentage: Float) : DownloadProgress() + object Success : DownloadProgress() + data class Failure(val error: String) : DownloadProgress() +} diff --git a/jmods-android/core-network/src/main/kotlin/com/jmods/network/api/PlayApiServiceImpl.kt b/jmods-android/core-network/src/main/kotlin/com/jmods/network/api/PlayApiServiceImpl.kt new file mode 100644 index 000000000..0bb35d07a --- /dev/null +++ b/jmods-android/core-network/src/main/kotlin/com/jmods/network/api/PlayApiServiceImpl.kt @@ -0,0 +1,94 @@ +package com.jmods.network.api + +import com.aurora.gplayapi.data.models.App +import com.aurora.gplayapi.helpers.AppDetailsHelper +import com.aurora.gplayapi.helpers.PurchaseHelper +import com.aurora.gplayapi.helpers.SearchHelper +import com.jmods.auth.AuthManager +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import okhttp3.OkHttpClient +import okhttp3.Request +import java.io.File +import java.io.FileOutputStream +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class PlayApiServiceImpl @Inject constructor( + private val authManager: AuthManager +) : PlayApiService { + + private val client = OkHttpClient() + + override fun getApps(category: String): Flow> = flow { + val authData = authManager.getAuthData() ?: return@flow + val helper = SearchHelper(authData) + val searchBundle = helper.searchResults(category) + emit(searchBundle.appList.map { it.toDto() }) + } + + override fun getAppDetails(packageName: String): Flow = flow { + val authData = authManager.getAuthData() ?: return@flow + val helper = AppDetailsHelper(authData) + val app = helper.getAppByPackageName(packageName) + emit(app.toDto()) + } + + override fun searchApps(query: String): Flow> = flow { + val authData = authManager.getAuthData() ?: return@flow + val helper = SearchHelper(authData) + val searchBundle = helper.searchResults(query) + emit(searchBundle.appList.map { it.toDto() }) + } + + override suspend fun downloadApp(packageName: String, versionCode: Int, outputFile: File): Flow = flow { + val authData = authManager.getAuthData() ?: throw Exception("Not authenticated") + + try { + val purchaseHelper = PurchaseHelper(authData) + val purchaseResponse = purchaseHelper.purchase(packageName, versionCode) + val downloadUrl = purchaseResponse.downloadUrl + + val request = Request.Builder().url(downloadUrl).build() + client.newCall(request).execute().use { response -> + if (!response.isSuccessful) throw Exception("Failed to download file: ${response.code}") + + val body = response.body ?: throw Exception("Response body is null") + val totalBytes = body.contentLength() + var bytesDownloaded = 0L + + body.byteStream().use { input -> + FileOutputStream(outputFile).use { output -> + val buffer = ByteArray(8 * 1024) + var bytesRead: Int + while (input.read(buffer).also { bytesRead = it } != -1) { + output.write(buffer, 0, bytesRead) + bytesDownloaded += bytesRead + if (totalBytes > 0) { + emit(DownloadProgress.Progress(bytesDownloaded.toFloat() / totalBytes)) + } + } + } + } + } + emit(DownloadProgress.Success) + } catch (e: Exception) { + emit(DownloadProgress.Failure(e.message ?: "Download failed")) + } + } +} + +private fun App.toDto(): AppDto = AppDto( + id = packageName, + name = displayName, + packageName = packageName, + description = shortDescription, + iconUrl = iconArtwork.url, + version = versionName, + size = size, + developer = developerName, + rating = 4.5f, + versionCode = versionCode, + screenshots = screenshots.map { it.url } +) diff --git a/jmods-android/core-network/src/main/kotlin/com/jmods/network/di/NetworkModule.kt b/jmods-android/core-network/src/main/kotlin/com/jmods/network/di/NetworkModule.kt new file mode 100644 index 000000000..1f1c81399 --- /dev/null +++ b/jmods-android/core-network/src/main/kotlin/com/jmods/network/di/NetworkModule.kt @@ -0,0 +1,17 @@ +package com.jmods.network.di + +import com.jmods.network.api.PlayApiService +import com.jmods.network.api.PlayApiServiceImpl +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +abstract class NetworkModule { + @Binds + @Singleton + abstract fun bindPlayApiService(impl: PlayApiServiceImpl): PlayApiService +} diff --git a/jmods-android/core-ui/build.gradle.kts b/jmods-android/core-ui/build.gradle.kts new file mode 100644 index 000000000..32e25714e --- /dev/null +++ b/jmods-android/core-ui/build.gradle.kts @@ -0,0 +1,31 @@ +plugins { + alias(libs.plugins.jetbrains.kotlin.android) + id("com.android.library") + alias(libs.plugins.jetbrains.kotlin.compose) +} + +android { + namespace = "com.jmods.ui" + compileSdk = 35 + defaultConfig { minSdk = 26 } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } + buildFeatures { + compose = true + } +} + +dependencies { + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + implementation(libs.coil.compose) + implementation(project(":jmods:core-domain")) +} diff --git a/jmods-android/core-ui/src/main/kotlin/com/jmods/ui/component/AppCard.kt b/jmods-android/core-ui/src/main/kotlin/com/jmods/ui/component/AppCard.kt new file mode 100644 index 000000000..6cb9a2791 --- /dev/null +++ b/jmods-android/core-ui/src/main/kotlin/com/jmods/ui/component/AppCard.kt @@ -0,0 +1,125 @@ +package com.jmods.ui.component + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Star +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import coil3.compose.AsyncImage +import com.jmods.domain.model.App + +@Composable +fun AppCard( + app: App, + onClick: () -> Unit, + modifier: Modifier = Modifier, + rank: Int? = null, + downloadProgress: Float? = null, + actionButton: @Composable (() -> Unit)? = null +) { + val sizeMb = app.size / 1024 / 1024 + Card( + modifier = modifier + .fillMaxWidth() + .clickable(onClick = onClick), + shape = RoundedCornerShape(20.dp), + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface), + elevation = CardDefaults.cardElevation(defaultElevation = 0.dp) + ) { + Column { + Row( + modifier = Modifier.padding(12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + if (rank != null) { + Text( + text = rank.toString(), + style = MaterialTheme.typography.titleMedium.copy( + fontWeight = FontWeight.Black, + color = MaterialTheme.colorScheme.primary.copy(alpha = 0.5f) + ), + modifier = Modifier.width(28.dp) + ) + } + + AsyncImage( + model = app.iconUrl, + contentDescription = null, + modifier = Modifier + .size(64.dp) + .clip(RoundedCornerShape(14.dp)), + contentScale = ContentScale.Crop + ) + Spacer(modifier = Modifier.width(16.dp)) + Column(modifier = Modifier.weight(1f)) { + Text( + text = app.name, + style = MaterialTheme.typography.titleMedium.copy( + fontWeight = FontWeight.Bold, + letterSpacing = (-0.2).sp + ), + maxLines = 1 + ) + Text( + text = app.developer, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.primary, + maxLines = 1 + ) + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(top = 4.dp) + ) { + Icon( + imageVector = Icons.Default.Star, + contentDescription = null, + modifier = Modifier.size(12.dp), + tint = MaterialTheme.colorScheme.secondary + ) + Spacer(modifier = Modifier.width(4.dp)) + Text( + text = String.format("%.1f", app.rating), + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.secondary + ) + Spacer(modifier = Modifier.width(12.dp)) + Text( + text = "$sizeMb MB", + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.outline + ) + } + } + + if (actionButton != null && downloadProgress == null) { + Box(modifier = Modifier.padding(start = 8.dp)) { + actionButton() + } + } + } + + if (downloadProgress != null) { + LinearProgressIndicator( + progress = { downloadProgress }, + modifier = Modifier + .fillMaxWidth() + .height(4.dp) + .padding(horizontal = 12.dp, vertical = 0.dp) + .clip(RoundedCornerShape(2.dp)), + color = MaterialTheme.colorScheme.primary, + trackColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f) + ) + Spacer(modifier = Modifier.height(12.dp)) + } + } + } +} diff --git a/jmods-android/core-ui/src/main/kotlin/com/jmods/ui/component/CategoryCard.kt b/jmods-android/core-ui/src/main/kotlin/com/jmods/ui/component/CategoryCard.kt new file mode 100644 index 000000000..8780accd3 --- /dev/null +++ b/jmods-android/core-ui/src/main/kotlin/com/jmods/ui/component/CategoryCard.kt @@ -0,0 +1,68 @@ +package com.jmods.ui.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun CategoryCard( + category: String, + icon: @Composable () -> Unit, + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + Card( + modifier = modifier + .fillMaxWidth() + .clickable(onClick = onClick), + shape = RoundedCornerShape(24.dp), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f), + contentColor = MaterialTheme.colorScheme.onSurfaceVariant + ), + elevation = CardDefaults.cardElevation(defaultElevation = 0.dp) + ) { + Row( + modifier = Modifier.padding(12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .size(48.dp) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.primaryContainer), + contentAlignment = Alignment.Center + ) { + CompositionLocalProvider( + LocalContentColor provides MaterialTheme.colorScheme.onPrimaryContainer + ) { + icon() + } + } + Spacer(modifier = Modifier.width(16.dp)) + Text( + text = category, + style = MaterialTheme.typography.titleMedium.copy( + fontWeight = FontWeight.Black, + letterSpacing = (-0.5).sp + ) + ) + Spacer(modifier = Modifier.weight(1f)) + Icon( + imageVector = androidx.compose.material.icons.Icons.AutoMirrored.Filled.KeyboardArrowRight, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.3f) + ) + } + } +} diff --git a/jmods-android/core-ui/src/main/kotlin/com/jmods/ui/component/JModsPlayer.kt b/jmods-android/core-ui/src/main/kotlin/com/jmods/ui/component/JModsPlayer.kt new file mode 100644 index 000000000..04d8862f5 --- /dev/null +++ b/jmods-android/core-ui/src/main/kotlin/com/jmods/ui/component/JModsPlayer.kt @@ -0,0 +1,85 @@ +package com.jmods.ui.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Close +import androidx.compose.material.icons.filled.PlayArrow +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun JModsPlayer( + title: String, + onClose: () -> Unit, + modifier: Modifier = Modifier +) { + var isPlaying by remember { mutableStateOf(false) } + + Surface( + modifier = modifier + .fillMaxWidth() + .padding(16.dp), + shape = RoundedCornerShape(32.dp), + color = Color(0xFF111827), // Dark grey/black + tonalElevation = 8.dp + ) { + Row( + modifier = Modifier + .padding(horizontal = 20.dp, vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .size(40.dp) + .clip(CircleShape) + .background(Color.White.copy(alpha = 0.1f)), + contentAlignment = Alignment.Center + ) { + Icon( + imageVector = Icons.Default.PlayArrow, + contentDescription = null, + tint = Color.White, + modifier = Modifier.size(24.dp) + ) + } + + Spacer(modifier = Modifier.width(16.dp)) + + Column(modifier = Modifier.weight(1f)) { + Text( + text = title, + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold, + color = Color.White, + maxLines = 1 + ) + Text( + text = "LIVE STREAM", + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.primary, + fontWeight = FontWeight.Black, + letterSpacing = 1.sp + ) + } + + IconButton(onClick = onClose) { + Icon( + imageVector = Icons.Default.Close, + contentDescription = "Close", + tint = Color.White.copy(alpha = 0.5f), + modifier = Modifier.size(20.dp) + ) + } + } + } +} diff --git a/jmods-android/core-ui/src/main/kotlin/com/jmods/ui/component/JModsTopBar.kt b/jmods-android/core-ui/src/main/kotlin/com/jmods/ui/component/JModsTopBar.kt new file mode 100644 index 000000000..11334643a --- /dev/null +++ b/jmods-android/core-ui/src/main/kotlin/com/jmods/ui/component/JModsTopBar.kt @@ -0,0 +1,43 @@ +package com.jmods.ui.component + +import androidx.compose.foundation.layout.RowScope +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.font.FontWeight + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun JModsTopBar( + title: String, + onBackClick: (() -> Unit)? = null, + navigationIcon: (@Composable () -> Unit)? = null, + actions: @Composable RowScope.() -> Unit = {} +) { + TopAppBar( + title = { + Text( + text = title, + style = MaterialTheme.typography.titleLarge.copy(fontWeight = FontWeight.Black) + ) + }, + navigationIcon = { + if (navigationIcon != null) { + navigationIcon() + } else if (onBackClick != null) { + IconButton(onClick = onBackClick) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = "Back" + ) + } + } + }, + actions = actions, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.surface, + titleContentColor = MaterialTheme.colorScheme.onSurface + ) + ) +} diff --git a/jmods-android/core-ui/src/main/kotlin/com/jmods/ui/theme/Theme.kt b/jmods-android/core-ui/src/main/kotlin/com/jmods/ui/theme/Theme.kt new file mode 100644 index 000000000..d026fe680 --- /dev/null +++ b/jmods-android/core-ui/src/main/kotlin/com/jmods/ui/theme/Theme.kt @@ -0,0 +1,43 @@ +package com.jmods.ui.theme + +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Color(0xFF2563EB), + secondary = Color(0xFF64748B), + tertiary = Color(0xFF0F172A) +) + +private val LightColorScheme = lightColorScheme( + primary = Color(0xFF2563EB), + secondary = Color(0xFF64748B), + tertiary = Color(0xFFF1F5F9), + background = Color(0xFFF8FAFC), + surface = Color.White +) + +@Composable +fun JMODSTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + content = content + ) +} diff --git a/jmods-android/feature-categories/build.gradle.kts b/jmods-android/feature-categories/build.gradle.kts new file mode 100644 index 000000000..ec6e6ffca --- /dev/null +++ b/jmods-android/feature-categories/build.gradle.kts @@ -0,0 +1,39 @@ +plugins { + alias(libs.plugins.jetbrains.kotlin.android) + alias(libs.plugins.jetbrains.kotlin.compose) + id("com.android.library") + alias(libs.plugins.hilt.android.plugin) + id("com.google.devtools.ksp") +} + +android { + namespace = "com.jmods.feature.categories" + compileSdk = 35 + defaultConfig { minSdk = 26 } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } + buildFeatures { + compose = true + } +} + +dependencies { + implementation(project(":jmods:core-domain")) + implementation(project(":jmods:core-navigation")) + implementation(project(":jmods:core-ui")) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + implementation(libs.hilt.android.core) + ksp(libs.hilt.android.compiler) + implementation(libs.androidx.lifecycle.viewmodel.ktx) + implementation("androidx.navigation:navigation-compose:2.8.5") +} diff --git a/jmods-android/feature-categories/src/main/kotlin/com/jmods/feature/categories/ui/CategoriesScreen.kt b/jmods-android/feature-categories/src/main/kotlin/com/jmods/feature/categories/ui/CategoriesScreen.kt new file mode 100644 index 000000000..b51ae3078 --- /dev/null +++ b/jmods-android/feature-categories/src/main/kotlin/com/jmods/feature/categories/ui/CategoriesScreen.kt @@ -0,0 +1,51 @@ +package com.jmods.feature.categories.ui + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.* +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.jmods.ui.component.CategoryCard +import com.jmods.ui.component.JModsTopBar + +@Composable +fun CategoriesScreen( + onCategoryClick: (String) -> Unit +) { + val categories = listOf( + "Productivity" to Icons.Default.Edit, + "Social" to Icons.Default.Email, + "Games" to Icons.Default.PlayArrow, + "Tools" to Icons.Default.Build, + "Media" to Icons.Default.Search, + "Security" to Icons.Default.Lock, + "Finance" to Icons.Default.ShoppingCart, + "Health" to Icons.Default.Favorite + ) + + Scaffold( + topBar = { + JModsTopBar(title = "Categories") + } + ) { padding -> + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(padding), + contentPadding = PaddingValues(16.dp), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + items(categories) { (name, icon) -> + CategoryCard( + category = name, + icon = { Icon(icon, contentDescription = name) }, + onClick = { onCategoryClick(name) } + ) + } + } + } +} diff --git a/jmods-android/feature-categories/src/main/kotlin/com/jmods/feature/categories/ui/CategoryResultsScreen.kt b/jmods-android/feature-categories/src/main/kotlin/com/jmods/feature/categories/ui/CategoryResultsScreen.kt new file mode 100644 index 000000000..fedc916a3 --- /dev/null +++ b/jmods-android/feature-categories/src/main/kotlin/com/jmods/feature/categories/ui/CategoryResultsScreen.kt @@ -0,0 +1,96 @@ +package com.jmods.feature.categories.ui + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.lifecycle.ViewModel +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.viewModelScope +import androidx.navigation.toRoute +import com.jmods.domain.error.AppResult +import com.jmods.domain.model.App +import com.jmods.domain.usecase.GetAppsUseCase +import com.jmods.navigation.AppDestination +import com.jmods.ui.component.AppCard +import com.jmods.ui.component.JModsTopBar +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class CategoryResultsViewModel @Inject constructor( + private val getAppsUseCase: GetAppsUseCase, + savedStateHandle: SavedStateHandle +) : ViewModel() { + + private val route = savedStateHandle.toRoute() + val categoryName = route.categoryName + + private val _uiState = MutableStateFlow>>(AppResult.Loading) + val uiState: StateFlow>> = _uiState.asStateFlow() + + init { + fetchApps() + } + + fun fetchApps() { + viewModelScope.launch { + getAppsUseCase(categoryName) + .onStart { _uiState.value = AppResult.Loading } + .catch { _uiState.value = AppResult.Error(com.jmods.domain.error.AppException.Unknown(it.message ?: "Unknown error")) } + .collect { apps -> + _uiState.value = AppResult.Success(apps) + } + } + } +} + +@Composable +fun CategoryResultsScreen( + viewModel: CategoryResultsViewModel, + onAppClick: (String) -> Unit, + onBack: () -> Unit +) { + val state by viewModel.uiState.collectAsState() + + Scaffold( + topBar = { + JModsTopBar( + title = viewModel.categoryName, + onBackClick = onBack + ) + } + ) { padding -> + Box(modifier = Modifier.fillMaxSize().padding(padding)) { + when (val result = state) { + is AppResult.Loading -> { + CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) + } + is AppResult.Success -> { + LazyColumn( + modifier = Modifier.fillMaxSize(), + contentPadding = PaddingValues(16.dp), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + items(result.data) { app -> + AppCard(app = app, onClick = { onAppClick(app.packageName) }) + } + } + } + is AppResult.Error -> { + Text( + text = "Error: ${result.exception.message}", + color = MaterialTheme.colorScheme.error, + modifier = Modifier.align(Alignment.Center) + ) + } + } + } + } +} diff --git a/jmods-android/feature-details/build.gradle.kts b/jmods-android/feature-details/build.gradle.kts new file mode 100644 index 000000000..28a8ec729 --- /dev/null +++ b/jmods-android/feature-details/build.gradle.kts @@ -0,0 +1,42 @@ +plugins { + alias(libs.plugins.jetbrains.kotlin.android) + alias(libs.plugins.jetbrains.kotlin.compose) + id("com.android.library") + alias(libs.plugins.hilt.android.plugin) + id("com.google.devtools.ksp") +} + +android { + namespace = "com.jmods.feature.details" + compileSdk = 35 + defaultConfig { minSdk = 26 } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } + buildFeatures { + compose = true + } +} + +dependencies { + implementation(project(":jmods:core-domain")) + implementation(project(":jmods:core-data")) + implementation(project(":jmods:core-installer")) + implementation(project(":jmods:core-navigation")) + implementation(project(":jmods:core-ui")) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + implementation(libs.hilt.android.core) + ksp(libs.hilt.android.compiler) + implementation(libs.androidx.lifecycle.viewmodel.ktx) + implementation(libs.coil.compose) + implementation("androidx.navigation:navigation-compose:2.8.5") +} diff --git a/jmods-android/feature-details/src/main/kotlin/com/jmods/feature/details/ui/DetailsScreen.kt b/jmods-android/feature-details/src/main/kotlin/com/jmods/feature/details/ui/DetailsScreen.kt new file mode 100644 index 000000000..fb9d0aef9 --- /dev/null +++ b/jmods-android/feature-details/src/main/kotlin/com/jmods/feature/details/ui/DetailsScreen.kt @@ -0,0 +1,212 @@ +package com.jmods.feature.details.ui + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Star +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import coil3.compose.AsyncImage +import com.jmods.data.download.DownloadState +import com.jmods.domain.error.AppResult +import com.jmods.domain.model.App +import com.jmods.feature.details.viewmodel.DetailsViewModel +import com.jmods.installer.InstallStatus +import com.jmods.ui.component.JModsTopBar + +@Composable +fun DetailsScreen( + viewModel: DetailsViewModel, + onBack: () -> Unit +) { + val state by viewModel.uiState.collectAsState() + val downloadState by viewModel.downloadState.collectAsState() + val installStatus by viewModel.installStatus.collectAsState() + + Scaffold( + topBar = { + JModsTopBar( + title = "App Details", + onBackClick = onBack + ) + } + ) { padding -> + Box(modifier = Modifier.fillMaxSize().padding(padding)) { + when (val result = state) { + is AppResult.Loading -> { + CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) + } + is AppResult.Success -> { + AppDetailsContent( + app = result.data, + downloadState = downloadState, + installStatus = installStatus, + onDownloadClick = { viewModel.startDownload(result.data) } + ) + } + is AppResult.Error -> { + Text( + text = "Error: ${result.exception.message}", + color = MaterialTheme.colorScheme.error, + modifier = Modifier.align(Alignment.Center) + ) + } + } + } + } +} + +@Composable +fun AppDetailsContent( + app: App, + downloadState: DownloadState, + installStatus: InstallStatus, + onDownloadClick: () -> Unit +) { + val sizeMb = app.size / 1024 / 1024 + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(16.dp) + ) { + Row(verticalAlignment = Alignment.CenterVertically) { + AsyncImage( + model = app.iconUrl, + contentDescription = null, + modifier = Modifier + .size(96.dp) + .clip(RoundedCornerShape(20.dp)), + contentScale = ContentScale.Crop + ) + Spacer(modifier = Modifier.width(16.dp)) + Column { + Text(text = app.name, style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.Black)) + Text(text = app.developer, style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.primary) + Row(verticalAlignment = Alignment.CenterVertically) { + Icon(Icons.Default.Star, contentDescription = null, modifier = Modifier.size(16.dp), tint = MaterialTheme.colorScheme.secondary) + Spacer(modifier = Modifier.width(4.dp)) + Text(text = String.format("%.1f", app.rating), style = MaterialTheme.typography.bodyMedium) + } + } + } + + Spacer(modifier = Modifier.height(24.dp)) + + DownloadInstallButton( + downloadState = downloadState, + installStatus = installStatus, + onDownloadClick = onDownloadClick + ) + + if (app.screenshots.isNotEmpty()) { + Spacer(modifier = Modifier.height(24.dp)) + Text(text = "Screenshots", style = MaterialTheme.typography.titleLarge.copy(fontWeight = FontWeight.Bold)) + Spacer(modifier = Modifier.height(12.dp)) + LazyRow( + horizontalArrangement = Arrangement.spacedBy(12.dp), + contentPadding = PaddingValues(horizontal = 4.dp) + ) { + items(app.screenshots) { screenshotUrl -> + AsyncImage( + model = screenshotUrl, + contentDescription = null, + modifier = Modifier + .height(240.dp) + .width(135.dp) + .clip(RoundedCornerShape(16.dp)) + .background(MaterialTheme.colorScheme.surfaceVariant), + contentScale = ContentScale.Crop + ) + } + } + } + + Spacer(modifier = Modifier.height(24.dp)) + + Text(text = "About this app", style = MaterialTheme.typography.titleLarge.copy(fontWeight = FontWeight.Bold)) + Spacer(modifier = Modifier.height(8.dp)) + Text(text = app.description, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) + + Spacer(modifier = Modifier.height(24.dp)) + + Text(text = "Information", style = MaterialTheme.typography.titleLarge.copy(fontWeight = FontWeight.Bold)) + Spacer(modifier = Modifier.height(8.dp)) + InfoRow(label = "Package Name", value = app.packageName) + InfoRow(label = "Version", value = app.version) + InfoRow(label = "Size", value = "$sizeMb MB") + } +} + +@Composable +fun DownloadInstallButton( + downloadState: DownloadState, + installStatus: InstallStatus, + onDownloadClick: () -> Unit +) { + when { + installStatus is InstallStatus.Success -> { + Button(onClick = {}, modifier = Modifier.fillMaxWidth().height(48.dp), enabled = false) { + Text("Installed") + } + } + installStatus is InstallStatus.Progress -> { + Button(onClick = {}, modifier = Modifier.fillMaxWidth().height(48.dp), enabled = false) { + CircularProgressIndicator(modifier = Modifier.size(24.dp), strokeWidth = 2.dp) + Spacer(modifier = Modifier.width(8.dp)) + Text("Installing...") + } + } + downloadState is DownloadState.Completed -> { + Button(onClick = {}, modifier = Modifier.fillMaxWidth().height(48.dp), enabled = false) { + Text("Verifying...") + } + } + downloadState is DownloadState.Downloading -> { + Column(modifier = Modifier.fillMaxWidth()) { + LinearProgressIndicator( + progress = { downloadState.progress }, + modifier = Modifier.fillMaxWidth().height(8.dp).clip(RoundedCornerShape(4.dp)) + ) + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = "Downloading ${(downloadState.progress * 100).toInt()}%", + style = MaterialTheme.typography.labelSmall, + modifier = Modifier.align(Alignment.CenterHorizontally) + ) + } + } + else -> { + Button( + onClick = onDownloadClick, + modifier = Modifier.fillMaxWidth().height(48.dp), + shape = RoundedCornerShape(12.dp) + ) { + Text("Install") + } + } + } +} + +@Composable +fun InfoRow(label: String, value: String) { + Row( + modifier = Modifier.fillMaxWidth().padding(vertical = 6.dp), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text(text = label, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.outline) + Text(text = value, style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight.Medium) + } +} diff --git a/jmods-android/feature-details/src/main/kotlin/com/jmods/feature/details/viewmodel/DetailsViewModel.kt b/jmods-android/feature-details/src/main/kotlin/com/jmods/feature/details/viewmodel/DetailsViewModel.kt new file mode 100644 index 000000000..47ccb5391 --- /dev/null +++ b/jmods-android/feature-details/src/main/kotlin/com/jmods/feature/details/viewmodel/DetailsViewModel.kt @@ -0,0 +1,77 @@ +package com.jmods.feature.details.viewmodel + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import androidx.navigation.toRoute +import com.jmods.data.download.DownloadState +import com.jmods.data.download.JModsDownloadManager +import com.jmods.domain.error.AppResult +import com.jmods.domain.model.App +import com.jmods.domain.usecase.GetAppDetailsUseCase +import com.jmods.installer.AppInstaller +import com.jmods.installer.InstallStatus +import com.jmods.navigation.AppDestination +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class DetailsViewModel @Inject constructor( + private val getAppDetailsUseCase: GetAppDetailsUseCase, + private val downloadManager: JModsDownloadManager, + private val installer: AppInstaller, + savedStateHandle: SavedStateHandle +) : ViewModel() { + + private val details = savedStateHandle.toRoute() + private val packageName = details.packageName + + private val _uiState = MutableStateFlow>(AppResult.Loading) + val uiState: StateFlow> = _uiState.asStateFlow() + + val downloadState = downloadManager.getDownloadStatus(packageName) + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), DownloadState.Idle) + + private val _installStatus = MutableStateFlow(InstallStatus.Idle) + val installStatus: StateFlow = _installStatus.asStateFlow() + + init { + fetchDetails() + observeDownloadCompletion() + } + + fun fetchDetails() { + viewModelScope.launch { + getAppDetailsUseCase(packageName) + .onStart { _uiState.value = AppResult.Loading } + .catch { _uiState.value = AppResult.Error(com.jmods.domain.error.AppException.Unknown(it.message ?: "Unknown error")) } + .collect { app -> + _uiState.value = AppResult.Success(app) + } + } + } + + fun startDownload(app: App) { + downloadManager.enqueueDownload(app) + } + + private fun observeDownloadCompletion() { + viewModelScope.launch { + downloadState.collect { state -> + if (state is DownloadState.Completed) { + installApp(packageName, state.apkPath) + } + } + } + } + + private fun installApp(packageName: String, apkPath: String) { + viewModelScope.launch { + installer.install(packageName, apkPath).collect { status -> + _installStatus.value = status + } + } + } +} diff --git a/jmods-android/feature-home/build.gradle.kts b/jmods-android/feature-home/build.gradle.kts new file mode 100644 index 000000000..dcf8fc20e --- /dev/null +++ b/jmods-android/feature-home/build.gradle.kts @@ -0,0 +1,41 @@ +plugins { + alias(libs.plugins.jetbrains.kotlin.android) + alias(libs.plugins.jetbrains.kotlin.compose) + id("com.android.library") + alias(libs.plugins.hilt.android.plugin) + id("com.google.devtools.ksp") +} + +android { + namespace = "com.jmods.feature.home" + compileSdk = 35 + defaultConfig { + minSdk = 26 + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } + buildFeatures { + compose = true + } +} + +dependencies { + implementation(project(":jmods:core-domain")) + implementation(project(":jmods:core-navigation")) + implementation(project(":jmods:core-ui")) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + implementation(libs.hilt.android.core) + ksp(libs.hilt.android.compiler) + implementation(libs.androidx.lifecycle.viewmodel.ktx) + implementation(libs.coil.compose) +} diff --git a/jmods-android/feature-home/src/main/kotlin/com/jmods/feature/home/ui/HomeScreen.kt b/jmods-android/feature-home/src/main/kotlin/com/jmods/feature/home/ui/HomeScreen.kt new file mode 100644 index 000000000..34afe341e --- /dev/null +++ b/jmods-android/feature-home/src/main/kotlin/com/jmods/feature/home/ui/HomeScreen.kt @@ -0,0 +1,192 @@ +package com.jmods.feature.home.ui + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Menu +import androidx.compose.material.icons.filled.Search +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import coil3.compose.AsyncImage +import com.jmods.domain.model.App +import com.jmods.feature.home.viewmodel.HomeViewModel +import com.jmods.feature.home.viewmodel.HomeUiState +import com.jmods.ui.component.AppCard +import com.jmods.ui.component.JModsTopBar + +@Composable +fun HomeScreen( + viewModel: HomeViewModel, + onAppClick: (String) -> Unit, + onSearchClick: () -> Unit, + onMenuClick: () -> Unit +) { + val state by viewModel.uiState.collectAsState() + + Scaffold( + topBar = { + JModsTopBar( + title = "J MODS", + navigationIcon = { + IconButton(onClick = onMenuClick) { + Icon(Icons.Default.Menu, contentDescription = "Menu") + } + }, + actions = { + IconButton(onClick = onSearchClick) { + Icon(Icons.Default.Search, contentDescription = "Search") + } + } + ) + } + ) { padding -> + Box(modifier = Modifier.fillMaxSize().padding(padding)) { + when (val result = state) { + is HomeUiState.Loading -> { + CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) + } + is HomeUiState.Success -> { + HomeContent( + featured = result.featured, + topCharts = result.topCharts, + onAppClick = onAppClick + ) + } + is HomeUiState.Error -> { + Column( + modifier = Modifier.align(Alignment.Center), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "Error: ${result.message}", + color = MaterialTheme.colorScheme.error + ) + Spacer(modifier = Modifier.height(16.dp)) + Button(onClick = { viewModel.fetchHomeData() }) { + Text("Retry") + } + } + } + } + } + } +} + +@Composable +fun HomeContent( + featured: List, + topCharts: List, + onAppClick: (String) -> Unit +) { + LazyColumn( + modifier = Modifier.fillMaxSize(), + contentPadding = PaddingValues(bottom = 16.dp), + verticalArrangement = Arrangement.spacedBy(24.dp) + ) { + if (featured.isNotEmpty()) { + item { + Column { + SectionHeader("Featured", modifier = Modifier.padding(horizontal = 16.dp)) + Spacer(modifier = Modifier.height(12.dp)) + LazyRow( + contentPadding = PaddingValues(horizontal = 16.dp), + horizontalArrangement = Arrangement.spacedBy(16.dp) + ) { + items(featured) { app -> + FeaturedAppCard(app = app, onClick = { onAppClick(app.packageName) }) + } + } + } + } + } + + if (topCharts.isNotEmpty()) { + item { + SectionHeader("Top Charts", modifier = Modifier.padding(horizontal = 16.dp)) + } + itemsIndexed(topCharts) { index, app -> + AppCard( + app = app, + onClick = { onAppClick(app.packageName) }, + rank = index + 1, + modifier = Modifier.padding(horizontal = 16.dp) + ) + if (index < topCharts.size - 1) { + Spacer(modifier = Modifier.height(8.dp)) + } + } + } + } +} + +@Composable +fun FeaturedAppCard(app: App, onClick: () -> Unit) { + Card( + onClick = onClick, + modifier = Modifier.width(300.dp).height(180.dp), + shape = RoundedCornerShape(28.dp), + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.primaryContainer) + ) { + Column(modifier = Modifier.padding(24.dp).fillMaxSize()) { + Row(verticalAlignment = Alignment.CenterVertically) { + AsyncImage( + model = app.iconUrl, + contentDescription = null, + modifier = Modifier + .size(56.dp) + .clip(RoundedCornerShape(16.dp)), + contentScale = ContentScale.Crop + ) + Spacer(modifier = Modifier.width(16.dp)) + Column { + Text( + text = app.name, + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.Black, + color = MaterialTheme.colorScheme.onPrimaryContainer, + maxLines = 1 + ) + Text( + text = app.developer, + style = MaterialTheme.typography.labelMedium, + color = MaterialTheme.colorScheme.onPrimaryContainer.copy(alpha = 0.8f), + maxLines = 1 + ) + } + } + Spacer(modifier = Modifier.weight(1f)) + Text( + text = "FEATURED APP", + style = MaterialTheme.typography.labelSmall.copy(letterSpacing = 2.sp), + fontWeight = FontWeight.Black, + color = MaterialTheme.colorScheme.onPrimaryContainer.copy(alpha = 0.5f) + ) + } + } +} + +@Composable +fun SectionHeader(title: String, modifier: Modifier = Modifier) { + Text( + text = title, + style = MaterialTheme.typography.headlineSmall.copy( + fontWeight = FontWeight.Black, + letterSpacing = (-0.5).sp + ), + color = MaterialTheme.colorScheme.onSurface, + modifier = modifier + ) +} diff --git a/jmods-android/feature-home/src/main/kotlin/com/jmods/feature/home/viewmodel/HomeViewModel.kt b/jmods-android/feature-home/src/main/kotlin/com/jmods/feature/home/viewmodel/HomeViewModel.kt new file mode 100644 index 000000000..33405091d --- /dev/null +++ b/jmods-android/feature-home/src/main/kotlin/com/jmods/feature/home/viewmodel/HomeViewModel.kt @@ -0,0 +1,50 @@ +package com.jmods.feature.home.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.jmods.domain.error.AppResult +import com.jmods.domain.model.App +import com.jmods.domain.usecase.GetAppsUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.launch +import javax.inject.Inject + +sealed class HomeUiState { + object Loading : HomeUiState() + data class Success(val featured: List, val topCharts: List) : HomeUiState() + data class Error(val message: String) : HomeUiState() +} + +@HiltViewModel +class HomeViewModel @Inject constructor( + private val getAppsUseCase: GetAppsUseCase +) : ViewModel() { + + private val _uiState = MutableStateFlow(HomeUiState.Loading) + val uiState: StateFlow = _uiState.asStateFlow() + + init { + fetchHomeData() + } + + fun fetchHomeData() { + viewModelScope.launch { + _uiState.value = HomeUiState.Loading + try { + // In a real app, these would be separate calls or zipped + getAppsUseCase("featured").collect { featured -> + getAppsUseCase("top").collect { top -> + _uiState.value = HomeUiState.Success(featured, top) + } + } + } catch (e: Exception) { + _uiState.value = HomeUiState.Error(e.message ?: "Failed to load home data") + } + } + } +} diff --git a/jmods-android/feature-search/build.gradle.kts b/jmods-android/feature-search/build.gradle.kts new file mode 100644 index 000000000..3fb62c254 --- /dev/null +++ b/jmods-android/feature-search/build.gradle.kts @@ -0,0 +1,40 @@ +plugins { + alias(libs.plugins.jetbrains.kotlin.android) + alias(libs.plugins.jetbrains.kotlin.compose) + id("com.android.library") + alias(libs.plugins.hilt.android.plugin) + id("com.google.devtools.ksp") +} + +android { + namespace = "com.jmods.feature.search" + compileSdk = 35 + defaultConfig { minSdk = 26 } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } + buildFeatures { + compose = true + } +} + +dependencies { + implementation(project(":jmods:core-domain")) + implementation(project(":jmods:core-navigation")) + implementation(project(":jmods:core-ui")) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + implementation(libs.hilt.android.core) + ksp(libs.hilt.android.compiler) + implementation(libs.androidx.lifecycle.viewmodel.ktx) + implementation(libs.coil.compose) + implementation("androidx.navigation:navigation-compose:2.8.5") +} diff --git a/jmods-android/feature-search/src/main/kotlin/com/jmods/feature/search/ui/SearchScreen.kt b/jmods-android/feature-search/src/main/kotlin/com/jmods/feature/search/ui/SearchScreen.kt new file mode 100644 index 000000000..734570b53 --- /dev/null +++ b/jmods-android/feature-search/src/main/kotlin/com/jmods/feature/search/ui/SearchScreen.kt @@ -0,0 +1,83 @@ +package com.jmods.feature.search.ui + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Search +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.jmods.domain.error.AppResult +import com.jmods.feature.search.viewmodel.SearchViewModel +import com.jmods.ui.component.AppCard +import com.jmods.ui.component.JModsTopBar + +@Composable +fun SearchScreen( + viewModel: SearchViewModel, + onAppClick: (String) -> Unit, + onBack: () -> Unit +) { + val query by viewModel.query.collectAsState() + val state by viewModel.uiState.collectAsState() + + Scaffold( + topBar = { + JModsTopBar( + title = "Search", + onBackClick = onBack + ) + } + ) { padding -> + Column(modifier = Modifier.padding(padding).fillMaxSize()) { + OutlinedTextField( + value = query, + onValueChange = { viewModel.onQueryChange(it) }, + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + placeholder = { Text("Search apps...") }, + leadingIcon = { Icon(Icons.Default.Search, contentDescription = null) }, + singleLine = true, + shape = MaterialTheme.shapes.medium + ) + + Box(modifier = Modifier.weight(1f)) { + when (val result = state) { + is AppResult.Loading -> { + CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) + } + is AppResult.Success -> { + if (result.data.isEmpty() && query.isNotEmpty()) { + Text( + text = "No results found for '$query'", + modifier = Modifier.align(Alignment.Center), + style = MaterialTheme.typography.bodyLarge + ) + } else { + LazyColumn( + modifier = Modifier.fillMaxSize(), + contentPadding = PaddingValues(16.dp), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + items(result.data) { app -> + AppCard(app = app, onClick = { onAppClick(app.packageName) }) + } + } + } + } + is AppResult.Error -> { + Text( + text = "Error: ${result.exception.message}", + color = MaterialTheme.colorScheme.error, + modifier = Modifier.align(Alignment.Center) + ) + } + } + } + } + } +} diff --git a/jmods-android/feature-search/src/main/kotlin/com/jmods/feature/search/viewmodel/SearchViewModel.kt b/jmods-android/feature-search/src/main/kotlin/com/jmods/feature/search/viewmodel/SearchViewModel.kt new file mode 100644 index 000000000..a37efdd04 --- /dev/null +++ b/jmods-android/feature-search/src/main/kotlin/com/jmods/feature/search/viewmodel/SearchViewModel.kt @@ -0,0 +1,49 @@ +package com.jmods.feature.search.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.jmods.domain.error.AppResult +import com.jmods.domain.model.App +import com.jmods.domain.usecase.GetAppsUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class SearchViewModel @Inject constructor( + private val getAppsUseCase: GetAppsUseCase +) : ViewModel() { + + private val _query = MutableStateFlow("") + val query = _query.asStateFlow() + + private val _uiState = MutableStateFlow>>(AppResult.Success(emptyList())) + val uiState: StateFlow>> = _uiState.asStateFlow() + + init { + _query + .debounce(500) + .filter { it.isNotEmpty() } + .onEach { performSearch(it) } + .launchIn(viewModelScope) + } + + fun onQueryChange(newQuery: String) { + _query.value = newQuery + if (newQuery.isEmpty()) { + _uiState.value = AppResult.Success(emptyList()) + } + } + + private fun performSearch(query: String) { + viewModelScope.launch { + getAppsUseCase(query) + .onStart { _uiState.value = AppResult.Loading } + .catch { _uiState.value = AppResult.Error(com.jmods.domain.error.AppException.Unknown(it.message ?: "Search failed")) } + .collect { results -> + _uiState.value = AppResult.Success(results) + } + } + } +} diff --git a/jmods-android/feature-updates/build.gradle.kts b/jmods-android/feature-updates/build.gradle.kts new file mode 100644 index 000000000..33dd5e15d --- /dev/null +++ b/jmods-android/feature-updates/build.gradle.kts @@ -0,0 +1,41 @@ +plugins { + alias(libs.plugins.jetbrains.kotlin.android) + alias(libs.plugins.jetbrains.kotlin.compose) + id("com.android.library") + alias(libs.plugins.hilt.android.plugin) + id("com.google.devtools.ksp") +} + +android { + namespace = "com.jmods.feature.updates" + compileSdk = 35 + defaultConfig { minSdk = 26 } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } + buildFeatures { + compose = true + } +} + +dependencies { + implementation(project(":jmods:core-domain")) + implementation(project(":jmods:core-data")) + implementation(project(":jmods:core-navigation")) + implementation(project(":jmods:core-ui")) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + implementation(libs.hilt.android.core) + ksp(libs.hilt.android.compiler) + implementation(libs.androidx.lifecycle.viewmodel.ktx) + implementation(libs.coil.compose) + implementation("androidx.navigation:navigation-compose:2.8.5") +} diff --git a/jmods-android/feature-updates/src/main/kotlin/com/jmods/feature/updates/ui/UpdatesScreen.kt b/jmods-android/feature-updates/src/main/kotlin/com/jmods/feature/updates/ui/UpdatesScreen.kt new file mode 100644 index 000000000..22165954b --- /dev/null +++ b/jmods-android/feature-updates/src/main/kotlin/com/jmods/feature/updates/ui/UpdatesScreen.kt @@ -0,0 +1,110 @@ +package com.jmods.feature.updates.ui + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Refresh +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import com.jmods.domain.error.AppResult +import com.jmods.domain.model.App +import com.jmods.feature.updates.viewmodel.UpdatesViewModel +import com.jmods.ui.component.AppCard +import com.jmods.ui.component.JModsTopBar + +@Composable +fun UpdatesScreen( + viewModel: UpdatesViewModel, + onAppClick: (String) -> Unit +) { + val state by viewModel.uiState.collectAsState() + + Scaffold( + topBar = { + JModsTopBar( + title = "Updates", + actions = { + IconButton(onClick = { viewModel.fetchUpdates() }) { + Icon(Icons.Default.Refresh, contentDescription = "Refresh") + } + } + ) + } + ) { padding -> + Box(modifier = Modifier.fillMaxSize().padding(padding)) { + when (val result = state) { + is AppResult.Loading -> { + CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) + } + is AppResult.Success -> { + if (result.data.isEmpty()) { + Column( + modifier = Modifier.align(Alignment.Center), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text("Your apps are up to date", style = MaterialTheme.typography.titleMedium) + Text("Check back later for new versions", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.outline) + } + } else { + UpdatesList( + updates = result.data, + onAppClick = onAppClick, + onUpdateAll = { /* TODO */ } + ) + } + } + is AppResult.Error -> { + Column( + modifier = Modifier.align(Alignment.Center), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text(text = "Error: ${result.exception.message}", color = MaterialTheme.colorScheme.error) + Button(onClick = { viewModel.fetchUpdates() }, modifier = Modifier.padding(top = 16.dp)) { + Text("Retry") + } + } + } + } + } + } +} + +@Composable +fun UpdatesList( + updates: List, + onAppClick: (String) -> Unit, + onUpdateAll: () -> Unit +) { + LazyColumn( + modifier = Modifier.fillMaxSize(), + contentPadding = PaddingValues(16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + item { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "${updates.size} updates available", + style = MaterialTheme.typography.titleSmall, + fontWeight = FontWeight.Bold + ) + TextButton(onClick = onUpdateAll) { + Text("Update All") + } + } + } + items(updates) { app -> + AppCard(app = app, onClick = { onAppClick(app.packageName) }) + } + } +} diff --git a/jmods-android/feature-updates/src/main/kotlin/com/jmods/feature/updates/viewmodel/UpdatesViewModel.kt b/jmods-android/feature-updates/src/main/kotlin/com/jmods/feature/updates/viewmodel/UpdatesViewModel.kt new file mode 100644 index 000000000..ef86136de --- /dev/null +++ b/jmods-android/feature-updates/src/main/kotlin/com/jmods/feature/updates/viewmodel/UpdatesViewModel.kt @@ -0,0 +1,35 @@ +package com.jmods.feature.updates.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.jmods.domain.error.AppResult +import com.jmods.domain.model.App +import com.jmods.domain.usecase.GetUpdatesUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class UpdatesViewModel @Inject constructor( + private val getUpdatesUseCase: GetUpdatesUseCase +) : ViewModel() { + + private val _uiState = MutableStateFlow>>(AppResult.Loading) + val uiState: StateFlow>> = _uiState.asStateFlow() + + init { + fetchUpdates() + } + + fun fetchUpdates() { + viewModelScope.launch { + getUpdatesUseCase() + .onStart { _uiState.value = AppResult.Loading } + .catch { _uiState.value = AppResult.Error(com.jmods.domain.error.AppException.Unknown(it.message ?: "Failed to fetch updates")) } + .collect { updates -> + _uiState.value = AppResult.Success(updates) + } + } + } +} diff --git a/lib/format.ts b/lib/format.ts new file mode 100644 index 000000000..0372f0cf8 --- /dev/null +++ b/lib/format.ts @@ -0,0 +1,18 @@ +export function formatBytes(bytes: number): string { + if (bytes < 1000000) return `${(bytes / 1000).toFixed(0)} KB` + return `${(bytes / 1000000).toFixed(1)} MB` +} + +export function formatRatingCount(count: number): string { + if (count >= 1000000) return `${(count / 1000000).toFixed(1)}M` + if (count >= 1000) return `${(count / 1000).toFixed(0)}K` + return String(count) +} + +export function formatDate(dateStr: string): string { + return new Date(`${dateStr}T00:00:00`).toLocaleDateString('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric', + }) +} diff --git a/lib/mock-data.ts b/lib/mock-data.ts new file mode 100644 index 000000000..0b754d718 --- /dev/null +++ b/lib/mock-data.ts @@ -0,0 +1,131 @@ +import type { App } from './types' + +export const MOCK_APPS: App[] = [ + { + packageName: 'org.signal.messenger', + name: 'Signal', + developer: 'Signal Foundation', + category: 'Social', + shortDescription: 'Private messenger. No ads, no trackers, no compromise.', + longDescription: + 'Signal is a cross-platform encrypted messaging service. All messages are end-to-end encrypted, and Signal collects minimal metadata. It is free, open-source, and supported by grants and donations.', + iconUrl: 'https://play-lh.googleusercontent.com/a1msHo9W52_K36SWfDyfPkHNtpDU_j9WKH7yrfzVyEqQC5hf2wROWuGfcvXzs4OGfQ', + headerImageUrl: 'https://play-lh.googleusercontent.com/a1msHo9W52_K36SWfDyfPkHNtpDU_j9WKH7yrfzVyEqQC5hf2wROWuGfcvXzs4OGfQ', + screenshotUrls: [], + rating: { average: 4.6, count: 2100000 }, + downloads: '100M+', + version: { + versionName: '7.5.1', + versionCode: 7501, + minSdk: 24, + targetSdk: 34, + sizeBytes: 41000000, + uploadDate: '2025-11-12', + changelog: 'Improved notification reliability, bug fixes.', + }, + permissions: [ + { name: 'CAMERA', description: 'Take photos and videos', dangerous: true }, + { name: 'CONTACTS', description: 'Read your contacts', dangerous: true }, + { name: 'INTERNET', description: 'Have full network access', dangerous: false }, + ], + trackers: [], + isOpenSource: true, + sourceUrl: 'https://github.com/signalapp/Signal-Android', + isFeatured: true, + }, + { + packageName: 'org.mozilla.firefox', + name: 'Firefox', + developer: 'Mozilla', + category: 'Tools', + shortDescription: 'Fast, private and secure browser by Mozilla.', + longDescription: + 'Firefox for Android is built on GeckoView. It supports uBlock Origin and hundreds of other extensions. Enhanced Tracking Protection blocks trackers by default.', + iconUrl: 'https://play-lh.googleusercontent.com/jLchAkTnGtgOBKyliuVnH5-JqJjHhL1TEKEAHfhQjGrAI-bdCvEE9fzgCgdV4OevLYE', + headerImageUrl: 'https://play-lh.googleusercontent.com/jLchAkTnGtgOBKyliuVnH5-JqJjHhL1TEKEAHfhQjGrAI-bdCvEE9fzgCgdV4OevLYE', + screenshotUrls: [], + rating: { average: 4.3, count: 1500000 }, + downloads: '500M+', + version: { + versionName: '133.0', + versionCode: 2016133000, + minSdk: 21, + targetSdk: 34, + sizeBytes: 92000000, + uploadDate: '2026-01-10', + changelog: 'Improved tab management. Updated security patches.', + }, + permissions: [ + { name: 'INTERNET', description: 'Have full network access', dangerous: false }, + { name: 'CAMERA', description: 'Take photos for web forms', dangerous: true }, + ], + trackers: [{ name: 'Adjust', website: 'https://www.adjust.com' }], + isOpenSource: true, + sourceUrl: 'https://github.com/mozilla-mobile/fenix', + isFeatured: true, + }, + { + packageName: 'org.telegram.messenger', + name: 'Telegram', + developer: 'Telegram FZ-LLC', + category: 'Social', + shortDescription: 'Fast. Secure. Powerful.', + longDescription: 'Pure instant messaging — simple, fast, secure, and synced across all your devices.', + iconUrl: 'https://play-lh.googleusercontent.com/ZU9v9D97S97_pA8Y9oH6S-77-hZ6m66-XN_5M-N_6M-N_6M-N_6M-N_6M-N_6M-N_6M', + headerImageUrl: 'https://play-lh.googleusercontent.com/ZU9v9D97S97_pA8Y9oH6S-77-hZ6m66-XN_5M-N_6M-N_6M-N_6M-N_6M-N_6M-N_6M', + screenshotUrls: [], + rating: { average: 4.4, count: 12000000 }, + downloads: '1B+', + version: { + versionName: '10.3.1', + versionCode: 4100, + minSdk: 21, + targetSdk: 33, + sizeBytes: 65000000, + uploadDate: '2025-12-01', + changelog: 'New features for channels and groups.', + }, + permissions: [], + trackers: [], + isOpenSource: false, + isFeatured: false, + } +] + +export function getAppByPackageName(packageName: string): App | undefined { + return MOCK_APPS.find((app) => app.packageName === packageName) +} + +export function getAppsByCategory(category: string): App[] { + return MOCK_APPS.filter((app) => app.category === category) +} + +export function getFeaturedApps(): App[] { + return MOCK_APPS.filter((app) => app.isFeatured) +} + +export function searchApps(query: string): App[] { + const q = query.toLowerCase() + return MOCK_APPS.filter( + (app) => + app.name.toLowerCase().includes(q) || + app.developer.toLowerCase().includes(q) || + app.shortDescription.toLowerCase().includes(q) || + app.packageName.toLowerCase().includes(q), + ) +} + +export function getRecentlyAddedApps(): App[] { + return [...MOCK_APPS].reverse() +} + +export const ALL_CATEGORIES = [ + 'Productivity', + 'Social', + 'Games', + 'Tools', + 'Media', + 'Security', + 'Finance', + 'Health', +] as const diff --git a/lib/types.ts b/lib/types.ts new file mode 100644 index 000000000..64716e986 --- /dev/null +++ b/lib/types.ts @@ -0,0 +1,57 @@ +export type AppCategory = + | 'Productivity' + | 'Social' + | 'Games' + | 'Tools' + | 'Media' + | 'Security' + | 'Finance' + | 'Health' + +export type InstallMethod = 'session' | 'root' | 'shizuku' + +export interface AppRating { + average: number + count: number +} + +export interface AppPermission { + name: string + description: string + dangerous: boolean +} + +export interface AppTracker { + name: string + website: string +} + +export interface AppVersion { + versionName: string + versionCode: number + minSdk: number + targetSdk: number + sizeBytes: number + uploadDate: string + changelog?: string +} + +export interface App { + packageName: string + name: string + developer: string + category: AppCategory + shortDescription: string + longDescription: string + iconUrl: string + headerImageUrl: string + screenshotUrls: string[] + rating: AppRating + downloads: string + version: AppVersion + permissions: AppPermission[] + trackers: AppTracker[] + isOpenSource: boolean + sourceUrl?: string + isFeatured?: boolean +} diff --git a/lib/utils.ts b/lib/utils.ts new file mode 100644 index 000000000..d084ccade --- /dev/null +++ b/lib/utils.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/next-env.d.ts b/next-env.d.ts new file mode 100644 index 000000000..9edff1c7c --- /dev/null +++ b/next-env.d.ts @@ -0,0 +1,6 @@ +/// +/// +import "./.next/types/routes.d.ts"; + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/next.config.mjs b/next.config.mjs new file mode 100644 index 000000000..793a24973 --- /dev/null +++ b/next.config.mjs @@ -0,0 +1,21 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + images: { + remotePatterns: [ + { + protocol: 'https', + hostname: 'play-lh.googleusercontent.com', + }, + { + protocol: 'https', + hostname: 'lh3.googleusercontent.com', + }, + { + protocol: 'https', + hostname: 'placehold.co', + }, + ], + }, +} + +export default nextConfig diff --git a/next.config.ts b/next.config.ts new file mode 100644 index 000000000..e9ffa3083 --- /dev/null +++ b/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + /* config options here */ +}; + +export default nextConfig; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..ebe3dbdd8 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1928 @@ +{ + "name": "aurora-next-web", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "aurora-next-web", + "version": "1.0.0", + "dependencies": { + "clsx": "^2.1.1", + "lucide-react": "^0.577.0", + "next": "^16.2.0", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "tailwind-merge": "^3.5.0" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4.2.2", + "@types/node": "^25.5.0", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "autoprefixer": "^10.4.27", + "postcss": "^8.5.8", + "tailwindcss": "^4.2.2", + "typescript": "^5.9.3" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz", + "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@next/env": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.0.tgz", + "integrity": "sha512-OZIbODWWAi0epQRCRjNe1VO45LOFBzgiyqmTLzIqWq6u1wrxKnAyz1HH6tgY/Mc81YzIjRPoYsPAEr4QV4l9TA==", + "license": "MIT" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.0.tgz", + "integrity": "sha512-/JZsqKzKt01IFoiLLAzlNqys7qk2F3JkcUhj50zuRhKDQkZNOz9E5N6wAQWprXdsvjRP4lTFj+/+36NSv5AwhQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.0.tgz", + "integrity": "sha512-/hV8erWq4SNlVgglUiW5UmQ5Hwy5EW/AbbXlJCn6zkfKxTy/E/U3V8U1Ocm2YCTUoFgQdoMxRyRMOW5jYy4ygg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.0.tgz", + "integrity": "sha512-GkjL/Q7MWOwqWR9zoxu1TIHzkOI2l2BHCf7FzeQG87zPgs+6WDh+oC9Sw9ARuuL/FUk6JNCgKRkA6rEQYadUaw==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.0.tgz", + "integrity": "sha512-1ffhC6KY5qWLg5miMlKJp3dZbXelEfjuXt1qcp5WzSCQy36CV3y+JT7OC1WSFKizGQCDOcQbfkH/IjZP3cdRNA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.0.tgz", + "integrity": "sha512-FmbDcZQ8yJRq93EJSL6xaE0KK/Rslraf8fj1uViGxg7K4CKBCRYSubILJPEhjSgZurpcPQq12QNOJQ0DRJl6Hg==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.0.tgz", + "integrity": "sha512-HzjIHVkmGAwRbh/vzvoBWWEbb8BBZPxBvVbDQDvzHSf3D8RP/4vjw7MNLDXFF9Q1WEzeQyEj2zdxBtVAHu5Oyw==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.0.tgz", + "integrity": "sha512-UMiFNQf5H7+1ZsZPxEsA064WEuFbRNq/kEXyepbCnSErp4f5iut75dBA8UeerFIG3vDaQNOfCpevnERPp2V+nA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.0.tgz", + "integrity": "sha512-DRrNJKW+/eimrZgdhVN1uvkN1OI4j6Lpefwr44jKQ0YQzztlmOBUUzHuV5GxOMPK3nmodAYElUVCY8ZXo/IWeA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.2.tgz", + "integrity": "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.19.0", + "jiti": "^2.6.1", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.2.2" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.2.tgz", + "integrity": "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.2.2", + "@tailwindcss/oxide-darwin-arm64": "4.2.2", + "@tailwindcss/oxide-darwin-x64": "4.2.2", + "@tailwindcss/oxide-freebsd-x64": "4.2.2", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2", + "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2", + "@tailwindcss/oxide-linux-arm64-musl": "4.2.2", + "@tailwindcss/oxide-linux-x64-gnu": "4.2.2", + "@tailwindcss/oxide-linux-x64-musl": "4.2.2", + "@tailwindcss/oxide-wasm32-wasi": "4.2.2", + "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2", + "@tailwindcss/oxide-win32-x64-msvc": "4.2.2" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.2.tgz", + "integrity": "sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.2.tgz", + "integrity": "sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.2.tgz", + "integrity": "sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.2.tgz", + "integrity": "sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.2.tgz", + "integrity": "sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.2.tgz", + "integrity": "sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.2.tgz", + "integrity": "sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.2.tgz", + "integrity": "sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.2.tgz", + "integrity": "sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.2.tgz", + "integrity": "sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.8.1", + "@emnapi/runtime": "^1.8.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.1", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.2.tgz", + "integrity": "sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.2.tgz", + "integrity": "sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.2.2.tgz", + "integrity": "sha512-n4goKQbW8RVXIbNKRB/45LzyUqN451deQK0nzIeauVEqjlI49slUlgKYJM2QyUzap/PcpnS7kzSUmPb1sCRvYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.2.2", + "@tailwindcss/oxide": "4.2.2", + "postcss": "^8.5.6", + "tailwindcss": "4.2.2" + } + }, + "node_modules/@types/node": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", + "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.27", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.27.tgz", + "integrity": "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1", + "caniuse-lite": "^1.0.30001774", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.9", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.9.tgz", + "integrity": "sha512-OZd0e2mU11ClX8+IdXe3r0dbqMEznRiT4TfbhYIbcRPZkqJ7Qwer8ij3GZAmLsRKa+II9V1v5czCkvmHH3XZBg==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001780", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001780.tgz", + "integrity": "sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.321", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.321.tgz", + "integrity": "sha512-L2C7Q279W2D/J4PLZLk7sebOILDSWos7bMsMNN06rK482umHUrh/3lM8G7IlHFOYip2oAg5nha1rCMxr/rs6ZQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/enhanced-resolve": { + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", + "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lucide-react": { + "version": "0.577.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.577.0.tgz", + "integrity": "sha512-4LjoFv2eEPwYDPg/CUdBJQSDfPyzXCRrVW1X7jrx/trgxnxkHFjnVZINbzvzxjN70dxychOfg+FTYwBiS3pQ5A==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/next": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/next/-/next-16.2.0.tgz", + "integrity": "sha512-NLBVrJy1pbV1Yn00L5sU4vFyAHt5XuSjzrNyFnxo6Com0M0KrL6hHM5B99dbqXb2bE9pm4Ow3Zl1xp6HVY9edQ==", + "license": "MIT", + "dependencies": { + "@next/env": "16.2.0", + "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.9.19", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=20.9.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "16.2.0", + "@next/swc-darwin-x64": "16.2.0", + "@next/swc-linux-arm64-gnu": "16.2.0", + "@next/swc-linux-arm64-musl": "16.2.0", + "@next/swc-linux-x64-gnu": "16.2.0", + "@next/swc-linux-x64-musl": "16.2.0", + "@next/swc-win32-arm64-msvc": "16.2.0", + "@next/swc-win32-x64-msvc": "16.2.0", + "sharp": "^0.34.5" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/node-releases": { + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/tailwind-merge": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.5.0.tgz", + "integrity": "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz", + "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 000000000..2d26b3a6c --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "aurora-next-web", + "version": "1.0.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "clsx": "^2.1.1", + "lucide-react": "^0.577.0", + "next": "^16.2.0", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "tailwind-merge": "^3.5.0" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4.2.2", + "@types/node": "^25.5.0", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "autoprefixer": "^10.4.27", + "postcss": "^8.5.8", + "tailwindcss": "^4.2.2", + "typescript": "^5.9.3" + } +} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 000000000..e5640725a --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,5 @@ +module.exports = { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; diff --git a/settings.gradle.kts b/settings.gradle.kts index 9b265199c..a415c9cab 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,9 +1,3 @@ -/* - * SPDX-FileCopyrightText: 2021-2025 Rahul Kumar Patel - * SPDX-FileCopyrightText: 2022-2025 The Calyx Institute - * SPDX-License-Identifier: GPL-3.0-or-later - */ - pluginManagement { repositories { gradlePluginPortal() @@ -16,20 +10,42 @@ dependencyResolutionManagement { repositories { google() mavenCentral() - // libsu is only available via jitpack maven("https://jitpack.io/") { content { includeModule("com.github.topjohnwu.libsu", "core") } } - // Only included in huawei variants - maven("https://developer.huawei.com/repo/") { - content { - includeGroup("com.huawei.hms") - includeGroup("com.huawei.android.hms") - } - } } } include(":app") -rootProject.name = "AuroraStore4" +include(":jmods:core-domain") +include(":jmods:core-data") +include(":jmods:core-network") +include(":jmods:core-auth") +include(":jmods:core-installer") +include(":jmods:core-navigation") +include(":jmods:core-database") +include(":jmods:core-ui") +include(":jmods:feature-home") +include(":jmods:feature-details") +include(":jmods:feature-categories") +include(":jmods:feature-search") +include(":jmods:feature-updates") +include(":jmods:app") + +project(":jmods:core-domain").projectDir = file("jmods-android/core-domain") +project(":jmods:core-data").projectDir = file("jmods-android/core-data") +project(":jmods:core-network").projectDir = file("jmods-android/core-network") +project(":jmods:core-auth").projectDir = file("jmods-android/core-auth") +project(":jmods:core-installer").projectDir = file("jmods-android/core-installer") +project(":jmods:core-navigation").projectDir = file("jmods-android/core-navigation") +project(":jmods:core-database").projectDir = file("jmods-android/core-database") +project(":jmods:core-ui").projectDir = file("jmods-android/core-ui") +project(":jmods:feature-home").projectDir = file("jmods-android/feature-home") +project(":jmods:feature-details").projectDir = file("jmods-android/feature-details") +project(":jmods:feature-categories").projectDir = file("jmods-android/feature-categories") +project(":jmods:feature-search").projectDir = file("jmods-android/feature-search") +project(":jmods:feature-updates").projectDir = file("jmods-android/feature-updates") +project(":jmods:app").projectDir = file("jmods-android/app") + +rootProject.name = "JMODS" diff --git a/tailwind.config.ts b/tailwind.config.ts new file mode 100644 index 000000000..d43da912d --- /dev/null +++ b/tailwind.config.ts @@ -0,0 +1,19 @@ +import type { Config } from "tailwindcss"; + +const config: Config = { + content: [ + "./pages/**/*.{js,ts,jsx,tsx,mdx}", + "./components/**/*.{js,ts,jsx,tsx,mdx}", + "./app/**/*.{js,ts,jsx,tsx,mdx}", + ], + theme: { + extend: { + colors: { + background: "var(--background)", + foreground: "var(--foreground)", + }, + }, + }, + plugins: [], +}; +export default config; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..abe252433 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,42 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": [ + "./*" + ] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/vercel.json b/vercel.json new file mode 100644 index 000000000..8ea0f21d0 --- /dev/null +++ b/vercel.json @@ -0,0 +1,5 @@ +{ + "framework": "nextjs", + "buildCommand": "npm run build", + "installCommand": "npm install" +}