commit 1a13c28a049cf8ae7f815e595748cf37ccd44d38 Author: S4NKALP Date: Mon Jun 30 04:54:24 2025 +0545 idk diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml new file mode 100644 index 0000000..e67b48a --- /dev/null +++ b/.github/workflows/gradle.yml @@ -0,0 +1,34 @@ +name: Last Launcher CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - uses: actions/cache@v2 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Compile with Gradle + run: ./gradlew assembleDebug + - uses: actions/upload-artifact@v2 + with: + name: lunox-debug.apk + path: app/build/outputs/apk/debug/*.apk diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d57e7f1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,102 @@ +# Built application files +*.apk +*.ap_ +*.ab_ + + + +app/src/release/*.json +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ + + +# Gradle files +.gradle/ +build/ + + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# IntelliJ +*.iml +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/assetWizardSettings.xml +.idea/dictionaries +.idea/libraries +.idea/caches +.idea/*.* +.idea/* +.idea/ +.idea/*.xml +.idea/copyright/ +.idea/copyright/* +.idea/copyright/profiles_settings.xml + + +# Keystore files +# Uncomment the following line if you do not want to check your keystore files in. +*.jks + + + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild + + +# Google Services (e.g. APIs or Firebase) +google-services.json +*.json + + + +# Freeline +freeline.py +freeline/ +freeline_project_description.json + +# fastlane +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output +fastlane/readme.md + + +# Zip file +*.zip +*.rar +*.gz +*.tz + + +#heap dump file +*.hprof +*.alloc + +#todo file +todo.txt + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 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 new file mode 100644 index 0000000..aeb3dfa --- /dev/null +++ b/README.md @@ -0,0 +1,109 @@ +# Lunox + +

+ Fast, minimal, and customizable single-page Android launcher
+ License + YouTube Demo +

+ +> **Note:** This is a maintained fork of the original [lastlauncher](https://github.com/SubhamTyagi/Last-Launcher.git) project by [Subham Tyagi](https://github.com/SubhamTyagi). All original contributions are credited to the author. This fork may include additional features, fixes, and updates. + +--- + +## 📖 Table of Contents +- [Introduction](#introduction) +- [Features](#features) +- [Build & Install](#build--install) +- [Screenshots](#screenshots) +- [To Do](#to-do) +- [Contributing](#contributing) +- [Third-party Libraries and Fonts](#third-party-libraries-and-fonts) +- [Credits](#credits) +- [License](#license) + +--- + +## Introduction +Lunox is a fast, simple, minimal, and highly customizable single-page Android launcher. Designed for speed and simplicity, Lunox offers a distraction-free experience with a focus on performance and usability. + +--- + +## ✨ Features +- ⚡ **Ultra-fast**: Lightning-quick app launches and smooth navigation. +- 🔋 **Low battery & CPU usage**: Optimized for efficiency. +- 🆓 **Free & Open Source**: No ads, no tracking, GPLv3 licensed. +- 🎨 **Material Design**: Clean, modern, and minimal interface. +- 🏷️ **Colorful app names**: Personalize your app list. +- 🔠 **Custom font selection**: Choose your favorite font. +- 🚫 **No icons or widgets**: Pure focus on your apps. +- 🌐 **Multilingual**: Community-driven translations. +- 📺 [See it in action](https://www.youtube.com/watch?v=SzhJgH4a2cU) + +--- + +## 🛠️ Build & Install + +1. **Clone the repository:** + ```bash + git clone https://github.com/S4NKALP/Lunox.git + cd Lunox + ``` +2. **Open in Android Studio:** + - Open the `Lunox` folder in Android Studio. + - Let Gradle sync and download dependencies. +3. **Build & Run:** + - Connect your Android device or start an emulator. + - Click **Run** or use `./gradlew assembleDebug` to build the APK. + +--- + +## 📸 Screenshots + +| Home (Light) | Home (Dark) | App List | Font Selection | +|:-:|:-:|:-:|:-:| +| ![Home](/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png?raw=true "Home Light") | ![Home](/fastlane/metadata/android/en-US/images/phoneScreenshots/2.jpg?raw=true "Home Dark") | ![Home](/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png?raw=true "App List") | ![Home](/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png?raw=true "Font Selection") | +| Customization | Search | Settings | About | +| ![Home](/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png?raw=true "Customization") | ![Home](/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png?raw=true "Search") | ![Home](/fastlane/metadata/android/en-US/images/phoneScreenshots/7.png?raw=true "Settings") | ![Home](/fastlane/metadata/android/en-US/images/phoneScreenshots/8.png?raw=true "About") | + +--- + +## 📝 To Do +- [ ] FlowLayout improvements +- [ ] Background colors + +--- + +## 🤝 Contributing + +Contributions, bug reports, and translations are welcome! + +- Fork the repository and create your branch. +- Make your changes with clear, well-commented code. +- Submit a pull request. +- For translations, edit the relevant `strings.xml` in the `res/values-XX/` folders. +- For issues or feature requests, open a [GitHub Issue](https://github.com/S4NKALP/Lunox/issues). + +--- + +## 📚 Third-party Libraries and Fonts + +### Android Libraries +- [android-flowlayout](https://github.com/ApmeM/android-flowlayout) by [Artem.Votincev](https://github.com/ApmeM) ([Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0)) +- [ColorSeekBar](https://github.com/rtugeek/ColorSeekBar) by [Jack Fu](https://github.com/rtugeek) ([WTFPL](http://www.wtfpl.net/)) + +### Fonts +- [Raleway fonts](https://github.com/impallari/Raleway/) by [Pablo Impallari](https://github.com/impallari) ([SIL Open Font License, Version 1.1](http://scripts.sil.org/OFL)) + +--- + +## 📜 Credits + +This project is a fork of the original work by [Subham Tyagi](https://github.com/SubhamTyagi). All original contributions are credited to the author. + +--- + +## 📝 License + +This project is licensed under the terms of the GNU General Public License v3.0 (GPLv3). All modifications and redistributed versions remain under the same license. + +See [LICENSE](LICENSE) for details. diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..956c004 --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,2 @@ +/build +/release \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..07b837e --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,89 @@ +apply plugin: 'com.android.application' + + +android { + compileSdkVersion 29 + buildToolsVersion "35.0.1" + + defaultConfig { + applicationId "io.github.sankalp.lunox" + minSdkVersion 14 + targetSdkVersion 29 + versionCode 19 + versionName "0.19" + //resConfigs "en", "de" + buildConfigField "boolean", "enableColorSniffer", "false" + } + buildTypes { + debug { + def workingBranch = getGitWorkingBranch() + def normalizedWorkingBranch = workingBranch.replaceFirst("^[^A-Za-z]+", "").replaceAll("[^0-9A-Za-z]+", "") + if (normalizedWorkingBranch.isEmpty() || workingBranch == "master" ) { + applicationIdSuffix ".debug" + resValue "string", "app_name", "Last Launcher Dev" + } else { + archivesBaseName = 'Last_Launcher_' + normalizedWorkingBranch + applicationIdSuffix ".debug." + normalizedWorkingBranch + resValue "string", "app_name", "Last Launcher-" + workingBranch + } + + debuggable true + jniDebuggable true + versionNameSuffix "-debug" + minifyEnabled false + shrinkResources false + + } + release { + debuggable false + jniDebuggable false + minifyEnabled true + shrinkResources true + zipAlignEnabled true + resValue "string", "app_name", "Last Launcher" + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + lintOptions { + checkReleaseBuilds false + abortOnError false + } + + applicationVariants.all { variant -> + variant.outputs.all { + def date = new Date() + def formattedDate = date.format('yyyyMMddHHmmss') + outputFileName = "Last-Launcher-${variant.name}-${variant.versionName}-${formattedDate}.apk" + } + } + packagingOptions { + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':flowlayout:layouts') + debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.2' +} + +static String getGitWorkingBranch() { + try { + def gitProcess = "git rev-parse --abbrev-ref HEAD".execute() + gitProcess.waitFor() + if (gitProcess.exitValue() == 0) { + return gitProcess.text.trim() + } else { + // .git folder not present + return "" + } + } catch (IOException ignored) { + // git is not installed + return "" + } +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..8df5800 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,24 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in C:\Android\sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +-optimizationpasses 3 +-dontpreverify +-repackageclasses +-allowaccessmodification +-mergeinterfacesaggressively +-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*,method/inlining/short,class/merging/horizontal,class/merging/vertical \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..1944332 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/assets/fonts/raleway_bold.ttf b/app/src/main/assets/fonts/raleway_bold.ttf new file mode 100644 index 0000000..d4110f0 Binary files /dev/null and b/app/src/main/assets/fonts/raleway_bold.ttf differ diff --git a/app/src/main/ic_launcher-web.png b/app/src/main/ic_launcher-web.png new file mode 100644 index 0000000..0253f2c Binary files /dev/null and b/app/src/main/ic_launcher-web.png differ diff --git a/app/src/main/java/io/github/sankalp/lunox/LauncherActivity.java b/app/src/main/java/io/github/sankalp/lunox/LauncherActivity.java new file mode 100644 index 0000000..3228ec8 --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/LauncherActivity.java @@ -0,0 +1,1317 @@ +/* + * Last Launcher + * Copyright (C) 2019,2020 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox; + +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.app.Activity; +import android.app.Dialog; +import android.content.BroadcastReceiver; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.graphics.Color; +import android.graphics.Typeface; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Build; +import android.os.Bundle; +import android.os.ParcelFileDescriptor; +import android.os.PowerManager; +import android.text.Editable; +import android.text.SpannableString; +import android.text.TextWatcher; +import android.text.style.ForegroundColorSpan; +import android.util.ArrayMap; +import android.view.ContextThemeWrapper; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; +import android.view.Window; +import android.view.WindowManager; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.PopupMenu; +import android.widget.TextView; +import android.widget.Toast; + +import org.apmem.tools.layouts.FlowLayout; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + +import io.github.sankalp.lunox.dialogs.ColorSizeDialog; +import io.github.sankalp.lunox.dialogs.FrozenAppsDialogs; +import io.github.sankalp.lunox.dialogs.GlobalColorSizeDialog; +import io.github.sankalp.lunox.dialogs.GlobalSettingsDialog; +import io.github.sankalp.lunox.dialogs.HiddenAppsDialogs; +import io.github.sankalp.lunox.dialogs.PaddingDialog; +import io.github.sankalp.lunox.dialogs.RenameInputDialogs; +import io.github.sankalp.lunox.model.Apps; +import io.github.sankalp.lunox.model.Shortcut; +import io.github.sankalp.lunox.utils.CrashUtils; +import io.github.sankalp.lunox.utils.DbUtils; +import io.github.sankalp.lunox.utils.DeviceAdminManager; +import io.github.sankalp.lunox.utils.Gestures; +import io.github.sankalp.lunox.utils.ShortcutUtils; +import io.github.sankalp.lunox.utils.Utils; +import io.github.sankalp.lunox.views.textview.AppTextView; + +import static android.content.Intent.ACTION_PACKAGE_ADDED; +import static android.content.Intent.ACTION_PACKAGE_CHANGED; +import static android.content.Intent.ACTION_PACKAGE_REMOVED; +import static android.content.Intent.ACTION_PACKAGE_REPLACED; +import static io.github.sankalp.lunox.utils.Constants.BACKUP_REQUEST; +import static io.github.sankalp.lunox.utils.Constants.COLOR_SNIFFER_REQUEST; +import static io.github.sankalp.lunox.utils.Constants.DEFAULT_COLOR_FOR_APPS; +import static io.github.sankalp.lunox.utils.Constants.DEFAULT_TEXT_SIZE_NORMAL_APPS; +import static io.github.sankalp.lunox.utils.Constants.DEFAULT_TEXT_SIZE_OFTEN_APPS; +import static io.github.sankalp.lunox.utils.Constants.FONTS_REQUEST; +import static io.github.sankalp.lunox.utils.Constants.RESTORE_REQUEST; +import static io.github.sankalp.lunox.utils.Constants.SORT_BY_COLOR; +import static io.github.sankalp.lunox.utils.Constants.SORT_BY_NAME; +import static io.github.sankalp.lunox.utils.Constants.SORT_BY_OPENING_COUNTS; +import static io.github.sankalp.lunox.utils.Constants.SORT_BY_RECENT_OPEN; +import static io.github.sankalp.lunox.utils.Constants.SORT_BY_SIZE; +import static io.github.sankalp.lunox.utils.Constants.SORT_BY_UPDATE_TIME; + +/** + * -------------------------------------------------------------------------- + * People can criticise me all the time they want, + * by this is what I am and I won't change the way I live for them. + * I live the way I want to flow. + * ------------------------------------------------------------------------- + * - + * If we don't transform the world, who will? If not now, when? + * If you have something to give, give it now + * - + * Do your little bit of good where you are; + * it's those little bits of good put together that overwhelm the world." + * - + * Don't just think, do it. Now it is you turn, do it now, go fast and open pull request + * - + * ---------------------------------------------------------------------------- + * This Activity extends the api 14 Activity Class not latest AppCompatActivity + * Reason: Small apk size + */ +@SuppressLint("NonConstantResourceId") +public class LauncherActivity extends Activity implements View.OnClickListener, + View.OnLongClickListener, + Gestures.OnSwipeListener { + + + //region Field declarations + public static ArrayList mAppsList; + // home layout + private static FlowLayout mHomeLayout; + // when search bar is appear this will be true and show search result + private static boolean searching = false; + //todo: save this to db + private static int recentlyUsedCounter = 0; + private final String TAG = "LauncherActivity"; + // broadcast receiver + private BroadcastReceiver broadcastReceiverAppInstall; + private BroadcastReceiver broadcastReceiverShortcutInstall; + private Typeface mTypeface; + //multi dialogs + private Dialog dialogs; + //search box + private EditText mSearchBox; + + private InputMethodManager imm; + // gesture detector + private Gestures detector; + private ShortcutUtils shortcutUtils; + + private static final TextWatcher mTextWatcher= new TextWatcher() { + + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { + mSearchTask=new SearchTask(); + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { + //do here search + mSearchTask.execute(charSequence); + } + + @Override + public void afterTextChanged(Editable editable) { + + // do everything + } + }; + private static SearchTask mSearchTask; + //endregion + + private static void showSearchResult(ArrayList filteredApps) { + if (!searching) return; + + mHomeLayout.removeAllViews(); + mHomeLayout.setPadding(0, 150, 0, 0); + /*//sort the apps alphabetically + Collections.sort(filteredApps, (a, b) -> String.CASE_INSENSITIVE_ORDER.compare( + a.getAppName(), + b.getAppName() + ));*/ + for (Apps apps : filteredApps) { + mHomeLayout.addView(apps.getTextView(), new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + } + + + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + //pass touch event to detector + detector.onTouchEvent(ev); + return super.dispatchTouchEvent(ev); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // initialize the shared prefs may be done in application class + DbUtils.init(this); + shortcutUtils = new ShortcutUtils(this); + + if (BuildConfig.DEBUG) { + new CrashUtils(getApplicationContext(), ""); + } + + int theme = DbUtils.getTheme(); + //theme must be set before setContentView + setTheme(theme); + + setContentView(R.layout.activity_launcher); + + // set the status bar color as per theme + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + setNavigationAndStatusBarColor(theme); + } + // set the fonts + setFont(); + + mHomeLayout = findViewById(R.id.home_layout); + mHomeLayout.setOnLongClickListener(this); + + imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + + //our search box + mSearchBox = findViewById(R.id.search_box); + //setup listeners on mSearchBox + setSearchBoxListeners(); + + //set alignment default is center|center_vertical + mHomeLayout.setGravity(DbUtils.getFlowLayoutAlignment()); + + //set padding .. + mHomeLayout.setPadding(DbUtils.getPaddingLeft(), DbUtils.getPaddingTop(), DbUtils.getPaddingRight(), DbUtils.getPaddingBottom()); + + detector = new Gestures(this, this); + + // initGestures(); + + // loads the apps + loadApps(); + // register the receiver for installed, uninstall, update apps and shortcut pwa add + registerForReceivers(); + + } + + private void setSearchBoxListeners() { + mSearchBox.addTextChangedListener(mTextWatcher); + mSearchBox.setOnEditorActionListener((v, actionId, event) -> { + if (actionId == EditorInfo.IME_ACTION_DONE) { + mSearchBox.setVisibility(View.GONE); + imm.hideSoftInputFromWindow(mSearchBox.getWindowToken(), 0); + //do something on clicking enter + return true; + } + return false; + }); + } + + /** + * set the color of status bar and navigation bar as per theme + * if theme color is light then pass this to system so status icon color will turn into black + * + * @param theme current theme applied to launcher + */ + + @TargetApi(Build.VERSION_CODES.KITKAT) + private void setNavigationAndStatusBarColor(int theme) { + + getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); + // getWindow().setNavigationBarColor(getResources().getColor(android.R.color.transparent)); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + switch (theme) { + case R.style.White: + case R.style.WhiteOnGrey: + case R.style.BlackOnGrey: { + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + } + } + } + } + + public void setFont() { + // get and set fonts + String fontsPath = DbUtils.getFonts(); + if (fontsPath == null) { + mTypeface = Typeface.createFromAsset(getAssets(), "fonts/raleway_bold.ttf"); + } else { + try { + mTypeface = Typeface.createFromFile(fontsPath); + } catch (Exception i) { + mTypeface = Typeface.createFromAsset(getAssets(), "fonts/raleway_bold.ttf"); + } + } + + } + + public void loadApps() { + // get the apps installed on devices; + final Intent startupIntent = new Intent(Intent.ACTION_MAIN, null); + startupIntent.addCategory(Intent.CATEGORY_LAUNCHER); + + PackageManager pm = getPackageManager(); + List activities = pm.queryIntentActivities(startupIntent, 0); + + // check whether our app list is already initialized if yes then clear this(when new app or shortcut installed) + if (mAppsList != null) { + mAppsList.clear(); + mHomeLayout.removeAllViews(); + mHomeLayout.removeAllViewsInLayout(); + } + + // shortcut or pwa counts + final int installedShortcut = shortcutUtils.getShortcutCounts(); + + // Log.d(TAG, "loadApps: install shortcut sizes::" + installedShortcut); + final int appsCount = activities.size(); + + mAppsList = new ArrayList<>(appsCount + installedShortcut); + + // get the most used apps + // a list of app that are popular on f-droid and some of my apps + List oftenApps = Utils.getOftenAppsList(); + List coloredAppsList = Utils.getColoredAppsList(); + + String packageName, appName; + int color, textSize; + boolean hide; + // iterate over each app and initialize app list + for (ResolveInfo resolveInfo : activities) { + + packageName = resolveInfo.activityInfo.packageName; + // activity name as com.example/com.example.MainActivity + String activity = packageName + "/" + resolveInfo.activityInfo.name; + /// save the app original name so that we can use this later e.g if user change + /// the app name then we have the name in DB + DbUtils.putAppOriginalName(activity, resolveInfo.loadLabel(pm).toString()); + // check whether user set the custom app name for eg. long name to small name + appName = DbUtils.getAppName(activity, resolveInfo.loadLabel(pm).toString()); + // is app is hidden by user + hide = DbUtils.isAppHidden(activity); + // get the app text size + textSize = DbUtils.getAppSize(activity); + + // check if text size is null then set the size to default size + // size is null(-1) when user installed this app + if (textSize == DbUtils.NULL_TEXT_SIZE) { + if (oftenApps.contains(packageName)) { + textSize = DEFAULT_TEXT_SIZE_OFTEN_APPS; + } else { + textSize = DEFAULT_TEXT_SIZE_NORMAL_APPS; + } + + /// DbUtils.putAppSize(activity, textSize); + } + + // get app color + color = DbUtils.getAppColor(activity); + + /*Drawable icon = null; + try { + icon = getPackageManager().getApplicationIcon(packageName); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + color= Utils.getDominantColor(Utils.drawableToBitmap(icon));*/ + + + // check for default color : set default colors if random color is not set + if (!DbUtils.isRandomColor() && color == DbUtils.NULL_TEXT_COLOR) { + color = DbUtils.getAppsColorDefault(); + if (coloredAppsList.contains(packageName)) { + color = Utils.getColor(); + } + + } + // whether app size is frozen + boolean freeze = DbUtils.isAppFrozen(activity); + + // this is a separate implementation of ColorSniffer app + // if User set the color from external app like ColorSniffer + // then use that colors + if (BuildConfig.enableColorSniffer) { + if (DbUtils.isExternalSourceColor() && color == DbUtils.NULL_TEXT_COLOR) { + color = DbUtils.getAppColorExternalSource(activity); + } + } else if (DbUtils.isRandomColor() && color == DbUtils.NULL_TEXT_COLOR) { + color = Utils.generateColorFromString(appName); + } + + + int openingCounts = DbUtils.getOpeningCounts(activity); + + int updateTime; + try { + //ApplicationInfo appInfo = pm.getApplicationInfo(packageName, 0); + long time = pm.getPackageInfo(packageName, 0).lastUpdateTime; + time = time / 10000; + updateTime = (int) time; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + updateTime = 0; + } + // save all and add this is to app list + mAppsList.add(new Apps(false, activity, appName, getCustomView(), color, textSize, hide, freeze, openingCounts, updateTime)); + + } + + // now adds Shortcut + // shortcut are stored in DB, android doesn't store them + + ArrayList shortcuts = shortcutUtils.getAllShortcuts(); + if (shortcuts != null) { + for (Shortcut s : shortcuts) { + + // shortcut only have URI + String uri = s.getUri(); + // shortcut name + String sName = s.getName(); + + /* if (uri.isEmpty()) { + ++installedShortcut; + continue; + }*/ + + + // this is the unique code for each uri + // let store them in activity field app + // As we have to store some uniquely identified info in Db + // this be used as key as i have done for Each apps(see above) + // Usually URI sting is too long and so it will take more memory and storage + String sActivity = String.valueOf(Utils.hash(uri)); + + // get color and size for this shortcut + int sColor = DbUtils.getAppColor(sActivity); + int sSize = DbUtils.getAppSize(sActivity); + + if (sSize == DbUtils.NULL_TEXT_SIZE) { + sSize = DEFAULT_TEXT_SIZE_NORMAL_APPS; + } + + if (sColor == DbUtils.NULL_TEXT_COLOR) { + if (DbUtils.isRandomColor()) { + sColor = Utils.generateColorFromString(sName); + } else { + sColor = DbUtils.getAppsColorDefault(); + } + } + + boolean sFreeze = DbUtils.isAppFrozen(sActivity); + int sOpeningCount = DbUtils.getOpeningCounts(sActivity); + + // add this shortcut to list + // currently shortcut hide is disabled + mAppsList.add(new Apps(true, uri, sName, getCustomView(), sColor, sSize, false, sFreeze, sOpeningCount, 0)); + + } + } + + // now sort the app list + // and display this + sortApps(DbUtils.getSortsTypes()); + } + + /** + * @param type sorting type + */ + public void sortApps(final int type) { + new SortTask().execute(type); + } + + // the text view and set the various parameters + //TODO: new animated field for this(test randomly) + private AppTextView getCustomView() { + // AnimatedTextView textView=new AnimatedTextView(this); + // textView.setColorSpace(15); + AppTextView textView = new AppTextView(this); + textView.setOnClickListener(this); + textView.setOnLongClickListener(this); + textView.setPadding(10, 0, 4, -2); + textView.setTypeface(mTypeface); + return textView; + } + + // app text is clicked + // so launch the app + @Override + public void onClick(View view) { + if (view instanceof AppTextView) { + + // get the activity + String activity = (String) view.getTag(); + AppTextView appTextView = (AppTextView) view; + + if (searching) { + InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(mSearchBox.getWindowToken(), 0); + mSearchBox.setVisibility(View.GONE); + } + + if (appTextView.isShortcut()) { + try { + Intent intent = Intent.parseUri(appTextView.getUri(), 0); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); + appOpened(activity); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + //Notes to me:if view store package and component name then this could reduce this splits + String[] strings = activity.split("/"); + try { + final Intent intent = new Intent(Intent.ACTION_MAIN, null); + intent.setClassName(strings[0], strings[1]); + intent.setComponent(new ComponentName(strings[0], strings[1])); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); + // tell the our db that app is opened + appOpened(activity); + } catch (Exception ignore) { + // Log.e(TAG, "onClick: exception:::" + ignore); + } + } + + } + } + + @Override + protected void onResume() { + super.onResume(); + + if (searching) { + mSearchBox.setVisibility(View.GONE); + searching = false; + imm.hideSoftInputFromWindow(mSearchBox.getWindowToken(), 0); + mHomeLayout.setPadding(DbUtils.getPaddingLeft(), DbUtils.getPaddingTop(), DbUtils.getPaddingRight(), DbUtils.getPaddingBottom()); + sortApps(DbUtils.getSortsTypes()); + } + } + + @Override + protected void onStop() { + super.onStop(); + + if (dialogs != null) { + dialogs.dismiss(); + dialogs = null; + } + + if (mSearchTask!=null) { + mSearchTask.cancel(true); + mSearchTask=null; + } + } + + //show the option on long click + @Override + public boolean onLongClick(View view) { + if (view instanceof AppTextView) { + // show app setting + showPopup((String) view.getTag(), (AppTextView) view); + } else if (view instanceof FlowLayout) { + // show launcher setting + dialogs = new GlobalSettingsDialog(this, this); + dialogs.show(); + } + return true; + } + + private void showPopup(String activityName, AppTextView view) { + + Context context; + // set theme + // if theme wallpaper ie transparent then we have to show other theme + if (DbUtils.getTheme() == R.style.Wallpaper) + context = new ContextThemeWrapper(this, R.style.AppTheme); + else + context = new ContextThemeWrapper(this, DbUtils.getTheme()); + + PopupMenu popupMenu = new PopupMenu(context, view); + popupMenu.getMenuInflater().inflate(R.menu.menu, popupMenu.getMenu()); + + + int color = Color.parseColor("#E53935"); + + SpannableString s = new SpannableString(getString(R.string.hide)); + + s.setSpan(new ForegroundColorSpan(color), 0, s.length(), 0); + popupMenu.getMenu().findItem(R.id.menu_hide).setTitle(s); + + s = new SpannableString(getString(R.string.uninstall)); + s.setSpan(new ForegroundColorSpan(color), 0, s.length(), 0); + popupMenu.getMenu().findItem(R.id.menu_uninstall).setTitle(s); + + s = new SpannableString(getString(R.string.reset_to_default)); + s.setSpan(new ForegroundColorSpan(color), 0, s.length(), 0); + popupMenu.getMenu().findItem(R.id.menu_reset_to_default).setTitle(s); + + + // set proper item based on Db value + if (DbUtils.isAppFrozen(activityName)) { + popupMenu.getMenu().findItem(R.id.menu_freeze_size).setTitle(R.string.unfreeze_size); + } + + //disable some item for shortcut + // and change the uninstall to remove + if (view.isShortcut()) { + + SpannableString s1 = new SpannableString(getString(R.string.remove)); + s1.setSpan(new ForegroundColorSpan(Color.parseColor("#E53935")), 0, s1.length(), 0); + popupMenu.getMenu().findItem(R.id.menu_uninstall).setTitle(s1); + + popupMenu.getMenu().findItem(R.id.menu_hide).setVisible(false); + //renaming is also disabled; + // consider it later + popupMenu.getMenu().findItem(R.id.menu_rename).setVisible(false); + popupMenu.getMenu().findItem(R.id.menu_app_info).setVisible(false); + } + + popupMenu.setOnMenuItemClickListener(menuItem -> { + switch (menuItem.getItemId()) { + case R.id.menu_color: + changeColorSize(activityName, view); + break; + case R.id.menu_rename: + renameApp(activityName, view.getText().toString()); + break; + case R.id.menu_freeze_size: + freezeAppSize(activityName); + break; + case R.id.menu_hide: + hideApp(activityName); + break; + case R.id.menu_uninstall: + if (view.isShortcut()) { + removeShortcut(view); + } else { + uninstallApp(activityName); + } + break; + case R.id.menu_app_info: + showAppInfo(activityName); + break; + case R.id.menu_reset_to_default: + resetApp(activityName); + break; + case R.id.menu_reset_color: + resetAppColor(activityName); + break; + + default: + return true; + } + return true; + }); + // not forget to show popup + popupMenu.show(); + } + + //reset the app color to default color; + private void resetAppColor(String activityName) { + DbUtils.removeColor(activityName); + boolean sortNeeded = (DbUtils.getSortsTypes() == SORT_BY_COLOR); + addAppAfterReset(activityName, sortNeeded); + } + + // add a new app: generally called after reset + private void addAppAfterReset(String activityName, boolean sortNeeded) { + for (ListIterator iterator = mAppsList.listIterator(); iterator.hasNext(); ) { + Apps app = iterator.next(); + if (app.getActivityName().equalsIgnoreCase(activityName)) { + iterator.remove(); + //now add new App + int color; + if (DbUtils.isRandomColor()) { + color = Utils.generateColorFromString(activityName); + } else { + color = DbUtils.getAppsColorDefault(); + } + String appOriginalName = DbUtils.getAppOriginalName(activityName, ""); + String appName = DbUtils.getAppName(activityName, appOriginalName); + int openingCounts = DbUtils.getOpeningCounts(activityName); + boolean hide = app.isHidden(); + boolean freezeSize = app.isSizeFrozen(); + int appUpdateTime = app.getUpdateTime(); + Apps newApp = new Apps(app.isShortcut(), activityName, appName, getCustomView(), color, DEFAULT_TEXT_SIZE_NORMAL_APPS, hide, freezeSize, openingCounts, appUpdateTime); + + //mAppsList.add(newApp); + iterator.add(newApp); + if (sortNeeded) + sortApps(DbUtils.getSortsTypes()); + break; + } + } + } + + // as method name suggest + private void freezeAppSize(String activityName) { + boolean b = DbUtils.isAppFrozen(activityName); + for (Apps apps : mAppsList) { + if (activityName.equalsIgnoreCase(apps.getActivityName())) { + apps.setFreeze(!b); + } + } + + } + + // as method name suggest + private void hideApp(String activityName) { + for (Apps apps : mAppsList) { + if (activityName.equalsIgnoreCase(apps.getActivityName())) { + apps.setAppHidden(true); + } + } + + } + + // show the app rename Dialog + private void renameApp(String activityName, String appName) { + dialogs = new RenameInputDialogs(this, activityName, appName, this); + Window window = dialogs.getWindow(); + if (window != null) { + window.setGravity(Gravity.BOTTOM); + window.setBackgroundDrawableResource(android.R.color.transparent); + window.setLayout(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); + } + + dialogs.show(); + + } + + // this is called by RenameInput.class Dialog when user set the name and sort the apps + public void onAppRenamed(String activityName, String appNewName) { + for (Apps app : mAppsList) { + if (app.getActivityName().equalsIgnoreCase(activityName)) { + app.setAppName(appNewName.trim()); + if (SORT_BY_NAME == DbUtils.getSortsTypes()) { + sortApps(SORT_BY_NAME); + } + break; + } + } + } + + // reset the app + private void resetApp(String activityName) { + DbUtils.removeAppName(activityName); + DbUtils.removeColor(activityName); + DbUtils.removeSize(activityName); + addAppAfterReset(activityName, true); + } + + private void showAppInfo(String activityName) { + Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse("package:" + activityName.split("/")[0])); + startActivity(intent); + } + + private void uninstallApp(String activityName) { + Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE); + intent.setData(Uri.parse("package:" + activityName.split("/")[0])); + intent.putExtra(Intent.EXTRA_RETURN_RESULT, true); + startActivityForResult(intent, 97); + } + + //show dialog(i.e a color seek bar) for change color + private void changeColorSize(String activityName, TextView view) { + int color = DbUtils.getAppColor(activityName); + if (color == DbUtils.NULL_TEXT_COLOR) { + color = view.getCurrentTextColor(); + } + + int size = DbUtils.getAppSize(activityName); + if (size == DbUtils.NULL_TEXT_SIZE) { + for (Apps apps : mAppsList) { + if (apps.getActivityName().equals(activityName)) { + size = apps.getSize(); + break; + } + } + } + dialogs = new ColorSizeDialog(this, activityName, color, view, size); + + Window window = dialogs.getWindow(); + if (window != null) { + window.setGravity(Gravity.BOTTOM); + window.setBackgroundDrawableResource(android.R.color.transparent); + window.setLayout(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); + } + + + dialogs.show(); + } + + //TO1DO: multi thread check for memory leaks if any, or check any bad behaviour; + private void appOpened(String activity) { + /* new Thread() { + @Override + public void run() { + super.run();*/ + for (Apps apps : mAppsList) { + if (apps.getActivityName().equalsIgnoreCase(activity)) { + apps.increaseOpeningCounts();// save to Db that app is opened by user + recentlyUsedCounter++; + apps.setRecentUsedWeight(recentlyUsedCounter); + + if (DbUtils.getSortsTypes() == SORT_BY_OPENING_COUNTS) { + int counter = apps.getOpeningCounts(); + if (counter % 5 == 0) { + sortApps(SORT_BY_OPENING_COUNTS); + } + } else if (DbUtils.getSortsTypes() == SORT_BY_RECENT_OPEN) { + sortApps(SORT_BY_RECENT_OPEN); + } + + // increase the app view size if not frozen + if (!DbUtils.isSizeFrozen() && !DbUtils.isAppFrozen(activity)) { + int size = DbUtils.getAppSize(activity); + size += 2; + apps.setSize(size); + if (DbUtils.getSortsTypes() == SORT_BY_SIZE) { + sortApps(SORT_BY_SIZE); + } + } + + + break; + } + } + /* } + }.start();*/ + } + + @Override + public void onBackPressed() { + mSearchBox.setVisibility(View.GONE); + + if (searching) { + //check this line + imm.hideSoftInputFromWindow(mSearchBox.getWindowToken(), 0); + + searching = false; + if (mSearchTask!=null) { + mSearchTask.cancel(true); + mSearchTask=null; + } + mHomeLayout.setPadding(DbUtils.getPaddingLeft(), DbUtils.getPaddingTop(), DbUtils.getPaddingRight(), DbUtils.getPaddingBottom()); + sortApps(DbUtils.getSortsTypes()); + } + } + + // register the receiver + // when new app installed, app updated and app uninstalled launcher have to reflect it + private void registerForReceivers() { + /*if (broadcastReceiverShortcutInstall!=null){ + unregisterReceiver(broadcastReceiverShortcutInstall); + } + if (broadcastReceiverAppInstall!=null){ + unregisterReceiver(broadcastReceiverAppInstall); + }*/ + //app install and uninstall receiver + + // Log.d("WTF", "registerForReceivers: called "); + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(ACTION_PACKAGE_ADDED); + intentFilter.addAction(ACTION_PACKAGE_CHANGED); + intentFilter.addAction(ACTION_PACKAGE_REMOVED); + intentFilter.addAction(ACTION_PACKAGE_REPLACED); + intentFilter.addDataScheme("package"); + if (broadcastReceiverAppInstall == null) { + broadcastReceiverAppInstall = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + loadApps(); + } + }; + registerReceiver(broadcastReceiverAppInstall, intentFilter); + } + + //shortcut install receiver + IntentFilter filter = new IntentFilter(); + filter.addAction("com.android.launcher.action.INSTALL_SHORTCUT"); + filter.addAction("com.android.launcher.action.CREATE_SHORTCUT"); + + if (broadcastReceiverShortcutInstall == null) { + broadcastReceiverShortcutInstall = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Intent shortcutIntent = intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT); + String uri = shortcutIntent.toUri(0); + if (shortcutIntent.getAction() == null) { + shortcutIntent.setAction(Intent.ACTION_VIEW); + + } + String name = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME); + + if (shortcutUtils.isShortcutToApp(uri)) { + return; + } + + if (!shortcutUtils.isShortcutAlreadyAvailable(name)) { + addShortcut(uri, name); + } + } + }; + registerReceiver(broadcastReceiverShortcutInstall, filter); + } + + } + + // unregister the receivers on destroy + @Override + protected void onDestroy() { + super.onDestroy(); + + if (dialogs != null) { + dialogs.dismiss(); + dialogs = null; + } + + if (mSearchTask!=null) { + mSearchTask.cancel(true); + mSearchTask=null; + } + + if (imm!=null){ + if(imm.isActive()){ + imm.hideSoftInputFromWindow(mSearchBox.getWindowToken(), 0); + } + imm=null; + } + + unregisterReceiver(broadcastReceiverAppInstall); + unregisterReceiver(broadcastReceiverShortcutInstall); + broadcastReceiverAppInstall = null; + broadcastReceiverShortcutInstall = null; + shortcutUtils.close(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode != Activity.RESULT_OK) return; + // restore request + switch (requestCode) { + + case RESTORE_REQUEST: + + Uri uri = data.getData(); + ContentResolver cr = getContentResolver(); + try { + boolean b = DbUtils.loadDbFromFile(cr.openInputStream(uri)); + if (b) { + recreate(); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + break; + + case FONTS_REQUEST: + + try { + + /* String[] projection = {MediaStore.Images.Media.DATA}; + Cursor cursor = getContentResolver().query(data.getData(), projection, null, null, null); + int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + cursor.moveToFirst(); + String path = cursor.getString(column_index); + cursor.close();*/ + ///new + Uri uri1 = data.getData(); + ContentResolver cr1 = getContentResolver(); + + File fontFile = new File(getFilesDir(), "font.ttf"); + try (InputStream inputFontStream = cr1.openInputStream(uri1); + OutputStream out = new FileOutputStream(fontFile);) { + byte[] buf = new byte[1024]; + int len; + while ((len = inputFontStream.read(buf)) > 0) { + out.write(buf, 0, len); + } + } catch (IOException ioe) { + ioe.printStackTrace(); + } + + String path = fontFile.getPath(); + //Log.i(TAG, "onActivityResult: " + path); + mTypeface = Typeface.createFromFile(path); + DbUtils.setFonts(path); + loadApps(); + } catch (Exception i) { + //i.printStackTrace(); + mTypeface = Typeface.createFromAsset(getAssets(), "fonts/raleway_bold.ttf"); + } + break; + + case BACKUP_REQUEST: + + Uri uri2 = data.getData(); + ObjectOutputStream output = null; + try { + ParcelFileDescriptor pfd = this.getContentResolver().openFileDescriptor(uri2, "w"); + FileOutputStream fileOutputStream = new FileOutputStream(pfd.getFileDescriptor()); + output = new ObjectOutputStream(fileOutputStream); + output.writeObject(DbUtils.getDBData()); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (output != null) { + output.flush(); + output.close(); + } + } catch (IOException ex) { + ex.printStackTrace(); + } + } + break; + + + case COLOR_SNIFFER_REQUEST: + + colorSnifferCall(data.getBundleExtra("color_bundle")); + + break; + } + + } + + //may be override of abstract class method to be called from color sniffer #3 types + public void colorSnifferCall(Bundle bundle) { + boolean defaultColorSet = false;// for change set + final int DEFAULT_COLOR = bundle.getInt(DEFAULT_COLOR_FOR_APPS);//keys + // not set by ColorSniffer + if (DEFAULT_COLOR != DbUtils.NULL_TEXT_COLOR) { //NULL_TEXT_COLOR=-1 + defaultColorSet = true;// to save cpu cycle + } + + // get each value as proposed by Color Sniffer App developer + for (Apps apps : mAppsList) { + TextView textView = apps.getTextView(); + String appPackage = apps.getActivityName(); + int color = bundle.getInt(appPackage); + if (color != DbUtils.NULL_TEXT_COLOR) { + textView.setTextColor(color); + DbUtils.putAppColorExternalSource(appPackage, color); + // DbUtils.putAppColor(appPackage, color); + } else if (defaultColorSet) { + //set default color + DbUtils.putAppColor(appPackage, DEFAULT_COLOR); + textView.setTextColor(DEFAULT_COLOR); + }//else do nothing theme default color will apply + } + } + + //Clipboard manager + public Map clipboardData() { + Map result = null; + // Log.d(TAG, "clipboardData: "); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + try { + ClipboardManager clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clipData = clipboardManager.getPrimaryClip(); + if (clipData.getItemCount() > 0) { + ClipData.Item item = clipData.getItemAt(0); + String tabSeparatedData = item.getText().toString(); + + //validate tab Separated Data and get its data + //unique id bae73ae068dacc6cb659d1fb231e7b11 i.e lunox-ColorSniffer MD5-128 + + String[] line = tabSeparatedData.split("\n");//get each line + + Map colorsAndId = new ArrayMap<>(); // map to put all values in key and values format + // iterate over every line + for (String entry : line) { + String[] activityIdAndColor = entry.split("\t");// split line into id and color + int color = Color.parseColor(activityIdAndColor[1]); + colorsAndId.put(activityIdAndColor[0], color);// put id and color to map + + } + setAppsColorFromClipboard(colorsAndId); + result = colorsAndId;// return map + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + // return empty null/ + return result; + } + + private void setAppsColorFromClipboard(Map colorsAndId) { + if (colorsAndId == null) return; + DbUtils.externalSourceColor(true); + for (Apps apps : mAppsList) { + try { + TextView textView = apps.getTextView(); + String s = apps.getActivityName(); + Integer newColor = colorsAndId.get(s); + if (newColor == null) continue; + textView.setTextColor(newColor); + DbUtils.putAppColorExternalSource(s, newColor); + } catch (NullPointerException ignore) { + + } + } + } + + // show the hidden app dialog + public void showHiddenApps() { + HiddenAppsDialogs dialogs = new HiddenAppsDialogs(this, mAppsList); + if (dialogs.updateHiddenList() != 0) { + dialogs.show(); + } else { + //TODO: show no hidden apps + Toast tst = Toast.makeText(this, "No apps to show", Toast.LENGTH_SHORT); + TextView tv = (TextView) tst.getView().findViewById(android.R.id.message); + tv.setTextColor(Color.parseColor("#d5e0e2")); + tst.show(); + + } + } + + // show the frozen app dialog + public void showFrozenApps() { + FrozenAppsDialogs dialogs = new FrozenAppsDialogs(this, mAppsList); + if (dialogs.updateFrozenList() != 0) { + dialogs.show(); + } else { + //TODO: show no frozen apps + Toast tst = Toast.makeText(this, "No apps to show", Toast.LENGTH_SHORT); + TextView tv = (TextView) tst.getView().findViewById(android.R.id.message); + tv.setTextColor(Color.parseColor("#d5e0e2")); + tst.show(); + + } + } + + //set the flow layout alignment it is called from global settings + public void setFlowLayoutAlignment(int gravity) { + mHomeLayout.setGravity(gravity); + DbUtils.setFlowLayoutAlignment(gravity); + } + + public void setPadding() { + dialogs = new PaddingDialog(this, mHomeLayout); + // Window window = dialogs.getWindow(); + // window.setGravity(Gravity.BOTTOM); + // window.setBackgroundDrawableResource(android.R.color.transparent); + // window.setLayout(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); + dialogs.show(); + } + + public void setColorsAndSize() { + dialogs = new GlobalColorSizeDialog(this, mAppsList); + + Window window = dialogs.getWindow(); + if (window != null) { + window.setGravity(Gravity.BOTTOM); + window.setBackgroundDrawableResource(android.R.color.transparent); + window.setLayout(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); + } + dialogs.show(); + } + + private void addShortcut(String uri, String appName) { + if (mAppsList == null) return; + mAppsList.add(new Apps(true, uri, appName, getCustomView(), DbUtils.NULL_TEXT_COLOR, DEFAULT_TEXT_SIZE_NORMAL_APPS, false, false, 0, (int) System.currentTimeMillis() / 1000)); + shortcutUtils.addShortcut(new Shortcut(appName, uri)); + // Log.d(TAG, "addShortcut: shortcut name==" + appName); + sortApps(DbUtils.getSortsTypes()); + } + + /** + * remove the shortcut + * + * @param view shortcut view to be removed... + */ + private void removeShortcut(AppTextView view) { + // view.setVisibility(View.GONE); + shortcutUtils.removeShortcut(new Shortcut(view.getText().toString(), view.getUri())); + + // if (b) + loadApps(); + } + + @Override + public void onSwipe(Gestures.Direction direction) { + if (direction == Gestures.Direction.SWIPE_RIGHT) { + searching = true; + mSearchBox.setText(""); + mSearchBox.setVisibility(View.VISIBLE); + mSearchBox.requestFocus(); + imm.showSoftInput(mSearchBox, InputMethodManager.SHOW_IMPLICIT); + } else if (direction == Gestures.Direction.SWIPE_LEFT) { + if (searching) { + mSearchBox.setVisibility(View.GONE); + imm.hideSoftInputFromWindow(mSearchBox.getWindowToken(), 0); + onResume(); + } + } + } + + @Override + public void onDoubleTap() { + // Always lock the device on double tap + DeviceAdminManager.lockDevice(this); + } + + static class SearchTask extends AsyncTask> { + @Override + protected void onPostExecute(ArrayList filteredApps) { + super.onPostExecute(filteredApps); + showSearchResult(filteredApps); + } + + @Override + protected ArrayList doInBackground(CharSequence... charSequences) { + ArrayList filteredApps = new ArrayList<>(); + for (Apps app : mAppsList) { + if (charSequences[0].length() == 0) { + filteredApps.add(app); + } else if (Utils.simpleFuzzySearch(charSequences[0], app.getAppName())) { + filteredApps.add(app); + } + } + return filteredApps; + } + } + + static class SortTask extends AsyncTask { + + @Override + protected void onPostExecute(Void aVoid) { + super.onPostExecute(aVoid); + + mHomeLayout.removeAllViews(); + mHomeLayout.removeAllViewsInLayout(); + // now add the app textView to home + // FlowLayoutManager.LayoutParams params = new FlowLayoutManager.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT); + // params.setNewLine(true); + + for (Apps app : mAppsList) { + AppTextView textView=app.getTextView(); + if (textView.getParent()!=null){ + ( (ViewGroup)textView.getParent()).removeView(textView); + } + mHomeLayout.addView(textView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + } + + + } + + @Override + protected Void doInBackground(final Integer... integers) { + final int type = integers[0]; + DbUtils.setAppsSortsType(type); + + //sort the apps alphabetically + Collections.sort(mAppsList, (a, b) -> String.CASE_INSENSITIVE_ORDER.compare( + a.getAppName(), + b.getAppName() + )); + + switch (type) { + case SORT_BY_SIZE://descending + Collections.sort(mAppsList, (apps, t1) -> (t1.getSize() - apps.getSize())); + break; + case SORT_BY_OPENING_COUNTS://descending + Collections.sort(mAppsList, (apps, t1) -> t1.getOpeningCounts() - apps.getOpeningCounts()); + break; + case SORT_BY_COLOR: + Collections.sort(mAppsList, (apps, t1) -> { + float[] hsv = new float[3]; + Color.colorToHSV(apps.getColor(), hsv); + float[] another = new float[3]; + Color.colorToHSV(t1.getColor(), another); + for (int i = 0; i < 3; i++) { + if (hsv[i] != another[i]) { + return (hsv[i] < another[i]) ? -1 : 1; + } + } + return 0; + }); + break; + case SORT_BY_UPDATE_TIME://descending + Collections.sort(mAppsList, (apps, t1) -> t1.getUpdateTime() - apps.getUpdateTime()); + break; + case SORT_BY_RECENT_OPEN://descending + Collections.sort(mAppsList, (apps, t1) -> (t1.getRecentUsedWeight() - apps.getRecentUsedWeight())); + break; + } + return null; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/github/sankalp/lunox/adapters/UniversalAdapter.java b/app/src/main/java/io/github/sankalp/lunox/adapters/UniversalAdapter.java new file mode 100644 index 0000000..d7c8f75 --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/adapters/UniversalAdapter.java @@ -0,0 +1,72 @@ +/* + * Last Launcher + * Copyright (C) 2019 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.adapters; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.TextView; + +import java.util.ArrayList; + +import io.github.sankalp.lunox.R; +import io.github.sankalp.lunox.model.Apps; + +// +// this adapter class is used for Frozen app list and Hidden app list +// +public class UniversalAdapter extends ArrayAdapter { + + private final Context context; + private final ArrayList list; + private OnClickListener listener; + + public UniversalAdapter(Context context, ArrayList list) { + super(context, R.layout.list_item, list); + this.context = context; + this.list = list; + } + + public void setOnClickListener(OnClickListener listener) { + this.listener = listener; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View row = inflater.inflate(R.layout.list_item, parent, false); + row.setTag(position); + TextView textView = row.findViewById(R.id.app_label); + textView.setText(list.get(position).getAppName()); + textView.setTag(position); + + row.setOnClickListener(view -> listener.onClick(getItem((int) view.getTag()), view)); + + textView.setOnClickListener(view -> listener.onClick(getItem((int) view.getTag()), view)); + return row; + } + + + public interface OnClickListener { + void onClick(Apps apps, View view); + } + +} diff --git a/app/src/main/java/io/github/sankalp/lunox/dialogs/ColorSizeDialog.java b/app/src/main/java/io/github/sankalp/lunox/dialogs/ColorSizeDialog.java new file mode 100644 index 0000000..b0f34fe --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/dialogs/ColorSizeDialog.java @@ -0,0 +1,176 @@ +/* + * Last Launcher + * Copyright (C) 2019 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.dialogs; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.view.Window; +import android.widget.TextView; + +import io.github.sankalp.lunox.R; +import io.github.sankalp.lunox.utils.DbUtils; +import io.github.sankalp.lunox.views.colorseekbar.ColorSeekBar; + +// choose color Dialog +public class ColorSizeDialog extends Dialog { + + private static final int DELAY = 25; + //private static final String TAG = "ChooseSize"; + private final static int DEFAULT_MIN_TEXT_SIZE = DbUtils.getMinAppSize(); + private final static int DEFAULT_MAX_TEXT_SIZE = DbUtils.getMaxAppSize(); + + private final Handler handler = new Handler(); + private final String appPackage; + private final TextView textView; + + private int appSize; + private Runnable runnable; + private int appColor; + // boolean change=false; + + public ColorSizeDialog(Context context, String appPackage, int appColor, TextView textView, int appSize) { + super(context); + this.appPackage = appPackage; + this.appColor = appColor; + this.textView = textView; + this.appSize = appSize; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); + // no title please + requestWindowFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.dialog_color_size); + getWindow().setBackgroundDrawableResource(android.R.color.transparent); + + + ColorSeekBar colorSeekBar = findViewById(R.id.colorSlider1); + colorSeekBar.setMaxPosition(100); + //colorSeekBar.setColorSeeds(R.array.material_colors); + colorSeekBar.setShowAlphaBar(true); + colorSeekBar.setBarHeight(8); + + + // todo: is this still correct? + if (appColor != DbUtils.NULL_TEXT_COLOR) + colorSeekBar.setColor(appColor); + // set the color and save this to database + colorSeekBar.setOnColorChangeListener((colorBarPosition, alphaBarPosition, color) -> { + textView.setTextColor(color); + appColor = color; + // change=true; + // DbUtils.putAppColorImmediately(appPackage, color); + }); + + + // size related + TextView plus = findViewById(R.id.btn_plus); + TextView minus = findViewById(R.id.btn_minus); + TextView size = findViewById(R.id.tv_size); + + size.setText(String.valueOf(appSize)); + + + plus.setOnClickListener(view -> { + + // change=true; + appSize++; + + if (appSize >= DEFAULT_MAX_TEXT_SIZE) { + appSize = DEFAULT_MAX_TEXT_SIZE; + // plus.setClickable(false); + } + + size.setText(String.valueOf(appSize)); + textView.setTextSize(appSize); + }); + + minus.setOnClickListener(view -> { + //change=true; + --appSize; + if (appSize < DEFAULT_MIN_TEXT_SIZE) { + appSize = DEFAULT_MIN_TEXT_SIZE; + } + + size.setText(String.valueOf(appSize)); + textView.setTextSize(appSize); + }); + + + plus.setOnLongClickListener(view -> { + runnable = () -> { + if (!plus.isPressed()) { + handler.removeCallbacks(runnable); + return; + } + // increase value + // change=true; + appSize++; + + if (appSize >= DEFAULT_MAX_TEXT_SIZE) { + appSize = DEFAULT_MAX_TEXT_SIZE; + // plus.setClickable(false); + } + + size.setText(String.valueOf(appSize)); + textView.setTextSize(appSize); + handler.postDelayed(runnable, DELAY); + }; + handler.removeCallbacks(runnable); + handler.postDelayed(runnable, DELAY); + return true; + }); + + + minus.setOnLongClickListener(view -> { + runnable = () -> { + if (!minus.isPressed()) { + handler.removeCallbacks(runnable); + return; + } + // decrease value + --appSize; + // change=true; + if (appSize < DEFAULT_MIN_TEXT_SIZE) { + appSize = DEFAULT_MIN_TEXT_SIZE; + } + + size.setText(String.valueOf(appSize)); + textView.setTextSize(appSize); + handler.postDelayed(runnable, DELAY); + }; + handler.removeCallbacks(runnable); + handler.postDelayed(runnable, DELAY); + return true; + }); + + } + + @Override + protected void onStop() { + super.onStop(); + DbUtils.putAppColor(appPackage, appColor); + DbUtils.putAppSize(appPackage, appSize); + + } +} diff --git a/app/src/main/java/io/github/sankalp/lunox/dialogs/ColorSnifferDialog.java b/app/src/main/java/io/github/sankalp/lunox/dialogs/ColorSnifferDialog.java new file mode 100644 index 0000000..328a531 --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/dialogs/ColorSnifferDialog.java @@ -0,0 +1,131 @@ +/* + * Last Launcher + * Copyright (C) 2019 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.dialogs; + +import android.app.Dialog; +import android.content.ActivityNotFoundException; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.View; +import android.view.Window; +import android.widget.TextView; + +import io.github.sankalp.lunox.LauncherActivity; +import io.github.sankalp.lunox.R; +import io.github.sankalp.lunox.utils.Constants; +import io.github.sankalp.lunox.utils.DbUtils; + + +// color sniffer dialog +// may be removed from stable version +//Color sniffer developer halted the development of that app!! +public class ColorSnifferDialog extends Dialog implements View.OnClickListener { + private final LauncherActivity launcherActivity; + private final Context context; + private TextView onOffSwitch; + private TextView mStartColorSniffer; + private boolean change = false; + + ColorSnifferDialog(Context context, LauncherActivity launcherActivity) { + super(context); + this.context = context; + this.launcherActivity = launcherActivity; + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.text_color_sniffer_on_off: + onOffColorSnifferCustomisation(); + break; + case R.id.color_sniffer_clipboard: + launcherActivity.clipboardData(); + break; + case R.id.color_sniffer_external_app: { + if (DbUtils.isExternalSourceColor()) + startColorSnifferApp(); + + break; + } + } + } + + private void onOffColorSnifferCustomisation() { + boolean b = DbUtils.isExternalSourceColor(); + DbUtils.externalSourceColor(!b); + onOffSwitch.setText(!b ? R.string.on : R.string.off); + change = !change; + mStartColorSniffer.setVisibility(!b ? View.VISIBLE : View.GONE); + } + + + //TODO: uri update, data schema + private void startColorSnifferApp() { + //check app android compat currently colorSniffer api=19 and this app api=14 + try { + Intent intent = new Intent("android.intent.action.MAIN"); + //is this correct call Rui Zhao? + intent.setComponent(new ComponentName("ryey.colorsniffer", "ryey.colorsniffer.FormActivity")); + //currently default color is only provided by Theme: + //Is it required to send default colors of apps : YES + // is it required/ to send theme related data for better experience : ask for color sniffer developer + // 2121= dummy value + intent.putExtra(Constants.DEFAULT_COLOR_FOR_APPS, 2121); + launcherActivity.startActivityForResult(intent, Constants.COLOR_SNIFFER_REQUEST); + // for activity result see LauncherActivity line 509 + cancel(); + } catch (ActivityNotFoundException e) { + //this will never happen because this option is only shown after app is installed + Uri uri = Uri.parse("market://details?id=ryey.colorsniffer"); + Intent i = new Intent(Intent.ACTION_VIEW, uri); + i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(i); + } + } + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + requestWindowFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.dialog_color_sniffer_settings); + findViewById(R.id.text_color_sniffer_on_off).setOnClickListener(this); + findViewById(R.id.color_sniffer_clipboard).setOnClickListener(this); + mStartColorSniffer = findViewById(R.id.color_sniffer_external_app); + mStartColorSniffer.setOnClickListener(this); + onOffSwitch = findViewById(R.id.switch_color_sniffer_on_off); + boolean onOff = DbUtils.isExternalSourceColor(); + onOffSwitch.setText(onOff ? R.string.on : R.string.off); + mStartColorSniffer.setVisibility(onOff ? View.VISIBLE : View.GONE); + } + + + @Override + protected void onStop() { + super.onStop(); + //else Window decor leak happen + if (change) { + launcherActivity.recreate(); + } + + } +} diff --git a/app/src/main/java/io/github/sankalp/lunox/dialogs/FrozenAppsDialogs.java b/app/src/main/java/io/github/sankalp/lunox/dialogs/FrozenAppsDialogs.java new file mode 100644 index 0000000..cfaae77 --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/dialogs/FrozenAppsDialogs.java @@ -0,0 +1,97 @@ +/* + * Last Launcher + * Copyright (C) 2019,2020 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.dialogs; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.view.ContextThemeWrapper; +import android.view.View; +import android.view.Window; +import android.widget.ListView; +import android.widget.PopupMenu; + +import java.util.ArrayList; + +import io.github.sankalp.lunox.R; +import io.github.sankalp.lunox.adapters.UniversalAdapter; +import io.github.sankalp.lunox.model.Apps; +import io.github.sankalp.lunox.utils.DbUtils; + +public class FrozenAppsDialogs extends Dialog { + + private final ArrayList mAppsList; + private final Context context; + ArrayList frozenApps = new ArrayList<>(); + private ListView listView; + + public FrozenAppsDialogs(Context context, ArrayList appsList) { + super(context); + this.context = context; + mAppsList = appsList; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + requestWindowFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.dialog_hidden_apps); + listView = findViewById(R.id.hidden_app_list); + + UniversalAdapter adapter = new UniversalAdapter(context, frozenApps); + listView.setAdapter(adapter); + + adapter.setOnClickListener(this::confirmationAndRemove); + + } + + private void confirmationAndRemove(Apps apps, View view) { + Context ctx; + if (DbUtils.getTheme() == R.style.Wallpaper) + ctx = new ContextThemeWrapper(context, R.style.AppTheme); + else + ctx = new ContextThemeWrapper(context, DbUtils.getTheme()); + + PopupMenu popupMenu = new PopupMenu(ctx, view); + popupMenu.getMenuInflater().inflate(R.menu.remove_popup, popupMenu.getMenu()); + + popupMenu.setOnMenuItemClickListener(menuItem -> { + + if (menuItem.getItemId() == R.id.menu_remove_this) { + apps.setFreeze(false); + updateFrozenList(); + } + return true; + + }); + popupMenu.show(); + + } + + public int updateFrozenList() { + // only show frozen app + for (Apps apps : mAppsList) { + if (apps.isSizeFrozen()) { + frozenApps.add(apps); + } + } + return frozenApps.size(); + } + +} diff --git a/app/src/main/java/io/github/sankalp/lunox/dialogs/GlobalColorSizeDialog.java b/app/src/main/java/io/github/sankalp/lunox/dialogs/GlobalColorSizeDialog.java new file mode 100644 index 0000000..ed93c7b --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/dialogs/GlobalColorSizeDialog.java @@ -0,0 +1,251 @@ +/* + * Last Launcher + * Copyright (C) 2019,2020 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.dialogs; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.view.Window; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; + +import io.github.sankalp.lunox.R; +import io.github.sankalp.lunox.model.Apps; +import io.github.sankalp.lunox.utils.DbUtils; +import io.github.sankalp.lunox.utils.Utils; +import io.github.sankalp.lunox.views.colorseekbar.ColorSeekBar; + +import static io.github.sankalp.lunox.utils.Constants.DEFAULT_MAX_TEXT_SIZE; +import static io.github.sankalp.lunox.utils.Constants.DEFAULT_MIN_TEXT_SIZE; +import static io.github.sankalp.lunox.utils.Constants.DEFAULT_TEXT_SIZE_NORMAL_APPS; +import static io.github.sankalp.lunox.utils.Constants.DEFAULT_TEXT_SIZE_OFTEN_APPS; + + +public class GlobalColorSizeDialog extends Dialog { + + private static final long DELAY = 100; + + private final Handler handler = new Handler(); + private final ArrayList mAppsList; + private final List oftenApps = Utils.getOftenAppsList(); + private Runnable runnable; + private int appSize; + private int mColor; + + public GlobalColorSizeDialog(Context context, ArrayList appsList) { + super(context); + this.mAppsList = appsList; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); + // no title please + requestWindowFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.dialog_color_size); + getWindow().setBackgroundDrawableResource(android.R.color.transparent); + + + ColorSeekBar colorSeekBar = findViewById(R.id.colorSlider1); + colorSeekBar.setMaxPosition(100); + //colorSeekBar.setColorSeeds(R.array.material_colors); + colorSeekBar.setShowAlphaBar(true); + colorSeekBar.setBarHeight(8); + + int colorDefault = DbUtils.getAppsColorDefault(); + + if (colorDefault != DbUtils.NULL_TEXT_COLOR) { + colorSeekBar.setColor(colorDefault); + //} else { + //do something + } + + + // set the color and save this to database + colorSeekBar.setOnColorChangeListener((colorBarPosition, alphaBarPosition, color) -> { + // set the color + mColor = color; + for (Apps apps : mAppsList) { + // only change the color of app, which had not set yet + if (DbUtils.getAppColor(apps.getActivityName()) == DbUtils.NULL_TEXT_COLOR) { + // change only the text view color + // do not save the color of individuals apps + apps.getTextView().setTextColor(color); + } + } + // idea: save global color to Db + }); + + + // size related + TextView plus = findViewById(R.id.btn_plus); + TextView minus = findViewById(R.id.btn_minus); + TextView size = findViewById(R.id.tv_size); + + appSize = DbUtils.getGlobalSizeAdditionExtra(); + size.setText(String.valueOf(appSize)); + + plus.setOnClickListener(view -> { + + appSize++; + + if (appSize >= DEFAULT_MAX_TEXT_SIZE) { + appSize = DEFAULT_MAX_TEXT_SIZE; + // plus.setClickable(false); + + } else { + + for (Apps apps : mAppsList) { + int textSize = DbUtils.getAppSize(apps.getActivityName()); + // check if text size is null then set the size to default size + // size is null(-1) when user installed this app + if (textSize == DbUtils.NULL_TEXT_SIZE) { + if (oftenApps.contains(apps.getActivityName().split("/")[0])) { + textSize = DEFAULT_TEXT_SIZE_OFTEN_APPS; + } else { + textSize = DEFAULT_TEXT_SIZE_NORMAL_APPS; + } + /// DbUtils.putAppSize(activity, textSize); + } + apps.setSize(++textSize); + + } + } + size.setText(String.valueOf(appSize)); + }); + + minus.setOnClickListener(view -> { + --appSize; + if (appSize < DEFAULT_MIN_TEXT_SIZE) { + appSize = DEFAULT_MIN_TEXT_SIZE; + } else { + + + for (Apps apps : mAppsList) { + int textSize = DbUtils.getAppSize(apps.getActivityName()); + // check if text size is null then set the size to default size + // size is null(-1) when user installed this app + if (textSize == DbUtils.NULL_TEXT_SIZE) { + if (oftenApps.contains(apps.getActivityName().split("/")[0])) { + textSize = DEFAULT_TEXT_SIZE_OFTEN_APPS; + } else { + textSize = DEFAULT_TEXT_SIZE_NORMAL_APPS; + } + + /// DbUtils.putAppSize(activity, textSize); + } + apps.setSize(--textSize); + + } + } + size.setText(String.valueOf(appSize)); + }); + + + plus.setOnLongClickListener(view -> { + runnable = () -> { + if (!plus.isPressed()) { + handler.removeCallbacks(runnable); + return; + } + // increase value + appSize++; + + if (appSize >= DEFAULT_MAX_TEXT_SIZE) { + appSize = DEFAULT_MAX_TEXT_SIZE; + // plus.setClickable(false); + } else { + for (Apps apps : mAppsList) { + int textSize = DbUtils.getAppSize(apps.getActivityName()); + // check if text size is null then set the size to default size + // size is null(-1) when user installed this app + if (textSize == DbUtils.NULL_TEXT_SIZE) { + if (oftenApps.contains(apps.getActivityName().split("/")[0])) { + textSize = DEFAULT_TEXT_SIZE_OFTEN_APPS; + } else { + textSize = DEFAULT_TEXT_SIZE_NORMAL_APPS; + } + + /// DbUtils.putAppSize(activity, textSize); + } + apps.setSize(++textSize); + + } + } + size.setText(String.valueOf(appSize)); + handler.postDelayed(runnable, DELAY); + }; + handler.removeCallbacks(runnable); + handler.postDelayed(runnable, DELAY); + return true; + }); + + + minus.setOnLongClickListener(view -> { + runnable = () -> { + if (!minus.isPressed()) { + handler.removeCallbacks(runnable); + return; + } + // decrease value + --appSize; + if (appSize < DEFAULT_MIN_TEXT_SIZE) { + appSize = DEFAULT_MIN_TEXT_SIZE; + } else { + + for (Apps apps : mAppsList) { + int textSize = DbUtils.getAppSize(apps.getActivityName()); + // check if text size is null then set the size to default size + // size is null(-1) when user installed this app + if (textSize == DbUtils.NULL_TEXT_SIZE) { + if (oftenApps.contains(apps.getActivityName().split("/")[0])) { + textSize = DEFAULT_TEXT_SIZE_OFTEN_APPS; + } else { + textSize = DEFAULT_TEXT_SIZE_NORMAL_APPS; + } + + /// DbUtils.putAppSize(activity, textSize); + } + apps.setSize(--textSize); + + } + } + size.setText(String.valueOf(appSize)); + handler.postDelayed(runnable, DELAY); + }; + + handler.removeCallbacks(runnable); + handler.postDelayed(runnable, DELAY); + return true; + }); + + } + + @Override + protected void onStop() { + super.onStop(); + DbUtils.setGlobalSizeAdditionExtra(appSize); + DbUtils.setAppsColorDefault(mColor); + } + +} diff --git a/app/src/main/java/io/github/sankalp/lunox/dialogs/GlobalSettingsDialog.java b/app/src/main/java/io/github/sankalp/lunox/dialogs/GlobalSettingsDialog.java new file mode 100644 index 0000000..e427626 --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/dialogs/GlobalSettingsDialog.java @@ -0,0 +1,399 @@ +/* + * Last Launcher + * Copyright (C) 2019 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.dialogs; + +import android.app.Dialog; +import android.content.Context; +import android.content.Intent; +import android.graphics.Color; +import android.net.Uri; +import android.os.Bundle; +import android.view.ContextThemeWrapper; +import android.view.Gravity; +import android.view.View; +import android.view.Window; +import android.widget.PopupMenu; +import android.widget.TextView; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +import io.github.sankalp.lunox.BuildConfig; +import io.github.sankalp.lunox.LauncherActivity; +import io.github.sankalp.lunox.R; +import io.github.sankalp.lunox.model.Apps; +import io.github.sankalp.lunox.utils.Constants; +import io.github.sankalp.lunox.utils.DbUtils; +import io.github.sankalp.lunox.utils.Utils; + +import static io.github.sankalp.lunox.utils.Constants.BACKUP_REQUEST; +import static io.github.sankalp.lunox.utils.Constants.FONTS_REQUEST; +import static io.github.sankalp.lunox.utils.Constants.RESTORE_REQUEST; + +/** + * this the launcher setting Dialog + */ +public class GlobalSettingsDialog extends Dialog implements View.OnClickListener { + + + //private static final String TAG = "Global";/**/ + private final LauncherActivity launcherActivity; + private final Context context; + private TextView freezeSize; + + public GlobalSettingsDialog(Context context, LauncherActivity launcherActivity) { + super(context); + this.context = context; + this.launcherActivity = launcherActivity; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // no old title: Last Launcher use Activity class not AppCompatActivity so it show very old title + requestWindowFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.dialog_global_settings); + + + findViewById(R.id.settings_themes).setOnClickListener(this); + freezeSize = findViewById(R.id.settings_freeze_size); + freezeSize.setOnClickListener(this); + + findViewById(R.id.settings_fonts).setOnClickListener(this); + + TextView reset = findViewById(R.id.settings_reset_to_defaults); + reset.setOnClickListener(this); + reset.setTextColor(Color.parseColor("#E53935")); + findViewById(R.id.settings_backup).setOnClickListener(this); + findViewById(R.id.settings_restore).setOnClickListener(this); + findViewById(R.id.settings_alignment).setOnClickListener(this); + findViewById(R.id.settings_padding).setOnClickListener(this); + findViewById(R.id.settings_color_size).setOnClickListener(this); + findViewById(R.id.settings_sort_app_by).setOnClickListener(this); + findViewById(R.id.settings_restart_launcher).setOnClickListener(this); + + //TODO: remove this var + TextView colorSniffer = findViewById(R.id.settings_color_sniffer); + colorSniffer.setOnClickListener(this); + + if (!BuildConfig.enableColorSniffer) { + if (DbUtils.isRandomColor()) { + colorSniffer.setText(R.string.fixed_colors); + } else + colorSniffer.setText(R.string.random_colors); + } + + findViewById(R.id.settings_frozen_apps).setOnClickListener(this); + findViewById(R.id.settings_hidden_apps).setOnClickListener(this); + + + //reflect the DB value + if (DbUtils.isSizeFrozen()) { + freezeSize.setText(R.string.unfreeze_app_size); + } else + freezeSize.setText(R.string.freeze_apps_size); + + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.settings_fonts: + fontSelection(view); + break; + case R.id.settings_themes: + showThemeDialog(); + break; + case R.id.settings_color_sniffer: { + if (BuildConfig.enableColorSniffer) + showColorSnifferDialog(); + else randomColor(); + } + break; + + case R.id.settings_sort_app_by: { + sortApps(view); + break; + } + case R.id.settings_color_size: { + showColorAndSizeDialog(); + } + break; + case R.id.settings_freeze_size: + freezeAppsSize(); + break; + case R.id.settings_hidden_apps: + hiddenApps(); + break; + case R.id.settings_frozen_apps: + frozenApps(); + break; + case R.id.settings_backup: + backup(); + break; + case R.id.settings_restore: + restore(); + break; + case R.id.settings_reset_to_defaults: + defaultSettings(); + break; + case R.id.settings_alignment: + setFlowLayoutAlignment(view); + break; + case R.id.settings_padding: + launcherActivity.setPadding(); + cancel(); + break; + case R.id.settings_restart_launcher: + launcherActivity.recreate(); + break; + } + } + + private void sortApps(View view) { + Context context; + // set theme + // if theme wallpaper ie transparent then we have to show other theme + if (DbUtils.getTheme() == R.style.Wallpaper) + context = new ContextThemeWrapper(getContext(), R.style.AppTheme); + else + context = new ContextThemeWrapper(getContext(), DbUtils.getTheme()); + + PopupMenu popupMenu = new PopupMenu(context, view); + popupMenu.getMenuInflater().inflate(R.menu.sort_apps_popups, popupMenu.getMenu()); + + popupMenu.setOnMenuItemClickListener(menuItem -> { + cancel(); + switch (menuItem.getItemId()) { + case R.id.menu_sort_by_name: + launcherActivity.sortApps(Constants.SORT_BY_NAME); + break; + case R.id.menu_sort_by_opening_counts: + launcherActivity.sortApps(Constants.SORT_BY_OPENING_COUNTS); + break; + case R.id.menu_sort_by_color: + launcherActivity.sortApps(Constants.SORT_BY_COLOR); + break; + /* case R.id.menu_sort_by_customs: + launcherActivity.sortApps(LauncherActivity.SORT_BY_CUSTOM); + break;*/ + case R.id.menu_sort_by_size: + launcherActivity.sortApps(Constants.SORT_BY_SIZE); + break; + case R.id.menu_sort_by_update_time: + launcherActivity.sortApps(Constants.SORT_BY_UPDATE_TIME); + break; + case R.id.menu_sort_by_recent_use: + launcherActivity.sortApps(Constants.SORT_BY_RECENT_OPEN); + break; + } + return true; + }); + popupMenu.show(); + } + + private void showColorAndSizeDialog() { + launcherActivity.setColorsAndSize(); + cancel(); + } + + private void setFlowLayoutAlignment(View view) { + + Context context; + // set theme + // if theme is wallpaper i.e. transparent then we have to show other theme: + if (DbUtils.getTheme() == R.style.Wallpaper) + context = new ContextThemeWrapper(getContext(), R.style.AppTheme); + else + context = new ContextThemeWrapper(getContext(), DbUtils.getTheme()); + + PopupMenu popupMenu = new PopupMenu(context, view); + popupMenu.getMenuInflater().inflate(R.menu.alignment_popup, popupMenu.getMenu()); + + popupMenu.setOnMenuItemClickListener(menuItem -> { + switch (menuItem.getItemId()) { + case R.id.menu_center: + launcherActivity.setFlowLayoutAlignment(Gravity.CENTER | Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL); + break; + case R.id.menu_end: + launcherActivity.setFlowLayoutAlignment(Gravity.END | Gravity.CENTER_VERTICAL); + break; + case R.id.menu_start: + launcherActivity.setFlowLayoutAlignment(Gravity.START | Gravity.CENTER_VERTICAL); + break; + } + return true; + }); + popupMenu.show(); + + } + + private void randomColor() { + boolean rColor = !DbUtils.isRandomColor(); + DbUtils.randomColor(rColor); + cancel(); + if (rColor) { + int color; + for (Apps app : LauncherActivity.mAppsList) { + color = DbUtils.getAppColor(app.getActivityName()); + if (color == DbUtils.NULL_TEXT_COLOR) { + color = Utils.generateColorFromString(app.getActivityName()); + app.getTextView().setTextColor(color); + } + } + } else { + launcherActivity.recreate(); + } + } + + private void showColorSnifferDialog() { + cancel(); + Intent intent = context.getPackageManager().getLaunchIntentForPackage("ryey.colorsniffer"); + + // if color snifer app is not installed then send user to install it + // else show color sniffer option + if (intent == null) { + //Change this to proper url , currently this also show BASTARD PLAY STORE + Uri uri = Uri.parse("market://details?id=ryey.colorsniffer"); + Intent i = new Intent(Intent.ACTION_VIEW, uri); + i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(i); + } else { + new ColorSnifferDialog(getContext(), launcherActivity).show(); + + } + } + + private void freezeAppsSize() { + boolean b = DbUtils.isSizeFrozen(); + DbUtils.freezeSize(!b); + if (!b) { + freezeSize.setText(R.string.unfreeze_app_size); + } else + freezeSize.setText(R.string.freeze_apps_size); + } + + private void frozenApps() { + launcherActivity.showFrozenApps(); + cancel(); + } + + //show hidden apps + private void hiddenApps() { + launcherActivity.showHiddenApps(); + cancel(); + } + + private void showThemeDialog() { + cancel(); + new ThemeSelectorDialog(getContext(), launcherActivity).show(); + } + + private void defaultSettings() { + if (!BuildConfig.DEBUG) { + DbUtils.clearDB(); + launcherActivity.recreate(); + } else { + //DO SOME ESTER EGG.. FOR DEBUG BUILD.. + } + + } + + private void backup() { + cancel(); + Intent intentBackupFiles; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { + intentBackupFiles = new Intent(Intent.ACTION_CREATE_DOCUMENT); + } else { + intentBackupFiles = new Intent(Intent.ACTION_GET_CONTENT); + ; + } + intentBackupFiles.addCategory(Intent.CATEGORY_OPENABLE); + + intentBackupFiles.setType("*/*"); + + SimpleDateFormat df = new SimpleDateFormat("yyyy_MM_dd_HHSS", Locale.getDefault()); + df.format(new Date()); + String date = df.format(new Date()); + + intentBackupFiles.putExtra(Intent.EXTRA_TITLE, "Backup_lunox_" + date); + + Intent intent = Intent.createChooser(intentBackupFiles, launcherActivity.getString(R.string.choose_old_backup_files)); + launcherActivity.startActivityForResult(intent, BACKUP_REQUEST); + } + + private void restore() { + cancel(); + Intent intentRestoreFiles; + intentRestoreFiles = new Intent(Intent.ACTION_GET_CONTENT); + intentRestoreFiles.addCategory(Intent.CATEGORY_OPENABLE); + intentRestoreFiles.setType("*/*"); + Intent intent = Intent.createChooser(intentRestoreFiles, launcherActivity.getString(R.string.choose_old_backup_files)); + launcherActivity.startActivityForResult(intent, RESTORE_REQUEST); + } + + private void setFonts() { + cancel(); + Intent intentSetFonts = new Intent(Intent.ACTION_GET_CONTENT); + + intentSetFonts.addCategory(Intent.CATEGORY_OPENABLE); + //intentSetFonts.setType("application/x-font-ttf"); + // intentSetFonts.setType("file/plain"); + intentSetFonts.setType("*/*"); + Intent intent = Intent.createChooser(intentSetFonts, "Choose Fonts"); + launcherActivity.startActivityForResult(intent, FONTS_REQUEST); + + } + + private void fontSelection(View view) { + + Context context; + // set theme + // if theme wallpaper ie transparent then we have to show other theme + if (DbUtils.getTheme() == R.style.Wallpaper) + context = new ContextThemeWrapper(getContext(), R.style.AppTheme); + else + context = new ContextThemeWrapper(getContext(), DbUtils.getTheme()); + + PopupMenu popupMenu = new PopupMenu(context, view); + popupMenu.getMenuInflater().inflate(R.menu.font_selection_popup, popupMenu.getMenu()); + + popupMenu.setOnMenuItemClickListener(menuItem -> { + switch (menuItem.getItemId()) { + case R.id.menu_choose_fonts: + setFonts(); + break; + case R.id.menu_default_font: { + if (DbUtils.isFontExists()) { + DbUtils.removeFont(); + launcherActivity.setFont(); + launcherActivity.loadApps(); + cancel(); + break; + } + } + } + return true; + }); + popupMenu.show(); + + } + +} diff --git a/app/src/main/java/io/github/sankalp/lunox/dialogs/HiddenAppsDialogs.java b/app/src/main/java/io/github/sankalp/lunox/dialogs/HiddenAppsDialogs.java new file mode 100644 index 0000000..504c706 --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/dialogs/HiddenAppsDialogs.java @@ -0,0 +1,109 @@ +/* + * Last Launcher + * Copyright (C) 2019,2020 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.dialogs; + +import android.app.Dialog; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.ContextThemeWrapper; +import android.view.View; +import android.view.Window; +import android.widget.ListView; +import android.widget.PopupMenu; + +import java.util.ArrayList; + +import io.github.sankalp.lunox.R; +import io.github.sankalp.lunox.adapters.UniversalAdapter; +import io.github.sankalp.lunox.model.Apps; +import io.github.sankalp.lunox.utils.DbUtils; + +public class HiddenAppsDialogs extends Dialog { + + private final ArrayList mAppsList; + private final Context context; + ArrayList hiddenApps = new ArrayList<>(); + + public HiddenAppsDialogs(Context context, ArrayList appsList) { + super(context); + this.context = context; + mAppsList = appsList; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + requestWindowFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.dialog_hidden_apps); + ListView listView = findViewById(R.id.hidden_app_list); + + UniversalAdapter adapter = new UniversalAdapter(context, hiddenApps); + listView.setAdapter(adapter); + adapter.setOnClickListener(this::confirmationAndRemove); + + } + + + private void confirmationAndRemove(Apps apps, View view) { + + Context ctx; + if (DbUtils.getTheme() == R.style.Wallpaper) + ctx = new ContextThemeWrapper(context, R.style.AppTheme); + else + ctx = new ContextThemeWrapper(context, DbUtils.getTheme()); + + PopupMenu popupMenu = new PopupMenu(ctx, view); + popupMenu.getMenuInflater().inflate(R.menu.remove_popup, popupMenu.getMenu()); + + popupMenu.setOnMenuItemClickListener(menuItem -> { + + if (menuItem.getItemId() == R.id.menu_remove_this) { + apps.setAppHidden(false); + updateHiddenList(); + } else if (menuItem.getItemId() == R.id.menu_run_this_app) { + if (!apps.isShortcut()) { + String[] strings = apps.getActivityName().split("/"); + final Intent intent = new Intent(Intent.ACTION_MAIN, null); + intent.setClassName(strings[0], strings[1]); + intent.setComponent(new ComponentName(strings[0], strings[1])); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } + + } + return true; + + }); + popupMenu.show(); + + } + + + public int updateHiddenList() { + for (Apps apps : mAppsList) { + if (apps.isHidden()) { + hiddenApps.add(apps); + } + } + return hiddenApps.size(); + } + +} diff --git a/app/src/main/java/io/github/sankalp/lunox/dialogs/PaddingDialog.java b/app/src/main/java/io/github/sankalp/lunox/dialogs/PaddingDialog.java new file mode 100644 index 0000000..0ddb407 --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/dialogs/PaddingDialog.java @@ -0,0 +1,320 @@ +/* + * Last Launcher + * Copyright (C) 2019,2020 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.dialogs; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.view.View; +import android.view.Window; +import android.widget.TextView; + +import org.apmem.tools.layouts.FlowLayout; + +import io.github.sankalp.lunox.R; +import io.github.sankalp.lunox.utils.DbUtils; + +import static io.github.sankalp.lunox.utils.Constants.MAX_PADDING_BOTTOM; +import static io.github.sankalp.lunox.utils.Constants.MAX_PADDING_LEFT; +import static io.github.sankalp.lunox.utils.Constants.MAX_PADDING_RIGHT; +import static io.github.sankalp.lunox.utils.Constants.MAX_PADDING_TOP; +import static io.github.sankalp.lunox.utils.Constants.MIN_PADDING; + +public class PaddingDialog extends Dialog implements View.OnLongClickListener, View.OnClickListener { + + private static final long DELAY = 10; + + private final FlowLayout homeLayout; + + private final Handler handler = new Handler(); + + private TextView left; + private TextView right; + private TextView top; + private TextView bottom; + + private int topInt, leftInt, rightInt, bottomInt; + + private Runnable runnable; + + public PaddingDialog(Context context, FlowLayout mHomeLayout) { + super(context); + homeLayout = mHomeLayout; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + requestWindowFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.dialog_padding); + + TextView btnLeftMinus = findViewById(R.id.btn_left_minus); + btnLeftMinus.setOnLongClickListener(this); + btnLeftMinus.setOnClickListener(this); + + TextView btnRightMinus = findViewById(R.id.btn_right_minus); + btnRightMinus.setOnLongClickListener(this); + btnRightMinus.setOnClickListener(this); + + TextView btnTopMinus = findViewById(R.id.btn_top_minus); + btnTopMinus.setOnLongClickListener(this); + btnTopMinus.setOnClickListener(this); + + TextView btnBottomMinus = findViewById(R.id.btn_bottom_minus); + btnBottomMinus.setOnLongClickListener(this); + btnBottomMinus.setOnClickListener(this); + TextView btnLeftPlus = findViewById(R.id.btn_left_plus); + btnLeftPlus.setOnLongClickListener(this); + btnLeftPlus.setOnClickListener(this); + + TextView btnRightPlus = findViewById(R.id.btn_right_plus); + btnRightPlus.setOnLongClickListener(this); + btnRightPlus.setOnClickListener(this); + TextView btnTopPlus = findViewById(R.id.btn_top_plus); + btnTopPlus.setOnLongClickListener(this); + btnTopPlus.setOnClickListener(this); + + TextView btnBottomPlus = findViewById(R.id.btn_bottom_plus); + btnBottomPlus.setOnLongClickListener(this); + btnBottomPlus.setOnClickListener(this); + + left = findViewById(R.id.tv_left_padding); + right = findViewById(R.id.tv_right_padding); + top = findViewById(R.id.tv_top_padding); + bottom = findViewById(R.id.tv_bottom_padding); + + leftInt = DbUtils.getPaddingLeft(); + rightInt = DbUtils.getPaddingRight(); + topInt = DbUtils.getPaddingTop(); + bottomInt = DbUtils.getPaddingBottom(); + + left.setText(String.valueOf(leftInt)); + right.setText(String.valueOf(rightInt)); + top.setText(String.valueOf(topInt)); + bottom.setText(String.valueOf(bottomInt)); + + + } + + + @Override + protected void onStop() { + super.onStop(); + + // dialog is about to finish, so store the updated values to DB + DbUtils.setPaddingLeft(leftInt); + DbUtils.setPaddingRight(rightInt); + DbUtils.setPaddingTop(topInt); + DbUtils.setPaddingBottom(bottomInt); + } + + @Override + public boolean onLongClick(View button) { + switch (button.getId()) { + case R.id.btn_left_minus: + runner((TextView) button, left, -2, Padding.LEFT); + break; + case R.id.btn_left_plus: + runner((TextView) button, left, 2, Padding.LEFT); + break; + case R.id.btn_right_minus: + runner((TextView) button, right, -2, Padding.RIGHT); + break; + case R.id.btn_right_plus: + runner((TextView) button, right, 2, Padding.RIGHT); + break; + case R.id.btn_top_minus: + runner((TextView) button, top, -2, Padding.TOP); + break; + case R.id.btn_top_plus: + runner((TextView) button, top, 2, Padding.TOP); + break; + case R.id.btn_bottom_minus: + runner((TextView) button, bottom, -2, Padding.BOTTOM); + break; + case R.id.btn_bottom_plus: + runner((TextView) button, bottom, 2, Padding.BOTTOM); + break; + } + + return true; + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.btn_left_minus: + //decrease the value as minus button is pressed + leftInt--; + // check the lower limit i.e. 0 + if (leftInt < MIN_PADDING) { + leftInt = MIN_PADDING; + } + //reflect it on screen + left.setText(String.valueOf(leftInt)); + break; + case R.id.btn_left_plus: + leftInt++; + // check the upper limit + if (leftInt > MAX_PADDING_LEFT) { + leftInt = MAX_PADDING_LEFT; + } + left.setText(String.valueOf(leftInt)); + break; + case R.id.btn_right_minus: + rightInt--; + if (rightInt < MIN_PADDING) { + rightInt = MIN_PADDING; + } + right.setText(String.valueOf(rightInt)); + break; + case R.id.btn_right_plus: + rightInt++; + if (rightInt > MAX_PADDING_RIGHT) { + rightInt = MAX_PADDING_RIGHT; + } + right.setText(String.valueOf(rightInt)); + break; + case R.id.btn_top_minus: + topInt--; + if (topInt < MIN_PADDING) { + topInt = MIN_PADDING; + } + top.setText(String.valueOf(topInt)); + break; + case R.id.btn_top_plus: + topInt++; + if (topInt > MAX_PADDING_TOP) { + topInt = MAX_PADDING_TOP; + } + top.setText(String.valueOf(topInt)); + break; + case R.id.btn_bottom_minus: + bottomInt--; + if (bottomInt < MIN_PADDING) { + bottomInt = MIN_PADDING; + } + bottom.setText(String.valueOf(bottomInt)); + break; + case R.id.btn_bottom_plus: + bottomInt++; + if (bottomInt > MAX_PADDING_BOTTOM) { + bottomInt = MAX_PADDING_BOTTOM; + } + bottom.setText(String.valueOf(bottomInt)); + break; + } + // apply all padding to home layout + homeLayout.setPadding(leftInt, topInt, rightInt, bottomInt); + } + + + /** + * This runner continuously update the value when button is pressed continuously + * + * @param button which button is being pressed + * @param view which text view will be changed or updated + * @param step how much we increase or decrease the value -2 means we have to decrease the value by 2 + * @param whichSide to which side we apply padding usually @button @view and this param is interrelated + */ + private void runner(final TextView button, final TextView view, final int step, Padding whichSide) { + runnable = () -> { + if (!button.isPressed()) { + // button is released so destroy these calls + handler.removeCallbacks(runnable); + return; + } + + switch (whichSide) { + case LEFT: + leftInt += step; + // if step is positive means we are increasing the value so we have to check upper limit + //else we have to check lower limit i.e. 0 + if (step > 0) { + if (leftInt > MAX_PADDING_LEFT) { + leftInt = MAX_PADDING_LEFT; + } + } else { + if (leftInt < MIN_PADDING) { + leftInt = MIN_PADDING; + } + } + // reflect this in dialog view + view.setText(String.valueOf(leftInt)); + break; + case RIGHT: + rightInt += step; + if (step > 0) { + if (rightInt > MAX_PADDING_RIGHT) { + rightInt = MAX_PADDING_RIGHT; + } + } else { + if (rightInt < MIN_PADDING) { + rightInt = MIN_PADDING; + } + } + view.setText(String.valueOf(rightInt)); + break; + case TOP: + topInt += step; + if (step > 0) { + if (topInt > MAX_PADDING_TOP) { + topInt = MAX_PADDING_TOP; + } + } else { + if (topInt < MIN_PADDING) { + topInt = MIN_PADDING; + } + } + view.setText(String.valueOf(topInt)); + break; + case BOTTOM: + bottomInt += step; + if (step > 0) { + if (bottomInt > MAX_PADDING_BOTTOM) { + bottomInt = MAX_PADDING_BOTTOM; + } + } else { + if (bottomInt < MIN_PADDING) { + bottomInt = MIN_PADDING; + } + } + view.setText(String.valueOf(bottomInt)); + break; + } + + // set the padding to home layout + homeLayout.setPadding(leftInt, topInt, rightInt, bottomInt); + // currently button is still pressed so again call this runnable + handler.postDelayed(runnable, DELAY); + + }; + // remove callbacks if any + handler.removeCallbacks(runnable); + // first time runner + handler.postDelayed(runnable, DELAY); + } + + //enums for better understanding + private enum Padding { + LEFT, RIGHT, TOP, BOTTOM + } + +} diff --git a/app/src/main/java/io/github/sankalp/lunox/dialogs/RenameInputDialogs.java b/app/src/main/java/io/github/sankalp/lunox/dialogs/RenameInputDialogs.java new file mode 100644 index 0000000..3fb246b --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/dialogs/RenameInputDialogs.java @@ -0,0 +1,82 @@ +/* + * Last Launcher + * Copyright (C) 2019 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.dialogs; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.Window; +import android.view.WindowManager; +import android.view.inputmethod.EditorInfo; +import android.widget.EditText; +import android.widget.TextView; + +import io.github.sankalp.lunox.LauncherActivity; +import io.github.sankalp.lunox.R; +import io.github.sankalp.lunox.utils.DbUtils; + +public class RenameInputDialogs extends Dialog implements TextView.OnEditorActionListener { + + final private String appPackage; + private final LauncherActivity launcherActivity; + private final String oldAppName; + + + private EditText mAppName; + + public RenameInputDialogs(Context context, String appPackage, String oldAppName, LauncherActivity launcherActivity) { + super(context); + this.appPackage = appPackage; + this.launcherActivity = launcherActivity; + this.oldAppName = oldAppName; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + requestWindowFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.dialog_rename_input); + mAppName = findViewById(R.id.ed_input); + mAppName.setText(oldAppName); + mAppName.setOnEditorActionListener(this); + mAppName.setEnabled(true); + mAppName.requestFocus(); + getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); + + getWindow().setBackgroundDrawableResource(android.R.color.transparent); + } + + + @Override + public boolean onEditorAction(TextView tv, int i, KeyEvent keyEvent) { + boolean handled = false; + if (i == EditorInfo.IME_ACTION_DONE) { + String temp = mAppName.getText().toString(); + if (!temp.isEmpty()) { + DbUtils.putAppName(appPackage, temp); + //reflect this on screen immediately + launcherActivity.onAppRenamed(appPackage, temp); + cancel(); + } + handled = true; + } + return handled; + } +} diff --git a/app/src/main/java/io/github/sankalp/lunox/dialogs/ThemeSelectorDialog.java b/app/src/main/java/io/github/sankalp/lunox/dialogs/ThemeSelectorDialog.java new file mode 100644 index 0000000..eea1947 --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/dialogs/ThemeSelectorDialog.java @@ -0,0 +1,88 @@ +/* + * Last Launcher + * Copyright (C) 2019 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.dialogs; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.view.View; +import android.view.Window; +import android.widget.LinearLayout; + +import io.github.sankalp.lunox.LauncherActivity; +import io.github.sankalp.lunox.R; +import io.github.sankalp.lunox.utils.DbUtils; + +public class ThemeSelectorDialog extends Dialog implements View.OnClickListener { + + private final LauncherActivity context; + + ThemeSelectorDialog(Context context, LauncherActivity launcherActivity) { + super(context); + this.context = launcherActivity; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + requestWindowFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.dialog_theme_selector); + LinearLayout ll = findViewById(R.id.theme_linear_layout); + for (int i = 0; i < ll.getChildCount(); i++) { + ll.getChildAt(i).setOnClickListener(this); + } + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.t1: + setTheme(R.style.AppTheme); + break; + case R.id.t2: + setTheme(R.style.Wallpaper); + break; + case R.id.t3: + setTheme(R.style.Black); + break; + case R.id.t4: + setTheme(R.style.White); + break; + case R.id.t5: + setTheme(R.style.WhiteOnGrey); + break; + case R.id.t6: + setTheme(R.style.BlackOnGrey); + break; + case R.id.t35: + setTheme(R.style.Hacker_green); + break; + case R.id.t36: + setTheme(R.style.Hacker_red); + break; + } + } + + private void setTheme(int appTheme) { + DbUtils.setTheme(appTheme); + DbUtils.externalSourceColor(false); + cancel(); + context.recreate(); + } +} diff --git a/app/src/main/java/io/github/sankalp/lunox/model/Apps.java b/app/src/main/java/io/github/sankalp/lunox/model/Apps.java new file mode 100644 index 0000000..bb946be --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/model/Apps.java @@ -0,0 +1,219 @@ +/* + * Last Launcher + * Copyright (C) 2019 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.model; + +import android.view.View; + +import io.github.sankalp.lunox.utils.DbUtils; +import io.github.sankalp.lunox.utils.Utils; +import io.github.sankalp.lunox.views.textview.AppTextView; + + +// a model class that hold everything related to an app +public class Apps { + + // App activity name format package.name/package.name.ClassName + // For eg. com.example.app_name/com.example.app_name.MainActivity + // For eg io.github.sankalp.lunox/io.github.sankalp.lunox.LauncherActivity + // if this is a shortcut then this field represent a unique URI string + final private String activity; + // a text view or a subclass of TextView + private final AppTextView textView; + // tell whether this is a shortcut or not if this is shortcut then activity field wll holds the Uri not an activity + private final boolean isShortcut; + // app name to shown on screen + private String appName; + // app text color + private int color; + // app text size + private int size; + // is app text size frozen + private boolean isSizeFrozen; + // is app hidden from home screen + private boolean isAppHidden; + //store how many time this app is opened by user + // save this to DB. So launcher can sort the app based on this + // in theory this is a tracking count which store how many time user opened this apps + // Only locally and privately saved to user device + // and btw this launcher doesn't have INTERNET PERMISSION + private int openingCounts; + // This field is use for grouping the app: not in use + private String groupPrefix; + // app belongs to this categories,,: not in use + private String categories; + // last updated date and time + private int updateTime; + + private int recentUsedWeight; + + + /** + * @param isShortcut tell whether this shortcut or not + * @param activity activity path if this is shortcut then it will hold a unique strings + * @param appName App name + * @param tv a text view corresponding to App + * @param color Text color + * @param size Text Size + * @param isAppHidden boolean to tell 'is app hide + * @param isSizeFrozen is app size to freeze + * @param openingCounts how many time apps was opened before this addition + * @param updateTime update time of this app since epoch (use for sorting) + */ + public Apps(boolean isShortcut, String activity, String appName, AppTextView tv, int color, int size, boolean isAppHidden, boolean isSizeFrozen, int openingCounts, int updateTime) { + + this.isShortcut = isShortcut; + this.textView = tv; + this.appName = appName; + + this.color = color; + this.size = size; + this.updateTime = updateTime; + + if (isShortcut) { + this.activity = String.valueOf(Utils.hash(activity)); + textView.setUri(activity); + // textView.setUniqueCode(this.activity); + } else { + this.activity = activity; + //textView.setUniqueCode(String.valueOf(Utils.hash(activity))); + } + + textView.setText(this.appName); + textView.setTag(this.activity); + textView.setShortcut(this.isShortcut); + + // if color is not -1 then set this to color + // else not set the color default theme text color will handle the color + if (color != DbUtils.NULL_TEXT_COLOR) + textView.setTextColor(color); + + this.openingCounts = openingCounts; + + setSize(size); + setAppHidden(isAppHidden); + setFreeze(isSizeFrozen); + + } + + public boolean isShortcut() { + return isShortcut; + } + + public boolean isSizeFrozen() { + return isSizeFrozen; + } + + public boolean isHidden() { + return isAppHidden; + } + + public void setAppHidden(boolean appHidden) { + this.isAppHidden = appHidden; + textView.setVisibility(appHidden ? View.GONE : View.VISIBLE); + DbUtils.hideApp(activity, appHidden); + } + + public int getSize() { + return size; + } + + public void setSize(int size) { + this.size = size; + textView.setTextSize(size); + DbUtils.putAppSize(activity, size); + } + + public void setFreeze(boolean freezeSize) { + this.isSizeFrozen = freezeSize; + DbUtils.freezeAppSize(activity, freezeSize); + } + + + public String getActivityName() { + return activity; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + textView.setText(appName); + } + + public AppTextView getTextView() { + return textView; + } + + public int getColor() { + return color; + } + + public void setColor(int color) { + this.color = color; + if (color != DbUtils.NULL_TEXT_COLOR) + textView.setTextColor(color); + } + + + public int getOpeningCounts() { + return openingCounts; + } + + + public void increaseOpeningCounts() { + this.openingCounts++; + DbUtils.setOpeningCounts(this.activity, openingCounts); + } + + public String getGroupPrefix() { + return groupPrefix; + } + + public void setGroupPrefix(String groupPrefix) { + this.groupPrefix = groupPrefix; + DbUtils.setCategories(this.activity, groupPrefix); + } + + public String getCategories() { + return categories; + } + + public void setCategories(String categories) { + this.categories = categories; + DbUtils.setCategories(this.activity, categories); + } + + public int getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(int updateTime) { + this.updateTime = updateTime; + } + + public int getRecentUsedWeight() { + return recentUsedWeight; + } + + public void setRecentUsedWeight(int recentUsedWeight) { + this.recentUsedWeight = recentUsedWeight; + } +} diff --git a/app/src/main/java/io/github/sankalp/lunox/model/Shortcut.java b/app/src/main/java/io/github/sankalp/lunox/model/Shortcut.java new file mode 100644 index 0000000..ea90adc --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/model/Shortcut.java @@ -0,0 +1,55 @@ +/* + * Last Launcher + * Copyright (C) 2019,2020 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.model; + +/** + * AND THE........Shortcut model + */ +public class Shortcut { + + private String name; + private String uri; + + public Shortcut() { + + } + + public Shortcut(String name, String uris) { + this.name = name; + this.uri = uris; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + +} diff --git a/app/src/main/java/io/github/sankalp/lunox/utils/Constants.java b/app/src/main/java/io/github/sankalp/lunox/utils/Constants.java new file mode 100644 index 0000000..2b4e10d --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/utils/Constants.java @@ -0,0 +1,53 @@ +/* + * Last Launcher + * Copyright (C) 2019,2020 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.utils; + +public class Constants { + + public static final int COLOR_SNIFFER_REQUEST = 154; + public final static String DEFAULT_COLOR_FOR_APPS = "default_color_for_apps"; + //various sorting constant + //why constant? Why not enums for this ? + // may be lack from Shared Preference DB + public static final int SORT_BY_NAME = 1; + public static final int SORT_BY_SIZE = 2; + public static final int SORT_BY_COLOR = 3; + public static final int SORT_BY_OPENING_COUNTS = 4; + public static final int SORT_BY_CUSTOM = 5; + public static final int SORT_BY_UPDATE_TIME = 6; + public static final int SORT_BY_RECENT_OPEN = 7; + + public static final int RESTORE_REQUEST = 125; + public static final int FONTS_REQUEST = 126; + public static final int BACKUP_REQUEST = 128; + public static final int DEFAULT_MAX_TEXT_SIZE = 10; + public static final int DEFAULT_MIN_TEXT_SIZE = -10; + public static final int MAX_PADDING_LEFT = 99; + public static final int MAX_PADDING_RIGHT = 99; + public static final int MAX_PADDING_TOP = 999; + public static final int MAX_PADDING_BOTTOM = 999; + public static final int MIN_PADDING = 0; + //TODO: Dynamic height + public static int dynamicHeight = 20; + public static final int DEFAULT_TEXT_SIZE_NORMAL_APPS = dynamicHeight; + public static final int DEFAULT_TEXT_SIZE_OFTEN_APPS = dynamicHeight * 9 / 5; + public static final int MAX_TEXT_SIZE_FOR_APPS=90; + public static final int MIN_TEXT_SIZE_FOR_APPS=14; + +} diff --git a/app/src/main/java/io/github/sankalp/lunox/utils/CrashUtils.java b/app/src/main/java/io/github/sankalp/lunox/utils/CrashUtils.java new file mode 100644 index 0000000..6dbb15a --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/utils/CrashUtils.java @@ -0,0 +1,124 @@ +/* + * Last Launcher + * Copyright (C) 2019,2020 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.utils; + +import android.content.Context; +import android.text.TextUtils; +import android.util.Log; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +//ONLY included in DEBUG BUILD: +public class CrashUtils implements Thread.UncaughtExceptionHandler { + + private static final String EXCEPTION_SUFFIX = "_exception"; + private static final String CRASH_SUFFIX = "_crash"; + private static final String FILE_EXTENSION = ".txt"; + private static final String CRASH_REPORT_DIR = "crashReports"; + + private static final String TAG = "CrashUtils"; + + + private final Thread.UncaughtExceptionHandler exceptionHandler; + + private final Context applicationContext; + private final String crashReportPath; + + public CrashUtils(Context context, String crashReportSavePath) { + this.exceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); + applicationContext = context; + crashReportPath = crashReportSavePath; + if (!(Thread.getDefaultUncaughtExceptionHandler() instanceof CrashUtils)) { + Thread.setDefaultUncaughtExceptionHandler(this); + } + } + + private static String getStackTrace(Throwable e) { + final Writer result = new StringWriter(); + final PrintWriter printWriter = new PrintWriter(result); + e.printStackTrace(printWriter); + String crashLog = result.toString(); + printWriter.close(); + return crashLog; + } + + @Override + public void uncaughtException(Thread thread, Throwable throwable) { + saveCrashReport(throwable); + exceptionHandler.uncaughtException(thread, throwable); + } + + private void saveCrashReport(final Throwable throwable) { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); + String filename = dateFormat.format(new Date()) + CRASH_SUFFIX + FILE_EXTENSION; + writeToFile(crashReportPath, filename, getStackTrace(throwable)); + + } + + private void writeToFile(String crashReportPath, String filename, String crashLog) { + + if (TextUtils.isEmpty(crashReportPath)) { + crashReportPath = getDefaultPath(); + } + + File crashDir = new File(crashReportPath); + if (!crashDir.exists() || !crashDir.isDirectory()) { + crashReportPath = getDefaultPath(); + Log.e(TAG, "Path provided doesn't exists : " + crashDir + "\nSaving crash report at : " + getDefaultPath()); + } + + BufferedWriter bufferedWriter; + try { + bufferedWriter = new BufferedWriter(new FileWriter( + crashReportPath + File.separator + filename)); + + bufferedWriter.write(crashLog); + bufferedWriter.flush(); + bufferedWriter.close(); + Log.d(TAG, "crash report saved in : " + crashReportPath); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private String getDefaultPath() { + String defaultPath = applicationContext.getExternalFilesDir(null).getAbsolutePath() + + File.separator + CRASH_REPORT_DIR; + File file = new File(defaultPath); + file.mkdirs(); + return defaultPath; + } + + public void logException(final Exception exception) { + new Thread(() -> { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); + final String filename = dateFormat.format(new Date()) + EXCEPTION_SUFFIX + FILE_EXTENSION; + writeToFile(crashReportPath, filename, getStackTrace(exception)); + }).start(); + } + +} diff --git a/app/src/main/java/io/github/sankalp/lunox/utils/Database.java b/app/src/main/java/io/github/sankalp/lunox/utils/Database.java new file mode 100644 index 0000000..f88e5ce --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/utils/Database.java @@ -0,0 +1,127 @@ +/* + * Last Launcher + * Copyright (C) 2019,2020 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.utils; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.DatabaseUtils; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import java.util.ArrayList; + +import io.github.sankalp.lunox.model.Shortcut; + +//This is new database based on SQLITE +// Why not ROOM: simply make this launcher lightweight, BTW This app database is too small :) +class Database extends SQLiteOpenHelper { + + + private static final String DB_NAME = "launcher.db"; + private static final int DB_VERSION = 1; + private static final String TABLE_NAME_SHORTCUTS = "shortcuts"; + private static final String SHORTCUT_URI = "uri"; + private static final String SHORTCUT_NAME = "name"; + private static final String CREATE_SHORTCUTS_TABLE = "CREATE TABLE shortcuts(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, uri TEXT )"; + + //private static final String TABLE_NAME_APPS = "apps"; + /*private static final String APP_ACTIVITY = "activity"; + private static final String IS_SHORTCUTS="shortcut"; + private static final String APP_NAME = "name"; + private static final String APP_ORIGINAL_NAME = "original_name"; + private static final String APP_SIZE = "size"; + private static final String APP_COLOR = "color"; + private static final String APP_VISIBILITY = "visibility"; + private static final String APP_FROZEN = "frozen"; + private static final String APP_EXTERNAL_SOURCE_COLOR = "extrn_src_color"; + private static final String APP_GROUP_PREFIX = "gp_prefix"; + private static final String APP_CATEGORY = "category"; + private static final String APP_OPENING_COUNTS = "open_count"; + private static final String id="id"; + */ + // private static final String CREATE_APPS_TABLE = "CREATE TABLE + + public Database(Context context) { + super(context, DB_NAME, null, DB_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL(CREATE_SHORTCUTS_TABLE); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME_SHORTCUTS); + onCreate(db); + } + + public void insertShortcut(String name, String uri) { + SQLiteDatabase db = getWritableDatabase(); + ContentValues cValues = new ContentValues(); + cValues.put(SHORTCUT_NAME, name); + cValues.put(SHORTCUT_URI, uri); + db.insert(TABLE_NAME_SHORTCUTS, null, cValues); + db.close(); + } + + public void deleteShortcuts(String name) { + SQLiteDatabase db = this.getWritableDatabase(); + db.delete(TABLE_NAME_SHORTCUTS, SHORTCUT_NAME + " = ?", new String[]{name}); + db.close(); + } + + public ArrayList getAllShortcuts() { + SQLiteDatabase db = this.getWritableDatabase(); + ArrayList shortcuts = new ArrayList<>(); + String query = "SELECT uri,name FROM " + TABLE_NAME_SHORTCUTS; + Cursor cursor = db.rawQuery(query, null); + while (cursor.moveToNext()) { + Shortcut shortcut = new Shortcut(); + shortcut.setName(cursor.getString(cursor.getColumnIndex(SHORTCUT_NAME))); + shortcut.setUri(cursor.getString(cursor.getColumnIndex(SHORTCUT_URI))); + shortcuts.add(shortcut); + } + cursor.close(); + return shortcuts; + } + + public int getShortcutsCounts() { + SQLiteDatabase db = this.getWritableDatabase(); + long count = DatabaseUtils.queryNumEntries(db, TABLE_NAME_SHORTCUTS); + db.close(); + return (int) count; + } + + public boolean shortcutsExists(String name) { + SQLiteDatabase db = this.getReadableDatabase(); + String sql = "SELECT EXISTS (SELECT * FROM shortcuts WHERE uri='" + name + "' LIMIT 1)"; + Cursor cursor = db.rawQuery(sql, null); + cursor.moveToFirst(); + + if (cursor.getInt(0) == 1) { + cursor.close(); + return true; + } else { + cursor.close(); + return false; + } + } +} diff --git a/app/src/main/java/io/github/sankalp/lunox/utils/DbUtils.java b/app/src/main/java/io/github/sankalp/lunox/utils/DbUtils.java new file mode 100644 index 0000000..16bc899 --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/utils/DbUtils.java @@ -0,0 +1,418 @@ +/* + * Last Launcher + * Copyright (C) 2019 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.utils; + +import android.content.Context; +import android.view.Gravity; + +import java.io.InputStream; +import java.util.Map; + +import io.github.sankalp.lunox.R; + +/** + * This is the our database class + * This is purely based on Shared prefs bcz - + * 1. faster than Sql Db + * 2. low memory usage than Sql db + * 3. low Cpu usage than sql db + * 4. easy to add new column when updating the db + * 5. easy to backup and restore. + * 6. no overhead when updating db version. + *

+ *

+ */ +public class DbUtils { + + public static final int NULL_TEXT_SIZE = -1; + public final static int NULL_TEXT_COLOR = -1; + + private static final String PADDING_TOP = "padding_top"; + private static final String RANDOM_COLOR_FOR_APPS = "random_color_for_apps"; + private static final String READ_WRITE_PERMISSION = "read_write_permission"; + private static final String LAUNCHER_FONTS = "launcher_fonts"; + private static final String LAUNCHER_THEME = "launcher_theme"; + private static final String LAUNCHER_FREEZE_SIZE = "launcher_freeze_size"; + private static final String APPS_COLOR_FROM_EXTERNAL_SOURCE = "external_app_color"; + //new addition + private static final String FLOW_LAYOUT_ALIGNMENT = "flow_layout_alignment"; + private static final String MAX_APP_SIZE = "max_app_size"; + private static final String MIN_APP_SIZE = "max_app_size"; + private static final String PADDING_LEFT = "padding_left"; + private static final String PADDING_RIGHT = "padding_right"; + private static final String PADDING_BOTTOM = "padding_bottom"; + + private static final String GLOBAL_SIZE_ADDITION_EXTRA = "global_size_addition_extra"; + private static final String APPS_COLORS_DEFAULT = "apps_color_default"; + private static final String APPS_SORTS_TYPE = "apps_sorts_types"; + + + public static void init(Context context) { + SpUtils.getInstance().init(context); + } + + public static void clearDB() { + SpUtils.getInstance().clear(); + } + + public static Map getDBData() { + return SpUtils.getInstance().getAll(); + } + + public static boolean loadDbFromFile(InputStream inputStream) { + return SpUtils.getInstance().loadSharedPreferencesFromFile(inputStream); + } + + + public static void putAppOriginalName(String activityName, String value) { + activityName = activityName.replaceAll("\\.", "_") + "_app_original_name"; + SpUtils.getInstance().putString(activityName, value); + } + + public static void putAppName(String activityName, String value) { + activityName = activityName.replaceAll("\\.", "_") + "_app_name"; + SpUtils.getInstance().putString(activityName, value); + } + + public static void putAppSize(String activityName, int size) { + activityName = activityName.replaceAll("\\.", "_") + "_size"; + SpUtils.getInstance().putInt(activityName, size); + + } + + public static void putAppColor(String activityName, int color) { + activityName = activityName.replaceAll("\\.", "_") + "_color"; + SpUtils.getInstance().putInt(activityName, color); + } + + + public static void putAppColorImmediately(String activityName, int color) { + activityName = activityName.replaceAll("\\.", "_") + "_color"; + SpUtils.getInstance().putIntCommit(activityName, color); + } + + public static String getAppOriginalName(String activityName, String defaultValue) { + activityName = activityName.replaceAll("\\.", "_") + "_app_original_name"; + return SpUtils.getInstance().getString(activityName, defaultValue); + } + + public static String getAppName(String activityName, String defaultValue) { + activityName = activityName.replaceAll("\\.", "_") + "_app_name"; + return SpUtils.getInstance().getString(activityName, defaultValue); + } + + public static int getAppSize(String activityName) { + activityName = activityName.replaceAll("\\.", "_") + "_size"; + return SpUtils.getInstance().getInt(activityName, NULL_TEXT_SIZE); + } + + public static int getAppColor(String activityName) { + activityName = activityName.replaceAll("\\.", "_") + "_color"; + return SpUtils.getInstance().getInt(activityName, NULL_TEXT_COLOR); + } + + public static void hideApp(String activityName, boolean value) { + activityName = activityName.replaceAll("\\.", "_") + "_hide"; + SpUtils.getInstance().putBoolean(activityName, value); + } + + public static void freezeAppSize(String activityName, boolean value) { + activityName = activityName.replaceAll("\\.", "_") + "_freeze"; + SpUtils.getInstance().putBoolean(activityName, value); + } + + public static boolean isAppFrozen(String activityName) { + activityName = activityName.replaceAll("\\.", "_") + "_freeze"; + return SpUtils.getInstance().getBoolean(activityName, false); + + } + + public static boolean isAppHidden(String activityName) { + activityName = activityName.replaceAll("\\.", "_") + "_hide"; + return SpUtils.getInstance().getBoolean(activityName, false); + + } + + public static void removeColor(String activityName) { + activityName = activityName.replaceAll("\\.", "_") + "_color"; + SpUtils.getInstance().remove(activityName); + } + + public static void removeSize(String activityName) { + activityName = activityName.replaceAll("\\.", "_") + "_size"; + SpUtils.getInstance().remove(activityName); + } + + public static void removeAppName(String activityName) { + activityName = activityName.replaceAll("\\.", "_") + "_app_name"; + SpUtils.getInstance().remove(activityName); + } + + public static int getTheme() { + int theme = SpUtils.getInstance().getInt(LAUNCHER_THEME, 2); + switch (theme) { + case 1: + return R.style.Wallpaper; + case 2: + return R.style.AppTheme; + case 3: + return R.style.White; + case 4: + return R.style.WhiteOnGrey; + case 5: + return R.style.Black; + case 6: + return R.style.BlackOnGrey; + case 7: + return R.style.Hacker_green; + case 8: + return R.style.Hacker_red; + } + + return R.style.AppTheme; + } + + public static void setTheme(int id) { + int theme = 0; + switch (id) { + case R.style.Wallpaper: + theme = 1; + break; + case R.style.AppTheme: + theme = 2; + break; + case R.style.White: + theme = 3; + break; + case R.style.WhiteOnGrey: + theme = 4; + break; + case R.style.Black: + theme = 5; + break; + case R.style.BlackOnGrey: + theme = 6; + break; + case R.style.Hacker_green: + theme = 7; + break; + case R.style.Hacker_red: + theme = 8; + break; + } + SpUtils.getInstance().putInt(LAUNCHER_THEME, theme); + } + + public static String getFonts() { + return SpUtils.getInstance().getString(LAUNCHER_FONTS, null); + } + + public static void setFonts(String path) { + SpUtils.getInstance().putString(LAUNCHER_FONTS, path); + } + + + public static void permissionRequired(boolean b) { + SpUtils.getInstance().putBoolean(READ_WRITE_PERMISSION, b); + } + + public static boolean isRandomColor() { + return SpUtils.getInstance().getBoolean(RANDOM_COLOR_FOR_APPS, false); + } + + public static void randomColor(boolean b) { + SpUtils.getInstance().putBoolean(RANDOM_COLOR_FOR_APPS, b); + } + + public static void freezeSize(boolean b) { + SpUtils.getInstance().putBoolean(LAUNCHER_FREEZE_SIZE, b); + } + + public static boolean isSizeFrozen() { + return SpUtils.getInstance().getBoolean(LAUNCHER_FREEZE_SIZE, false); + + } + + + public static boolean isExternalSourceColor() { + return SpUtils.getInstance().getBoolean(APPS_COLOR_FROM_EXTERNAL_SOURCE, false); + } + + public static void externalSourceColor(boolean b) { + SpUtils.getInstance().putBoolean(APPS_COLOR_FROM_EXTERNAL_SOURCE, b); + } + + public static int getAppColorExternalSource(String activityName) { + activityName = activityName.replaceAll("\\.", "_") + "_external_color"; + return SpUtils.getInstance().getInt(activityName, NULL_TEXT_COLOR); + } + + public static void putAppColorExternalSource(String activityName, int color) { + activityName = activityName.replaceAll("\\.", "_") + "_external_color"; + SpUtils.getInstance().putInt(activityName, color); + } + + public static int getFlowLayoutAlignment() { + return SpUtils.getInstance().getInt(FLOW_LAYOUT_ALIGNMENT, Gravity.CENTER | Gravity.CENTER_VERTICAL); + } + + public static void setFlowLayoutAlignment(int gravity) { + SpUtils.getInstance().putInt(FLOW_LAYOUT_ALIGNMENT, gravity); + } + + public static int getMaxAppSize() { + return SpUtils.getInstance().getInt(MAX_APP_SIZE, Constants.MAX_TEXT_SIZE_FOR_APPS); + } + + public static void setMaxAppSize(int size) { + SpUtils.getInstance().putInt(MAX_APP_SIZE, size); + } + + public static int getMinAppSize() { + return SpUtils.getInstance().getInt(MIN_APP_SIZE, Constants.MIN_TEXT_SIZE_FOR_APPS); + } + + public static void setMinAppSize(int size) { + SpUtils.getInstance().putInt(MIN_APP_SIZE, size); + } + + /////// + public static int getPaddingLeft() { + return SpUtils.getInstance().getInt(PADDING_LEFT, 0); + } + + public static void setPaddingLeft(int padding) { + SpUtils.getInstance().putInt(PADDING_LEFT, padding); + } + + public static int getPaddingRight() { + return SpUtils.getInstance().getInt(PADDING_RIGHT, 0); + } + + public static void setPaddingRight(int padding) { + SpUtils.getInstance().putInt(PADDING_RIGHT, padding); + } + + public static int getPaddingTop() { + return SpUtils.getInstance().getInt(PADDING_TOP, 0); + } + + public static void setPaddingTop(int padding) { + SpUtils.getInstance().putInt(PADDING_TOP, padding); + } + + public static int getPaddingBottom() { + return SpUtils.getInstance().getInt(PADDING_BOTTOM, 0); + } + + public static void setPaddingBottom(int padding) { + SpUtils.getInstance().putInt(PADDING_BOTTOM, padding); + } + + + public static void setGroupPrefix(String activityName, String prefix) { + activityName = activityName.replaceAll("\\.", "_") + "_group_prefix"; + SpUtils.getInstance().putString(activityName, prefix); + } + + public static void setCategories(String activityName, String categories) { + activityName = activityName.replaceAll("\\.", "_") + "_categories"; + SpUtils.getInstance().putString(activityName, categories); + } + + public static void setOpeningCounts(String activityName, int count) { + activityName = activityName.replaceAll("\\.", "_") + "_opening_counts"; + SpUtils.getInstance().putString(activityName, codeCount(count)); + } + + public static String getGroupPrefix(String activityName) { + activityName = activityName.replaceAll("\\.", "_") + "_group_prefix"; + return SpUtils.getInstance().getString(activityName); + } + + public static String getCategories(String activityName) { + activityName = activityName.replaceAll("\\.", "_") + "_categories"; + return SpUtils.getInstance().getString(activityName); + } + + public static int getOpeningCounts(String activityName) { + activityName = activityName.replaceAll("\\.", "_") + "_opening_counts"; + return decodeCount(SpUtils.getInstance().getString(activityName, null)); + } + + public static int getGlobalSizeAdditionExtra() { + return SpUtils.getInstance().getInt(GLOBAL_SIZE_ADDITION_EXTRA, 0); + } + + public static void setGlobalSizeAdditionExtra(int extra) { + SpUtils.getInstance().putInt(GLOBAL_SIZE_ADDITION_EXTRA, extra); + } + + public static int getAppsColorDefault() { + return SpUtils.getInstance().getInt(APPS_COLORS_DEFAULT, NULL_TEXT_COLOR); + } + + public static void setAppsColorDefault(int color) { + SpUtils.getInstance().putInt(APPS_COLORS_DEFAULT, color); + } + + public static void removeFont() { + SpUtils.getInstance().remove(LAUNCHER_FONTS); + } + + public static boolean isFontExists() { + return SpUtils.getInstance().contains(LAUNCHER_FONTS); + } + + public static int getSortsTypes() { + return SpUtils.getInstance().getInt(APPS_SORTS_TYPE, 1); + } + + public static void setAppsSortsType(int type) { + SpUtils.getInstance().putInt(APPS_SORTS_TYPE, type); + } + + // a simple ciphered counter: "opening counter" is a private thing + // rest is on device security + private static String codeCount(int count) { + char[] map = "(e*+@_$k&m".toCharArray(); + int info = count ^ 86194; + StringBuilder enc = new StringBuilder(); + while (info > 0) { + int c = info % 10; + info /= 10; + enc.append(map[c]); + } + return enc.toString(); + } + + private static int decodeCount(String text) { + if (text == null) return 0; + + String map = "(e*+@_$k&m"; + int value = 0; + for (int i = text.length() - 1; i >= 0; i--) { + value *= 10; + value += map.indexOf(text.charAt(i)); + } + return value ^ 86194; + } + + +} diff --git a/app/src/main/java/io/github/sankalp/lunox/utils/DeviceAdminManager.java b/app/src/main/java/io/github/sankalp/lunox/utils/DeviceAdminManager.java new file mode 100644 index 0000000..bf566c4 --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/utils/DeviceAdminManager.java @@ -0,0 +1,50 @@ +package io.github.sankalp.lunox.utils; + +import android.app.admin.DevicePolicyManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.widget.Toast; + +import io.github.sankalp.lunox.R; + +public class DeviceAdminManager { + + private static final String TAG = "DeviceAdminManager"; + + public static boolean isDeviceAdminActive(Context context) { + DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); + ComponentName adminComponent = new ComponentName(context, io.github.sankalp.lunox.utils.lunoxDeviceAdminReceiver.class); + return dpm.isAdminActive(adminComponent); + } + + public static void requestDeviceAdminPermission(Context context) { + DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); + ComponentName adminComponent = new ComponentName(context, io.github.sankalp.lunox.utils.lunoxDeviceAdminReceiver.class); + + Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN); + intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, adminComponent); + intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, context.getString(R.string.device_admin_description)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } + + public static boolean lockDevice(Context context) { + if (!isDeviceAdminActive(context)) { + Toast.makeText(context, R.string.device_admin_disabled, Toast.LENGTH_SHORT).show(); + requestDeviceAdminPermission(context); + return false; + } + + try { + DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); + ComponentName adminComponent = new ComponentName(context, io.github.sankalp.lunox.utils.lunoxDeviceAdminReceiver.class); + dpm.lockNow(); + return true; + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(context, "Failed to lock device", Toast.LENGTH_SHORT).show(); + return false; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/github/sankalp/lunox/utils/Gestures.java b/app/src/main/java/io/github/sankalp/lunox/utils/Gestures.java new file mode 100644 index 0000000..656570e --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/utils/Gestures.java @@ -0,0 +1,93 @@ +/* + * Last Launcher + * Copyright (C) 2019,2020 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.utils; + +import android.app.Activity; +import android.view.GestureDetector; +import android.view.MotionEvent; + + +public class Gestures extends GestureDetector.SimpleOnGestureListener { + + private static final int minScrollDistanceX = 50; + private static final int minScrollDistanceY = 50; + + private final GestureDetector detector; + private final OnSwipeListener listener; + + public Gestures(Activity context, + OnSwipeListener onSwipeListener) { + + this.detector = new GestureDetector(context, this); + this.listener = onSwipeListener; + } + + public void onTouchEvent(MotionEvent event) { + detector.onTouchEvent(event); + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + boolean consumed = false; + float absDistanceX = Math.abs(distanceX); + float absDistanceY = Math.abs(distanceY); + if (absDistanceX > absDistanceY) { + // horizontal scroll + if (absDistanceX > minScrollDistanceX) { + if (distanceX > 0) { + this.listener.onSwipe(Direction.SWIPE_LEFT); + } else { + this.listener.onSwipe(Direction.SWIPE_RIGHT); + } + consumed = true; + } + + } else { + // vertical scroll + if (absDistanceY > minScrollDistanceY) { + if (distanceY > 0) { + this.listener.onSwipe(Direction.SWIPE_UP); + } else { + this.listener.onSwipe(Direction.SWIPE_DOWN); + } + consumed = true; + } + + } + return consumed; + } + + @Override + public boolean onDoubleTap(MotionEvent arg) { + this.listener.onDoubleTap(); + return true; + } + + + public enum Direction { + SWIPE_UP, SWIPE_DOWN, SWIPE_LEFT, SWIPE_RIGHT + } + + public interface OnSwipeListener { + void onSwipe(Direction direction); + + void onDoubleTap(); + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/github/sankalp/lunox/utils/ShortcutUtils.java b/app/src/main/java/io/github/sankalp/lunox/utils/ShortcutUtils.java new file mode 100644 index 0000000..d8ad76c --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/utils/ShortcutUtils.java @@ -0,0 +1,115 @@ +/* + * Last Launcher + * Copyright (C) 2019,2020 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.utils; + +import android.content.Context; +import android.content.Intent; + +import java.util.ArrayList; + +import io.github.sankalp.lunox.model.Shortcut; + +/** + * This class manages Shortcut installed by user + * most of the methods are now wrapper to Database + */ +public class ShortcutUtils { + + private Database db; + + public ShortcutUtils(Context context) { + if (null == db) { + synchronized (ShortcutUtils.class) { + if (null == db) { + db = new Database(context); + } + } + } + } + + public void close() { + db.close(); + } + + private void checkDB() throws Throwable { + if (db == null) { + throw new Throwable("Db is null"); + } + } + + public ArrayList getAllShortcuts() { + return db.getAllShortcuts(); + } + + /** + * Add new shortcut + * + * @param shortcut instance of shortcut to be added + */ + + public void addShortcut(Shortcut shortcut) { + + db.insertShortcut(shortcut.getName(), shortcut.getUri()); + } + + /** + * remove the shortcuts + * + * @param shortcut to be removed + */ + + + public void removeShortcut(Shortcut shortcut) { + db.deleteShortcuts(shortcut.getName()); + } + + + /** + * return true if shortcut is already install + * + * @param name uri of shortcut + * @return true if already installed + */ + public boolean isShortcutAlreadyAvailable(String name) { + return db.shortcutsExists(name); + } + + + /** + * number of shortcut installed + * + * @return number of shortcut installed in this launcher + */ + public int getShortcutCounts() { + return db.getShortcutsCounts(); + } + + public boolean isShortcutToApp(String uri) { + try { + Intent intent = Intent.parseUri(uri, 0); + if (intent.getCategories() != null && intent.getCategories().contains(Intent.CATEGORY_LAUNCHER) && Intent.ACTION_MAIN.equals(intent.getAction())) { + return true; + } + } catch (Exception e) { + return false; + } + return false; + } + +} diff --git a/app/src/main/java/io/github/sankalp/lunox/utils/SpUtils.java b/app/src/main/java/io/github/sankalp/lunox/utils/SpUtils.java new file mode 100644 index 0000000..d3c7e86 --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/utils/SpUtils.java @@ -0,0 +1,228 @@ +/* + * Last Launcher + * Copyright (C) 2019 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.utils; + + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; +import android.os.Environment; +import android.preference.PreferenceManager; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.Map; + +// utility to handle shared prefs +class SpUtils { + private volatile static SpUtils mInstance; + private SharedPreferences mPref; + + private SpUtils() { + } + + static SpUtils getInstance() { + if (null == mInstance) { + synchronized (SpUtils.class) { + if (null == mInstance) { + mInstance = new SpUtils(); + } + } + } + return mInstance; + } + + void init(Context context) { + if (mPref == null) { + mPref = PreferenceManager.getDefaultSharedPreferences(context); + } + } + + void putString(String key, String value) { + if (mPref != null) { + Editor editor = mPref.edit(); + editor.putString(key, value); + editor.apply(); + } else throw new RuntimeException("First Initialize context"); + } + + void putLong(String key, long value) { + if (mPref != null) { + Editor editor = mPref.edit(); + editor.putLong(key, value); + editor.apply(); + } else throw new RuntimeException("First Initialize context"); + } + + void putInt(String key, int value) { + + if (mPref != null) { + Editor editor = mPref.edit(); + editor.putInt(key, value); + editor.apply(); + } else throw new RuntimeException("First Initialize context"); + } + + void putIntCommit(String key, int value) { + + if (mPref != null) { + Editor editor = mPref.edit(); + editor.putInt(key, value); + editor.commit(); + } else throw new RuntimeException("First Initialize context"); + } + + void putBoolean(String key, boolean value) { + if (mPref != null) { + Editor editor = mPref.edit(); + editor.putBoolean(key, value); + editor.apply(); + } else throw new RuntimeException("First Initialize context"); + } + + public boolean getBoolean(String key) { + if (mPref != null) { + return mPref.getBoolean(key, false); + } else throw new RuntimeException("First Initialize context"); + } + + boolean getBoolean(String key, boolean def) { + if (mPref != null) { + return mPref.getBoolean(key, def); + } else throw new RuntimeException("First Initialize context"); + } + + + String getString(String key) { + if (mPref != null) { + return mPref.getString(key, ""); + } else throw new RuntimeException("First Initialize context"); + } + + String getString(String key, String def) { + if (mPref != null) { + return mPref.getString(key, def); + } else throw new RuntimeException("First Initialize context"); + } + + public long getLong(String key) { + if (mPref != null) { + return mPref.getLong(key, 0); + } else throw new RuntimeException("First Initialize context"); + } + + public long getLong(String key, int defInt) { + if (mPref != null) { + return mPref.getLong(key, defInt); + } else throw new RuntimeException("First Initialize context"); + } + + int getInt(String key) { + if (mPref != null) { + return mPref.getInt(key, 0); + } else throw new RuntimeException("First Initialize context"); + } + + int getInt(String key, int defInt) { + if (mPref != null) { + return mPref.getInt(key, defInt); + } else throw new RuntimeException("First Initialize context"); + } + + boolean contains(String key) { + if (mPref != null) { + return mPref.contains(key); + } else throw new RuntimeException("First Initialize context"); + } + + + void remove(String key) { + if (mPref != null) { + Editor editor = mPref.edit(); + editor.remove(key); + editor.apply(); + } else throw new RuntimeException("First Initialize context"); + } + + void clear() { + if (mPref != null) { + Editor editor = mPref.edit(); + editor.clear(); + editor.commit(); + } else throw new RuntimeException("First Initialize context"); + } + + + + + //stub + @SuppressWarnings("unchecked") + boolean loadSharedPreferencesFromFile(InputStream inputS) { + boolean res = false; + ObjectInputStream input = null; + try { + input = new ObjectInputStream(inputS); + clear(); + //noinspection unchecked + Map entries = (Map) input.readObject(); + for (Map.Entry entry : entries.entrySet()) { + Object v = entry.getValue(); + String key = entry.getKey(); + + if (v instanceof Boolean) + putBoolean(key, (Boolean) v); + else if (v instanceof Integer) + putInt(key, (Integer) v); + else if (v instanceof Long) + putLong(key, (Long) v); + else if (v instanceof String) + putString(key, ((String) v)); + } + + res = true; + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } finally { + try { + if (input != null) { + input.close(); + } + } catch (IOException ex) { + ex.printStackTrace(); + } + } + return res; + } + + Map getAll() { + return mPref.getAll(); + } +} diff --git a/app/src/main/java/io/github/sankalp/lunox/utils/UserUtils.java b/app/src/main/java/io/github/sankalp/lunox/utils/UserUtils.java new file mode 100644 index 0000000..8ed2d94 --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/utils/UserUtils.java @@ -0,0 +1,61 @@ +/* + * Last Launcher + * Copyright (C) 2019 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.utils; + +import android.annotation.TargetApi; +import android.content.Context; +import android.os.Process; +import android.os.UserHandle; +import android.os.UserManager; + + +// not in use +@Deprecated +@TargetApi(21) +public class UserUtils { + private final UserManager userManager; + + + public UserUtils(Context context) { + + this.userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); + + } + + public long getSerial(UserHandle user) { + + return userManager.getSerialNumberForUser(user); + + } + + public UserHandle getUser(long serial) { + return userManager.getUserForSerialNumber(serial); + } + + public long getCurrentSerial() { + + return getSerial(getCurrentUser()); + + } + + public UserHandle getCurrentUser() { + return Process.myUserHandle(); + + } +} \ No newline at end of file diff --git a/app/src/main/java/io/github/sankalp/lunox/utils/Utils.java b/app/src/main/java/io/github/sankalp/lunox/utils/Utils.java new file mode 100644 index 0000000..da9bd89 --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/utils/Utils.java @@ -0,0 +1,304 @@ +/* + * Last Launcher + * Copyright (C) 2019 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.utils; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +@SuppressWarnings("SpellCheckingInspection") +public class Utils { + + // popular and often used app on fdroid and in android system + // and some of my favourite apps + public static List getOftenAppsList() { + String[] list = { + "com.google.android.apps.maps",//map + "com.android.gallery3d",// + "com.android.settings", + "com.android.mms", + "com.android.contacts", + "com.android.email", + "com.android.vending",//play store + "com.android.chrome", + "com.android.calendar", + "org.thoughtcrime.securesms", + "org.telegram.messenger", + "com.whatsapp", + "org.sufficientlysecure.viewer", //pdf viewer + "org.fdroid.fdroid", + "org.mozilla.firefox", + "org.schabi.newpipe", + "eu.faircode.email", + "com.simplemobiletools.gallery.pro", + "com.simplemobiletools.contacts.pro", + "com.simplemobiletools.calendar.pro", + "com.kunzisoft.keepas.libre", + "org.videolan.vlc", + "com.termux", + "com.nextcloud.android", + "ryey.easer.beta", + "it.niedermann.owncloud.notes", + "com.keylesspalace.tusky", + "de.nproth.pin", + "io.github.sankalp.privacyapplock", + "superfreeze.tool.android", + "fr.gouv.etalab.mastodon", + "im.vector.alpha", + "com.nextcloud.client", + "com.duckduckgo.mobile.android", + "eu.siacs.conversations", + "org.torproject.torbrowser", + "com.aurora.adroid", + "net.osmand.plus", + "org.torproject.android", + "com.mediatek.filemanager", + "com.sec.android.gallery3d", + "com.sec.android.app.myfiles", + "com.android.dialer", + "com.android.camera", + "org.mozilla.fennec_fdroid", + "com.mi.android.globalFileexplorer", + "com.miui.gallery", + "com.miui.calculator", + "com.nonsenseapps.feeder", + "com.foobnix.pro.pdf.reader", + "com.mixplorer", + "io.github.sankalp.ocr" + + }; + return Arrays.asList(list); + + } + + public static List getColoredAppsList() { + String[] list = { + "com.android.settings", + "com.android.contacts", + "com.android.calendar", + "org.telegram.messenger", + "com.whatsapp", + "org.fdroid.fdroid", + "org.mozilla.firefox", + "org.schabi.newpipe", + "com.aurora.adroid", + "com.android.dialer", + "com.android.camera", + "org.mozilla.fennec_fdroid", + "com.miui.gallery", + "com.miui.calculator", + "com.foobnix.pro.pdf.reader", + "com.mixplorer", + "io.github.sankalp.ocr" + + }; + return Arrays.asList(list); + } + + public static int generateColorFromString(String string) { + // List of material colors + String[] colors = { + "#F44336", "#FFEBEE", "#FFCDD2", "#EF9A9A", "#E57373", "#EF5350", "#E53935", "#D32F2F", "#C62828", "#B71C1C", "#FF8A80", "#FF5252", "#FF1744", "#D50000", "#FCE4EC", "#F8BBD0", + "#F48FB1", "#F06292", "#EC407A", "#E91E63", "#D81B60", "#C2185B", "#AD1457", "#880E4F", "#FF80AB", "#FF4081", "#F50057", "#C51162", "#F3E5F5", "#E1BEE7", "#CE93D8", "#BA68C8", + "#AB47BC", "#9C27B0", "#8E24AA", "#7B1FA2", "#6A1B9A", "#4A148C", "#EA80FC", "#E040FB", "#D500F9", "#AA00FF", "#EDE7F6", "#D1C4E9", "#B39DDB", "#9575CD", "#7E57C2", "#673AB7", + "#5E35B1", "#512DA8", "#4527A0", "#311B92", "#B388FF", "#7C4DFF", "#651FFF", "#6200EA", "#E8EAF6", "#C5CAE9", "#9FA8DA", "#7986CB", "#5C6BC0", "#3F51B5", "#3949AB", "#303F9F", + "#283593", "#1A237E", "#8C9EFF", "#536DFE", "#3D5AFE", "#304FFE", "#E3F2FD", "#BBDEFB", "#90CAF9", "#64B5F6", "#42A5F5", "#2196F3", "#1E88E5", "#1976D2", "#1565C0", "#0D47A1", + "#82B1FF", "#448AFF", "#2979FF", "#2962FF", "#E1F5FE", "#B3E5FC", "#81D4FA", "#4FC3F7", "#29B6F6", "#03A9F4", "#039BE5", "#0288D1", "#0277BD", "#01579B", "#80D8FF", "#40C4FF", + "#00ACC1", "#0097A7", "#00838F", "#006064", "#84FFFF", "#18FFFF", "#00E5FF", "#00B8D4", "#E0F2F1", "#B2DFDB", "#80CBC4", "#4DB6AC", "#26A69A", "#009688", "#00897B", "#00796B", + "#00695C", "#004D40", "#A7FFEB", "#64FFDA", "#1DE9B6", "#00BFA5", "#E8F5E9", "#C8E6C9", "#A5D6A7", "#81C784", "#66BB6A", "#4CAF50", "#43A047", "#388E3C", "#2E7D32", "#1B5E20", + "#B9F6CA", "#69F0AE", "#00E676", "#00C853", "#F1F8E9", "#DCEDC8", "#C5E1A5", "#AED581", "#9CCC65", "#8BC34A", "#7CB342", "#689F38", "#558B2F", "#33691E", "#CCFF90", "#B2FF59", + "#76FF03", "#64DD17", "#F9FBE7", "#F0F4C3", "#E6EE9C", "#DCE775", "#D4E157", "#CDDC39", "#C0CA33", "#AFB42B", "#9E9D24", "#827717", "#F4FF81", "#EEFF41", "#C6FF00", "#AEEA00", + "#FFFDE7", "#FFF9C4", "#FFF59D", "#FFF176", "#FFEE58", "#FFEB3B", "#FDD835", "#FBC02D", "#F9A825", "#F57F17", "#FFFF8D", "#FFFF00", "#FFEA00", "#FFD600", "#FFF8E1", "#FFECB3", + "#FFE082", "#FFD54F", "#FFCA28", "#FFC107", "#FFB300", "#FFA000", "#FF8F00", "#FF6F00", "#FFE57F", "#FFD740", "#FFC400", "#FFAB00", "#FFF3E0", "#FFE0B2", "#FFCC80", "#FFB74D", + "#FFA726", "#FF9800", "#FB8C00", "#F57C00", "#EF6C00", "#E65100", "#FFD180", "#FFAB40", "#FF9100", "#FF6D00", "#FBE9E7", "#FFCCBC", "#FFAB91", "#FF8A65", "#FF7043", "#FF5722", + "#F4511E", "#E64A19", "#D84315", "#BF360C", "#FF9E80", "#FF6E40", "#FF3D00", "#DD2C00", "#EFEBE9", "#D7CCC8", "#BCAAA4", "#A1887F", "#8D6E63", "#795548", "#6D4C41", "#5D4037", + "#4E342E", "#3E2723", "#FAFAFA", "#F5F5F5", "#EEEEEE", "#E0E0E0", "#BDBDBD", "#9E9E9E", "#757575", "#616161", "#424242", "#212121", "#ECEFF1", "#CFD8DC", "#B0BEC5", "#90A4AE", + "#78909C", "#607D8B", "#546E7A", "#455A64", "#37474F", "#263238", "#000000", "#00B0FF", "#0091EA", "#E0F7FA", "#B2EBF2", "#80DEEA", "#4DD0E1", "#26C6DA", "#00BCD4" + }; + + int choice = 0; + + for (int i = string.length() - 1; i > 0; i -= 1) { + choice += string.codePointAt(i); + + } + return Color.parseColor(colors[choice % colors.length]); + } + + public static int hash(final String text) { + final byte[] data = text.getBytes(); + final int length = data.length; + final int seed = 0x9747b28c; + final int m = 0x5bd1e995; + final int r = 24; + + // Initialize the hash to a random value + int h = seed ^ length; + int length4 = length / 4; + + for (int i = 0; i < length4; i++) { + final int i4 = i * 4; + int k = (data[i4] & 0xff) + ((data[i4 + 1] & 0xff) << 8) + + ((data[i4 + 2] & 0xff) << 16) + ((data[i4 + 3] & 0xff) << 24); + k *= m; + k ^= k >>> r; + k *= m; + h *= m; + h ^= k; + } + + // Handle the last few bytes of the input array + switch (length % 4) { + case 3: + h ^= (data[(length & ~3) + 2] & 0xff) << 16; + case 2: + h ^= (data[(length & ~3) + 1] & 0xff) << 8; + case 1: + h ^= (data[length & ~3] & 0xff); + h *= m; + } + + h ^= h >>> 13; + h *= m; + h ^= h >>> 15; + + return h; + } + + + /** + * @param query strings to be find + * @param strings strings where to find + * @return true if @query is sequentially found in @strings else false + */ + public static boolean simpleFuzzySearch(CharSequence query, String strings) { + //convert to lowercase + query = query.toString().toLowerCase(); + strings = strings.toLowerCase(); + + int patternIdx = 0; + int strIdx = 0; + int patternLength = query.length(); + int strLength = strings.length(); + + while (patternIdx != patternLength && strIdx != strLength) { + char patternChar = query.charAt(patternIdx); + char strChar = strings.charAt(strIdx); + if (patternChar == strChar) ++patternIdx; + ++strIdx; + } + return patternLength != 0 && strLength != 0 && patternIdx == patternLength; + + } + + + + public static int getColor() { + Random random = new Random(); + int c = random.nextInt(4); + switch (c) { + case 0: + return Color.parseColor("#FF5722"); + case 1: + return Color.parseColor("#FFEB3B"); + case 2: + return Color.parseColor("#03A9F4"); + case 3: + return Color.parseColor("#8BC34A"); + } + return Color.parseColor("#FF5722"); + } + + public static int getDominantColor(Bitmap bitmap) { + if (bitmap == null) { + return Color.TRANSPARENT; + } + int width = bitmap.getWidth(); + int height = bitmap.getHeight(); + int size = width * height; + int[] pixels = new int[size]; + //Bitmap bitmap2 = bitmap.copy(Bitmap.Config.ARGB_4444, false); + bitmap.getPixels(pixels, 0, width, 0, 0, width, height); + int color; + int r = 0; + int g = 0; + int b = 0; + int a; + int count = 0; + for (int i = 0; i < pixels.length; i++) { + color = pixels[i]; + a = Color.alpha(color); + if (a > 0) { + r += Color.red(color); + g += Color.green(color); + b += Color.blue(color); + count++; + } + } + r /= count; + g /= count; + b /= count; + r = (r << 16) & 0x00FF0000; + g = (g << 8) & 0x0000FF00; + b = b & 0x000000FF; + color = 0xFF000000 | r | g | b; + return color; + } + public static Bitmap drawableToBitmap (Drawable drawable) { + Bitmap bitmap = null; + + if (drawable instanceof BitmapDrawable) { + BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; + if(bitmapDrawable.getBitmap() != null) { + return bitmapDrawable.getBitmap(); + } + } + + if(drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) { + bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel + } else { + bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); + } + + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + return bitmap; + } + + private boolean isDefaultLauncher(Context ctx) { + final Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_HOME); + final ResolveInfo resolveInfo = + ctx.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); + return resolveInfo != null && + ctx.getPackageName().equals(resolveInfo.activityInfo.packageName); + } + +} diff --git a/app/src/main/java/io/github/sankalp/lunox/utils/lunoxDeviceAdminReceiver.java b/app/src/main/java/io/github/sankalp/lunox/utils/lunoxDeviceAdminReceiver.java new file mode 100644 index 0000000..5f5f5b1 --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/utils/lunoxDeviceAdminReceiver.java @@ -0,0 +1,21 @@ +package io.github.sankalp.lunox.utils; + +import android.app.admin.DeviceAdminReceiver; +import android.content.Context; +import android.content.Intent; +import android.widget.Toast; + +public class lunoxDeviceAdminReceiver extends DeviceAdminReceiver { + + @Override + public void onEnabled(Context context, Intent intent) { + super.onEnabled(context, intent); + Toast.makeText(context, "Device Admin Enabled", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onDisabled(Context context, Intent intent) { + super.onDisabled(context, intent); + Toast.makeText(context, "Device Admin Disabled", Toast.LENGTH_SHORT).show(); + } +} \ No newline at end of file diff --git a/app/src/main/java/io/github/sankalp/lunox/views/colorseekbar/ColorSeekBar.java b/app/src/main/java/io/github/sankalp/lunox/views/colorseekbar/ColorSeekBar.java new file mode 100644 index 0000000..45f8309 --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/views/colorseekbar/ColorSeekBar.java @@ -0,0 +1,808 @@ +/* + * created by https://github.com/rtugeek/ColorSeekBar + */ + +package io.github.sankalp.lunox.views.colorseekbar; + + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.RadialGradient; +import android.graphics.RectF; +import android.graphics.Shader; +import android.os.Build; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +import java.util.ArrayList; +import java.util.List; + +import io.github.sankalp.lunox.R; + + +//https://github.com/rtugeek/ColorSeekBar + +// NOT in priority +public class ColorSeekBar extends View { + + private final List mCachedColors = new ArrayList<>(); + private final Paint colorPaint = new Paint(); + private final Paint alphaThumbGradientPaint = new Paint(); + private final Paint alphaBarPaint = new Paint(); + private final Paint mDisabledPaint = new Paint(); + private final Paint thumbGradientPaint = new Paint(); + private int[] mColorSeeds = new int[]{ + 0xFFFFFFFF, + 0xFF9900FF, + 0xFF0000FF, + 0xFF00FF00, + 0xFF00FFFF, + 0xFFFF0000, + 0xFFFF00FF, + 0xFFFF6600, + 0xFFFFFF00, + 0xFF8F8C8C, + 0xFF000000 + // 0xFFEAFEAF + }; + private int mAlpha; + private OnColorChangeListener mOnColorChangeLister; + private Context mContext; + private boolean mIsShowAlphaBar = false; + private boolean mIsVertical; + private boolean mMovingColorBar; + private boolean mMovingAlphaBar; + private Bitmap mTransparentBitmap; + private RectF mColorRect; + private int mThumbHeight = 20; + private float mThumbRadius; + private int mBarHeight = 2; + private Paint mColorRectPaint; + private int realLeft; + private int realRight; + private int mBarWidth; + private int mMaxPosition; + private RectF mAlphaRect; + private int mColorBarPosition; + private int mAlphaBarPosition; + private int mDisabledColor; + private int mBarMargin = 5; + private int mAlphaMinPosition = 0; + private int mAlphaMaxPosition = 255; + private int mBarRadius; + private int mColorsToInvoke = -1; + private boolean mInit = false; + private boolean mFirstDraw = true; + private boolean mShowThumb = true; + private OnInitDoneListener mOnInitDoneListener; + + public ColorSeekBar(Context context) { + super(context); + init(context, null, 0, 0); + } + + public ColorSeekBar(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs, 0, 0); + } + + public ColorSeekBar(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs, defStyleAttr, 0); + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public ColorSeekBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(context, attrs, defStyleAttr, defStyleRes); + } + + protected void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + applyStyle(context, attrs, defStyleAttr, defStyleRes); + } + + public void applyStyle(int resId) { + applyStyle(getContext(), null, 0, resId); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int mViewWidth = widthMeasureSpec; + int mViewHeight = heightMeasureSpec; + + int widthSpeMode = MeasureSpec.getMode(widthMeasureSpec); + int heightSpeMode = MeasureSpec.getMode(heightMeasureSpec); + + int barHeight = mIsShowAlphaBar ? mBarHeight * 2 : mBarHeight; + int thumbHeight = mIsShowAlphaBar ? mThumbHeight * 2 : mThumbHeight; + + + if (isVertical()) { + if (widthSpeMode == MeasureSpec.AT_MOST || widthSpeMode == MeasureSpec.UNSPECIFIED) { + mViewWidth = thumbHeight + barHeight + mBarMargin; + setMeasuredDimension(mViewWidth, mViewHeight); + } + + } else { + if (heightSpeMode == MeasureSpec.AT_MOST || heightSpeMode == MeasureSpec.UNSPECIFIED) { + mViewHeight = thumbHeight + barHeight + mBarMargin; + setMeasuredDimension(mViewWidth, mViewHeight); + } + } + } + + + protected void applyStyle(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + mContext = context; + //get attributes + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ColorSeekBar, defStyleAttr, defStyleRes); + int colorsId = a.getResourceId(R.styleable.ColorSeekBar_colorSeeds, 0); + mMaxPosition = a.getInteger(R.styleable.ColorSeekBar_maxPosition, 100); + mColorBarPosition = a.getInteger(R.styleable.ColorSeekBar_colorBarPosition, 0); + mAlphaBarPosition = a.getInteger(R.styleable.ColorSeekBar_alphaBarPosition, mAlphaMinPosition); + mDisabledColor = a.getInteger(R.styleable.ColorSeekBar_disabledColor, Color.GRAY); + mIsVertical = a.getBoolean(R.styleable.ColorSeekBar_isVertical, false); + mIsShowAlphaBar = a.getBoolean(R.styleable.ColorSeekBar_showAlphaBar, false); + mShowThumb = a.getBoolean(R.styleable.ColorSeekBar_showAlphaBar, true); + + int backgroundColor = a.getColor(R.styleable.ColorSeekBar_bgColor, Color.TRANSPARENT); + + mBarHeight = (int) a.getDimension(R.styleable.ColorSeekBar_barHeight, (float) dp2px(2)); + mBarRadius = (int) a.getDimension(R.styleable.ColorSeekBar_barRadius, 0); + mThumbHeight = (int) a.getDimension(R.styleable.ColorSeekBar_thumbHeight, (float) dp2px(30)); + mBarMargin = (int) a.getDimension(R.styleable.ColorSeekBar_barMargin, (float) dp2px(5)); + a.recycle(); + + mDisabledPaint.setAntiAlias(true); + mDisabledPaint.setColor(mDisabledColor); + + if (colorsId != 0) { + mColorSeeds = getColorsById(colorsId); + } + + setBackgroundColor(backgroundColor); + } + + /** + * @param id color array resource + * @return + */ + private int[] getColorsById(int id) { + if (isInEditMode()) { + String[] s = mContext.getResources().getStringArray(id); + int[] colors = new int[s.length]; + for (int j = 0; j < s.length; j++) { + colors[j] = Color.parseColor(s[j]); + } + return colors; + } else { + TypedArray typedArray = mContext.getResources().obtainTypedArray(id); + int[] colors = new int[typedArray.length()]; + for (int j = 0; j < typedArray.length(); j++) { + colors[j] = typedArray.getColor(j, Color.BLACK); + } + typedArray.recycle(); + return colors; + } + } + + private void init() { + + //init size + mThumbRadius = mThumbHeight / 2; + int mPaddingSize = (int) mThumbRadius; + int viewBottom = getHeight() - getPaddingBottom() - mPaddingSize; + int viewRight = getWidth() - getPaddingRight() - mPaddingSize; + //init left right top bottom + realLeft = getPaddingLeft() + mPaddingSize; + realRight = mIsVertical ? viewBottom : viewRight; + int realTop = getPaddingTop() + mPaddingSize; + + mBarWidth = realRight - realLeft; + + //init rect + mColorRect = new RectF(realLeft, realTop, realRight, realTop + mBarHeight); + + //init paint + LinearGradient mColorGradient = new LinearGradient(0, 0, mColorRect.width(), 0, mColorSeeds, null, Shader.TileMode.CLAMP); + mColorRectPaint = new Paint(); + mColorRectPaint.setShader(mColorGradient); + mColorRectPaint.setAntiAlias(true); + cacheColors(); + setAlphaValue(); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + if (mIsVertical) { + mTransparentBitmap = Bitmap.createBitmap(h, w, Bitmap.Config.ARGB_4444); + } else { + mTransparentBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_4444); + } + mTransparentBitmap.eraseColor(Color.TRANSPARENT); + init(); + mInit = true; + if (mColorsToInvoke != -1) { + setColor(mColorsToInvoke); + } + } + + + private void cacheColors() { + //if the view's size hasn't been initialized. do not cache. + if (mBarWidth < 1) { + return; + } + mCachedColors.clear(); + for (int i = 0; i <= mMaxPosition; i++) { + mCachedColors.add(pickColor(i)); + } + } + + @Override + protected void onDraw(Canvas canvas) { + + + if (mIsVertical) { + canvas.rotate(-90); + canvas.translate(-getHeight(), 0); + canvas.scale(-1, 1, getHeight() / 2, getWidth() / 2); + } + + float colorPosition = (float) mColorBarPosition / mMaxPosition * mBarWidth; + + colorPaint.setAntiAlias(true); + + int color = isEnabled() ? getColor(false) : mDisabledColor; + + int colorStartTransparent = Color.argb(mAlphaMaxPosition, Color.red(color), Color.green(color), Color.blue(color)); + int colorEndTransparent = Color.argb(mAlphaMinPosition, Color.red(color), Color.green(color), Color.blue(color)); + colorPaint.setColor(color); + int[] toAlpha = new int[]{colorStartTransparent, colorEndTransparent}; + //clear + canvas.drawBitmap(mTransparentBitmap, 0, 0, null); + + //draw color bar + canvas.drawRoundRect(mColorRect, mBarRadius, mBarRadius, isEnabled() ? mColorRectPaint : mDisabledPaint); + //draw color bar thumb + if (mShowThumb) { + float thumbX = colorPosition + realLeft; + float thumbY = mColorRect.top + mColorRect.height() / 2; + canvas.drawCircle(thumbX, thumbY, mBarHeight / 2 + 5, colorPaint); + + //draw color bar thumb radial gradient shader + RadialGradient thumbShader = new RadialGradient(thumbX, thumbY, mThumbRadius, toAlpha, null, Shader.TileMode.MIRROR); + thumbGradientPaint.setAntiAlias(true); + thumbGradientPaint.setShader(thumbShader); + canvas.drawCircle(thumbX, thumbY, mThumbHeight / 2, thumbGradientPaint); + } + + + if (mIsShowAlphaBar) { + //init rect + int top = (int) (mThumbHeight + mThumbRadius + mBarHeight + mBarMargin); + mAlphaRect = new RectF(realLeft, top, realRight, top + mBarHeight); + //draw alpha bar + alphaBarPaint.setAntiAlias(true); + LinearGradient alphaBarShader = new LinearGradient(0, 0, mAlphaRect.width(), 0, toAlpha, null, Shader.TileMode.CLAMP); + alphaBarPaint.setShader(alphaBarShader); + canvas.drawRect(mAlphaRect, alphaBarPaint); + + //draw alpha bar thumb + if (mShowThumb) { + float alphaPosition = (float) (mAlphaBarPosition - mAlphaMinPosition) / (mAlphaMaxPosition - mAlphaMinPosition) * mBarWidth; + float alphaThumbX = alphaPosition + realLeft; + float alphaThumbY = mAlphaRect.top + mAlphaRect.height() / 2; + canvas.drawCircle(alphaThumbX, alphaThumbY, mBarHeight / 2 + 5, colorPaint); + + //draw alpha bar thumb radial gradient shader + RadialGradient alphaThumbShader = new RadialGradient(alphaThumbX, alphaThumbY, mThumbRadius, toAlpha, null, Shader.TileMode.MIRROR); + + alphaThumbGradientPaint.setAntiAlias(true); + alphaThumbGradientPaint.setShader(alphaThumbShader); + canvas.drawCircle(alphaThumbX, alphaThumbY, mThumbHeight / 2, alphaThumbGradientPaint); + } + } + + if (mFirstDraw) { + if (mOnColorChangeLister != null) { + mOnColorChangeLister.onColorChangeListener(mColorBarPosition, mAlphaBarPosition, getColor()); + } + mFirstDraw = false; + + if (mOnInitDoneListener != null) { + mOnInitDoneListener.done(); + } + } + super.onDraw(canvas); + } + + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (!isEnabled()) { + return true; + } + float x = mIsVertical ? event.getY() : event.getX(); + float y = mIsVertical ? event.getX() : event.getY(); + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + if (isOnBar(mColorRect, x, y)) { + mMovingColorBar = true; + float value = (x - realLeft) / mBarWidth * mMaxPosition; + setColorBarPosition((int) value); + } else if (mIsShowAlphaBar) { + if (isOnBar(mAlphaRect, x, y)) { + mMovingAlphaBar = true; + } + } + break; + case MotionEvent.ACTION_MOVE: + getParent().requestDisallowInterceptTouchEvent(true); + if (mMovingColorBar) { + float value = (x - realLeft) / mBarWidth * mMaxPosition; + setColorBarPosition((int) value); + } else if (mIsShowAlphaBar) { + if (mMovingAlphaBar) { + float value = (x - realLeft) / (float) mBarWidth * (mAlphaMaxPosition - mAlphaMinPosition) + mAlphaMinPosition; + mAlphaBarPosition = (int) value; + if (mAlphaBarPosition < mAlphaMinPosition) { + mAlphaBarPosition = mAlphaMinPosition; + } else if (mAlphaBarPosition > mAlphaMaxPosition) { + mAlphaBarPosition = mAlphaMaxPosition; + } + setAlphaValue(); + } + } + if (mOnColorChangeLister != null && (mMovingAlphaBar || mMovingColorBar)) { + mOnColorChangeLister.onColorChangeListener(mColorBarPosition, mAlphaBarPosition, getColor()); + } + invalidate(); + break; + case MotionEvent.ACTION_UP: + mMovingColorBar = false; + mMovingAlphaBar = false; + break; + default: + } + return true; + } + + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + } + + public int getAlphaMaxPosition() { + return mAlphaMaxPosition; + } + + /*** + * + * @param alphaMaxPosition <= 255 && > alphaMinPosition + */ + public void setAlphaMaxPosition(int alphaMaxPosition) { + mAlphaMaxPosition = alphaMaxPosition; + if (mAlphaMaxPosition > 255) { + mAlphaMaxPosition = 255; + } else if (mAlphaMaxPosition <= mAlphaMinPosition) { + mAlphaMaxPosition = mAlphaMinPosition + 1; + } + + if (mAlphaBarPosition > mAlphaMinPosition) { + mAlphaBarPosition = mAlphaMaxPosition; + } + invalidate(); + } + + public int getAlphaMinPosition() { + return mAlphaMinPosition; + } + + /*** + * + * @param alphaMinPosition >=0 && < alphaMaxPosition + */ + public void setAlphaMinPosition(int alphaMinPosition) { + this.mAlphaMinPosition = alphaMinPosition; + if (mAlphaMinPosition >= mAlphaMaxPosition) { + mAlphaMinPosition = mAlphaMaxPosition - 1; + } else if (mAlphaMinPosition < 0) { + mAlphaMinPosition = 0; + } + + if (mAlphaBarPosition < mAlphaMinPosition) { + mAlphaBarPosition = mAlphaMinPosition; + } + invalidate(); + } + + /** + * @param r + * @param x + * @param y + * @return whether MotionEvent is performing on bar or not + */ + private boolean isOnBar(RectF r, float x, float y) { + return r.left - mThumbRadius < x && x < r.right + mThumbRadius && r.top - mThumbRadius < y && y < r.bottom + mThumbRadius; + } + + /** + * @return + * @deprecated use {@link #setOnInitDoneListener(OnInitDoneListener)} instead. + */ + public boolean isFirstDraw() { + return mFirstDraw; + } + + + /** + * @param value + * @return color + */ + private int pickColor(int value) { + return pickColor((float) value / mMaxPosition * mBarWidth); + } + + /** + * @param position + * @return color + */ + private int pickColor(float position) { + float unit = position / mBarWidth; + if (unit <= 0.0) { + return mColorSeeds[0]; + } + + + if (unit >= 1) { + return mColorSeeds[mColorSeeds.length - 1]; + } + + float colorPosition = unit * (mColorSeeds.length - 1); + int i = (int) colorPosition; + colorPosition -= i; + int c0 = mColorSeeds[i]; + int c1 = mColorSeeds[i + 1]; + + // mAlpha = mix(Color.alpha(c0), Color.alpha(c1), colorPosition); + + int mRed = mix(Color.red(c0), Color.red(c1), colorPosition); + int mGreen = mix(Color.green(c0), Color.green(c1), colorPosition); + int mBlue = mix(Color.blue(c0), Color.blue(c1), colorPosition); + + return Color.rgb(mRed, mGreen, mBlue); + } + + /** + * @param start + * @param end + * @param position + * @return + */ + private int mix(int start, int end, float position) { + return start + Math.round(position * (end - start)); + } + + public int getColor() { + return getColor(mIsShowAlphaBar); + } + + /** + * Set color,the mCachedColors must contains the specified color, if not ,invoke setColorBarPosition(0); + * + * @param color + */ + public void setColor(int color) { + int withoutAlphaColor = Color.rgb(Color.red(color), Color.green(color), Color.blue(color)); + if (mInit) { + int value = mCachedColors.indexOf(withoutAlphaColor); + setAlphaValue(Color.alpha(color)); + setColorBarPosition(value); + + } else { + mColorsToInvoke = color; + } + + } + + /** + * @param withAlpha + * @return + */ + public int getColor(boolean withAlpha) { + //pick mode + if (mColorBarPosition >= mCachedColors.size()) { + int color = pickColor(mColorBarPosition); + if (withAlpha) { + return color; + } else { + return Color.argb(getAlphaValue(), Color.red(color), Color.green(color), Color.blue(color)); + } + } + + //cache mode + int color = mCachedColors.get(mColorBarPosition); + + if (withAlpha) { + return Color.argb(getAlphaValue(), Color.red(color), Color.green(color), Color.blue(color)); + } + return color; + } + + public int getAlphaBarPosition() { + return mAlphaBarPosition; + } + + public void setAlphaBarPosition(int value) { + this.mAlphaBarPosition = value; + setAlphaValue(); + invalidate(); + } + + public int getAlphaValue() { + return mAlpha; + } + + private void setAlphaValue(int value) { + mAlpha = value; + mAlphaBarPosition = 255 - mAlpha; + // invalidate(); + } + + /** + * @param onColorChangeListener + */ + public void setOnColorChangeListener(OnColorChangeListener onColorChangeListener) { + this.mOnColorChangeLister = onColorChangeListener; + } + + public int dp2px(float dpValue) { + final float scale = mContext.getResources().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } + + /** + * Set colors by resource id. The resource's type must be ArrayRes + * + * @param resId + */ + public void setColorSeeds(int resId) { + setColorSeeds(getColorsById(resId)); + } + + public void setColorSeeds(int[] colors) { + mColorSeeds = colors; + init(); + invalidate(); + if (mOnColorChangeLister != null) { + mOnColorChangeLister.onColorChangeListener(mColorBarPosition, mAlphaBarPosition, getColor()); + } + } + + /** + * @param color + * @return the color's position in the bar, if not in the bar ,return -1; + */ + public int getColorIndexPosition(int color) { + return mCachedColors.indexOf(Color.argb(255, Color.red(color), Color.green(color), Color.blue(color))); + } + + public List getColors() { + return mCachedColors; + } + +// public void setVertical(boolean vertical) { +// mIsVertical = vertical; +// refreshLayoutParams(); +// invalidate(); +// } + + public boolean isShowAlphaBar() { + return mIsShowAlphaBar; + } + + public void setShowAlphaBar(boolean show) { + mIsShowAlphaBar = show; + refreshLayoutParams(); + invalidate(); + if (mOnColorChangeLister != null) { + mOnColorChangeLister.onColorChangeListener(mColorBarPosition, mAlphaBarPosition, getColor()); + } + } + + private void refreshLayoutParams() { + setLayoutParams(getLayoutParams()); + } + + public boolean isVertical() { + return mIsVertical; + } + + /** + * @param px + */ + public void setBarHeightPx(int px) { + mBarHeight = px; + refreshLayoutParams(); + invalidate(); + } + + private void setAlphaValue() { + mAlpha = 255 - mAlphaBarPosition; + } + + public int getMaxValue() { + return mMaxPosition; + } + + public void setMaxPosition(int value) { + this.mMaxPosition = value; + invalidate(); + cacheColors(); + } + + /** + * set margin between bars + * + * @param mBarMargin + */ + public void setBarMarginPx(int mBarMargin) { + this.mBarMargin = mBarMargin; + refreshLayoutParams(); + invalidate(); + } + + public void setPosition(int colorBarPosition, int alphaBarPosition) { + this.mColorBarPosition = colorBarPosition; + mColorBarPosition = Math.min(mColorBarPosition, mMaxPosition); + mColorBarPosition = Math.max(mColorBarPosition, 0); + this.mAlphaBarPosition = alphaBarPosition; + setAlphaValue(); + invalidate(); + if (mOnColorChangeLister != null) { + mOnColorChangeLister.onColorChangeListener(mColorBarPosition, mAlphaBarPosition, getColor()); + } + } + + public void setOnInitDoneListener(OnInitDoneListener listener) { + this.mOnInitDoneListener = listener; + } + + /** + * set thumb's height by pixels + * + * @param px + */ + public void setThumbHeightPx(int px) { + this.mThumbHeight = px; + mThumbRadius = mThumbHeight / 2; + refreshLayoutParams(); + invalidate(); + } + + public int getBarHeight() { + return mBarHeight; + } + + /** + * @param dp + */ + public void setBarHeight(float dp) { + mBarHeight = dp2px(dp); + refreshLayoutParams(); + invalidate(); + } + + public int getThumbHeight() { + return mThumbHeight; + } + + /** + * set thumb's height by dpi + * + * @param dp + */ + public void setThumbHeight(float dp) { + this.mThumbHeight = dp2px(dp); + mThumbRadius = mThumbHeight / 2; + refreshLayoutParams(); + invalidate(); + } + + public int getBarMargin() { + return mBarMargin; + } + + /** + * set margin between bars + * + * @param mBarMargin + */ + public void setBarMargin(float mBarMargin) { + this.mBarMargin = dp2px(mBarMargin); + refreshLayoutParams(); + invalidate(); + } + + public float getColorBarValue() { + return mColorBarPosition; + } + + public int getColorBarPosition() { + return mColorBarPosition; + } + + /** + * Set the value of color bar, if out of bounds , it will be 0 or maxValue; + * + * @param value + */ + public void setColorBarPosition(int value) { + this.mColorBarPosition = value; + mColorBarPosition = Math.min(mColorBarPosition, mMaxPosition); + mColorBarPosition = Math.max(mColorBarPosition, 0); + invalidate(); + + if (mOnColorChangeLister != null) { + mOnColorChangeLister.onColorChangeListener(mColorBarPosition, mAlphaBarPosition, getColor()); + } + } + + public int getDisabledColor() { + return mDisabledColor; + } + + public void setDisabledColor(int disabledColor) { + this.mDisabledColor = disabledColor; + mDisabledPaint.setColor(disabledColor); + } + + public boolean isShowThumb() { + return mShowThumb; + } + + public void setShowThumb(boolean showThumb) { + this.mShowThumb = showThumb; + invalidate(); + } + + public int getBarRadius() { + return mBarRadius; + } + + /** + * Set bar radius with px unit + * + * @param barRadiusInPx + */ + public void setBarRadius(int barRadiusInPx) { + this.mBarRadius = barRadiusInPx; + invalidate(); + } + + public interface OnColorChangeListener { + /** + * @param colorBarPosition between 0-maxValue + * @param alphaBarPosition between 0-255 + * @param color return the color contains alpha value whether showAlphaBar is true or without alpha value + */ + void onColorChangeListener(int colorBarPosition, int alphaBarPosition, int color); + } + + public interface OnInitDoneListener { + void done(); + } + +} diff --git a/app/src/main/java/io/github/sankalp/lunox/views/textview/AnimatedTextView.java b/app/src/main/java/io/github/sankalp/lunox/views/textview/AnimatedTextView.java new file mode 100644 index 0000000..183a3ba --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/views/textview/AnimatedTextView.java @@ -0,0 +1,113 @@ +/* + * Last Launcher + * Copyright (C) 2019,2020 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.views.textview; + + +/** + * RainbowTextView + * Created by hanks on 2017/3/14. + */ + + +// a new and animated text view may be used in future +public class AnimatedTextView /*extends AppTextView*/ { + + /* private Matrix mMatrix; + private float mTranslate; + private float colorSpeed; + private float colorSpace; + + private int[] colors = {0xFFFF2B22, 0xFFFF7F22, 0xFFEDFF22, 0xFF22FF22, 0xFF22F4FF, 0xFF2239FF, 0xFF5400F7}; + + private LinearGradient mLinearGradient; + + public AnimatedTextView(Context context) { + this(context, null); + } + + public AnimatedTextView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public AnimatedTextView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(attrs, defStyleAttr); + } + + + private void init(AttributeSet attrs, int defStyleAttr) { + + TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.AnimatedTextView); + colorSpace = typedArray.getDimension(R.styleable.AnimatedTextView_colorSpace, dp2px(150)); + colorSpeed = typedArray.getDimension(R.styleable.AnimatedTextView_colorSpeed, dp2px(5)); + typedArray.recycle(); + + mMatrix = new Matrix(); + initPaint(); + } + + public float getColorSpace() { + return colorSpace; + } + + public void setColorSpace(float colorSpace) { + this.colorSpace = colorSpace; + } + + public float getColorSpeed() { + return colorSpeed; + } + + public void setColorSpeed(float colorSpeed) { + this.colorSpeed = colorSpeed; + } + + public void setColors(int... colors) { + this.colors = colors; + initPaint(); + } + + private void initPaint() { + mLinearGradient = new LinearGradient(0, 0, colorSpace, 0, colors, null, Shader.TileMode.MIRROR); + getPaint().setShader(mLinearGradient); + } + + @Override + protected void onDraw(Canvas canvas) { + if (mMatrix == null) { + mMatrix = new Matrix(); + } + mTranslate += colorSpeed; + mMatrix.setTranslate(mTranslate, 0); + mLinearGradient.setLocalMatrix(mMatrix); + super.onDraw(canvas); + postInvalidateDelayed(100); + } + + public static int dp2px(float dp) { + return Math.round(dp * getDisplayMetrics().density); + } + + public static DisplayMetrics getDisplayMetrics() { + // Math.round(150* Resources.getSystem().getDisplayMetrics().density); + return Resources.getSystem().getDisplayMetrics(); + } +*/ + +} \ No newline at end of file diff --git a/app/src/main/java/io/github/sankalp/lunox/views/textview/AppTextView.java b/app/src/main/java/io/github/sankalp/lunox/views/textview/AppTextView.java new file mode 100644 index 0000000..8be6908 --- /dev/null +++ b/app/src/main/java/io/github/sankalp/lunox/views/textview/AppTextView.java @@ -0,0 +1,87 @@ +/* + * Last Launcher + * Copyright (C) 2019,2020 Shubham Tyagi + * + * 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 . + */ + +package io.github.sankalp.lunox.views.textview; + +import android.content.Context; +import android.graphics.Canvas; +import android.util.AttributeSet; +import android.widget.TextView; + + +/** + * App TextView class + * Simple TextView no cosmetic, no styling.. + * only hold some extra fields that are useful for this launcher + */ +public class AppTextView extends TextView { + + //private String activity; + // private String packageID; + //private int size; + // private int color; + // private int isFrozen; + // private int openingCounts; + + + //private String uniqueCode; + private boolean isShortcut; + private String uri; + + public AppTextView(Context context) { + super(context); + } + + public AppTextView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + + public AppTextView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + /* public String getUniqueCode() { + return uniqueCode; + } + + public void setUniqueCode(String uniqueCode) { + this.uniqueCode = uniqueCode; + }*/ + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public boolean isShortcut() { + return isShortcut; + } + + public void setShortcut(boolean shortcut) { + isShortcut = shortcut; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + } +} diff --git a/app/src/main/res/drawable/cursor.xml b/app/src/main/res/drawable/cursor.xml new file mode 100644 index 0000000..dc7d5fa --- /dev/null +++ b/app/src/main/res/drawable/cursor.xml @@ -0,0 +1,24 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/edit_text.xml b/app/src/main/res/drawable/edit_text.xml new file mode 100644 index 0000000..12bc6cc --- /dev/null +++ b/app/src/main/res/drawable/edit_text.xml @@ -0,0 +1,28 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/edit_text_select_handle.xml b/app/src/main/res/drawable/edit_text_select_handle.xml new file mode 100644 index 0000000..5dd8d63 --- /dev/null +++ b/app/src/main/res/drawable/edit_text_select_handle.xml @@ -0,0 +1,26 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/search_box.xml b/app/src/main/res/drawable/search_box.xml new file mode 100644 index 0000000..6a11b57 --- /dev/null +++ b/app/src/main/res/drawable/search_box.xml @@ -0,0 +1,27 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_launcher.xml b/app/src/main/res/layout/activity_launcher.xml new file mode 100644 index 0000000..2d2e0cc --- /dev/null +++ b/app/src/main/res/layout/activity_launcher.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + diff --git a/app/src/main/res/layout/dialog_color_size.xml b/app/src/main/res/layout/dialog_color_size.xml new file mode 100644 index 0000000..41f0e90 --- /dev/null +++ b/app/src/main/res/layout/dialog_color_size.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/dialog_color_sniffer_settings.xml b/app/src/main/res/layout/dialog_color_sniffer_settings.xml new file mode 100644 index 0000000..a9ccd5b --- /dev/null +++ b/app/src/main/res/layout/dialog_color_sniffer_settings.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_global_settings.xml b/app/src/main/res/layout/dialog_global_settings.xml new file mode 100644 index 0000000..92c95bb --- /dev/null +++ b/app/src/main/res/layout/dialog_global_settings.xml @@ -0,0 +1,277 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_hidden_apps.xml b/app/src/main/res/layout/dialog_hidden_apps.xml new file mode 100644 index 0000000..4be4386 --- /dev/null +++ b/app/src/main/res/layout/dialog_hidden_apps.xml @@ -0,0 +1,35 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_padding.xml b/app/src/main/res/layout/dialog_padding.xml new file mode 100644 index 0000000..c2c184e --- /dev/null +++ b/app/src/main/res/layout/dialog_padding.xml @@ -0,0 +1,259 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/dialog_rename_input.xml b/app/src/main/res/layout/dialog_rename_input.xml new file mode 100644 index 0000000..2b2c579 --- /dev/null +++ b/app/src/main/res/layout/dialog_rename_input.xml @@ -0,0 +1,39 @@ + + + + diff --git a/app/src/main/res/layout/dialog_theme_selector.xml b/app/src/main/res/layout/dialog_theme_selector.xml new file mode 100644 index 0000000..dc23c26 --- /dev/null +++ b/app/src/main/res/layout/dialog_theme_selector.xml @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/list_item.xml b/app/src/main/res/layout/list_item.xml new file mode 100644 index 0000000..d531311 --- /dev/null +++ b/app/src/main/res/layout/list_item.xml @@ -0,0 +1,45 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/alignment_popup.xml b/app/src/main/res/menu/alignment_popup.xml new file mode 100644 index 0000000..9ef97e6 --- /dev/null +++ b/app/src/main/res/menu/alignment_popup.xml @@ -0,0 +1,30 @@ + + +

+ + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/font_selection_popup.xml b/app/src/main/res/menu/font_selection_popup.xml new file mode 100644 index 0000000..bcd37cc --- /dev/null +++ b/app/src/main/res/menu/font_selection_popup.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu.xml b/app/src/main/res/menu/menu.xml new file mode 100644 index 0000000..ff161f2 --- /dev/null +++ b/app/src/main/res/menu/menu.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/remove_popup.xml b/app/src/main/res/menu/remove_popup.xml new file mode 100644 index 0000000..e555f55 --- /dev/null +++ b/app/src/main/res/menu/remove_popup.xml @@ -0,0 +1,27 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/sort_apps_popups.xml b/app/src/main/res/menu/sort_apps_popups.xml new file mode 100644 index 0000000..dcb155c --- /dev/null +++ b/app/src/main/res/menu/sort_apps_popups.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml new file mode 100644 index 0000000..d4e3350 --- /dev/null +++ b/app/src/main/res/values-da/strings.xml @@ -0,0 +1,58 @@ + + + Sikkerhedkopi gemt i Hentet + Frigør Apps Størrelse + App brug + Vælg gammel sikkerhedskopi fil + Størrelse + Tilpas + Farve + Navn + Sortér apps efter + Nulstil Farve + Åben + Fjern + Tilpasning + Afslut + Centrum + Start + Justering + :Fra + Der opstod en fejl + Fra FarveSniffer App + Fra Udklipsholder + Hacker Rød + Hacker Grøn + Sort på Grå + Hvid på Grå + Sort på Hvid + Baggrundsbilleder + Standardtema + Gendan + Skjult Apps + Skjul + Indstil primære farver + Temaer + Skrifttyper + Omdøb + Indstillinger + App Information + Nulstil til Standardindstillinger + Sikkerhedskopi + Afinstallér + Sidst Brugt + Sidst opdateret + Vælg skrifttyper + Gendan Standardskrifttyper + :Til + Vælg forrige sikkerhedskopi + Hvid på Sort + Lås Apps Størrelse + Faste Farver + Låst Apps + Frigør Størrelse + Lås Størrelse + Genstart Alt + Tilfældige Farver + Farver & Størrelse + \ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml new file mode 100644 index 0000000..e5e9d6e --- /dev/null +++ b/app/src/main/res/values-de/strings.xml @@ -0,0 +1,70 @@ + + + Farben & Größe + Einstellungen + Umbenenen + + Deinstallieren + Schriftarten + Designs + Hauptfarben setzen + Sicherung + Auf Standardeinstellung zurücksetzen + App-Info + Zufällige Farben + Alle zurücksetzen + Größe einfrieren + Verstecken + Größe nicht mehr Einfrieren + Versteckte Apps + Eingefrorene Apps + Wiederherstellen + Feste Farben + Größe einfrieren + Größe nicht mehr einfrieren + Standarddesign + Hintergrundbild + Weiß auf Schwarz + Schwarz auf Weiß + Weiß auf Grau + Schwarz auf Grau + Hackergrün + Hackerrot + ColorSniffer … + + Wählen Sie die vorherige Sicherungsdatei + + Aus der Zwischenablage + + Von der ColorSniffer App + + + + Sicherung im Download-Ordner gespeichert + + Ein Fehler ist aufgetreten + + Sicherungsdatei auswählen + + :An + + :Aus + Ausrichtung + linksbündig + zentriert + rechtsbündig + Randabstand + Entfernen + Öffnen + Farbe zurücksetzen + Standardschriftarten wiederherstellen + Schriftart wählen + Sortierung + Meist genutzt + Farbe + Benutzerdefiniert + Größe + Name + Neueste + zuletzt Aktualisiert + diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml new file mode 100644 index 0000000..cb86a5b --- /dev/null +++ b/app/src/main/res/values-eo/strings.xml @@ -0,0 +1,59 @@ + + + Propre + Restarigi Koloron + Restarigi Ĉiujn + Restarigi la defaŭltajn Agordojn + Lastatempaj unue + Grando + Koloro + Aplikaĵa Uzado + Nomo + Ordigi Aplikaĵojn laŭ + Restaŭri Defaŭltajn tiparojn + Elekti tiparojn + Malfermi + Forigi + Ŝtopado + Fino + Centro + Lanĉi + Ĝisrandigo + :Mŝal. + :Ŝal. + Io misokazis + Savkopio konservita je Elŝutoj + El CollorSniffer Aplikaĵo + El Tondejo + Ruĝa Kodrompisto + Verda Kodrompisto + Nigraj sur Grizaj + Blankaj sur Grizaj + Nigraj sur Blankaj + Blankaj sur Nigraj + Ekranfono + Defaŭlta Etoso + Malfrostigi Aplikaĵan Grandon + Frostigi Aplikaĵan Grandon + Fiksi Kolorojn + Restaŭri + Frostitaj Aplikaĵoj + Kaŝitaj Aplikaĵoj + Malfrostigi grandon + Kaŝi + Frostigi Grandon + Hazardaj Koloroj + Aplikaĵa Informaro + Savkopio + Agordi Ĉefajn Kolorojn + Etosoj + Tiparoj + Malinstali + Alinomi + Koloro kaj Grando + Agordoj + Elektu malnovan savkopion + Elektu antaŭan savkopion + Ĝisdatigi tempon + Relanĉi ĉi tiun programon + \ No newline at end of file diff --git a/app/src/main/res/values-es-rMX/strings.xml b/app/src/main/res/values-es-rMX/strings.xml new file mode 100644 index 0000000..a484552 --- /dev/null +++ b/app/src/main/res/values-es-rMX/strings.xml @@ -0,0 +1,66 @@ + + + Last Launcher + + Ajustes + + + Tamaño + Color + Renombrar + + Desinstalar + Fuentes + Temas + Elegir colores primarios + Copia de seguridad + Volver a los ajustes predeterminados + Info de la app + Colores aleatorios + ColorSniffer… + Reiniciar + Fijar tamaño + Ocultar + Cambiar tamaño + Apps ocultas + Apps fijas + Restaurar + Colores fijos + Fijar tamaño de la app + Permitir cambiar tamaño de las apps + Tema predefinido + Fondo de pantalla + Blanco sobre negro + Negro sobre blanco + Blanco sobre gris + Negro sobre gris + Verde hacker + Rojo hacker + Elegir copia de seguridad anterior + Desde el portapapeles + Desde ColorSniffer + Copia de seguridad guardada en Descargas + Un error ha ocurrido + Elegir copia de seguridad antigua + :Encendido + :Apagado + Alineación + Iniciar + Centrar + Terminar + Más recientes primero + Hora de actualización + Tamaño + Personalizado + Color + Uso de las apps + Nombre + Ordenar apps por + Elegir fuentes + Restaurar fuentes predeterminadas + Reiniciar color + Abrir + Borrar + Espaciado + Aplicaciones congeladas + \ No newline at end of file diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml new file mode 100644 index 0000000..06eb093 --- /dev/null +++ b/app/src/main/res/values-es/strings.xml @@ -0,0 +1,59 @@ + + + :Encendido + :Apagado + Desde la aplicación ColorSniffer + Tamaño de aplicaciones descongeladas + Tamaño de aplicaciones congeladas + Aplicaciones congeladas + Tamaño descongelado + Tamaño congelado + Recientes primero + Actualizado + Tamaño + Personalizado + Color + Tiempo de uso + Nombre + Ordenar aplicaciones por + Seleccionar fuentes + Restaurar fuentes por defecto + Reiniciar color + Abrir + Quitar + Relleno + Fin + Centro + Inicio + Alineación + Escoger fichero de respaldo + Ha ocurrido un error + Respaldo guardado en Descargas + Desde el portapapeles + Escoger fichero de respaldo + Rojo hacker + Verde hacker + Negro sobre gris + Blanco sobre gris + Negro sobre blanco + Blanco sobre negro + Fondo de pantalla + Tema por defecto + Colores fijos + Restaurar + Aplicaciones ocultas + Ocultar + Restablecer todo + Colores aleatorios + Información de la aplicación + Restaurar ajustes por defecto + Respaldo + Establecer colores primarios + Temas + Fuentes + Desinstalar + Renombrar + Colores y tamaño + Ajustes + Reiniciar Lanzador + \ No newline at end of file diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml new file mode 100644 index 0000000..16d61dc --- /dev/null +++ b/app/src/main/res/values-fa/strings.xml @@ -0,0 +1,58 @@ + + + گوشه‌دهی + ابتدا اخیرها + زمان به‌روزرسانی + اندازه + متفرقه + رنگ + کاربرد برنامه + اسم + ترتیب برنامه‌ها با + انتخاب فونت + بازگردانی فونت‌های پیش‌فرض + بازنشانی رنگ + حذف‌کردن + بازکردن + پایان + وسط + آغاز + تراز + :خاموش + :روشن + انتخاب‌کردن پوشهٔ پشتیبان قدیمی + خطایی رخ داده است + فایل پشتیبان در پوشهٔ بارگیری‌ها ذخیره شد + از برنامه‌ی ColorSniffer + از بریده‌دان + انتخاب فایل پشتیبان قدیمی + قرمز هکری + سبز هکری + سیاه روی خاکستری + سیاه روی خاکستری + سیاه روی سفید + سفید روی سیاه + پس‌زمینه + پوستهٔ پیش‌فرض + وایخاندن اندازه برنامه‌ها + یخاندن اندازه برنامه‌ها + ثابت‌سازی رنگ‌ها + بازگرداندن + برنامه‌های یخیده + برنامه‌های پنهان + وایخاندن اندازه + پنهان‌سازی + یخاندن اندازه + بازنشانی تنظیمات پیش‌فرض + بازنشانی همه + رنگ‌بندی تصادفی + اطلاعات برنامه + پشتیبان‌گیری + تنظیم رنگ‌های اصلی + پوسته‌ها + فونت‌ها + حذف نصب + تغییر نام + رنگ‌ها و اندازه + تنظیمات + \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml new file mode 100644 index 0000000..62320c1 --- /dev/null +++ b/app/src/main/res/values-fr/strings.xml @@ -0,0 +1,60 @@ + + + Récemment d’abord + Heure de mise à jour + Taille + Personnalisé + Couleur + Utilisation appli + Nom + Trier les applis par + Sélectionnez les polices + Rétablir les polices par défaut + Réinitialiser la couleur + Ouvrir + Retirer + Remplir + Fin + Centrer + Début + Alignement + :Désactivé + :Activé + Choisissez un ancien fichier de sauvegarde + Une erreur s’est produite + Sauvegarde placée dans les téléchargements + + À partir du presse-papier + Choisissez le fichier de sauvegarde précédent + Rouge hacker + Vert hacker + Noir sur gris + Blanc sur gris + Noir sur blanc + Blanc sur noir + Fond d’écran + Thème par défaut + Défiger les tailles + Figer les tailles + Couleurs fixes + Restaurer + Applis gelées + Applis masquées + Défiger la taille + Masquer + Figer la taille + Réinitialiser tout + ColorSniffer… + Couleurs aléatoires + Infos sur l’appli + Rétablir les paramètres par défaut + Sauvegarder + Définir les couleurs primaires + Thèmes + Polices + Désinstaller + Renommer + Couleur et taille + Paramètres + De l’application ColorSniffer + diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml new file mode 100644 index 0000000..3e05ed0 --- /dev/null +++ b/app/src/main/res/values-hr/strings.xml @@ -0,0 +1,59 @@ + + + Ukloni + Otvori + Veličina + Postavi primarne boje + Početak + Hakerska zelena + Odaberi fontove + Odaberi prethodnu datoteku sigurnosne kopije + Fiksne boje + :Isključeno + Zaključaj veličinu programa + Najprije nedavne + Vrati na standardne postavke + Odmak + Skriveni programi + Iz međuspremnika + Odaberi staru datoteku sigurnosne kopije + Boja + Prilagodbe + Fontovi + Centrirano + Upotreba programa + Crna na sivoj + Boje i veličina + Sakrij + Podaci programa + Deinstaliraj + :Uključeno + Zaključani programi + Dogodila se greška + Otključaj veličinu programa + Hakerska crvena + Resetiraj boje + Bijela na crnoj + Teme + Slika pozadine + Obnovi standardne fontove + Ime + Vrijeme aktualiziranja + Razvrstaj programe po + Obnovi + Postavke + Poravnanje + Preimenuj + Slučajni odabir boja + Bijela na sivoj + Sigurnosna kopija + Resetiraj sve + Od programa za biranje boja + Standardna tema + Crna na bijeloj + Kraj + Sigurnosna kopija spremljena u Preuzimanja + Otključaj veličinu + Zaključaj veličinu + Ponovo pokreni program + \ No newline at end of file diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml new file mode 100644 index 0000000..3cdabdb --- /dev/null +++ b/app/src/main/res/values-hu/strings.xml @@ -0,0 +1,60 @@ + + + A biztonsági mentés elmentve a letöltésekhez + Megnyitás + Szegély + Legutóbbi elöl + Frissítési idő + Méret + Egyéni + Szín + Használat + Név + Alkalmazások rendezése + Betűtípus kiválasztása + Alapértelmezett betűtípus visszaállítása + Szín visszaállítása + Eltávolítás + Hátra + Középre + Előre + Igazítás + :Ki + :Be + Régi biztonságimentés-fájl kiválasztása + Hiba történt + + Vágólapról + Előző biztonságimentés-fájl kiválasztása + Hacker vörös + Hacker zöld + Fekete a szürkén + Fehér a szürkén + Fekete a fehéren + Fehér a feketén + Háttérkép + Alapértelmezett téma + Alkalmazások méretének feloldása + Alkalmazások + Rögzített színek + Visszaállítás + Rögzített alkalmazások + Rejtett alkalmazások + méret feloldása + Elrejtés + Méret rögzítése + Összes visszaállítása + Színválasztó… + Véletlen színek + Alkalmazásinformáció + Alapértelmezett beállítások visszaállítása + Biztonsági mentés + Elsődleges színek beállítása + Témák + Betűtípus + Eltávolítás + Beállítások + Átnevezés + Színek és méret + A színválasztó alkalmazásból + \ No newline at end of file diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml new file mode 100644 index 0000000..edd94f8 --- /dev/null +++ b/app/src/main/res/values-it/strings.xml @@ -0,0 +1,59 @@ + + + App con dimensione bloccata + Dall\'app ColorSniffer + Prima le recenti + Tempo di aggiornamento + Spaziatura + Backup salvato in Download + Colori Fissati + Imposta Colori Primari + Riavvia Launcher + Si è verificato un errore + Scegli vecchio backup + Rimuovi + Personalizzato + Colore + Utilizzo App + Nome + Ordina App Per + Seleziona font + Ripristina Font Predefiniti + Ripristina Colore + Apri + Centro + Nero su Bianco + Bianco su Nero + Sfondo + Tema Predefinito + Sblocca Dimensione App + Blocca Dimensione App + Dagli Appunti + Allineamento + :Off + :On + Verde Hacker + Nero su Grigio + Bianco su Grigio + Inizia + Dimensione + Fine + Scegli backup precedente + Rosso Hacker + Ripristina + App Nascoste + Font + Blocca Dimensione + Sblocca dimensione + Nascondi + Ripristina Tutto + Colori Casuali + Info App + Ripristina impostazioni + Backup + Temi + Disinstalla + Rinomina + Colore e Dimensione + Impostazioni + \ No newline at end of file diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml new file mode 100644 index 0000000..6802252 --- /dev/null +++ b/app/src/main/res/values-lt/strings.xml @@ -0,0 +1,59 @@ + + + Atrakinti programų dydį + Apvalkalas + Fiksuoti programų dydį + Paleisti iš naujo + Vėliausiai naudotą + Atnaujinimo laiką + Individualiai + Dydį + Spalvą + Programėlės naudojimą + Pavadinimą + Rūšiuoti programėles pagal + Pasirinkti šriftus + Atkurti numatytuosius šriftus + Iš naujo nustatyti spalvą + Atidaryti + Šalinti + Pabaiga + Pradžia + Centras + Lygiavimas + :Išjungta + :Įjungta + Pasirinkti seną atsarginės kopijos failą + Įvyko klaida + Atsarginė kopija įrašyta atsisiuntimuose + Iš „ColorSniffer“ programėlės + Iš iškarpinės + Pasirinkti ankstesnį atsarginės kopijos failą + Programišiaus raudona + Programišiaus žalia + Juoda ant pilkos + Balta ant pilkos + Juoda ant balto + Balta ant juodo + Fono paveikslėlis + Numatytoji tema + Fiksuotos spalvos + Atkurti + Užšaldytos programos + Paslėptos programėlės + Atrakinti dydį + Slėpti + Fiksuoti dydį + Atstatyti viską + Atsitiktinės spalvos + Programėlės informacija + Atstatyti numatytuosius nustatymus + Atsarginė kopija + Nustatyti pagrindines spalvas + Temos + Šriftai + Išinstaliuoti + Pervadinti + Spalvos ir dydis + Nustatymai + \ No newline at end of file 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 0000000..c5f4f55 --- /dev/null +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -0,0 +1,60 @@ + + + Innstillinger + Tilbakestill til forvalgte innstillinger + Nylige først + Oppdateringstid + Størrelse + Brukerdefinert + Farge + Programbruk + Navn + Sorter programmer etter + Velg skrifter + Gjenopprett forvalgte skrifter + Tilbakestill farge + Åpne + Fjern + Luft + Slutt + Sentrer + Start + Justering + :Avslått + :Påslått + Velg gammel sikkerhetskopifil + En feil inntraff + Sikkerhetskopi lagret til nedlastinger + Fra fargesnifferprogram + Fra utklippstavle + Velg forrige sikkerhetskopifil + Hacker-rød + Hacker-grønn + Hvitt på grått + Svart på grått + Svart på hvitt + Hvitt på svart + Bakgrunnsbilde + Forvalgt drakt + Lås opp programstørrelse + Frys programstørrelse + Faste farger + Gjenopprett + Fryste programmer + Skjulte programmer + Lås opp størrelse + Skjul + Frys størrelse + Tilbakestill alt + Fargesniffer… + Tilfeldige farger + Programinfo + Sikkerhetskopi + Sett hovedfarger + Drakter + Skrifter + Avinstaller + Gi nytt navn + Farger og størrelse + Fra ColorSniffer-program + \ No newline at end of file diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml new file mode 100644 index 0000000..5a7d018 --- /dev/null +++ b/app/src/main/res/values-nl/strings.xml @@ -0,0 +1,58 @@ + + + Ontdooi Apps Grootte + Ontdooi Grootte + Begin + Standaardthema + App-info + Herstart Launcher + Recent eerst + Tijd van Updaten + Grootte + Kleur + Appgebruik + Naam + Sorteer Apps Op + Selecteer Lettertypes + Herstel Standaardlettertype + Reset Kleuren + Openen + Verwijder + Tussenruimte + Eind + Gecentreerd + Uitlijning + :Uit + :Aan + Kies oud backup bestand + Er is een fout opgetreden + Backup opgeslagen in Downloads + Van KleurenKiezer App + Van Klembord + Kies vorige backup bestand + Hacker rood + Hacker Groen + Zwart op Grijs + Wit op Grijs + Zwart op Wit + Wit op Zwart + Achtergrond Wallpaper + Bevries Apps Grootte + Vaste Kleuren + Herstel + Bevroren Apps + Verborgen Apps + Verberg + Bevries Grootte + Reset Alles + Willekeurige Kleuren + Terug naar Standaardinstellingen + Backup + Primaire Kleuren Instellen + Thema\'s + Lettertypes + Verwijderen + Hernoemen + Kleuren & Grootte + Instellingen + \ No newline at end of file diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml new file mode 100644 index 0000000..49fde1f --- /dev/null +++ b/app/src/main/res/values-pl/strings.xml @@ -0,0 +1,58 @@ + + + Ostatnio używane + Czas aktualizacji + Rozmiar + Niestandardowe + Kolor + Użycie aplikacji + Nazwa + Sortuj aplikacje według + Wybierz czcionki + Przywróć czcionki domyślne + Resetuj kolor + Otwórz + Usuń + Dopełnienie + Koniec + Środek + Uruchom + Wyrównanie + :Wył. + :Wł. + Wybierz stary plik kopii zapasowej + Wystąpił błąd + Kopia zapasowa zapisana w Pobranych + Z aplikacji ColorSniffer + Ze schowka + Wybierz poprzedni plik kopii zapasowej + Haker Zielony + Zablokuj Rozmiar + Haker Czerwony + Czarne na szarym + Białe na szarym + Czarne na białym + Białe na czarnym + Tapeta tła + Domyślny motyw + Odblokuj rozmiar aplikacji + Zablokuj rozmiar aplikacji + Popraw kolory + Przywrócić + Zamrożone aplikacje + Ukryte aplikacje + Odblokuj rozmiar + Ukryj + Zresetuj wszystko + Losowe kolory + Informacje o aplikacji + Przywróć ustawienia domyślne + Kopia zapasowa + Ustawianie kolorów podstawowych + Motywy + Czcionki + Odinstaluj + Zmień nazwę + Kolory i rozmiar + Ustawienia + \ No newline at end of file diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml new file mode 100644 index 0000000..3ba753e --- /dev/null +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -0,0 +1,58 @@ + + + Recentes primeiro + Hora de Atualização + Tamanho + Personalizado + Cor + Utilização de Aplicativo + Nome + Organizar Aplicativos Por + Selecionar fontes + Restaurar fontes padrão + Resetar Cor + Abrir + Remover + Preenchimento + Fim + Centro + Início + Alinhamento + :Desativado + :Ativado + Escolher um arquivo antigo de backup + Algum erro ocorreu + Backup salvo em Downloads + Do Aplicativo ColorSniffer + Da área de transferência + Escolher arquivo prévio de backup + Vermelho Hacker + Verde Hacker + Preto sobre Cinza + Branco sobre Cinza + Preto sobre Branco + Branco sobre Preto + Papel de Parede + Tema Padrão + Descongelar Tamanho das Aplicações + Congelar o Tamanho das Aplicações + Cores Fixas + Restaurar + Aplicativos Congelados + Aplicativos Ocultos + Descongelar tamanho + Ocultar + Congelar Tamanho + Resetar Tudo + Cores Aleatórias + Informação do Aplicativo + Resetar para as configurações padrão + Backup + Configurar Cores Primárias + Temas + Fontes + Desinstalar + Renomear + Cor e Tamanho + Configurações + \ No newline at end of file diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml new file mode 100644 index 0000000..ac04268 --- /dev/null +++ b/app/src/main/res/values-ro/strings.xml @@ -0,0 +1,57 @@ + + + Start + Îngheață aplicațiile + Reporniți Lansatorul + Recente + Timp de actualizare + Mărime + Culoare + Utilizarea aplicației + Nume + Sortarea aplicațiilor după + Selectați fonturile + Restabilirea fonturilor implicite + Resetați culoarea + Deschideți + Eliminați + Sfârșit + Centru + Aliniere + :Pe + :Oprit + Alegeți fișierul vechi de rezervă + A apărut o eroare + Copie de rezervă salvată în Descărcări + Din aplicația ColorSniffer + Din Clipboard + Alegeți fișierul de rezervă anterior + Roşu Hacker + Verde Hacker + Negru pe gri + Alb pe gri + Negru pe alb + Alb pe negru + Poză de fundal + Tema implicită + Deblocați dimensiunea aplicațiilor + Îngheață dimensiunea aplicațiilor + Culori fixe + Restaurați + Aplicații ascunse + Blocaţi dimensiunea + Deblocați dimensiunea + Ascundeți + Resetează tot + Culori aleatorii + Informații despre aplicație + Resetați la setările implicite + Backup + Setați culorile primare + Aspect + Fonturi + Dezinstalați + Redenumiți + Culori și dimensiuni + Setări + \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml new file mode 100644 index 0000000..c85f5d5 --- /dev/null +++ b/app/src/main/res/values-ru/strings.xml @@ -0,0 +1,59 @@ + + + ColorSniffer… + Разморозить размер + Заморозить размер + Недавние сначала + Времени обновления + Размеру + Настраиваемые + Цвету + Частоте использования + Имени + Упорядочить приложения по + Выбрать шрифты + Восстановить шрифты по умолчанию + Сбросить цвет + Открыть + Удалить + Отступ + Начало + Конец + Центр + Выравнивание + :Выкл + :Вкл + Выберите старый файл резервной копии + Произошла какая-то ошибка + Резервная копия сохранена в папке загрузок + Из буфера обмена + Выберите файл предыдущей резервной копии + Хакерский красный + Хакерский зелёный + Чёрное на сером + Белое на сером + Чёрное на белом + Белое на чёрном + Фоновое изображение + Тема по умолчанию + Разморозить размер приложений + Заморозить размер приложений + Фиксированные цвета + Восстановить + Замороженные приложения + Скрытые приложения + Скрыть + Сбросить все + Случайные цвета + Информация о приложении + Сбросить до настроек по умолчанию + Резервное копирование + Установить основные цвета + Темы + Шрифты + Деинсталлировать + Переименовать + Цвета и размер + Настройки + Из приложения ColorSniffer + \ No newline at end of file diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml new file mode 100644 index 0000000..e58fb4a --- /dev/null +++ b/app/src/main/res/values-sk/strings.xml @@ -0,0 +1,58 @@ + + + Z aplikácie ColorSniffer + Času aktualizácie + Veľkosti + Farby + Využitia aplikácie + Mena + Zoradiť aplikácie podľa + Zvoliť písma + Obnoviť predvolené písma + Resetovať farby + Otvoriť + Odstrániť + Odsadenie + Koniec + Stred + Začiatok + Zarovnanie + :Vypnuté + :Zapnuté + Zvoľte súbor predošlej zálohy + Vyskytla sa chyba + Záloha uložená do Stiahnutých súborov + Zo schránky + Zvoľte súbor predošlej zálohy + Hekerská Červená + Hekerská Zelená + Čierna na Sivej + Biela na Sivej + Čierna na Bielej + Biela na Čiernej + Obrázok pozadia + Predvolená téma + Odomknúť veľkosť aplikácií + Zamknúť veľkosť aplikácií + Fixné Farby + Obnoviť + Zamknuté aplikácie + Skryté aplikácie + Uzamknúť veľkosť + Odomknúť veľkosť + Skryť + Resetovať všetko + Náhodné farby + Info o aplikácii + Resetovať do predvolených Nastavení + Zálohovať + Nastaviť primárne farby + Témy + Písma + Odinštalovať + Premenovať + Farby & Veľkosť + Nastavenia + Nedávneho použitia + Vlastné + \ No newline at end of file diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml new file mode 100644 index 0000000..4dee055 --- /dev/null +++ b/app/src/main/res/values-uk/strings.xml @@ -0,0 +1,59 @@ + + + Резервне копіювання + Відступання + Недавно використовуваними + Часом оновлення + Розміром + Особистими вподобаннями + Кольором + Часом використання + Назвою + Сортувати застосунки за + Вибрати шрифти + Повернути стандартні шрифти + Скинути колір + Відкрити + Усунути + Кінець + Середина + Початок + Вирівнювання + :Вимк + :Увімк + Виберіть стару резервну копію + Трапилась якась помилка + Резервну копію збережено до завантажень + Із застосунку ColorSniffer + З буферу обміну + Виберіть попередню резервну копію + Червона гакерська + Зелена гакерська + Чорна на сірому + Біла на сірому + Чорна на білому + Біла на чорному + Фонові шпалери + Стандартна тема + Прибрати сталість розміру застосунків + Зробити розмір застосунків сталим + Сталі кольори + Відновити + Застосунки зі сталим розміром + Заховані застосунки + Зробити розмір сталим + Прибрати сталість розміру + Сховати + Скинути все + Випадкові кольори + Інформація про застосунок + Скинути до початкових налаштувань + Встановити основні кольори + Теми + Шрифти + Видалити + Змінити назву + Кольори і розмір + Налаштування + Перезапустити запускач + \ No newline at end of file diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml new file mode 100644 index 0000000..e106508 --- /dev/null +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -0,0 +1,59 @@ + + + 最近使用优先 + 更新时间 + 大小 + 自定义 + 颜色 + 应用使用 + 明朝 + 应用排序依据 + 选择字体 + 恢复默认字体 + 重置色彩 + 打开 + 移除 + 填充 + 开头 + 末尾 + 居中 + 对齐 + :关闭 + :开启 + 选择旧备份文件 + 发生了一些错误 + 备份已保存到 Downloads + 从 ColorSniffer 应用 + 从剪贴板 + 选择先前备份文件 + 黑客红 + 黑客绿 + 灰底黑字 + 灰底白字 + 白底黑字 + 黑底白字 + 背景壁纸 + 默认主题 + 取消冻结应用尺寸 + 冻结应用尺寸 + 固定的颜色 + 恢复 + 冻结的应用 + 隐藏的应用 + 取消冻结尺寸 + 隐藏 + 冻结尺寸 + 重置所有 + 随机颜色 + 应用信息 + 重置为默认设置 + 备份 + 设置主色 + 主题 + 字体 + 卸载 + 重命名 + 颜色&尺寸 + 设置 + 重启启动器 + \ No newline at end of file diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml new file mode 100644 index 0000000..ffaa0cb --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -0,0 +1,58 @@ + + + 凍結應用程式 + 近期優先 + 更新時間 + 大小 + 自訂 + 顏色 + 應用程式使用量 + 名稱 + 分類應用程式以 + 選擇字型 + 恢復預設字型 + 重置顏色 + 開啟 + 移除 + 墊高 + 切齊 + 尾 + 中 + 頭 + :關閉 + :開啟 + 選擇舊備份檔 + 發生一些錯誤 + 備份已儲存至下載資料夾 + 自調色盤應用程式 + 自剪貼簿 + 選擇先前的備份檔 + 駭客紅 + 駭客綠 + 黑字灰底 + 黑字白底 + 白字灰底 + 白字黑底 + 壁紙背景 + 預設主題 + 解除固定應用程式大小 + 固定應用程式大小 + 固定顏色 + 復原 + 隱藏的應用程式 + 解除固定大小 + 隱藏 + 固定大小 + 全部重設 + 隨機顏色 + 應用程式資訊 + 重置回預設設定 + 備份 + 設定主要顏色 + 主題 + 字體 + 解除安裝 + 重新命名 + 顏色與大小 + 設定 + \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml new file mode 100644 index 0000000..ae6d3c5 --- /dev/null +++ b/app/src/main/res/values/arrays.xml @@ -0,0 +1,16 @@ + + + + #F44336 + #9C27B0 + #3F51B5 + #03A9F4 + #009688 + #8BC34A + #FFEB3B + #FF9800 + #795548 + #607D8B + #8F8C8C + + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml new file mode 100644 index 0000000..60b5fd8 --- /dev/null +++ b/app/src/main/res/values/attrs.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..34fc92d --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,52 @@ + + + + #8F8C8C + + + + #8F8C8C + #F44336 + #E91E63 + #9C27B0 + #673AB7 + #3F51B5 + #2196F3 + #03A9F4 + #00BCD4 + #009688 + #4CAF50 + #8BC34A + #CDDC39 + #FFEB3B + #FFC107 + #FF9800 + #FF5722 + #ffffff + #000000 + + + + + #3F51B5 + #303F9F + #FF4081 + + + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000..b29b166 --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,8 @@ + + 20dp + + 5dp + 0dp + 20dp + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..fa122c2 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,99 @@ + + + Settings + + + Colors & Size + + Rename + + + Uninstall + Fonts + Themes + Set Primary Colors + Backup + + Reset to default Settings + App Info + + Random Colors + + + ColorSniffer… + + Reset All + Freeze Size + Hide + Unfreeze size + Hidden Apps + + Frozen Apps + Restore + Fixed Colors + Freeze Apps Size + Unfreeze Apps Size + Default Theme + Background Wallpaper + + White on Black + + Black on White + + White on Grey + + Black on Grey + + Hacker Green + + Hacker Red + Choose previous backup file + Color Sniffer + + From Clipboard + + From ColorSniffer App + + Backup saved to Downloads + Some error occurred + Choose old backup file + + :On + + :Off + Alignment + Start + Center + End + Padding + + Remove + + Open + Reset Color + Restore Default fonts + + Select fonts + Sort Apps By + + Name + + App Usage + + Color + + Customs + + Size + + Update time + + Recently first + Restart Launcher + + + Last Launcher Device Admin + Required for double-tap to lock screen functionality + Enable Device Admin + Device Admin is required for lock screen functionality + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..6729bf1 --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/xml/device_admin.xml b/app/src/main/res/xml/device_admin.xml new file mode 100644 index 0000000..e4383ba --- /dev/null +++ b/app/src/main/res/xml/device_admin.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..56d4add --- /dev/null +++ b/build.gradle @@ -0,0 +1,23 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:7.4.2' + + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + jcenter() + maven { url 'https://jitpack.io' } + } +} diff --git a/fastlane/metadata/android/da/changelogs/1.txt b/fastlane/metadata/android/da/changelogs/1.txt new file mode 100644 index 0000000..344bcdb --- /dev/null +++ b/fastlane/metadata/android/da/changelogs/1.txt @@ -0,0 +1 @@ +*Smugkig udgivelse* diff --git a/fastlane/metadata/android/da/changelogs/10.txt b/fastlane/metadata/android/da/changelogs/10.txt new file mode 100644 index 0000000..fb4780a --- /dev/null +++ b/fastlane/metadata/android/da/changelogs/10.txt @@ -0,0 +1,7 @@ +*Smugkig udgivelse 10* + +- Sortér App efter Navn, Størrelse, Farve, App brug +- Vis genveje til apps, webstedsgenveje og PWA'er, +- fejlrettelse til tema er ikke korrekt efter sikkerhedskopiering +- fejlrettelse for røde elementer vises ikke korrekt +- forbedringer af ydeevnen. diff --git a/fastlane/metadata/android/da/changelogs/11.txt b/fastlane/metadata/android/da/changelogs/11.txt new file mode 100644 index 0000000..6f3d5b7 --- /dev/null +++ b/fastlane/metadata/android/da/changelogs/11.txt @@ -0,0 +1,13 @@ +*Beta udgivelse 1* + +* Efter tidligere smugkig udgivelser gik Last Launcher ind i beta fase. + +* Hvad er nyt denne udgivelse + +- Søg i gennem App. +- Ydelsesforbedringer (opstart, sortering og tilfældig farve). +- Stor reduktion (23%) i apk-størrelse. +- Yderligere hukommelsesforbrugsreduktion. +- Rettet fejl relateret til genveje og PWA'er, der yderligere forårsagede hukommelseslækage. + +- Denne opdatering fjerner den gamle genvej fra denne launcher, så du skal genlæse dem efter denne opdatering. diff --git a/fastlane/metadata/android/da/changelogs/12.txt b/fastlane/metadata/android/da/changelogs/12.txt new file mode 100644 index 0000000..4d5d0ac --- /dev/null +++ b/fastlane/metadata/android/da/changelogs/12.txt @@ -0,0 +1,11 @@ +*Beta udgivelse 2* + + +* Hvad er nyt denne udgivelse + +- Søg i gennem App. +- Ydelsesforbedringer (opstart, sortering og tilfældig farve). +- Yderligere hukommelsesforbrugsreduktion. +- Fejlrettelse relateret til genveje og PWA'er, der yderligere forårsagede hukommelseslækage. + +- Denne opdatering fjerner den gamle genvej fra denne launcher, så du skal genlæse dem efter denne opdatering. diff --git a/fastlane/metadata/android/da/changelogs/13.txt b/fastlane/metadata/android/da/changelogs/13.txt new file mode 100644 index 0000000..f404060 --- /dev/null +++ b/fastlane/metadata/android/da/changelogs/13.txt @@ -0,0 +1,9 @@ +*Beta udgivelse 3* + + +* Hvad er nyt denne udgivelse + +- Sortér apps efter Sidst opdateret, Sidst brugt. +- Lysere og materiel farve. +- Gestusforbedring (FIX: Søgelinjen åbnede for meget) +- Genvejsrelateret fejlrettelse. diff --git a/fastlane/metadata/android/da/changelogs/14.txt b/fastlane/metadata/android/da/changelogs/14.txt new file mode 100644 index 0000000..4fc3ba4 --- /dev/null +++ b/fastlane/metadata/android/da/changelogs/14.txt @@ -0,0 +1,8 @@ +Beta udgivelse 4* + + +* Hvad er nyt denne udgivelse + +- Søgefeltet er nu tilgængelig ved at swipe VENSTRE/HØJRE i stedet for OP +- Sikkerhedskopiering bug er rettet til Android 6 eller tidligere. +- Spansk oversættelse diff --git a/fastlane/metadata/android/da/changelogs/15.txt b/fastlane/metadata/android/da/changelogs/15.txt new file mode 100644 index 0000000..166dec2 --- /dev/null +++ b/fastlane/metadata/android/da/changelogs/15.txt @@ -0,0 +1,9 @@ +*Beta udgivelse 5* + +*ALLE TIDLIGERE INSTALLEREDE GENVEJE VIL IKKE VÆRE TILGÆNGELIGE* + +* Hvad er nyt denne udgivelse + +- Fejlrettelser til "Genveje fungerer ikke godt efter sletning". +- Det er meste baggrunds arbejde. +- Oversættelse til Fransk, Tysk, Ungarsk, Norsk Bokmål og Russisk diff --git a/fastlane/metadata/android/da/changelogs/2.txt b/fastlane/metadata/android/da/changelogs/2.txt new file mode 100644 index 0000000..aa3ec09 --- /dev/null +++ b/fastlane/metadata/android/da/changelogs/2.txt @@ -0,0 +1,10 @@ +*Smugkig udgivelse 2* + +- Omdøb Appnavn +- Få appoplysninger med et enkelt klik +- Afinstallér mulighed +- Bedre Farvekontrol +- Forbedring af Farve og Størrelse UI + +- Globale Indstillinger (ikke implementeret) + For at få adgang til langt tryk på baggrundsområdet diff --git a/fastlane/metadata/android/da/changelogs/3.txt b/fastlane/metadata/android/da/changelogs/3.txt new file mode 100644 index 0000000..dd6a185 --- /dev/null +++ b/fastlane/metadata/android/da/changelogs/3.txt @@ -0,0 +1,10 @@ +*Smugkig udgivelse* +-For at få adgang til Launcher indstillinger langt tryk på tom område. + +-Lås/frigør app størrelse. +-Skjul apps (midlertidigt) +-Tilpas skrifttyper +-Flere temaer +-Nulstil til standardindstillinger +-Sikkerhedskopier og gendan indstillinger +-Tilfældige farver diff --git a/fastlane/metadata/android/da/changelogs/4.txt b/fastlane/metadata/android/da/changelogs/4.txt new file mode 100644 index 0000000..d9d8167 --- /dev/null +++ b/fastlane/metadata/android/da/changelogs/4.txt @@ -0,0 +1,4 @@ +*Smugkig udgivelse* + +* Nødopdateringer +* Fejlrettelse af App forsvinder fra launcher diff --git a/fastlane/metadata/android/da/changelogs/5.txt b/fastlane/metadata/android/da/changelogs/5.txt new file mode 100644 index 0000000..f786542 --- /dev/null +++ b/fastlane/metadata/android/da/changelogs/5.txt @@ -0,0 +1,5 @@ +*Smugkig udgivelse 5* + +- Skjul og Lås appliste +- tidligere indstillinger kan i stykker +- tidligere Sikkerhedskopiering fil fungerede muligvis ikke diff --git a/fastlane/metadata/android/da/changelogs/6.txt b/fastlane/metadata/android/da/changelogs/6.txt new file mode 100644 index 0000000..eef8f81 --- /dev/null +++ b/fastlane/metadata/android/da/changelogs/6.txt @@ -0,0 +1,10 @@ +*Smugkig udgivelse 6* + +- Forbedringer af forstørrelseslinje i App størrelse. +- App Farvefelt forbedringer. +- App Omdøb feltforbedringer. +- App åbning animation. +- Layouts ydeevne forbedring. +- Fejlrettelse relateret til den seneste menu. +- Fejlrettelse relateret til app størrelsesreduktion ved tryk. +- Fejlrettelse relateret til en eller anden app, der ikke åbnes. diff --git a/fastlane/metadata/android/da/changelogs/7.txt b/fastlane/metadata/android/da/changelogs/7.txt new file mode 100644 index 0000000..7a04950 --- /dev/null +++ b/fastlane/metadata/android/da/changelogs/7.txt @@ -0,0 +1,7 @@ +*Smugkig udgivelse 7* + +- Statuslinje og navigationslinjefarve pr. Valgt tema. +- Generér den samme tilfældige farve hver gang til en bestemt app (tak til Sylvia). +- Justeringer(midt, venstre og højre) af Apps. +- Ombestilling af popmenupunkter og forsigtig rød farve for nogle emner. +- Fejlrettelse af Hacker Rød tema. diff --git a/fastlane/metadata/android/da/changelogs/8.txt b/fastlane/metadata/android/da/changelogs/8.txt new file mode 100644 index 0000000..da40932 --- /dev/null +++ b/fastlane/metadata/android/da/changelogs/8.txt @@ -0,0 +1,8 @@ +*Smugkig udgivelse 8* + +- Øgede Tilpasning af startskærm. +- Kombineret menu med Farve og Størrelse giver hurtig og nem adgang. +- En ny størrelse UX til nøjagtige værdier. +- Forbedring af appkildekode for bedre forståelse. + +- kommer snart: App søgefelt diff --git a/fastlane/metadata/android/da/changelogs/9.txt b/fastlane/metadata/android/da/changelogs/9.txt new file mode 100644 index 0000000..f7b3fab --- /dev/null +++ b/fastlane/metadata/android/da/changelogs/9.txt @@ -0,0 +1,9 @@ +*Smugkig udgivelse 9* + +- Mulighed for at skjulte apps. +- Mulighed for at nulstille Appfarver. +- Valg af Farve og Størrelse Globalt. +- Mulighed for at gendanne standardskrifttyper. +- Farveforbedringer til uigenkaldelig drift. +- Øgede Tilpasning af startskærm. +- Fejlrettelse relateret til nulstilling fungerer ikke for appstørrelse. diff --git a/fastlane/metadata/android/da/full_description.txt b/fastlane/metadata/android/da/full_description.txt new file mode 100644 index 0000000..78e692b --- /dev/null +++ b/fastlane/metadata/android/da/full_description.txt @@ -0,0 +1,40 @@ +Last Launcher er Hurtig, Enkel, Minimalistisk, Tilpasselig Android launcher. Det sigter mod at give den hurtigste og enkleste brugeroplevelse nogensinde. + +

+************************* +**Dette er Beta udgivelse** +************************* +

+ +

Projekt

+ +▶ Altid Fri som i Frihed og reklamefri. +▶ F-droid eksklusiv. + +

🚀 Ydeevne

+▶ Hurtigere end hurtigt :) +▶ Let og lille størrelse apk mindre end 100 KB. +▶ Lav hukommelse og cpu forbrug. + +

💥 Funktioner

+ +▶ Søg blandt apps. +▶ Genveje og understøtter PWA'er. +▶ Ændre skriftstørrelse og farverige appnavne. +▶ Sortér apps på forskellige måder. +▶ Tilpas efter eget behov. +▶ Tilfældige Farver. +▶ Flere temaer. +▶ Skjul apps. +▶ Lås apps størrelse. +▶ Sikkerhedskopiering/Gendannelse af launcher data. +▶ Ingen ikoner og widgets(kan være en ulempe). +▶ For mere prøv launcheren og se forskellen. + +

Navigation

+ +▶ Langt tryk på TOMT OMRÅDE for at få adgang til launcher indstillinger. +▶ Swipe HØJRE for at få adgang til Søgelinjen. +▶ For at skjule søgefeltet skal du trykke på Tilbage / Hjem eller Swipe VENSTRE på skærmen. + +

Oversæt denne app på Weblate til dit lokale sprog.

diff --git a/fastlane/metadata/android/da/short_description.txt b/fastlane/metadata/android/da/short_description.txt new file mode 100644 index 0000000..a011aa8 --- /dev/null +++ b/fastlane/metadata/android/da/short_description.txt @@ -0,0 +1 @@ +Hurtigere end lys diff --git a/fastlane/metadata/android/da/title.txt b/fastlane/metadata/android/da/title.txt new file mode 100644 index 0000000..de66edb --- /dev/null +++ b/fastlane/metadata/android/da/title.txt @@ -0,0 +1 @@ +Last Launcher diff --git a/fastlane/metadata/android/da/video.txt b/fastlane/metadata/android/da/video.txt new file mode 100644 index 0000000..3d6486d --- /dev/null +++ b/fastlane/metadata/android/da/video.txt @@ -0,0 +1 @@ +https://www.youtube.com/watch?v=SzhJgH4a2cU diff --git a/fastlane/metadata/android/en-US/changelogs/1.txt b/fastlane/metadata/android/en-US/changelogs/1.txt new file mode 100644 index 0000000..a49f23c --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/1.txt @@ -0,0 +1 @@ +*Preview release* diff --git a/fastlane/metadata/android/en-US/changelogs/10.txt b/fastlane/metadata/android/en-US/changelogs/10.txt new file mode 100644 index 0000000..1b58c29 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/10.txt @@ -0,0 +1,7 @@ +*Preview release 10* + +- Sort App by Name, Size, Color, App usage +- Show Apps Shortcut, Website Shortcuts and PWAs, +- bug fix for theme is not correct after backup +- bug fix for red item are not displayed correctly +- performance improvements. diff --git a/fastlane/metadata/android/en-US/changelogs/11.txt b/fastlane/metadata/android/en-US/changelogs/11.txt new file mode 100644 index 0000000..c3d043d --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/11.txt @@ -0,0 +1,13 @@ +*Beta release 1* + +* After a lots of preview release Last Launcher entered into beta phase. + +* What's New in this release + +- Search through Apps. +- Performance improvements(startup, sorting and Random color). +- Big reduction(23%) in apk size. +- Further memory consumption reduction. +- Fixed bug related to Shortcuts and PWAs that was further causing Memory leak. + +- This update will remove old shortcut from this launcher so you readded them after this update. diff --git a/fastlane/metadata/android/en-US/changelogs/12.txt b/fastlane/metadata/android/en-US/changelogs/12.txt new file mode 100644 index 0000000..96192e0 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/12.txt @@ -0,0 +1,11 @@ +*Beta release 2* + + +* What's New in this release + +- Search through Apps. +- Performance improvements(startup, sorting and Random color). +- Further memory consumption reduction. +- Fixed bug related to Shortcuts and PWAs that was further causing Memory leak. + +- This update will remove old shortcut from this launcher so you readded them after this update. diff --git a/fastlane/metadata/android/en-US/changelogs/13.txt b/fastlane/metadata/android/en-US/changelogs/13.txt new file mode 100644 index 0000000..4d69d0b --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/13.txt @@ -0,0 +1,9 @@ +*Beta release 3* + + +* What's New in this release + +- Sort Apps by Updates time, Recently first. +- Brighter and material color. +- Gesture improvement (FIX: Search bar was opening too much) +- Shortcuts related bug fix. diff --git a/fastlane/metadata/android/en-US/changelogs/14.txt b/fastlane/metadata/android/en-US/changelogs/14.txt new file mode 100644 index 0000000..1371f53 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/14.txt @@ -0,0 +1,8 @@ +*Beta release 4* + + +* What's New in this release + +- Search Bar is now accessiable via LEFT/RIGHT swipe instead of UP +- Backup fixed for Android 6 or prior. +- Spanish Translation diff --git a/fastlane/metadata/android/en-US/changelogs/15.txt b/fastlane/metadata/android/en-US/changelogs/15.txt new file mode 100644 index 0000000..7e8a56d --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/15.txt @@ -0,0 +1,11 @@ +*Beta release 5* + +*ALL PREVIOUS INSALLED SHORTCUTS WILL NOT BE ACCESSIABLE* + +* What's New in this release + +- Bug fixes for "Shortcuts are not working well after deletion". +- Bug fixes for "App is not showing or disappearing after enable or disable" +- Most of the work is done under the hood. +- Translation for French, German, Hungarian, Norwegian Bokmāl, Russian, Danish, Polish, Slovak, Croatian and Spanish. +- Thanks to all translators diff --git a/fastlane/metadata/android/en-US/changelogs/16.txt b/fastlane/metadata/android/en-US/changelogs/16.txt new file mode 100644 index 0000000..c8e4214 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/16.txt @@ -0,0 +1,12 @@ +*Beta release 6* + +* What's New in this release + +- Orientation gots liberty, Enjoy Orientations. +- Bug fix for "Can't select files to restore" +- Bug fix for "ConcurrentModificationException"(Thanks @btimofeev). +- Bug fix for "Toast Text not visible". +- Translation update for Slovak, Croatian, Hungarian, Portuguese, Ukrainian, Chinese via Weblate(Thanks all contributors) +- Fix typos. +- Don't show empty 'Hidden' or 'Frozen' Apps. +- Code improvement. diff --git a/fastlane/metadata/android/en-US/changelogs/17.txt b/fastlane/metadata/android/en-US/changelogs/17.txt new file mode 100644 index 0000000..46f58fc --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/17.txt @@ -0,0 +1,18 @@ +*Beta release 7* + +* What's New in this release +- Increased MAX app size to 90. +- Option to restart Launcher. +- Bug fix for "Can't select fonts". +- Bug fix for "Crashing the Launcher on Updating apps". +- Bug fix for "Random color generation to fixed color show white color". +- Performance improvements. +- Removed Storage permission. +- Move Backup/restore to SAF. + +* Project Source codes Changes. + +- Translation update. +- Source Code improvement. +- Fix possible memory leak in TextWatcher. +- SDK targets 28->29(android 10). \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/18.txt b/fastlane/metadata/android/en-US/changelogs/18.txt new file mode 100644 index 0000000..84a9d58 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/18.txt @@ -0,0 +1,10 @@ +*Beta release 8* + +* What's New in this release + +- Bug fix for "Crashing the Launcher on Updating apps". +- Fix memory leak + +* Project Source codes Changes. + +- Translation update. \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/19.txt b/fastlane/metadata/android/en-US/changelogs/19.txt new file mode 100644 index 0000000..e503a2d --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/19.txt @@ -0,0 +1,9 @@ +*Glory to Ukraine 🇺🇦 * +*StandWithUkraine* + +Translation Update for: + +Lithuanian +Romanian +Spanish +Ukrainian \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/2.txt b/fastlane/metadata/android/en-US/changelogs/2.txt new file mode 100644 index 0000000..0a7172f --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/2.txt @@ -0,0 +1,10 @@ +*Preview release 2* + +- Rename App Name +- Get App info in single Click +- Uninstall option +- More Colors controls +- Color and Size UI refinement + +- Global Settings Stub (not implemented) + To access long click on background area diff --git a/fastlane/metadata/android/en-US/changelogs/3.txt b/fastlane/metadata/android/en-US/changelogs/3.txt new file mode 100644 index 0000000..1427cfb --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/3.txt @@ -0,0 +1,10 @@ +*Preview release 3* +-To access Launcher settings long click on empty area + +-Freeze/unfreeze app size +-Hide apps(temporary) +-Custom Fonts +-Multiple Themes +-Reset to default setings +-Backup and restore settings +-Random colors diff --git a/fastlane/metadata/android/en-US/changelogs/4.txt b/fastlane/metadata/android/en-US/changelogs/4.txt new file mode 100644 index 0000000..66bbe3b --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/4.txt @@ -0,0 +1,4 @@ +*Preview release * + +* Emergency Updates +* fix App disappear from launchers diff --git a/fastlane/metadata/android/en-US/changelogs/5.txt b/fastlane/metadata/android/en-US/changelogs/5.txt new file mode 100644 index 0000000..7a16d0a --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/5.txt @@ -0,0 +1,5 @@ +*Preview release 5* + +- Hide and Freeze app list +- previous settings may break +- previous backup file may not worked diff --git a/fastlane/metadata/android/en-US/changelogs/6.txt b/fastlane/metadata/android/en-US/changelogs/6.txt new file mode 100644 index 0000000..8106cc1 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/6.txt @@ -0,0 +1,10 @@ +*Preview release 6* + +- App Size seekbar improvements. +- App Color bar improvements. +- App Rename field improvements. +- App opening animation. +- Layouts performance improvement. +- Fix bug related to recent menu. +- Fix bug related to app size decrease on click. +- Fix bug related to some app not opening. diff --git a/fastlane/metadata/android/en-US/changelogs/7.txt b/fastlane/metadata/android/en-US/changelogs/7.txt new file mode 100644 index 0000000..530371c --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/7.txt @@ -0,0 +1,7 @@ +*Preview release 7* + +- Status bar and navigation bar color as per selected theme. +- Generate the Same Random Color each time for a perticular app(Thanks to Sylvia). +- Alignments(center, left and right) of Apps. +- Re-ordering of PopMenu items and Cautious Red color for some items. +- Hacker Red theme bug fix. diff --git a/fastlane/metadata/android/en-US/changelogs/8.txt b/fastlane/metadata/android/en-US/changelogs/8.txt new file mode 100644 index 0000000..b08835b --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/8.txt @@ -0,0 +1,8 @@ +*Preview release 8* + +- Padding to home screen. +- Combined Color and Size menu for fast and convenient access. +- A new Size selection UX for exact values. +- App source code improvement for better understanding. + +- comming soon: App Search bar diff --git a/fastlane/metadata/android/en-US/changelogs/9.txt b/fastlane/metadata/android/en-US/changelogs/9.txt new file mode 100644 index 0000000..77ca6e7 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/9.txt @@ -0,0 +1,9 @@ +*Preview release 9* + +- Option to run hidden apps. +- Option to reset App Colors. +- Color and Size Selection Globally. +- Option to restore default fonts. +- Color improvements for irrevocable operation. +- Increased padding limits. +- Bug fix related to reset is not working for app size. diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt new file mode 100644 index 0000000..fc95c31 --- /dev/null +++ b/fastlane/metadata/android/en-US/full_description.txt @@ -0,0 +1,44 @@ +Last Launcher is Quick, Simple, Minimalist, Customizable Android launcher. It aims to provide fastest and simplest ever user experience. + +

+************************* +**This is Beta release*** +************************* +

+ +

Translate this app on Weblate(https://hosted.weblate.org/projects/last-launcher) in your local language.

+ +

Project

+▶ Always Free (Gratis and Libre). +▶ F-droid exclusive. + +

🚀 Performance

+▶ Faster than Fastest :) +▶ Lightweight and small APK size of less than 130KB. +▶ Low memory and CPU usage. + +

💥 Features

+▶ Search among apps. +▶ Shortcuts and PWAs support. +▶ Resizable and colourful app names. +▶ Sort apps by various ways. +▶ Custom alignment and padding. +▶ Random Colors. +▶ Multiple themes. +▶ Hide apps. +▶ Freeze apps size. +▶ Backup/restore launcher data. +▶ No icon and widgets (may be a disadvantage). +▶ For more try launcher and see the difference. + +

Privacy

+▶ No Internet access permission. +▶ No Storage access permission. +▶ All data is stored on your device private storage and sensitive data is cipher with a simple algorithm. + +

Navigation

+▶ Long click on EMPTY AREA to access launcher settings. +▶ Swipe RIGHT to access Search Bar. +▶ To hide search bar press Back/Home or Swipe LEFT onthe screen. + +

Translate this app on Weblate(https://hosted.weblate.org/projects/last-launcher) in your local language.

diff --git a/fastlane/metadata/android/en-US/images/icon.png b/fastlane/metadata/android/en-US/images/icon.png new file mode 100644 index 0000000..1306ae7 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/icon.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png new file mode 100644 index 0000000..102fa3e Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/2.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/2.jpg new file mode 100644 index 0000000..9129a86 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/2.jpg differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png new file mode 100644 index 0000000..817004c Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png new file mode 100644 index 0000000..4e6d223 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png new file mode 100644 index 0000000..34e8846 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png new file mode 100644 index 0000000..dd55d28 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/7.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/7.png new file mode 100644 index 0000000..c13d851 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/7.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/8.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/8.png new file mode 100644 index 0000000..ba429b4 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/8.png differ diff --git a/fastlane/metadata/android/en-US/short_description.txt b/fastlane/metadata/android/en-US/short_description.txt new file mode 100644 index 0000000..e4a60f5 --- /dev/null +++ b/fastlane/metadata/android/en-US/short_description.txt @@ -0,0 +1 @@ +Faster than Light diff --git a/fastlane/metadata/android/en-US/title.txt b/fastlane/metadata/android/en-US/title.txt new file mode 100644 index 0000000..de66edb --- /dev/null +++ b/fastlane/metadata/android/en-US/title.txt @@ -0,0 +1 @@ +Last Launcher diff --git a/fastlane/metadata/android/en-US/video.txt b/fastlane/metadata/android/en-US/video.txt new file mode 100644 index 0000000..3d6486d --- /dev/null +++ b/fastlane/metadata/android/en-US/video.txt @@ -0,0 +1 @@ +https://www.youtube.com/watch?v=SzhJgH4a2cU diff --git a/fastlane/metadata/android/es-MX/short_description.txt b/fastlane/metadata/android/es-MX/short_description.txt new file mode 100644 index 0000000..0e9ac24 --- /dev/null +++ b/fastlane/metadata/android/es-MX/short_description.txt @@ -0,0 +1 @@ +Más rápido que la luz diff --git a/fastlane/metadata/android/es-MX/title.txt b/fastlane/metadata/android/es-MX/title.txt new file mode 100644 index 0000000..de66edb --- /dev/null +++ b/fastlane/metadata/android/es-MX/title.txt @@ -0,0 +1 @@ +Last Launcher diff --git a/fastlane/metadata/android/es-MX/video.txt b/fastlane/metadata/android/es-MX/video.txt new file mode 100644 index 0000000..3d6486d --- /dev/null +++ b/fastlane/metadata/android/es-MX/video.txt @@ -0,0 +1 @@ +https://www.youtube.com/watch?v=SzhJgH4a2cU diff --git a/fastlane/metadata/android/fa/changelogs/1.txt b/fastlane/metadata/android/fa/changelogs/1.txt new file mode 100644 index 0000000..97943f8 --- /dev/null +++ b/fastlane/metadata/android/fa/changelogs/1.txt @@ -0,0 +1 @@ +*نسخه‌ی پیش‌نمایشی* diff --git a/fastlane/metadata/android/fa/full_description.txt b/fastlane/metadata/android/fa/full_description.txt new file mode 100644 index 0000000..cbccfe7 --- /dev/null +++ b/fastlane/metadata/android/fa/full_description.txt @@ -0,0 +1,42 @@ +آخرین لانچر یک لانچر اندرویدی سریع، ساده،‌ کمینه‌گرا و قابل شخصی‌سازی است. این لانچر با هدف ارائه‌ی ساده‌ترین و سریع‌ترین تجربه‌ی کاربری ساخته شده است. + +

+************************* +**این برنامه هنوز در نسخه آزمایشی قرار دارد** +************************* +

+ +

این برنامه را در Weblate به زبان محلی خود ترجمه کنید.

+ +

پروژه

+ +▶ همیشه رایگان و آزاد. +▶ مختص اف‌دروید. + +

عملکرد 🚀

+▶ سریع‌تر از سریع‌ترین :) +▶ سبک و با فاصل نصبی کمتر از ۱۳۰ کیلوبایت. +▶ استفاده‌ی حداقلی از رم و سی‌پی‌یو. + +

ویژگی‌ها 💥

+ +▶ جست‌وجو میان برنامه‌ها. +▶ پشتیبانی از میانبرها و PWAها. +▶ قابلیت تغییر اندازه و رنگ نام برنامه‌ها. +▶ چینش برنامه‌ها طبق معیارهای مختلف. +▶ گوشه‌دهی و تراز شخصی‌سازی شده. +▶ رنگ‌های تصادفی. +▶ چندین پوسته‌ی مختلف. +▶ پنهان‌سازی برخی برنامه‌ها. +▶ یخاندن اندازه برنامه‌ها. +▶ پشتیبان‌گیری/بازگردانی اطلاعات لانچر. +▶ هیچ آیکون یا ابزارکی در کار نیست (ممکن است مزیت حساب نشود). +▶ برای بیشتر دانستن این لانچر را امتحان کنید و تفاوت را ببینید. + +

ناوبری

+ +▶ برای دسترسی به تنظیمات لانچر انگشت را روی قسمت‌های خالی نگه دارید. +▶ برای جست‌وجو انگشت را به سمت راست بکشید. +▶ برای مخفی کردن جست‌وجو یا به سمت چپ بکشید یا دکمه‌ی بازگشت/خانه را بزنید. + +

این برنامه را در Weblate به زبان محلی خود ترجمه کنید.

diff --git a/fastlane/metadata/android/fa/short_description.txt b/fastlane/metadata/android/fa/short_description.txt new file mode 100644 index 0000000..fffa3ff --- /dev/null +++ b/fastlane/metadata/android/fa/short_description.txt @@ -0,0 +1 @@ +سریع‌تر از نور diff --git a/fastlane/metadata/android/fa/title.txt b/fastlane/metadata/android/fa/title.txt new file mode 100644 index 0000000..bd5916a --- /dev/null +++ b/fastlane/metadata/android/fa/title.txt @@ -0,0 +1 @@ +آخرین لانچر diff --git a/fastlane/metadata/android/fa/video.txt b/fastlane/metadata/android/fa/video.txt new file mode 100644 index 0000000..3d6486d --- /dev/null +++ b/fastlane/metadata/android/fa/video.txt @@ -0,0 +1 @@ +https://www.youtube.com/watch?v=SzhJgH4a2cU diff --git a/fastlane/metadata/android/hr/changelogs/1.txt b/fastlane/metadata/android/hr/changelogs/1.txt new file mode 100644 index 0000000..1957012 --- /dev/null +++ b/fastlane/metadata/android/hr/changelogs/1.txt @@ -0,0 +1 @@ +* Pregled izdanja * diff --git a/fastlane/metadata/android/hr/changelogs/10.txt b/fastlane/metadata/android/hr/changelogs/10.txt new file mode 100644 index 0000000..a5c8166 --- /dev/null +++ b/fastlane/metadata/android/hr/changelogs/10.txt @@ -0,0 +1,7 @@ +* Pregled izdanja 10 * + +- razvrstajvanje programa po imenu, veličini, boji, upotrebi +- prikaz prečaca za programe, web mjesta i PWA-ove, +- ispravljena greška: temu nije ispravna nakon sigurnosne kopije +- ispravljena greška: crveni elementi se ne prikazuju ispravno +- poboljšanja učinkovitosti. diff --git a/fastlane/metadata/android/hr/changelogs/11.txt b/fastlane/metadata/android/hr/changelogs/11.txt new file mode 100644 index 0000000..973be4f --- /dev/null +++ b/fastlane/metadata/android/hr/changelogs/11.txt @@ -0,0 +1,13 @@ +*Beta izdanje 1* + +* Nakon mnogih predizdanja, „Last Launcher” se nalazi u beta fazi. + +* Novosti u ovom izdanju + +- Pretraži aplikacije. +- Poboljšanja performanse (pokretanje, razvrstavanje i slučajna boja). +- Značajno smanjenje (23 %) apk veličine. +- Daljnje smanjenje potrošnje memorije. +- Ispravljena je greška koja se odnosi na prečace i PWA-e, koja je dodatno uzrokovala gubljenje memorije. + +- Ova verzija uklanja stari prečac iz pokretača, stoga se mora ponovo dodati nakon ovog aktualiziranja. diff --git a/fastlane/metadata/android/hr/full_description.txt b/fastlane/metadata/android/hr/full_description.txt new file mode 100644 index 0000000..3388be0 --- /dev/null +++ b/fastlane/metadata/android/hr/full_description.txt @@ -0,0 +1,47 @@ +Last Launcher je brz, jednostavan, minimalistički, prilagodljiv pokretač za Android. Cilj mu je pružiti najbrže i najjednostavnije korisničko iskustvo ikad. + +

+************************* +**Ovo je beta izdanje** +************************* +

+ +

Prevedi program na Weblate stranicama na tvoj jezik.

+ +

Projekt

+ +▶ Uvijek slobodan (besplatan i slobodan). +▶ Ekskluzivno za F-droid. + +

🚀 Učinkovitost

+▶ Brži od najbržeg :) +▶ Jednostavan i mali program s manje od 130 KB. +▶ Niska upotreba memorije i procesora. + +

💥 Funkcije

+ +▶ Pretraživanje programa. +▶ Podrška za prečace i PWA. +▶ Promjenjiva i živopisna imena programa. +▶ Razvrstavanje programa na razne načine. +▶ Prilagođeno poravnanje i odmaci. +▶ Slučajni odabir boja. +▶ Razne teme. +▶ Skrivanje programa. +▶ Zaključavanje veličine programa. +▶ Izrada sigurnosnih kopija / obnavljanje podataka pokretača. +▶ Bez ikona i dodataka (može biti nedostatak). +▶ Za sve ostalo, isprobaj pokretača i doživi razliku. + +

Privatnost

+▶ Bez dozvole za pristup internetu. +▶ Bez dozvole za pristup spremištu. +▶ Svi se podaci spremaju u privatno spremište tvog uređaja, a osjetljivi podaci šifriraju se jednostavnim algoritmom. + +

Navigacija

+ +▶ Pritisni dugo na PRAZNO PODRUČJE za pristup postavkama pokretača. +▶ Povuci prst udesno za pristup traci pretrage. +▶ Za skrivanje trake pretrage, pritisni Natrag/Početna ili povuci prstom LIJEVO na ekranu. + +

Prevedi program na Weblate stranicama na tvoj jezik.

diff --git a/fastlane/metadata/android/hr/short_description.txt b/fastlane/metadata/android/hr/short_description.txt new file mode 100644 index 0000000..1f3bf65 --- /dev/null +++ b/fastlane/metadata/android/hr/short_description.txt @@ -0,0 +1 @@ +Brže od brzine svjetlosti diff --git a/fastlane/metadata/android/hr/title.txt b/fastlane/metadata/android/hr/title.txt new file mode 100644 index 0000000..de66edb --- /dev/null +++ b/fastlane/metadata/android/hr/title.txt @@ -0,0 +1 @@ +Last Launcher diff --git a/fastlane/metadata/android/hr/video.txt b/fastlane/metadata/android/hr/video.txt new file mode 100644 index 0000000..3d6486d --- /dev/null +++ b/fastlane/metadata/android/hr/video.txt @@ -0,0 +1 @@ +https://www.youtube.com/watch?v=SzhJgH4a2cU diff --git a/fastlane/metadata/android/hu/short_description.txt b/fastlane/metadata/android/hu/short_description.txt new file mode 100644 index 0000000..70a7f8e --- /dev/null +++ b/fastlane/metadata/android/hu/short_description.txt @@ -0,0 +1 @@ +Gyorsabb a fénynél diff --git a/fastlane/metadata/android/hu/title.txt b/fastlane/metadata/android/hu/title.txt new file mode 100644 index 0000000..de66edb --- /dev/null +++ b/fastlane/metadata/android/hu/title.txt @@ -0,0 +1 @@ +Last Launcher diff --git a/fastlane/metadata/android/it/changelogs/1.txt b/fastlane/metadata/android/it/changelogs/1.txt new file mode 100644 index 0000000..099cbc0 --- /dev/null +++ b/fastlane/metadata/android/it/changelogs/1.txt @@ -0,0 +1 @@ +*Anteprima versione* diff --git a/fastlane/metadata/android/it/changelogs/10.txt b/fastlane/metadata/android/it/changelogs/10.txt new file mode 100644 index 0000000..dc87f3d --- /dev/null +++ b/fastlane/metadata/android/it/changelogs/10.txt @@ -0,0 +1,7 @@ +*Anteprima versione 10* + +- Ordina app per nome, dimensione, colore, utilizzo app +- Mostra scorciatoie per app, scorciatoie per siti web e PWA, +- Correzione bug per il tema non è corretto dopo il backup +- Correzione bug per l'elemento rosso non viene visualizzato correttamente +- miglioramenti delle prestazioni. diff --git a/fastlane/metadata/android/it/changelogs/11.txt b/fastlane/metadata/android/it/changelogs/11.txt new file mode 100644 index 0000000..ae1f354 --- /dev/null +++ b/fastlane/metadata/android/it/changelogs/11.txt @@ -0,0 +1,11 @@ +*Versione beta 1* + +* Dopo un sacco di versioni in anteprima, Last Launcher è entrato in fase beta. + +* Novità di questa versione + +- Cerca tra le app. +- Miglioramenti delle prestazioni (avvio, ordinamento e colore casuale). +- Grande riduzione (23%) della dimensione dell'apk. +- Ulteriore riduzione del consumo di memoria. +- Risolto bug relativo a scorciatoie e PWA che causava ulteriori perdite di memoria. diff --git a/fastlane/metadata/android/it/changelogs/12.txt b/fastlane/metadata/android/it/changelogs/12.txt new file mode 100644 index 0000000..8297443 --- /dev/null +++ b/fastlane/metadata/android/it/changelogs/12.txt @@ -0,0 +1,11 @@ +* Versione beta 2 * + + +* Novità di questa versione + +- Cerca tra le app. +- Miglioramenti delle prestazioni (avvio, ordinamento e colore casuale). +- Ulteriore riduzione del consumo di memoria. +- Risolto bug relativo a scorciatoie e PWA che causava ulteriori perdite di memoria. + +- Questo aggiornamento rimuoverà i vecchi collegamenti da questo launcher, quindi riaggiungili dopo questo aggiornamento. diff --git a/fastlane/metadata/android/it/changelogs/13.txt b/fastlane/metadata/android/it/changelogs/13.txt new file mode 100644 index 0000000..fbac894 --- /dev/null +++ b/fastlane/metadata/android/it/changelogs/13.txt @@ -0,0 +1,9 @@ +*versione beta 3* + + +* Novità di questa versione + +- Ordina le app in base all'ora degli aggiornamenti, prima le recenti. +- Colore più luminoso e colore 'material'. +- Miglioramento dei gesti (FIX: la barra di ricerca si apriva troppo) +- Correzione di bug relativi alle scorciatoie. diff --git a/fastlane/metadata/android/it/changelogs/14.txt b/fastlane/metadata/android/it/changelogs/14.txt new file mode 100644 index 0000000..c9f35ec --- /dev/null +++ b/fastlane/metadata/android/it/changelogs/14.txt @@ -0,0 +1,8 @@ +*versione beta 4* + + +* Novità di questa versione + +- La barra di ricerca è ora accessibile scorrendo a SINISTRA/DESTRA invece di SU +- Risolto il backup per Android 6 o precedente. +- Traduzione in spagnolo diff --git a/fastlane/metadata/android/it/changelogs/15.txt b/fastlane/metadata/android/it/changelogs/15.txt new file mode 100644 index 0000000..be5299f --- /dev/null +++ b/fastlane/metadata/android/it/changelogs/15.txt @@ -0,0 +1,11 @@ +*versione beta 5* + +*TUTTE LE SCORCIATOIE PRECEDENTI NON SARANNO ACCESSIBILI* + +* Novità di questa versione + +- Correzioni di bug per "I collegamenti non funzionano bene dopo l'eliminazione". +- Correzioni di bug per "L'app non viene visualizzata o scompare dopo l'attivazione o la disattivazione" +- Miglioramenti del codice. +- Traduzione per francese, tedesco, ungherese, norvegese Bokmāl, russo, danese, polacco, slovacco, croato e spagnolo. +- Grazie a tutti i traduttori diff --git a/fastlane/metadata/android/it/changelogs/2.txt b/fastlane/metadata/android/it/changelogs/2.txt new file mode 100644 index 0000000..1ad072b --- /dev/null +++ b/fastlane/metadata/android/it/changelogs/2.txt @@ -0,0 +1,10 @@ +*Anteprima versione 2* + +- Rinomina il nome dell'app +- Ottieni informazioni sull'app con un solo clic +- Opzione di disinstallazione +- Più controlli sui Colori +- Perfezionamento dell'interfaccia utente di colore e dimensione + +- Stub delle impostazioni globali (non implementato) + Per accedere cliccare a lungo sull'area di sfondo diff --git a/fastlane/metadata/android/it/changelogs/3.txt b/fastlane/metadata/android/it/changelogs/3.txt new file mode 100644 index 0000000..aac03ec --- /dev/null +++ b/fastlane/metadata/android/it/changelogs/3.txt @@ -0,0 +1,10 @@ +*Anteprima versione 3* +-Per accedere alle impostazioni del Launcher fare clic a lungo sull'area vuota + +-Blocca/sblocca la dimensione dell'app +-Nascondi app (temporanee) +-Caratteri personalizzati +-Temi multipli +-Ripristina le impostazioni predefinite +-Backup e ripristino delle impostazioni +-Colori casuali diff --git a/fastlane/metadata/android/it/changelogs/4.txt b/fastlane/metadata/android/it/changelogs/4.txt new file mode 100644 index 0000000..1007ead --- /dev/null +++ b/fastlane/metadata/android/it/changelogs/4.txt @@ -0,0 +1,4 @@ +*Anteprima versione * + +* Aggiornamenti di emergenza +* correzione l'app scompare dai launcher diff --git a/fastlane/metadata/android/it/changelogs/5.txt b/fastlane/metadata/android/it/changelogs/5.txt new file mode 100644 index 0000000..bb93018 --- /dev/null +++ b/fastlane/metadata/android/it/changelogs/5.txt @@ -0,0 +1,5 @@ +*Anteprima versione 5* + +- Nascondi e blocca l'elenco delle app +- le impostazioni precedenti potrebbero rompersi +- Il file di backup precedente potrebbe non funzionare diff --git a/fastlane/metadata/android/it/changelogs/6.txt b/fastlane/metadata/android/it/changelogs/6.txt new file mode 100644 index 0000000..02f03b8 --- /dev/null +++ b/fastlane/metadata/android/it/changelogs/6.txt @@ -0,0 +1,10 @@ +*Anteprima versione 6* + +- Miglioramenti della barra di ricerca delle dimensioni dell'app. +- Miglioramenti della barra dei colori dell'app. +- Miglioramenti al campo Rinomina app. +- Animazione di apertura dell'app. +- Miglioramento delle prestazioni dei layout. +- Risolto bug relativo al menu recente. +- Risolto bug relativo alla riduzione delle dimensioni dell'app al clic. +- Risolto bug relativo ad alcune app che non si aprivano. diff --git a/fastlane/metadata/android/it/changelogs/7.txt b/fastlane/metadata/android/it/changelogs/7.txt new file mode 100644 index 0000000..ecb7ad4 --- /dev/null +++ b/fastlane/metadata/android/it/changelogs/7.txt @@ -0,0 +1,7 @@ +*Anteprima versione 7* + +- Colore della barra di stato e della barra di navigazione in base al tema selezionato. +- Genera lo stesso colore casuale ogni volta per un'app specifica (grazie a Sylvia). +- Allineamenti (centro, sinistra e destra) delle app. +- Riordino delle voci del menu pop e colore rosso prudente per alcune voci. +- Correzione di bug del tema Rosso Hacker. diff --git a/fastlane/metadata/android/it/changelogs/8.txt b/fastlane/metadata/android/it/changelogs/8.txt new file mode 100644 index 0000000..78c5645 --- /dev/null +++ b/fastlane/metadata/android/it/changelogs/8.txt @@ -0,0 +1,8 @@ +*Anteprima versione 8* + +- Spaziatura nella schermata iniziale. +- Menu combinato Colore e Dimensione per un accesso rapido e conveniente. +- Una nuova UX di selezione delle dimensioni per i valori esatti. +- Miglioramento del codice sorgente dell'app per una migliore comprensione. + +- prossimamente: barra di ricerca app diff --git a/fastlane/metadata/android/it/changelogs/9.txt b/fastlane/metadata/android/it/changelogs/9.txt new file mode 100644 index 0000000..a8af702 --- /dev/null +++ b/fastlane/metadata/android/it/changelogs/9.txt @@ -0,0 +1,9 @@ +*Anteprima versione 9* + +- Possibilità di eseguire app nascoste. +- Opzione per ripristinare i colori dell'app. +- Selezione colore e dimensione a livello globale. +- Opzione per ripristinare i caratteri predefiniti. +- Miglioramenti del colore per un funzionamento irrevocabile. +- Aumento dei limiti di spaziatura. +- Correzione bug relativa al reset per la dimensione dell'app. diff --git a/fastlane/metadata/android/it/full_description.txt b/fastlane/metadata/android/it/full_description.txt new file mode 100644 index 0000000..8e3555e --- /dev/null +++ b/fastlane/metadata/android/it/full_description.txt @@ -0,0 +1,44 @@ +Last Launcher è un launcher Android veloce, semplice, minimalista e personalizzabile. Ha lo scopo di fornire un'esperienza utente più rapida e semplice di sempre. + +

+************************* +**This is Versione beta*** +************************* +

+ +

Traduci quest'app su Weblate(https://hosted.weblate.org/projects/last-launcher) nella tua lingua.

+ +

Progetto

+▶ Sempre Gratuito (Gratis e Libre). +▶ Esclusiva F-droid. + +

🚀 Performance

+▶ Più veloce del più veloce :) +▶ Leggero e piccolo apk di dimensioni inferiori a 130KB. +▶ Utilizza poca memoria e CPU. + +

💥 Features

+▶ Cerca tra le app. +▶ Supporto per scorciatoie e PWA. +▶ Nomi di app ridimensionabili e colorati. +▶ Ordina le app in vari modi. +▶ Allineamento e riempimento personalizzati. +▶ Colori Casuali. +▶ Temi multipli. +▶ Nascondi app. +▶ Blocca dimensioni app. +▶ Backup/ripristino dati launcher. +▶ Nessuna icona e widgets (potrebbe essere uno svantaggio). +▶ Per saperne di più prova il launcher e vedi la differenza. + +

Privacy

+▶ Nessuna autorizzazione per l'accesso a Internet. +▶ Nessuna autorizzazione per l'accesso all'archivio. +▶ Tutti i dati sono archiviati nella memoria privata del tuo dispositivo e i dati sensibili sono cifrati con un semplice algoritmo. + +

Navigazione

+▶ Fare clic a lungo su AREA VUOTA per accedere alle impostazioni del launcher. +▶ Scorri a DESTRA per accedere alla barra di ricerca. +▶ Per nascondere la barra di ricerca, premi Indietro/Home o scorri a SINISTRA sullo schermo. + +

Traduci quest'app su Weblate(https://hosted.weblate.org/projects/last-launcher) nella tua lingua.

diff --git a/fastlane/metadata/android/it/short_description.txt b/fastlane/metadata/android/it/short_description.txt new file mode 100644 index 0000000..8db1e00 --- /dev/null +++ b/fastlane/metadata/android/it/short_description.txt @@ -0,0 +1 @@ +Più veloce della luce diff --git a/fastlane/metadata/android/it/title.txt b/fastlane/metadata/android/it/title.txt new file mode 100644 index 0000000..de66edb --- /dev/null +++ b/fastlane/metadata/android/it/title.txt @@ -0,0 +1 @@ +Last Launcher diff --git a/fastlane/metadata/android/it/video.txt b/fastlane/metadata/android/it/video.txt new file mode 100644 index 0000000..3d6486d --- /dev/null +++ b/fastlane/metadata/android/it/video.txt @@ -0,0 +1 @@ +https://www.youtube.com/watch?v=SzhJgH4a2cU diff --git a/fastlane/metadata/android/nb-NO/changelogs/1.txt b/fastlane/metadata/android/nb-NO/changelogs/1.txt new file mode 100644 index 0000000..7f59cf6 --- /dev/null +++ b/fastlane/metadata/android/nb-NO/changelogs/1.txt @@ -0,0 +1 @@ +*Forhåndsutgivelse* diff --git a/fastlane/metadata/android/nb-NO/changelogs/10.txt b/fastlane/metadata/android/nb-NO/changelogs/10.txt new file mode 100644 index 0000000..6464de8 --- /dev/null +++ b/fastlane/metadata/android/nb-NO/changelogs/10.txt @@ -0,0 +1,7 @@ +*Forhåndsutgivelse 10* + +- Sorter programmer etter navn, størrelse, farge, bruk. +- Vis programsnarveier, nettsidesnarveier, og PWA-er. +- Feilfiks for drakt som ikke er rett etter oppstart. +- Feilfiks for element som ikke vises rett. +- Ytelsesforbedringer. diff --git a/fastlane/metadata/android/nb-NO/full_description.txt b/fastlane/metadata/android/nb-NO/full_description.txt new file mode 100644 index 0000000..5491128 --- /dev/null +++ b/fastlane/metadata/android/nb-NO/full_description.txt @@ -0,0 +1,43 @@ +Last Launcher er en rask, enkel, minimalistisk, tilpasningsvennlig Android-oppstarter. +Den tar sikte på å gi den enkleste og raskeste brukeropplevelsen. + +

+************************* +**Dette er en betautgave** +************************* +

+ +

Oversett dette programmet på Weblate på ditt lokale språk.

+ +

Prosjekt

+ +▶ Alltid gratis og fritt. +▶ Eksklusivt på F-droid. + +

🚀 Ytelse

+▶ Raskere enn raskt :) +▶ Lett og liten APK-størrelse på mindre enn 130 KB. +▶ Lite minne- og prosessorbruk. + +

💥 Funksjoner

+ +▶ Søk etter programmer. +▶ Snarveier og PWA-støtte. +▶ Fargerike programnavn som kan endre størrelse. +▶ Sorter programmer på forskjellige vis. +▶ Egendefinert justering og utfylling. +▶ Tilfeldige farger. +▶ Flere drakter. +▶ Skjul programmer. +▶ Frys programstørrelse. +▶ Sikkerhetskopier/gjenopprett opppstarterdata. +▶ Ingen ikoner eller miniprogrammer (kan være en bakdel). +▶ For mer info, prøv oppstarteren og opplev forskjellen. + +

Navigasjon

+ +▶ Trykk lenge på et tomt område for å få tilgang til oppstarterinnstillinger. +▶ Dra til høyre for å få tilgang til søkefelt. +▶ For å skjule søkefeltet kan du trykke tilbake/hjem eller dra til venstre på skjermen. + +

Oversett dette programmet på Weblate på ditt lokale språk.

diff --git a/fastlane/metadata/android/nb-NO/short_description.txt b/fastlane/metadata/android/nb-NO/short_description.txt new file mode 100644 index 0000000..9f0433f --- /dev/null +++ b/fastlane/metadata/android/nb-NO/short_description.txt @@ -0,0 +1 @@ +Raskere enn lyset diff --git a/fastlane/metadata/android/nb-NO/title.txt b/fastlane/metadata/android/nb-NO/title.txt new file mode 100644 index 0000000..de66edb --- /dev/null +++ b/fastlane/metadata/android/nb-NO/title.txt @@ -0,0 +1 @@ +Last Launcher diff --git a/fastlane/metadata/android/nb-NO/video.txt b/fastlane/metadata/android/nb-NO/video.txt new file mode 100644 index 0000000..b9177e3 --- /dev/null +++ b/fastlane/metadata/android/nb-NO/video.txt @@ -0,0 +1 @@ +https://yewtu.be/watch?v=SzhJgH4a2cU diff --git a/fastlane/metadata/android/pl/changelogs/1.txt b/fastlane/metadata/android/pl/changelogs/1.txt new file mode 100644 index 0000000..c45ce53 --- /dev/null +++ b/fastlane/metadata/android/pl/changelogs/1.txt @@ -0,0 +1 @@ +* Wersja próbna * diff --git a/fastlane/metadata/android/pl/changelogs/10.txt b/fastlane/metadata/android/pl/changelogs/10.txt new file mode 100644 index 0000000..d7b7161 --- /dev/null +++ b/fastlane/metadata/android/pl/changelogs/10.txt @@ -0,0 +1,7 @@ +* Wersja testowa 10 * + +- Sortuj aplikację według nazwy, rozmiaru, koloru, użycia aplikacji +- Pokaż skróty do aplikacji, skróty do stron internetowych i PWA, +- poprawka błędu dla motywu nie jest poprawna po utworzeniu kopii zapasowej +- poprawka błędu dla czerwonego przedmiotu nie jest wyświetlana poprawnie +- ulepszenia w wydajności. diff --git a/fastlane/metadata/android/pl/changelogs/11.txt b/fastlane/metadata/android/pl/changelogs/11.txt new file mode 100644 index 0000000..571631d --- /dev/null +++ b/fastlane/metadata/android/pl/changelogs/11.txt @@ -0,0 +1,13 @@ +* Wersja beta 1 * + +* Po wielu wersjach zapoznawczych Last Launcher wszedł do fazy beta. + +* Co nowego w tej wersji + +- Szukaj w aplikacjach. +- Ulepszenia wydajności (uruchamianie, sortowanie i losowy kolor). +- Duża redukcja (23%) w rozmiarze apk. +- Dalsza redukcja zużycia pamięci. +- Naprawiono błąd związany ze skrótami i PWA, który dalej powodował wyciek pamięci. + +- Ta aktualizacja usunie stary skrót z tego programu uruchamiającego, więc przeczytałeś je po tej aktualizacji. diff --git a/fastlane/metadata/android/pl/changelogs/12.txt b/fastlane/metadata/android/pl/changelogs/12.txt new file mode 100644 index 0000000..23772c3 --- /dev/null +++ b/fastlane/metadata/android/pl/changelogs/12.txt @@ -0,0 +1,11 @@ +* Wersja beta 2 * + + +* Co nowego w tej wersji + +- Szukaj w aplikacjach. +- Ulepszenia wydajności (uruchamianie, sortowanie i losowy kolor). +- Dalsza redukcja zużycia pamięci. +- Naprawiono błąd związany ze skrótami i PWA, który dalej powodował wyciek pamięci. + +- Ta aktualizacja usunie stary skrót z tego programu uruchamiającego, więc przeczytałeś je po tej aktualizacji. diff --git a/fastlane/metadata/android/pl/changelogs/13.txt b/fastlane/metadata/android/pl/changelogs/13.txt new file mode 100644 index 0000000..a1ee8f8 --- /dev/null +++ b/fastlane/metadata/android/pl/changelogs/13.txt @@ -0,0 +1,9 @@ +* Wersja beta 3 * + + +* Co nowego w tej wersji + +- Sortuj aplikacje według czasu aktualizacji, najpierw ostatnie. +- Jaśniejszy i material kolor. +- Ulepszenie gestów (NAPRAWA: Pasek wyszukiwania otwierał się zbyt mocno) +- Naprawiono błąd związany ze skrótami. diff --git a/fastlane/metadata/android/pl/changelogs/14.txt b/fastlane/metadata/android/pl/changelogs/14.txt new file mode 100644 index 0000000..67b908b --- /dev/null +++ b/fastlane/metadata/android/pl/changelogs/14.txt @@ -0,0 +1,8 @@ +* Wersja beta 4 * + + +* Co nowego w tej wersji + +- Pasek wyszukiwania jest teraz dostępny poprzez przesunięcie w LEWO/W PRAWO zamiast w GÓRĘ +- Kopia zapasowa naprawiona dla Androida 6 lub wcześniejszego. +- Hiszpańskie tłumaczenie diff --git a/fastlane/metadata/android/pl/changelogs/15.txt b/fastlane/metadata/android/pl/changelogs/15.txt new file mode 100644 index 0000000..3cf3991 --- /dev/null +++ b/fastlane/metadata/android/pl/changelogs/15.txt @@ -0,0 +1,9 @@ +* Wersja beta 5 * + +* WSZYSTKIE POPRZEDNIE ZAINSTALOWANE SKRÓTY NIE BĘDĄ DOSTĘPNE * + +* Co nowego w tej wersji + +- Poprawki błędów „Skróty nie działają dobrze po usunięciu”. +- Większość prac wykonywana jest pod maską. +- Tłumaczenie na francuski, niemiecki, węgierski, norweski bokmāl i rosyjski diff --git a/fastlane/metadata/android/pl/changelogs/2.txt b/fastlane/metadata/android/pl/changelogs/2.txt new file mode 100644 index 0000000..2106fe1 --- /dev/null +++ b/fastlane/metadata/android/pl/changelogs/2.txt @@ -0,0 +1,10 @@ +* Wersja zapoznawcza 2 * + +- Zmień nazwę aplikacji +- Uzyskaj informacje o aplikacji jednym kliknięciem +- Opcja odinstalowania +- Więcej kontroli kolorów +- Udoskonalenie interfejsu użytkownika dotyczącego koloru i rozmiaru + +- Kod dostępu do ustawień globalnych (nie zaimplementowany) + Aby uzyskać dostęp do długiego kliknięcia w obszarze tła diff --git a/fastlane/metadata/android/pl/changelogs/3.txt b/fastlane/metadata/android/pl/changelogs/3.txt new file mode 100644 index 0000000..073a1ec --- /dev/null +++ b/fastlane/metadata/android/pl/changelogs/3.txt @@ -0,0 +1,10 @@ +* Wersja zapoznawcza 3 * +-Aby uzyskać dostęp do ustawień Launchera, kliknij i przytrzymaj pusty obszar + +-Zamroź/odblokuj rozmiar aplikacji +-Ukryj aplikacje (tymczasowo) +-Niestandardowe czcionki +-Wiele motywów +-Zresetuj do ustawień domyślnych +-Ustawienia kopii zapasowych i przywracania +-Losowe kolory diff --git a/fastlane/metadata/android/pl/changelogs/4.txt b/fastlane/metadata/android/pl/changelogs/4.txt new file mode 100644 index 0000000..fa74fa8 --- /dev/null +++ b/fastlane/metadata/android/pl/changelogs/4.txt @@ -0,0 +1,4 @@ +* Wersja próbna * + +* Aktualizacje awaryjne +* naprawienie aplikacji znikającej z programów uruchamiających diff --git a/fastlane/metadata/android/pl/changelogs/5.txt b/fastlane/metadata/android/pl/changelogs/5.txt new file mode 100644 index 0000000..3c62aeb --- /dev/null +++ b/fastlane/metadata/android/pl/changelogs/5.txt @@ -0,0 +1,5 @@ +* Wersja próbna 5 * + +- Lista aplikacji Hide and Freeze +- poprzednie ustawienia mogą przerwać +- poprzedni plik kopii zapasowej może nie działał diff --git a/fastlane/metadata/android/pl/changelogs/6.txt b/fastlane/metadata/android/pl/changelogs/6.txt new file mode 100644 index 0000000..a7dae87 --- /dev/null +++ b/fastlane/metadata/android/pl/changelogs/6.txt @@ -0,0 +1,10 @@ +* Wersja próbna 6 * + +- Ulepszenia paska wyszukiwania rozmiaru aplikacji. +- Ulepszenia paska kolorów aplikacji. +- Ulepszenia pola zmiany nazwy aplikacji. +- Animacja otwierania aplikacji. +- Poprawiono wydajności układów. +- Naprawiono błąd związany z ostatnim menu. +- Naprawiono błąd związany ze zmniejszaniem rozmiaru aplikacji po kliknięciu. +- Naprawiono błąd związany z brakiem otwierania niektórych aplikacji. diff --git a/fastlane/metadata/android/pl/changelogs/7.txt b/fastlane/metadata/android/pl/changelogs/7.txt new file mode 100644 index 0000000..bc91530 --- /dev/null +++ b/fastlane/metadata/android/pl/changelogs/7.txt @@ -0,0 +1,7 @@ +* Wersja próbna 7 * + +- Pasek stanu i kolor paska nawigacji zgodnie z wybranym motywem. +- Generuj ten sam losowy kolor za każdym razem dla aplikacji perticular (dzięki Sylvia). +- Wyrównanie (środek, lewa i prawa) aplikacji. +- Zmiana kolejności elementów PopMenu i Cautious Red dla niektórych pozycji. +- Poprawka błędu motywu Hacker Red. diff --git a/fastlane/metadata/android/pl/changelogs/8.txt b/fastlane/metadata/android/pl/changelogs/8.txt new file mode 100644 index 0000000..16b564a --- /dev/null +++ b/fastlane/metadata/android/pl/changelogs/8.txt @@ -0,0 +1,8 @@ +* Wersja zapoznawcza 8 * + +- Dopełnienie ekranu głównego. +- Połączone menu kolorów i rozmiarów dla szybkiego i wygodnego dostępu. +- Nowy interfejs wyboru rozmiaru dla dokładnych wartości. +- Poprawa kodu źródłowego aplikacji w celu lepszego zrozumienia. + +- już wkrótce: pasek wyszukiwania aplikacji diff --git a/fastlane/metadata/android/pl/changelogs/9.txt b/fastlane/metadata/android/pl/changelogs/9.txt new file mode 100644 index 0000000..7239dbf --- /dev/null +++ b/fastlane/metadata/android/pl/changelogs/9.txt @@ -0,0 +1,9 @@ +* Wersja zapoznawcza 9 * + +- Możliwość uruchamiania ukrytych aplikacji. +- Możliwość resetowania kolorów aplikacji. +- Wybór koloru i rozmiaru na całym świecie. +- Możliwość przywrócenia domyślnych czcionek. +- Poprawki kolorów umożliwiające nieodwołalne działanie. +- Zwiększone limity wypełnienia. +- Poprawka błędu związana z resetowaniem nie działa w przypadku rozmiaru aplikacji. diff --git a/fastlane/metadata/android/pl/full_description.txt b/fastlane/metadata/android/pl/full_description.txt new file mode 100644 index 0000000..a76b13f --- /dev/null +++ b/fastlane/metadata/android/pl/full_description.txt @@ -0,0 +1,40 @@ +Last Launcher to szybki, prosty, minimalistyczny, konfigurowalny program uruchamiający system Android. Ma na celu zapewnienie najszybszego i najprostszego w historii doznania użytkownika. + +

+************************* +** To jest wersja beta ** +************************* +

+ +

Projekt

+ +▶ Zawsze za darmo (Gratis i Wolny). +▶ Wyłącznie F-droid. + +

🚀 Wydajność

+▶ Szybciej niż najszybciej :) +▶ Lekki i mały rozmiar apk mniejszy niż 100KB. +▶ Niskie zużycie pamięci i procesora. + +

💥 Funkcje

+ +▶ Szukaj wśród aplikacji. +▶ Obsługa skrótów i PWA. +▶ Zmiana rozmiaru i kolorowe nazwy aplikacji. +▶ Sortuje aplikacje na różne sposoby. +▶ Niestandardowe wyrównanie i wypełnienie. +▶ Losowe kolory. +▶ Wiele motywów. +▶ Ukryj aplikacje. +▶ Zablokuj rozmiar aplikacji. +▶ Kopia zapasowa/przywracanie danych launcher. +▶ Brak ikon i widżetów (może to być wada) . +▶ Więcej wypróbuj launcher i zobacz różnicę. + +

Nawigacja

+ +▶ Długie kliknięcie na PUSTY OBSZAR, aby uzyskać dostęp do ustawień programu uruchamiającego. +▶ Przesuń w PRAWO, aby uzyskać dostęp do paska wyszukiwania. +▶ Aby ukryć pasek wyszukiwania, naciśnij Wstecz/Ekran główny lub Przesuń w LEWO ekran. + +

Przetłumacz tę aplikację na Weblate w swoim lokalnym języku.

diff --git a/fastlane/metadata/android/pl/short_description.txt b/fastlane/metadata/android/pl/short_description.txt new file mode 100644 index 0000000..cfdcd85 --- /dev/null +++ b/fastlane/metadata/android/pl/short_description.txt @@ -0,0 +1 @@ +Szybszy niż światło diff --git a/fastlane/metadata/android/pl/title.txt b/fastlane/metadata/android/pl/title.txt new file mode 100644 index 0000000..de66edb --- /dev/null +++ b/fastlane/metadata/android/pl/title.txt @@ -0,0 +1 @@ +Last Launcher diff --git a/fastlane/metadata/android/pl/video.txt b/fastlane/metadata/android/pl/video.txt new file mode 100644 index 0000000..3d6486d --- /dev/null +++ b/fastlane/metadata/android/pl/video.txt @@ -0,0 +1 @@ +https://www.youtube.com/watch?v=SzhJgH4a2cU diff --git a/fastlane/metadata/android/pt-BR/changelogs/1.txt b/fastlane/metadata/android/pt-BR/changelogs/1.txt new file mode 100644 index 0000000..9dca72e --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/1.txt @@ -0,0 +1 @@ +*Versão de pré-lançamento* diff --git a/fastlane/metadata/android/pt-BR/changelogs/10.txt b/fastlane/metadata/android/pt-BR/changelogs/10.txt new file mode 100644 index 0000000..b375896 --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/10.txt @@ -0,0 +1,7 @@ +** Versão de pré-lançamento 10 * + +- Classifica o aplicativo por Nome, Tamanho, Cor, Uso do Aplicativo +- Mostra Atalhos de Aplicativos, Atalhos de Sites e PWAs, +- Correção do bug do tema não correto após o backup +- Correção de bug do item vermelho não exibido corretamente +- Melhorias de desempenho. diff --git a/fastlane/metadata/android/pt-BR/changelogs/11.txt b/fastlane/metadata/android/pt-BR/changelogs/11.txt new file mode 100644 index 0000000..0155f37 --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/11.txt @@ -0,0 +1,13 @@ +* Versão Beta 1 * + +* Depois de muitas versões de pré-lançamento, o Last Launcher está na fase beta. + +* O Que Há de Novo + +- Pesquisar Aplicativos. +- Melhorias de desempenho (inicialização, classificação e cor aleatória). +- Redução (23%) no tamanho do apk. +- Redução do consumo de memória. +- Corrigido bug relacionado a atalhos e PWAs que causava vazamento de memória. + +- Esta atualização removerá o atalho antigo do aplicativo, então é preciso adicioná-lo após a atualização. diff --git a/fastlane/metadata/android/pt-BR/changelogs/12.txt b/fastlane/metadata/android/pt-BR/changelogs/12.txt new file mode 100644 index 0000000..434ddcb --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/12.txt @@ -0,0 +1,11 @@ +* Versão beta 2 * + + +* O Que Há de Novo Nesta Versão + +- Pesquisar Aplicativos. +- Melhorias de desempenho (inicialização, classificação e cor aleatória). +- Maior redução do consumo de memória. +- Corrigido bug relacionado a atalhos e PWAs que estava causando vazamento de memória. + +- Esta atualização removerá o atalho antigo deste inicializador, então você deve adicioná-lo novamente após esta atualização. diff --git a/fastlane/metadata/android/pt-BR/changelogs/13.txt b/fastlane/metadata/android/pt-BR/changelogs/13.txt new file mode 100644 index 0000000..298917e --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/13.txt @@ -0,0 +1,9 @@ +* Versão beta 3 * + + +* O Que Há de Novo Nesta Versão + +- Classifica os aplicativos por tempo de atualizações, as mais recentes primeiro. +- Cor mais brilhante e material. +- Melhoria gestual (CORREÇÃO: a barra de pesquisa estava abrindo muito) +- Correção de erros relacionados a atalhos. diff --git a/fastlane/metadata/android/pt-BR/changelogs/14.txt b/fastlane/metadata/android/pt-BR/changelogs/14.txt new file mode 100644 index 0000000..e71d8a5 --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/14.txt @@ -0,0 +1,8 @@ +* Versão beta 4 * + + +* O Que Há de Novo Nesta Versão + +- A barra de pesquisa agora está acessível deslizando para a ESQUERDA/DIREITA em vez de PARA CIMA +- Backup corrigido para o Android 6 ou anterior. +- Tradução para o Espanhol diff --git a/fastlane/metadata/android/pt-BR/changelogs/15.txt b/fastlane/metadata/android/pt-BR/changelogs/15.txt new file mode 100644 index 0000000..6ddb2b1 --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/15.txt @@ -0,0 +1,11 @@ +*Versão Beta 5* + +* TODOS OS ATALHOS INSTALADOS ANTERIORMENTE NÃO ESTARÃO ACESSÍVEIS * + +* O Que Há de Novo Nesta Versão + +- Correções do bug "Atalhos não estão funcionado bem após o delete". +- Correções do bug "App não está aparecendo ou desaparecendo após o habilitar ou desabilitar". +- A maioria das tarefas é feita internamente. +- Tradução para o Francês, Alemão, Húngaro, Norueguês, Bokmāl, Russo, Dinamarquês, Polonês, Eslovaco, Croata e Espanhol. +- Obrigado a todos os tradutores diff --git a/fastlane/metadata/android/pt-BR/changelogs/2.txt b/fastlane/metadata/android/pt-BR/changelogs/2.txt new file mode 100644 index 0000000..01baa6d --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/2.txt @@ -0,0 +1,10 @@ +* Versão de pré-lançamento 2 * + +- Renomear o nome do aplicativo +- Obtenha informações do aplicativo com um único clique +- Opção de desinstalação +- Mais controles de cores +- Refinamento da IU de cor e tamanho + +- Stub de configurações globais (não implementado) + Para acessar dê um clique longo na área de fundo diff --git a/fastlane/metadata/android/pt-BR/changelogs/3.txt b/fastlane/metadata/android/pt-BR/changelogs/3.txt new file mode 100644 index 0000000..a16964c --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/3.txt @@ -0,0 +1,10 @@ +* Versão de pré-lançamento 3 * +- Para acessar as configurações do Launcher, dê um clique longo na área vazia + +- Congelar/descongelar o tamanho do aplicativo +-Ocultar aplicativos (temporariamente) +-Fontes personalizadas +-Múltiplos Temas +-Redefinir para as configurações padrão +-Backup e restaurar configurações +-Cores aleatórias diff --git a/fastlane/metadata/android/pt-BR/changelogs/4.txt b/fastlane/metadata/android/pt-BR/changelogs/4.txt new file mode 100644 index 0000000..aed7891 --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/4.txt @@ -0,0 +1,4 @@ +*Versão de pré-lançamento * + +* Atualizações de Emergência +* Correção do Aplicativo desaparecendo do inicializador diff --git a/fastlane/metadata/android/pt-BR/changelogs/5.txt b/fastlane/metadata/android/pt-BR/changelogs/5.txt new file mode 100644 index 0000000..9732274 --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/5.txt @@ -0,0 +1,5 @@ +*Versão de pré-lançamento 5* + +- Lista de ocultar ou congelar aplicativos +- configurações anteriores podem falhar +- backups anteriores podem não funcionar diff --git a/fastlane/metadata/android/pt-BR/changelogs/6.txt b/fastlane/metadata/android/pt-BR/changelogs/6.txt new file mode 100644 index 0000000..cc1fc25 --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/6.txt @@ -0,0 +1,10 @@ +* Versão de pré-lançamento 6 * + +- Melhorias na barra de busca do Tamanho do Aplicativo. +- Melhorias na barra de Cores do Aplicativo. +- Melhorias no campo Renomear Aplicativo +- Animação na abertura do aplicativo. +- Melhoria de performance de layouts. +- Correção do bug relacionado ao menu recente. +- Correção do bug relacionado à diminuição do tamanho do aplicativo com um clique. +- Correção do bug relacionado a algum aplicativo não abrir. diff --git a/fastlane/metadata/android/pt-BR/changelogs/7.txt b/fastlane/metadata/android/pt-BR/changelogs/7.txt new file mode 100644 index 0000000..312244c --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/7.txt @@ -0,0 +1,7 @@ +* Versão de pré-lançamento 7 * + +- Barra de status e cor da barra de navegação de acordo com o tema selecionado. +- Gera a mesma cor aleatória a cada vez para um aplicativo em particular (graças à Sylvia). +- Alinhamentos (centro, esquerda e direita) dos Aplicativos. +- Reordenamento de itens do PopMenu e a cor vermelha de atenção para alguns itens. +- Correção de bug do tema Vermelho Hacker. diff --git a/fastlane/metadata/android/pt-BR/changelogs/8.txt b/fastlane/metadata/android/pt-BR/changelogs/8.txt new file mode 100644 index 0000000..bbb7241 --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/8.txt @@ -0,0 +1,8 @@ +* Versão de pré-lançamento 8 * + +- Preenchimento da tela inicial. +- Menu de Cores e Tamanhos combinados para acesso rápido e conveniente. +- Uma nova UX de seleção de tamanho para valores exatos. +- Melhoria do código fonte do aplicativo para melhor compreensão. + +- em breve: Barra de pesquisa de aplicativos diff --git a/fastlane/metadata/android/pt-BR/changelogs/9.txt b/fastlane/metadata/android/pt-BR/changelogs/9.txt new file mode 100644 index 0000000..07c6663 --- /dev/null +++ b/fastlane/metadata/android/pt-BR/changelogs/9.txt @@ -0,0 +1,9 @@ +* Versão de pré-lançamento 9 * + +- Opção para executar aplicativos ocultos. +- Opção para redefinir as Cores do Aplicativo. +- Seleção de Cor e Tamanho Global. +- Opção para restaurar as fontes padrão. +- Melhorias de cor para funcionamento perfeito. +- Limites de preenchimento aumentados. +- A correção do bug relacionado à "redefinição não está funcionando para o tamanho do aplicativo". diff --git a/fastlane/metadata/android/pt-BR/full_description.txt b/fastlane/metadata/android/pt-BR/full_description.txt new file mode 100644 index 0000000..2607d2b --- /dev/null +++ b/fastlane/metadata/android/pt-BR/full_description.txt @@ -0,0 +1,42 @@ +Last Launcher é um launcher para Android Rápido, Simples, Minumalista e Customizável. É feito para dar a mais rápida e simples experiência para o usuário final. + +

+************************* +**Esta é uma Versão Beta** +************************* +

+ +

Ajude a traduzir este app no Weblate para seu idioma nativo.

+ +

Projeto

+ +▶ Sempre de Graça(Gratis e Libre). +▶ Exclusivo ao F-droid. + +

🚀 Performance

+▶ Mais rápido que o mais rápido :) +▶ Peso-pena e apk de pequeno tamanho, menos de 100KB. +▶ Baixa utilização de memória e CPU. + +

💥 Funções

+ +▶ Buscar aplicativos. +▶ Suporte a atalhos e PWAs. +▶ Nomes de aplicativos com cores e tamanhos customizáveis. +▶ Ordene aplicativos por diversos métodos. +▶ Customize a distância entre os aplicativos. +▶ Cores aleatórias. +▶ Multiplos temas. +▶ Esconda apps. +▶ Congele o tamanho de apps. +▶ Faça Backup/Restauração de dados do launcher. +▶ Sem ícones e widgets(pode ser uma desvantágem). +▶ Para mais, experimente o launcher e veja as diferenças. + +

Navegação

+ +▶ Toque e segure em qualquer ÁREA VAZIA para acessar as configurações do launcher. +▶ Deslize para a DIREITA para acessar a Barra de Pesquisa. +▶ Para esconder a barra de pesquisa, pressione Voltar/Home, ou Deslize para a ESQUERDA. + +

Ajude a traduzir este app no Weblate para seu idioma nativo.

diff --git a/fastlane/metadata/android/pt-BR/short_description.txt b/fastlane/metadata/android/pt-BR/short_description.txt new file mode 100644 index 0000000..c7d7ef5 --- /dev/null +++ b/fastlane/metadata/android/pt-BR/short_description.txt @@ -0,0 +1 @@ +Mais rápido que a luz diff --git a/fastlane/metadata/android/pt-BR/title.txt b/fastlane/metadata/android/pt-BR/title.txt new file mode 100644 index 0000000..de66edb --- /dev/null +++ b/fastlane/metadata/android/pt-BR/title.txt @@ -0,0 +1 @@ +Last Launcher diff --git a/fastlane/metadata/android/pt-BR/video.txt b/fastlane/metadata/android/pt-BR/video.txt new file mode 100644 index 0000000..3d6486d --- /dev/null +++ b/fastlane/metadata/android/pt-BR/video.txt @@ -0,0 +1 @@ +https://www.youtube.com/watch?v=SzhJgH4a2cU diff --git a/fastlane/metadata/android/ro/changelogs/10.txt b/fastlane/metadata/android/ro/changelogs/10.txt new file mode 100644 index 0000000..63a091e --- /dev/null +++ b/fastlane/metadata/android/ro/changelogs/10.txt @@ -0,0 +1,7 @@ +*Preview release 10* + +- Sortează aplicația după nume, mărime, culoare, utilizarea aplicației +- Afișați comenzile rapide ale aplicațiilor, comenzile rapide ale site-urilor web și PWA-urile, +- remedierea unei erori pentru tema nu este corectă după backup +- remediere de erori pentru elementul roșu nu este afișat corect +- îmbunătățiri de performanță. diff --git a/fastlane/metadata/android/ro/changelogs/12.txt b/fastlane/metadata/android/ro/changelogs/12.txt new file mode 100644 index 0000000..11e5153 --- /dev/null +++ b/fastlane/metadata/android/ro/changelogs/12.txt @@ -0,0 +1,11 @@ +*Beta release 2* + + +* Ce este nou în această versiune + +- Căutare prin aplicații. +- Îmbunătățiri de performanță (pornire, sortare și culoare aleatorie). +- Reducerea suplimentară a consumului de memorie. +- Corectarea unui bug legat de Shortcuts și PWAs care provoca în continuare pierderi de memorie. + +- Această actualizare va elimina vechile scurtături din acest lansator, astfel încât să le readuceți după această actualizare. diff --git a/fastlane/metadata/android/ro/changelogs/13.txt b/fastlane/metadata/android/ro/changelogs/13.txt new file mode 100644 index 0000000..a126984 --- /dev/null +++ b/fastlane/metadata/android/ro/changelogs/13.txt @@ -0,0 +1,9 @@ +*Beta release 3* + + +* Ce este nou în această versiune + +- Sortați aplicațiile în funcție de timpul de actualizare, mai întâi cele mai recente. +- Culoare mai luminoasă și materială. +- Îmbunătățirea gesturilor (FIX: Bara de căutare se deschidea prea mult). +- Corectarea bug-urilor legate de scurtături. diff --git a/fastlane/metadata/android/ro/changelogs/14.txt b/fastlane/metadata/android/ro/changelogs/14.txt new file mode 100644 index 0000000..37d1424 --- /dev/null +++ b/fastlane/metadata/android/ro/changelogs/14.txt @@ -0,0 +1,8 @@ +*Beta release 4* + + +* Ce este nou în această versiune + +- Bara de căutare este acum accesibilă prin glisare stânga/dreapta în loc de sus +- Backup fixat pentru Android 6 sau anterior. +- Traducere în limba spaniolă diff --git a/fastlane/metadata/android/ro/changelogs/15.txt b/fastlane/metadata/android/ro/changelogs/15.txt new file mode 100644 index 0000000..0888830 --- /dev/null +++ b/fastlane/metadata/android/ro/changelogs/15.txt @@ -0,0 +1,11 @@ +*Beta release 5* + +*TOATE COMENZILE RAPIDE INSTALATE ANTERIOR NU VOR MAI FI ACCESIBILE* + +* Ce este nou în această versiune + +- Corecții de erori pentru "Shortcuts are not working well after deletion". +- Corecții de erori pentru "Aplicația nu se afișează sau dispare după activare sau dezactivare" +- Cea mai mare parte a muncii se face sub capotă. +- Traducere pentru franceză, germană, maghiară, norvegiană Bokmāl, rusă, daneză, poloneză, slovacă, croată și spaniolă. +- Mulțumim tuturor traducătorilor diff --git a/fastlane/metadata/android/ro/changelogs/18.txt b/fastlane/metadata/android/ro/changelogs/18.txt new file mode 100644 index 0000000..21469a3 --- /dev/null +++ b/fastlane/metadata/android/ro/changelogs/18.txt @@ -0,0 +1,10 @@ +*Beta release 8* + +* Ce este nou în această versiune + +- Corectare de eroare pentru "Blocajul lansatorului la actualizarea aplicațiilor". +- Corectarea scurgerii de memorie + +* Modificări ale codurilor sursă ale proiectului. + +- Actualizare traducere. diff --git a/fastlane/metadata/android/ro/changelogs/2.txt b/fastlane/metadata/android/ro/changelogs/2.txt new file mode 100644 index 0000000..7e6a4b8 --- /dev/null +++ b/fastlane/metadata/android/ro/changelogs/2.txt @@ -0,0 +1,10 @@ +*Preview release 2* + +- Redenumiți numele aplicației +- Obțineți informații despre aplicație cu un singur clic +- Opțiunea de dezinstalare +- Mai multe controale de culori +- Culoare și dimensiune rafinament UI UI + +- Stub de setări globale (neimplementat) + Pentru a accesa clic lung pe zona de fundal diff --git a/fastlane/metadata/android/ro/changelogs/3.txt b/fastlane/metadata/android/ro/changelogs/3.txt new file mode 100644 index 0000000..e9eb201 --- /dev/null +++ b/fastlane/metadata/android/ro/changelogs/3.txt @@ -0,0 +1,10 @@ +*Preview release 3* +-Pentru a accesa setările lansatorului, faceți clic lung pe o zonă goală. + +-Înghețare/dezghețare a dimensiunii aplicației +-Ascundeți aplicațiile (temporar) +-Fonturi personalizate +-Multe teme +-Resetare la setările implicite +-Salvare și restaurare setări +-Culori aleatorii diff --git a/fastlane/metadata/android/ro/changelogs/4.txt b/fastlane/metadata/android/ro/changelogs/4.txt new file mode 100644 index 0000000..5e14236 --- /dev/null +++ b/fastlane/metadata/android/ro/changelogs/4.txt @@ -0,0 +1,4 @@ +*Preview release * + +* Actualizări de urgență +* Fix App dispare din lansatoare diff --git a/fastlane/metadata/android/ro/changelogs/5.txt b/fastlane/metadata/android/ro/changelogs/5.txt new file mode 100644 index 0000000..0dd49b8 --- /dev/null +++ b/fastlane/metadata/android/ro/changelogs/5.txt @@ -0,0 +1,5 @@ +*Preview release 5* + +- Ascundeți și înghețați lista de aplicații +- setările anterioare pot întrerupe +- fișierul de backup anterior poate să nu funcționeze diff --git a/fastlane/metadata/android/ro/changelogs/6.txt b/fastlane/metadata/android/ro/changelogs/6.txt new file mode 100644 index 0000000..00beb8c --- /dev/null +++ b/fastlane/metadata/android/ro/changelogs/6.txt @@ -0,0 +1,10 @@ +*Preview release 6* + +- Îmbunătățiri ale barei de căutare App Size. +- Îmbunătățiri la bara de culori a aplicației. +- Îmbunătățiri ale câmpului de redenumire a aplicației. +- Animație de deschidere a aplicației. +- Îmbunătățirea performanțelor Layout-urilor. +- Corectarea unei erori legate de meniul recent. +- Corectare eroare legată de scăderea dimensiunii aplicației la clic. +- Corectarea unei erori legate de unele aplicații care nu se deschid. diff --git a/fastlane/metadata/android/ro/changelogs/7.txt b/fastlane/metadata/android/ro/changelogs/7.txt new file mode 100644 index 0000000..f5ff683 --- /dev/null +++ b/fastlane/metadata/android/ro/changelogs/7.txt @@ -0,0 +1,7 @@ +*Preview release 7* + +- Culoarea barei de stare și a barei de navigare în funcție de tema selectată. +- Generarea aceleiași culori aleatorii de fiecare dată pentru o aplicație perticulară (mulțumiri lui Sylvia). +- Alinieri (centru, stânga și dreapta) ale aplicațiilor. +- Reordonarea elementelor din PopMenu și culoare roșie prudentă pentru unele elemente. +- Corectarea erorilor din tema Hacker Red. diff --git a/fastlane/metadata/android/ro/changelogs/9.txt b/fastlane/metadata/android/ro/changelogs/9.txt new file mode 100644 index 0000000..f243f95 --- /dev/null +++ b/fastlane/metadata/android/ro/changelogs/9.txt @@ -0,0 +1,9 @@ +*Preview release 9* + +- Opțiunea de a rula aplicații ascunse. +- Opțiunea de resetare a culorilor aplicațiilor. +- Selectarea culorilor și a dimensiunilor la nivel global. +- Opțiunea de a restabili fonturile implicite. +- Îmbunătățiri de culoare pentru funcționarea irevocabilă. +- Limite de umplutură mărite. +- Corectare eroare legată de resetarea nu funcționează pentru dimensiunea aplicației. diff --git a/fastlane/metadata/android/ro/full_description.txt b/fastlane/metadata/android/ro/full_description.txt new file mode 100644 index 0000000..81d3dfe --- /dev/null +++ b/fastlane/metadata/android/ro/full_description.txt @@ -0,0 +1,44 @@ +Last Launcher este un lansator Android rapid, simplu, minimalist și personalizabil. Scopul său este de a oferi cea mai rapidă și mai simplă experiență de utilizare vreodată. + +

+************************* +**Aceasta este Beta release*** +************************* +

+ +

Traduceți această aplicație pe Weblate(https://hosted.weblate.org/projects/last-launcher) în limba dvs. locală.

. + +

Proiect

+▶ Always Free (Gratis și Liber). +▶ Exclusiv pentru F-droid. + +

🚀 Performanță

+▶ Mai rapid decât cel mai rapid :) +▶ APK ușor și de dimensiuni mici de mai puțin de 130KB. +▶ Utilizare redusă a memoriei și a procesorului. + +

💥 Caracteristici

+▶ Căutare printre aplicații. +▶ Suport pentru comenzi rapide și PWA-uri. +▶ Nume de aplicații redimensionabile și colorate. +▶ Sortați aplicațiile în diverse moduri. +▶ Aliniere și padding personalizate. +▶ Culori aleatorii. +▶ Teme multiple. +▶ Ascundeți aplicațiile. +▶ Îngheață dimensiunea aplicațiilor. +▶ Copie de rezervă/restaurare a datelor lansatorului. +▶ Fără pictograme și widget-uri (poate fi un dezavantaj). +▶ Pentru mai multe încercați launcher și vedeți diferența. + +

Confidențialitate

+▶ Fără permisiune de acces la internet. +▶ Fără permisiune de acces la stocare. +▶ Toate datele sunt stocate în memoria privată a dispozitivului, iar datele sensibile sunt cifrate cu un algoritm simplu. + +

Navigație

+▶ Faceți clic lung pe EMPTY AREA pentru a accesa setările lansatorului.. +▶ Glisați spre dreapta pentru a accesa bara de căutare.. +▶ Pentru a ascunde bara de căutare apăsați Back/Home sau Swipe LEFT pe ecran.. + +

Traduceți această aplicație pe Weblate(https://hosted.weblate.org/projects/last-launcher) în limba dvs. locală.

diff --git a/fastlane/metadata/android/ro/short_description.txt b/fastlane/metadata/android/ro/short_description.txt new file mode 100644 index 0000000..71c7d41 --- /dev/null +++ b/fastlane/metadata/android/ro/short_description.txt @@ -0,0 +1 @@ +Mai rapid decât lumina diff --git a/fastlane/metadata/android/ro/title.txt b/fastlane/metadata/android/ro/title.txt new file mode 100644 index 0000000..261e0b8 --- /dev/null +++ b/fastlane/metadata/android/ro/title.txt @@ -0,0 +1 @@ +Ultimul lansator diff --git a/fastlane/metadata/android/ro/video.txt b/fastlane/metadata/android/ro/video.txt new file mode 100644 index 0000000..3d6486d --- /dev/null +++ b/fastlane/metadata/android/ro/video.txt @@ -0,0 +1 @@ +https://www.youtube.com/watch?v=SzhJgH4a2cU diff --git a/fastlane/metadata/android/sk/full_description.txt b/fastlane/metadata/android/sk/full_description.txt new file mode 100644 index 0000000..37f9c09 --- /dev/null +++ b/fastlane/metadata/android/sk/full_description.txt @@ -0,0 +1,42 @@ +Last Launcher je Rýchla, Jednoduchá, Minimalistická, Upraviteľná domovská obrazovka pre Android. Jej cieľom je čo najrýchlejšie a najjednoduchšie používanie. + +

+************************* +**Toto je Beta vydanie** +************************* +

+ +

Pomôcť s prekladom do Vášho jazyka môžete na stránke Weblate.

+ +

Projekt

+ +▶ Navždy otvorený (Zadarmo a Slobodný). +▶ Exkluzívne na F-Droid. + +

🚀 Výkon

+▶ Rýchlejší ako najrýchlejší :) +▶ Ľahký s malou veľkosťou apk súboru aplikácie, menšou ako 100 KB. +▶ Nízke pamäťové a CPU nároky. + +

💥 Funkcie

+ +▶ Vyhľadávanie medzi aplikáciami. +▶ Rýchle odkazy a podpora PWAs. +▶ Meniteľné veľkosti a farvy názvov aplikácií. +▶ Zoraďovanie aplikácii na základe rôznych vlastností. +▶ Voliteľné zarovnanie a odsadenie. +▶ Náhodné farby. +▶ Viaceré témy vzhľadu. +▶ Skrytie aplikácií. +▶ Uzamknutie veľkostí názvov aplikácií. +▶ Záloha/Obnovenie dát/nastavení. +▶ Žiadne ikony a widgety(môže byť nevýhoda). +▶ Pre viac informácií vyskúšajte túto domovskú obrazovku a zistite ten rozdiel oproti klasickým. + +

Navigácia

+ +▶ Dlhý klik na PRÁZDNE MIESTO pre prístup do nastavení domovskej obrazovky. +▶ Potiahnutie DOPRAVA pre vyhľadávanie. +▶ Pre skrytie vyhľadávania stlačte Naspäť/Domov alebo potiahnite prstom DOĽAVA po obrazovke. + +

Pomôcť s prekladom do Vášho jazyka môžete na stránke Weblate.

diff --git a/fastlane/metadata/android/sk/short_description.txt b/fastlane/metadata/android/sk/short_description.txt new file mode 100644 index 0000000..343f44b --- /dev/null +++ b/fastlane/metadata/android/sk/short_description.txt @@ -0,0 +1 @@ +Rýchlejší ako svetlo diff --git a/fastlane/metadata/android/sk/title.txt b/fastlane/metadata/android/sk/title.txt new file mode 100644 index 0000000..de66edb --- /dev/null +++ b/fastlane/metadata/android/sk/title.txt @@ -0,0 +1 @@ +Last Launcher diff --git a/fastlane/metadata/android/sk/video.txt b/fastlane/metadata/android/sk/video.txt new file mode 100644 index 0000000..3d6486d --- /dev/null +++ b/fastlane/metadata/android/sk/video.txt @@ -0,0 +1 @@ +https://www.youtube.com/watch?v=SzhJgH4a2cU diff --git a/fastlane/metadata/android/uk/changelogs/1.txt b/fastlane/metadata/android/uk/changelogs/1.txt new file mode 100644 index 0000000..0ca1249 --- /dev/null +++ b/fastlane/metadata/android/uk/changelogs/1.txt @@ -0,0 +1 @@ +*Попередній перегляд випуску* diff --git a/fastlane/metadata/android/uk/changelogs/10.txt b/fastlane/metadata/android/uk/changelogs/10.txt new file mode 100644 index 0000000..0e2c954 --- /dev/null +++ b/fastlane/metadata/android/uk/changelogs/10.txt @@ -0,0 +1,7 @@ +*Попередній перегляд випуску 10* + +- Упорядкування застосунків за назвою, розміром, кольором, використанням +- Показ ярликів застосунків, ярликів вебсайтів та PWAs, +- правки помилок для теми не є правильним після резервного копіювання +- правки помилок для червоного елемента відображаються неправильно +- поліпшення продуктивності. diff --git a/fastlane/metadata/android/uk/full_description.txt b/fastlane/metadata/android/uk/full_description.txt new file mode 100644 index 0000000..b5d2fdd --- /dev/null +++ b/fastlane/metadata/android/uk/full_description.txt @@ -0,0 +1,42 @@ +Last Launcher - швидкий, простий, мінімалістичний та налаштовувальний лаунчер для Андроїду. Мета - надання користувачеві швидкого та простого інтерфейсу. + +

+************************* +**Це Бета-випуск** +************************* +

+ +

Перекладіть застосунок на Weblate вашою мовою.

+ +

Проєкт

+ +▶ Назавжди вільний(Gratis і Libre). +▶ Лише на F-droid. + +

🚀 Функціонування

+▶ Дуже швидкий +▶ Мінімалістичний, застосунок займає менше 200КБ. +▶ Низьке споживання ресурсів. + +

💥 Можливості

+ +▶ Пошук серед застосунків. +▶ Підтримка скорочень та PWA. +▶ Зміна розміру назв та кольорів. +▶ Сортування застосунків. +▶ Налаштовувальне вирівнювання і відступання. +▶ Випадкові кольори. +▶ Різні теми. +▶ Можливість ховання застосунків. +▶ Можливість робити розмір назв сталим. +▶ Резервне копіювання/відновлення даних лаунчера. +▶ Відсутність образків та віджетів(можливо не є перевагою). +▶ Аби дізнатися більше, спробуйте лаунчер та відчуйте різницю. + +

Навігація

+ +▶ Затисніть ПОРОЖНЄ МІСЦЕ, аби відкрити налаштування. +▶ Ковзніть ВПРАВО, аби відкрити пошуковий рядок. +▶ Аби сховати пошуковий рядок, натисніть Назад/Додому чи ковзніть пальцем УЛІВО. + +

Перекладіть застосунок на Weblate вашою мовою.

diff --git a/fastlane/metadata/android/uk/short_description.txt b/fastlane/metadata/android/uk/short_description.txt new file mode 100644 index 0000000..b2df7fc --- /dev/null +++ b/fastlane/metadata/android/uk/short_description.txt @@ -0,0 +1 @@ +Швидший за світло diff --git a/fastlane/metadata/android/uk/title.txt b/fastlane/metadata/android/uk/title.txt new file mode 100644 index 0000000..de66edb --- /dev/null +++ b/fastlane/metadata/android/uk/title.txt @@ -0,0 +1 @@ +Last Launcher diff --git a/fastlane/metadata/android/uk/video.txt b/fastlane/metadata/android/uk/video.txt new file mode 100644 index 0000000..3d6486d --- /dev/null +++ b/fastlane/metadata/android/uk/video.txt @@ -0,0 +1 @@ +https://www.youtube.com/watch?v=SzhJgH4a2cU diff --git a/fastlane/metadata/android/zh-Hant/full_description.txt b/fastlane/metadata/android/zh-Hant/full_description.txt new file mode 100644 index 0000000..69ffa13 --- /dev/null +++ b/fastlane/metadata/android/zh-Hant/full_description.txt @@ -0,0 +1,42 @@ +萊斯特啟動器為一個快速,簡單,極簡風,可自訂化的Android啟動器。目標為提供最快速及最簡潔的使用者體驗。 + +

+************************* +**此版本為 Beta 測試版** +************************* +

+ +

於 Weblate 翻譯此應用程式.

+ +

專案

+ +▶ 永遠免費(免費和自由). +▶ F-droid 獨家提供. + +

🚀 效能

+▶ 比桐谷和人還快 :) +▶ 輕量化與超小的小於 100KB apk 檔。 +▶ 低記憶體及處理器使用量。 + +

💥 特色

+ +▶ 應用程式間搜尋。 +▶ 支援捷徑與PWA。 +▶ 可調整大小以及五彩繽紛的應用程式名稱顯示。 +▶ 以不同方式分類應用程式。 +▶ 自訂對齊模式與墊高。 +▶ 隨機顏色。 +▶ 多個主題。 +▶ 隱藏應用程式。 +▶ 固定應用程式顯示大小。 +▶ 備份/還原啟動器資料。 +▶ 無圖標以及小工具(可能是個缺點). +▶ 給予更多實驗啟動器 與看見不同。 + +

導覽

+ +▶ 長按 空白處 以存取啟動器設定。 +▶ 於螢幕上 右滑 以存取搜尋列。 +▶ 隱藏搜尋欄,輕觸返回/首頁鍵或於螢幕上 左滑 。 + +

於 Weblate 上翻譯此應用程式成您使用的語言

diff --git a/fastlane/metadata/android/zh-Hant/short_description.txt b/fastlane/metadata/android/zh-Hant/short_description.txt new file mode 100644 index 0000000..cb7df76 --- /dev/null +++ b/fastlane/metadata/android/zh-Hant/short_description.txt @@ -0,0 +1 @@ +更甚光速 diff --git a/fastlane/metadata/android/zh-Hant/title.txt b/fastlane/metadata/android/zh-Hant/title.txt new file mode 100644 index 0000000..950e8b1 --- /dev/null +++ b/fastlane/metadata/android/zh-Hant/title.txt @@ -0,0 +1 @@ +萊斯特啟動器 diff --git a/fastlane/metadata/android/zh-Hant/video.txt b/fastlane/metadata/android/zh-Hant/video.txt new file mode 100644 index 0000000..3d6486d --- /dev/null +++ b/fastlane/metadata/android/zh-Hant/video.txt @@ -0,0 +1 @@ +https://www.youtube.com/watch?v=SzhJgH4a2cU diff --git a/flowlayout/layouts/build.gradle b/flowlayout/layouts/build.gradle new file mode 100644 index 0000000..8275d07 --- /dev/null +++ b/flowlayout/layouts/build.gradle @@ -0,0 +1,31 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 29 + buildToolsVersion "35.0.1" + + defaultConfig { + versionCode 2 + versionName "0.2" + minSdkVersion 14 + targetSdkVersion 29 + } + buildTypes { + release { + debuggable false + jniDebuggable false + minifyEnabled true + zipAlignEnabled true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + lintOptions { + abortOnError false + } +} + +dependencies { + //implementation 'com.android.support:recyclerview-v7:28.0.0' +} + + diff --git a/flowlayout/layouts/src/main/AndroidManifest.xml b/flowlayout/layouts/src/main/AndroidManifest.xml new file mode 100644 index 0000000..e0900dd --- /dev/null +++ b/flowlayout/layouts/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/flowlayout/layouts/src/main/java/org/apmem/tools/layouts/FlowLayout.java b/flowlayout/layouts/src/main/java/org/apmem/tools/layouts/FlowLayout.java new file mode 100644 index 0000000..1549206 --- /dev/null +++ b/flowlayout/layouts/src/main/java/org/apmem/tools/layouts/FlowLayout.java @@ -0,0 +1,416 @@ +package org.apmem.tools.layouts; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.Build; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.view.ViewDebug; +import android.view.ViewGroup; + +import org.apmem.tools.layouts.logic.CommonLogic; +import org.apmem.tools.layouts.logic.ConfigDefinition; +import org.apmem.tools.layouts.logic.LineDefinition; +import org.apmem.tools.layouts.logic.ViewDefinition; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +public class FlowLayout extends ViewGroup { + + private final ConfigDefinition config; + List lines = new ArrayList<>(); + List views = new ArrayList<>(); + + public FlowLayout(Context context) { + super(context); + this.config = new ConfigDefinition(); + readStyleParameters(context, null); + } + + public FlowLayout(Context context, AttributeSet attributeSet) { + super(context, attributeSet); + this.config = new ConfigDefinition(); + readStyleParameters(context, attributeSet); + } + + public FlowLayout(Context context, AttributeSet attributeSet, int defStyle) { + super(context, attributeSet, defStyle); + this.config = new ConfigDefinition(); + readStyleParameters(context, attributeSet); + } + + private void readStyleParameters(Context context, AttributeSet attributeSet) { + TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.FlowLayout); + try { + this.config.setOrientation(a.getInteger(R.styleable.FlowLayout_android_orientation, CommonLogic.HORIZONTAL)); + this.config.setMaxLines(a.getInteger(R.styleable.FlowLayout_maxLines, 0)); + this.config.setDebugDraw(a.getBoolean(R.styleable.FlowLayout_debugDraw, false)); + this.config.setWeightDefault(a.getFloat(R.styleable.FlowLayout_weightDefault, 0.0f)); + this.config.setGravity(a.getInteger(R.styleable.FlowLayout_android_gravity, Gravity.NO_GRAVITY)); + + int layoutDirection; + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + layoutDirection = a.getInteger(R.styleable.FlowLayout_layoutDirection, LAYOUT_DIRECTION_LTR); + } else { + layoutDirection = a.getInteger(R.styleable.FlowLayout_layoutDirection, super.getLayoutDirection()); + } + //noinspection ResourceType + this.setLayoutDirection(layoutDirection); + + } finally { + a.recycle(); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int count = this.getChildCount(); + views.clear(); + lines.clear(); + for (int i = 0; i < count; i++) { + final View child = this.getChildAt(i); + if (child.getVisibility() == GONE) { + continue; + } + + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + child.measure( + getChildMeasureSpec(widthMeasureSpec, this.getPaddingLeft() + this.getPaddingRight(), lp.width), + getChildMeasureSpec(heightMeasureSpec, this.getPaddingTop() + this.getPaddingBottom(), lp.height) + ); + + ViewDefinition view = new ViewDefinition(this.config, child); + view.setWidth(child.getMeasuredWidth()); + view.setHeight(child.getMeasuredHeight()); + view.setNewLine(lp.isNewLine()); + view.setGravity(lp.getGravity()); + view.setWeight(lp.getWeight()); + view.setMargins(lp.leftMargin, lp.topMargin, lp.rightMargin, lp.bottomMargin); + views.add(view); + } + + this.config.setMaxWidth(MeasureSpec.getSize(widthMeasureSpec) - this.getPaddingRight() - this.getPaddingLeft()); + this.config.setMaxHeight(MeasureSpec.getSize(heightMeasureSpec) - this.getPaddingTop() - this.getPaddingBottom()); + this.config.setWidthMode(MeasureSpec.getMode(widthMeasureSpec)); + this.config.setHeightMode(MeasureSpec.getMode(heightMeasureSpec)); + this.config.setCheckCanFit(this.config.getLengthMode() != View.MeasureSpec.UNSPECIFIED); + + CommonLogic.fillLines(views, lines, config); + CommonLogic.calculateLinesAndChildPosition(lines); + + int contentLength = 0; + final int linesCount = lines.size(); + for (int i = 0; i < linesCount; i++) { + LineDefinition l = lines.get(i); + contentLength = Math.max(contentLength, l.getLineLength()); + } + + LineDefinition currentLine = lines.get(lines.size() - 1); + int contentThickness = currentLine.getLineStartThickness() + currentLine.getLineThickness(); + int realControlLength = CommonLogic.findSize(this.config.getLengthMode(), this.config.getMaxLength(), contentLength); + int realControlThickness = CommonLogic.findSize(this.config.getThicknessMode(), this.config.getMaxThickness(), contentThickness); + + CommonLogic.applyGravityToLines(lines, realControlLength, realControlThickness, config); + + for (int i = 0; i < linesCount; i++) { + LineDefinition line = lines.get(i); + applyPositionsToViews(line); + } + + /* need to take padding into account */ + int totalControlWidth = this.getPaddingLeft() + this.getPaddingRight(); + int totalControlHeight = this.getPaddingBottom() + this.getPaddingTop(); + if (this.config.getOrientation() == CommonLogic.HORIZONTAL) { + totalControlWidth += contentLength; + totalControlHeight += contentThickness; + } else { + totalControlWidth += contentThickness; + totalControlHeight += contentLength; + } + this.setMeasuredDimension(resolveSize(totalControlWidth, widthMeasureSpec), resolveSize(totalControlHeight, heightMeasureSpec)); + } + + private void applyPositionsToViews(LineDefinition line) { + final List childViews = line.getViews(); + final int childCount = childViews.size(); + for (int i = 0; i < childCount; i++) { + final ViewDefinition child = childViews.get(i); + final View view = child.getView(); + view.measure( + MeasureSpec.makeMeasureSpec(child.getWidth(), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(child.getHeight(), MeasureSpec.EXACTLY) + ); + } + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + final int linesCount = this.lines.size(); + for (int i = 0; i < linesCount; i++) { + final LineDefinition line = this.lines.get(i); + + final int count = line.getViews().size(); + for (int j = 0; j < count; j++) { + ViewDefinition child = line.getViews().get(j); + View view = child.getView(); + LayoutParams lp = (LayoutParams) view.getLayoutParams(); + view.layout( + this.getPaddingLeft() + line.getX() + child.getInlineX() + lp.leftMargin, + this.getPaddingTop() + line.getY() + child.getInlineY() + lp.topMargin, + this.getPaddingLeft() + line.getX() + child.getInlineX() + lp.leftMargin + child.getWidth(), + this.getPaddingTop() + line.getY() + child.getInlineY() + lp.topMargin + child.getHeight() + ); + } + } + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + boolean more = super.drawChild(canvas, child, drawingTime); + this.drawDebugInfo(canvas, child); + return more; + } + + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof LayoutParams; + } + + @Override + protected LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + } + + @Override + public LayoutParams generateLayoutParams(AttributeSet attributeSet) { + return new LayoutParams(this.getContext(), attributeSet); + } + + @Override + protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { + return new LayoutParams(p); + } + + private void drawDebugInfo(Canvas canvas, View child) { + if (!isDebugDraw()) { + return; + } + + Paint childPaint = this.createPaint(0xffffff00); + Paint newLinePaint = this.createPaint(0xffff0000); + + LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + if (lp.rightMargin > 0) { + float x = child.getRight(); + float y = child.getTop() + child.getHeight() / 2.0f; + canvas.drawLine(x, y, x + lp.rightMargin, y, childPaint); + canvas.drawLine(x + lp.rightMargin - 4.0f, y - 4.0f, x + lp.rightMargin, y, childPaint); + canvas.drawLine(x + lp.rightMargin - 4.0f, y + 4.0f, x + lp.rightMargin, y, childPaint); + } + + if (lp.leftMargin > 0) { + float x = child.getLeft(); + float y = child.getTop() + child.getHeight() / 2.0f; + canvas.drawLine(x, y, x - lp.leftMargin, y, childPaint); + canvas.drawLine(x - lp.leftMargin + 4.0f, y - 4.0f, x - lp.leftMargin, y, childPaint); + canvas.drawLine(x - lp.leftMargin + 4.0f, y + 4.0f, x - lp.leftMargin, y, childPaint); + } + + if (lp.bottomMargin > 0) { + float x = child.getLeft() + child.getWidth() / 2.0f; + float y = child.getBottom(); + canvas.drawLine(x, y, x, y + lp.bottomMargin, childPaint); + canvas.drawLine(x - 4.0f, y + lp.bottomMargin - 4.0f, x, y + lp.bottomMargin, childPaint); + canvas.drawLine(x + 4.0f, y + lp.bottomMargin - 4.0f, x, y + lp.bottomMargin, childPaint); + } + + if (lp.topMargin > 0) { + float x = child.getLeft() + child.getWidth() / 2.0f; + float y = child.getTop(); + canvas.drawLine(x, y, x, y - lp.topMargin, childPaint); + canvas.drawLine(x - 4.0f, y - lp.topMargin + 4.0f, x, y - lp.topMargin, childPaint); + canvas.drawLine(x + 4.0f, y - lp.topMargin + 4.0f, x, y - lp.topMargin, childPaint); + } + + if (lp.isNewLine()) { + if (this.config.getOrientation() == CommonLogic.HORIZONTAL) { + float x = child.getLeft(); + float y = child.getTop() + child.getHeight() / 2.0f; + canvas.drawLine(x, y - 6.0f, x, y + 6.0f, newLinePaint); + } else { + float x = child.getLeft() + child.getWidth() / 2.0f; + float y = child.getTop(); + canvas.drawLine(x - 6.0f, y, x + 6.0f, y, newLinePaint); + } + } + } + + private Paint createPaint(int color) { + Paint paint = new Paint(); + paint.setAntiAlias(true); + paint.setColor(color); + paint.setStrokeWidth(2.0f); + return paint; + } + + public int getOrientation() { + return this.config.getOrientation(); + } + + public void setOrientation(int orientation) { + this.config.setOrientation(orientation); + this.requestLayout(); + } + + public boolean isDebugDraw() { + return this.config.isDebugDraw() || debugDraw(); + } + + public void setDebugDraw(boolean debugDraw) { + this.config.setDebugDraw(debugDraw); + this.invalidate(); + } + + private boolean debugDraw() { + try { + // android add this method at 4.1 + Method m = ViewGroup.class.getDeclaredMethod("debugDraw", (Class[]) null); + m.setAccessible(true); + return (boolean) m.invoke(this, new Object[]{null}); + } catch (Exception e) { + // if no such method (android not support this at lower api level), return false + // ignore this, it's safe here + } + + return false; + } + + public float getWeightDefault() { + return this.config.getWeightDefault(); + } + + public void setWeightDefault(float weightDefault) { + this.config.setWeightDefault(weightDefault); + this.requestLayout(); + } + + public int getGravity() { + return this.config.getGravity(); + } + + public void setGravity(int gravity) { + this.config.setGravity(gravity); + this.requestLayout(); + } + + @Override + public int getLayoutDirection() { + if (this.config == null) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + return View.LAYOUT_DIRECTION_LTR; + } else { + return super.getLayoutDirection(); + } + } + + //noinspection ResourceType + return this.config.getLayoutDirection(); + } + + @Override + public void setLayoutDirection(int layoutDirection) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + super.setLayoutDirection(layoutDirection); + } + + //noinspection ResourceType + if (this.config.getLayoutDirection() != layoutDirection) { + this.config.setLayoutDirection(layoutDirection); + requestLayout(); + } + } + + public int getMaxLines() { + return this.config.getMaxLines(); + } + + public void setMaxLines(int maxLines) { + this.config.setMaxLines(maxLines); + this.requestLayout(); + } + + public static class LayoutParams extends MarginLayoutParams { + @ViewDebug.ExportedProperty(mapping = { + @ViewDebug.IntToString(from = Gravity.NO_GRAVITY, to = "NONE"), + @ViewDebug.IntToString(from = Gravity.TOP, to = "TOP"), + @ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"), + @ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"), + @ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"), + @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"), + @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"), + @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"), + @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL, to = "FILL_HORIZONTAL"), + @ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"), + @ViewDebug.IntToString(from = Gravity.FILL, to = "FILL") + }) + + private boolean newLine = false; + private int gravity = Gravity.NO_GRAVITY; + private float weight = -1.0f; + + public LayoutParams(Context context, AttributeSet attributeSet) { + super(context, attributeSet); + this.readStyleParameters(context, attributeSet); + } + + public LayoutParams(int width, int height) { + super(width, height); + } + + public LayoutParams(ViewGroup.LayoutParams layoutParams) { + super(layoutParams); + } + + private void readStyleParameters(Context context, AttributeSet attributeSet) { + TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.FlowLayout_LayoutParams); + try { + this.newLine = a.getBoolean(R.styleable.FlowLayout_LayoutParams_layout_newLine, false); + this.gravity = a.getInt(R.styleable.FlowLayout_LayoutParams_android_layout_gravity, Gravity.NO_GRAVITY); + this.weight = a.getFloat(R.styleable.FlowLayout_LayoutParams_layout_weight, -1.0f); + } finally { + a.recycle(); + } + } + + public int getGravity() { + return gravity; + } + + public void setGravity(int gravity) { + this.gravity = gravity; + } + + public float getWeight() { + return weight; + } + + public void setWeight(float weight) { + this.weight = weight; + } + + public boolean isNewLine() { + return newLine; + } + + public void setNewLine(boolean newLine) { + this.newLine = newLine; + } + } +} diff --git a/flowlayout/layouts/src/main/java/org/apmem/tools/layouts/FlowLayoutManager.java b/flowlayout/layouts/src/main/java/org/apmem/tools/layouts/FlowLayoutManager.java new file mode 100644 index 0000000..a8a265b --- /dev/null +++ b/flowlayout/layouts/src/main/java/org/apmem/tools/layouts/FlowLayoutManager.java @@ -0,0 +1,175 @@ +package org.apmem.tools.layouts; + + +public class FlowLayoutManager/* extends RecyclerView.LayoutManager*/ { +/* + private final ConfigDefinition config; + List lines = new ArrayList<>(); + List views = new ArrayList<>(); + + public FlowLayoutManager(ConfigDefinition config) { + this.config = config; + } + + public FlowLayoutManager() { + this.config = new ConfigDefinition(); + } + + @Override + public boolean checkLayoutParams(RecyclerView.LayoutParams lp) { + return super.checkLayoutParams(lp); + } + + @Override + public RecyclerView.LayoutParams generateDefaultLayoutParams() { + return null; + } + + @Override + public RecyclerView.LayoutParams generateLayoutParams(Context c, AttributeSet attrs) { + return new LayoutParams(c, attrs); + } + + @Override + public RecyclerView.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { + return new LayoutParams(p); + } + + @Override + public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { + detachAndScrapAttachedViews(recycler); + + final int count = this.getItemCount(); + views.clear(); + lines.clear(); + for (int i = 0; i < count; i++) { + View child = recycler.getViewForPosition(i); + addView(child); + measureChildWithMargins(child, 0, 0); + + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + ViewDefinition view = new ViewDefinition(this.config, child); + view.setWidth(child.getMeasuredWidth()); + view.setHeight(child.getMeasuredHeight()); + view.setNewLine(lp.isNewLine()); + view.setGravity(lp.getGravity()); + view.setWeight(lp.getWeight()); + view.setMargins(lp.leftMargin, lp.topMargin, lp.rightMargin, lp.bottomMargin); + views.add(view); + } + + this.config.setMaxWidth(this.getWidth() - this.getPaddingRight() - this.getPaddingLeft()); + this.config.setMaxHeight(this.getHeight() - this.getPaddingTop() - this.getPaddingBottom()); + this.config.setWidthMode(View.MeasureSpec.EXACTLY); + this.config.setHeightMode(View.MeasureSpec.EXACTLY); + this.config.setCheckCanFit(true); + + CommonLogic.fillLines(views, lines, config); + CommonLogic.calculateLinesAndChildPosition(lines); + + int contentLength = 0; + final int linesCount = lines.size(); + for (int i = 0; i < linesCount; i++) { + LineDefinition l = lines.get(i); + contentLength = Math.max(contentLength, l.getLineLength()); + } + + LineDefinition currentLine = lines.get(lines.size() - 1); + int contentThickness = currentLine.getLineStartThickness() + currentLine.getLineThickness(); + int realControlLength = CommonLogic.findSize(this.config.getLengthMode(), this.config.getMaxLength(), contentLength); + int realControlThickness = CommonLogic.findSize(this.config.getThicknessMode(), this.config.getMaxThickness(), contentThickness); + + CommonLogic.applyGravityToLines(lines, realControlLength, realControlThickness, config); + + for (int i = 0; i < linesCount; i++) { + LineDefinition line = lines.get(i); + applyPositionsToViews(line); + } + } + + private void applyPositionsToViews(LineDefinition line) { + final List childViews = line.getViews(); + final int childCount = childViews.size(); + for (int i = 0; i < childCount; i++) { + final ViewDefinition child = childViews.get(i); + final View view = child.getView(); + measureChildWithMargins(view, child.getWidth(), child.getHeight()); + + layoutDecorated(view, + this.getPaddingLeft() + line.getLineStartLength() + child.getInlineStartLength(), + this.getPaddingTop() + line.getLineStartThickness() + child.getInlineStartThickness(), + this.getPaddingLeft() + line.getLineStartLength() + child.getInlineStartLength() + child.getWidth(), + this.getPaddingTop() + line.getLineStartThickness() + child.getInlineStartThickness() + child.getHeight() + ); + } + } + + public static class LayoutParams extends RecyclerView.LayoutParams { + @ViewDebug.ExportedProperty(mapping = { + @ViewDebug.IntToString(from = Gravity.NO_GRAVITY, to = "NONE"), + @ViewDebug.IntToString(from = Gravity.TOP, to = "TOP"), + @ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"), + @ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"), + @ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"), + @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"), + @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"), + @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"), + @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL, to = "FILL_HORIZONTAL"), + @ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"), + @ViewDebug.IntToString(from = Gravity.FILL, to = "FILL") + }) + + private boolean newLine = false; + private int gravity = Gravity.NO_GRAVITY; + private float weight = -1.0f; + + public LayoutParams(Context context, AttributeSet attributeSet) { + super(context, attributeSet); + this.readStyleParameters(context, attributeSet); + } + + public LayoutParams(ViewGroup.LayoutParams layoutParams) { + super(layoutParams); + } + + public LayoutParams(int width, int height) { + super(width, height); + } + + private void readStyleParameters(Context context, AttributeSet attributeSet) { + TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.FlowLayout_LayoutParams); + try { + this.newLine = a.getBoolean(R.styleable.FlowLayout_LayoutParams_layout_newLine, false); + this.gravity = a.getInt(R.styleable.FlowLayout_LayoutParams_android_layout_gravity, Gravity.NO_GRAVITY); + this.weight = a.getFloat(R.styleable.FlowLayout_LayoutParams_layout_weight, -1.0f); + } finally { + a.recycle(); + } + } + + public int getGravity() { + return gravity; + } + + public void setGravity(int gravity) { + this.gravity = gravity; + } + + public float getWeight() { + return weight; + } + + public void setWeight(float weight) { + this.weight = weight; + } + + public boolean isNewLine() { + return newLine; + } + + public void setNewLine(boolean newLine) { + this.newLine = newLine; + } + }*/ +} \ No newline at end of file diff --git a/flowlayout/layouts/src/main/java/org/apmem/tools/layouts/logic/CommonLogic.java b/flowlayout/layouts/src/main/java/org/apmem/tools/layouts/logic/CommonLogic.java new file mode 100644 index 0000000..c32d7c4 --- /dev/null +++ b/flowlayout/layouts/src/main/java/org/apmem/tools/layouts/logic/CommonLogic.java @@ -0,0 +1,237 @@ +package org.apmem.tools.layouts.logic; + +import android.graphics.Rect; +import android.view.Gravity; +import android.view.View; + +import java.util.List; + +public class CommonLogic { + public static final int HORIZONTAL = 0; + public static final int VERTICAL = 1; + + public static void calculateLinesAndChildPosition(List lines) { + int prevLinesThickness = 0; + final int linesCount = lines.size(); + for (int i = 0; i < linesCount; i++) { + final LineDefinition line = lines.get(i); + line.setLineStartThickness(prevLinesThickness); + prevLinesThickness += line.getLineThickness(); + int prevChildThickness = 0; + final List childViews = line.getViews(); + final int childCount = childViews.size(); + for (int j = 0; j < childCount; j++) { + ViewDefinition child = childViews.get(j); + child.setInlineStartLength(prevChildThickness); + prevChildThickness += child.getLength() + child.getSpacingLength(); + } + } + } + + public static void applyGravityToLines(List lines, int realControlLength, int realControlThickness, ConfigDefinition config) { + final int linesCount = lines.size(); + if (linesCount <= 0) { + return; + } + + int remainingWeight = linesCount; + LineDefinition lastLine = lines.get(linesCount - 1); + int excessThickness = realControlThickness - (lastLine.getLineThickness() + lastLine.getLineStartThickness()); + + if (excessThickness < 0) { + excessThickness = 0; + } + + int excessOffset = 0; + for (int i = 0; i < linesCount; i++) { + final LineDefinition child = lines.get(i); + int weight = 1; + int gravity = getGravity(null, config); + int extraThickness = Math.round(excessThickness * weight / remainingWeight); + + excessThickness -= extraThickness; + remainingWeight -= weight; + + final int childLength = child.getLineLength(); + final int childThickness = child.getLineThickness(); + + Rect container = new Rect(); + container.top = excessOffset; + container.left = 0; + container.right = realControlLength; + container.bottom = childThickness + extraThickness + excessOffset; + + Rect result = new Rect(); + Gravity.apply(gravity, childLength, childThickness, container, result); + + excessOffset += extraThickness; + child.setLineStartLength(child.getLineStartLength() + result.left); + child.setLineStartThickness(child.getLineStartThickness() + result.top); + child.setLength(result.width()); + child.setThickness(result.height()); + + applyGravityToLine(child, config); + } + } + + public static void applyGravityToLine(LineDefinition line, ConfigDefinition config) { + final List views = line.getViews(); + final int viewCount = views.size(); + if (viewCount <= 0) { + return; + } + + float remainingWeight = 0; + for (int i = 0; i < viewCount; i++) { + final ViewDefinition child = views.get(i); + remainingWeight += getWeight(child, config); + } + final boolean weightBased = remainingWeight > 0; + + ViewDefinition lastChild = views.get(viewCount - 1); + int excessLengthRemaining = line.getLineLength() - (lastChild.getLength() + lastChild.getSpacingLength() + lastChild.getInlineStartLength()); + int excessOffset = 0; + for (int i = 0; i < viewCount; i++) { + final ViewDefinition child = views.get(i); + float weight = getWeight(child, config); + int gravity = getGravity(child, config); + int extraLength; + if (!weightBased) { + extraLength = excessLengthRemaining / (viewCount - i); + } else { + extraLength = Math.round(excessLengthRemaining * weight / remainingWeight); + remainingWeight -= weight; + } + excessLengthRemaining -= extraLength; + + final int childLength = child.getLength() + child.getSpacingLength(); + final int childThickness = child.getThickness() + child.getSpacingThickness(); + + Rect container = new Rect(); + container.top = 0; + container.left = excessOffset; + container.right = childLength + extraLength + excessOffset; + container.bottom = line.getLineThickness(); + + Rect result = new Rect(); + Gravity.apply(gravity, childLength, childThickness, container, result); + + excessOffset += extraLength; + child.setInlineStartLength(result.left + child.getInlineStartLength()); + child.setInlineStartThickness(result.top); + child.setLength(result.width() - child.getSpacingLength()); + child.setThickness(result.height() - child.getSpacingThickness()); + } + } + + public static int findSize(int modeSize, int controlMaxSize, int contentSize) { + int realControlSize; + switch (modeSize) { + /* duplicate of default + case View.MeasureSpec.UNSPECIFIED: + realControlSize = contentSize; + break; + */ + case View.MeasureSpec.AT_MOST: + realControlSize = Math.min(contentSize, controlMaxSize); + break; + case View.MeasureSpec.EXACTLY: + realControlSize = controlMaxSize; + break; + default: + realControlSize = contentSize; + break; + } + return realControlSize; + } + + private static float getWeight(ViewDefinition child, ConfigDefinition config) { + return child.weightSpecified() ? child.getWeight() : config.getWeightDefault(); + } + + + private static int getGravity(ViewDefinition child, ConfigDefinition config) { + int parentGravity = config.getGravity(); + + int childGravity; + // get childGravity of child view (if exists) + if (child != null && child.gravitySpecified()) { + childGravity = child.getGravity(); + } else { + childGravity = parentGravity; + } + + childGravity = getGravityFromRelative(childGravity, config); + parentGravity = getGravityFromRelative(parentGravity, config); + + // add parent gravity to child gravity if child gravity is not specified + if ((childGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) { + childGravity |= parentGravity & Gravity.HORIZONTAL_GRAVITY_MASK; + } + if ((childGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { + childGravity |= parentGravity & Gravity.VERTICAL_GRAVITY_MASK; + } + + // if childGravity is still not specified - set default top - left gravity + if ((childGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) { + childGravity |= Gravity.START; + } + if ((childGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { + childGravity |= Gravity.TOP; + } + + return childGravity; + } + + + public static int getGravityFromRelative(int childGravity, ConfigDefinition config) { + // swap directions for vertical non relative view + // if it is relative, then START is TOP, and we do not need to switch it here. + // it will be switched later on onMeasure stage when calculations will be with length and thickness + if (config.getOrientation() == CommonLogic.VERTICAL && (childGravity & Gravity.RELATIVE_LAYOUT_DIRECTION) == 0) { + int horizontalGravity = childGravity; + childGravity = 0; + childGravity |= (horizontalGravity & Gravity.HORIZONTAL_GRAVITY_MASK) >> Gravity.AXIS_X_SHIFT << Gravity.AXIS_Y_SHIFT; + childGravity |= (horizontalGravity & Gravity.VERTICAL_GRAVITY_MASK) >> Gravity.AXIS_Y_SHIFT << Gravity.AXIS_X_SHIFT; + } + + // for relative layout and RTL direction swap left and right gravity + if (config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL && (childGravity & Gravity.RELATIVE_LAYOUT_DIRECTION) != 0) { + int ltrGravity = childGravity; + childGravity = 0; + childGravity |= (ltrGravity & Gravity.START) == Gravity.START ? Gravity.END : 0; + childGravity |= (ltrGravity & Gravity.END) == Gravity.END ? Gravity.START : 0; + } + + return childGravity; + } + + public static void fillLines(List views, List lines, ConfigDefinition config) { + LineDefinition currentLine = new LineDefinition(config); + lines.add(currentLine); + final int count = views.size(); + for (int i = 0; i < count; i++) { + final ViewDefinition child = views.get(i); + + boolean newLine = child.isNewLine() || (config.isCheckCanFit() && !currentLine.canFit(child)); + + if (newLine && config.getMaxLines() > 0 && lines.size() == config.getMaxLines()) + break; + + if (newLine) { + currentLine = new LineDefinition(config); + if (config.getOrientation() == CommonLogic.VERTICAL && config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) { + lines.add(0, currentLine); + } else { + lines.add(currentLine); + } + } + + if (config.getOrientation() == CommonLogic.HORIZONTAL && config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) { + currentLine.addView(0, child); + } else { + currentLine.addView(child); + } + } + } +} diff --git a/flowlayout/layouts/src/main/java/org/apmem/tools/layouts/logic/ConfigDefinition.java b/flowlayout/layouts/src/main/java/org/apmem/tools/layouts/logic/ConfigDefinition.java new file mode 100644 index 0000000..7d1a4a8 --- /dev/null +++ b/flowlayout/layouts/src/main/java/org/apmem/tools/layouts/logic/ConfigDefinition.java @@ -0,0 +1,124 @@ +package org.apmem.tools.layouts.logic; + +import android.view.Gravity; +import android.view.View; + +public class ConfigDefinition { + private int orientation; + private boolean debugDraw; + private float weightDefault; + private int gravity; + private int layoutDirection; + private int maxWidth; + private int maxHeight; + private boolean checkCanFit; + private int widthMode; + private int heightMode; + private int maxLines; + + public ConfigDefinition() { + this.setOrientation(CommonLogic.HORIZONTAL); + this.setDebugDraw(false); + this.setWeightDefault(0.0f); + this.setGravity(Gravity.NO_GRAVITY); + this.setLayoutDirection(View.LAYOUT_DIRECTION_LTR); + this.setCheckCanFit(true); + this.setMaxLines(0); + } + + public int getOrientation() { + return this.orientation; + } + + public void setOrientation(int orientation) { + if (orientation == CommonLogic.VERTICAL) { + this.orientation = orientation; + } else { + this.orientation = CommonLogic.HORIZONTAL; + } + } + + public boolean isDebugDraw() { + return this.debugDraw; + } + + public void setDebugDraw(boolean debugDraw) { + this.debugDraw = debugDraw; + } + + public float getWeightDefault() { + return this.weightDefault; + } + + public void setWeightDefault(float weightDefault) { + this.weightDefault = Math.max(0, weightDefault); + } + + public int getGravity() { + return this.gravity; + } + + public void setGravity(int gravity) { + this.gravity = gravity; + } + + public int getLayoutDirection() { + return layoutDirection; + } + + public void setLayoutDirection(int layoutDirection) { + if (layoutDirection == View.LAYOUT_DIRECTION_RTL) { + this.layoutDirection = layoutDirection; + } else { + this.layoutDirection = View.LAYOUT_DIRECTION_LTR; + } + } + + public void setMaxWidth(int maxWidth) { + this.maxWidth = maxWidth; + } + + public void setMaxHeight(int maxHeight) { + this.maxHeight = maxHeight; + } + + public int getMaxLength() { + return this.orientation == CommonLogic.HORIZONTAL ? this.maxWidth : this.maxHeight; + } + + public int getMaxThickness() { + return this.orientation == CommonLogic.HORIZONTAL ? this.maxHeight : this.maxWidth; + } + + public void setCheckCanFit(boolean checkCanFit) { + this.checkCanFit = checkCanFit; + } + + public boolean isCheckCanFit() { + return checkCanFit; + } + + public void setWidthMode(int widthMode) { + this.widthMode = widthMode; + } + + public void setHeightMode(int heightMode) { + this.heightMode = heightMode; + } + + public int getLengthMode() { + return this.orientation == CommonLogic.HORIZONTAL ? this.widthMode : this.heightMode; + } + + public int getThicknessMode() { + return this.orientation == CommonLogic.HORIZONTAL ? this.heightMode : this.widthMode; + } + + public int getMaxLines() { + return this.maxLines; + } + + public void setMaxLines(int maxLines) { + this.maxLines = maxLines; + } +} diff --git a/flowlayout/layouts/src/main/java/org/apmem/tools/layouts/logic/LineDefinition.java b/flowlayout/layouts/src/main/java/org/apmem/tools/layouts/logic/LineDefinition.java new file mode 100644 index 0000000..7ed258d --- /dev/null +++ b/flowlayout/layouts/src/main/java/org/apmem/tools/layouts/logic/LineDefinition.java @@ -0,0 +1,77 @@ +package org.apmem.tools.layouts.logic; + +import java.util.ArrayList; +import java.util.List; + +public class LineDefinition { + private final List views = new ArrayList<>(); + private final ConfigDefinition config; + private int lineLength; + private int lineThickness; + private int lineStartThickness; + private int lineStartLength; + + public LineDefinition(ConfigDefinition config) { + this.config = config; + this.lineStartThickness = 0; + this.lineStartLength = 0; + } + + public void addView(ViewDefinition child) { + this.addView(this.views.size(), child); + } + + public void addView(int i, ViewDefinition child) { + this.views.add(i, child); + + this.lineLength = this.lineLength + child.getLength() + child.getSpacingLength(); + this.lineThickness = Math.max(this.lineThickness, child.getThickness() + child.getSpacingThickness()); + } + + public boolean canFit(ViewDefinition child) { + return lineLength + child.getLength() + child.getSpacingLength() <= config.getMaxLength(); + } + + public int getLineStartThickness() { + return lineStartThickness; + } + + public void setLineStartThickness(int lineStartThickness) { + this.lineStartThickness = lineStartThickness; + } + + public int getLineThickness() { + return lineThickness; + } + + public int getLineLength() { + return lineLength; + } + + public int getLineStartLength() { + return lineStartLength; + } + + public void setLineStartLength(int lineStartLength) { + this.lineStartLength = lineStartLength; + } + + public List getViews() { + return views; + } + + public void setThickness(int thickness) { + this.lineThickness = thickness; + } + + public void setLength(int length) { + this.lineLength = length; + } + + public int getX() { + return this.config.getOrientation() == CommonLogic.HORIZONTAL ? this.lineStartLength : this.lineStartThickness; + } + public int getY() { + return this.config.getOrientation() == CommonLogic.HORIZONTAL ? this.lineStartThickness : this.lineStartLength; + } +} \ No newline at end of file diff --git a/flowlayout/layouts/src/main/java/org/apmem/tools/layouts/logic/ViewDefinition.java b/flowlayout/layouts/src/main/java/org/apmem/tools/layouts/logic/ViewDefinition.java new file mode 100644 index 0000000..3506e4c --- /dev/null +++ b/flowlayout/layouts/src/main/java/org/apmem/tools/layouts/logic/ViewDefinition.java @@ -0,0 +1,140 @@ +package org.apmem.tools.layouts.logic; + +import android.view.Gravity; +import android.view.View; + +public class ViewDefinition { + private final ConfigDefinition config; + private final View view; + private int inlineStartLength; + private float weight; + private int gravity; + private boolean newLine; + private int inlineStartThickness; + private int width; + private int height; + + private int leftMargin; + private int topMargin; + private int rightMargin; + private int bottomMargin; + + public ViewDefinition(ConfigDefinition config, View child) { + this.config = config; + this.view = child; + } + + public int getLength() { + return this.config.getOrientation() == CommonLogic.HORIZONTAL ? width : height; + } + + public void setLength(int length) { + if (this.config.getOrientation() == CommonLogic.HORIZONTAL) { + width = length; + } else { + height = length; + } + } + + public int getSpacingLength() { + return this.config.getOrientation() == CommonLogic.HORIZONTAL ? this.leftMargin + this.rightMargin : this.topMargin + this.bottomMargin; + } + + public int getThickness() { + return this.config.getOrientation() == CommonLogic.HORIZONTAL ? height : width; + } + + public void setThickness(int thickness) { + if (this.config.getOrientation() == CommonLogic.HORIZONTAL) { + height = thickness; + } else { + width = thickness; + } + } + + public int getSpacingThickness() { + return this.config.getOrientation() == CommonLogic.HORIZONTAL ? this.topMargin + this.bottomMargin : this.leftMargin + this.rightMargin; + } + + public float getWeight() { + return weight; + } + + public void setWeight(float weight) { + this.weight = weight; + } + + public boolean weightSpecified() { + return this.weight >= 0; + } + + public int getInlineStartLength() { + return inlineStartLength; + } + + public void setInlineStartLength(int inlineStartLength) { + this.inlineStartLength = inlineStartLength; + } + + public boolean gravitySpecified() { + return gravity != Gravity.NO_GRAVITY; + } + + public int getGravity() { + return gravity; + } + + public void setGravity(int gravity) { + this.gravity = gravity; + } + + public boolean isNewLine() { + return newLine; + } + + public void setNewLine(boolean newLine) { + this.newLine = newLine; + } + + public View getView() { + return view; + } + + public int getWidth() { + return width; + } + + public void setWidth(int width) { + this.width = width; + } + + public int getHeight() { + return height; + } + + public void setHeight(int height) { + this.height = height; + } + + public int getInlineStartThickness() { + return inlineStartThickness; + } + + public void setInlineStartThickness(int inlineStartThickness) { + this.inlineStartThickness = inlineStartThickness; + } + + public void setMargins(int leftMargin, int topMargin, int rightMargin, int bottomMargin) { + this.leftMargin = leftMargin; + this.topMargin = topMargin; + this.rightMargin = rightMargin; + this.bottomMargin = bottomMargin; + } + + public int getInlineX() { + return this.config.getOrientation() == CommonLogic.HORIZONTAL ? this.inlineStartLength : this.inlineStartThickness; + } + public int getInlineY() { + return this.config.getOrientation() == CommonLogic.HORIZONTAL ? this.inlineStartThickness : this.inlineStartLength; + } +} diff --git a/flowlayout/layouts/src/main/res/values/attrs.xml b/flowlayout/layouts/src/main/res/values/attrs.xml new file mode 100644 index 0000000..2784876 --- /dev/null +++ b/flowlayout/layouts/src/main/res/values/attrs.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..e0d6560 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,30 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# +# +org.gradle.parallel=true +org.gradle.jvmargs=-Xmx1024m -Dfile.encoding=UTF-8 +android.useAndroidX=false +android.enableJetifier=false +#exerimental +#android.enableR8=true +#deprecated +android.enableR8.fullMode=true +android.enableResourceOptimizations=true +#enable +android.nonTransitiveRClass=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..f6b961f Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..bbd85d4 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Mar 23 13:07:03 IST 2021 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..cccdd3d --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +: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%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..1d0b3ce --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +include ':app' +include ':flowlayout:layouts'